diff --git a/.github/workflows/benchmark_models.yml b/.github/workflows/benchmark_models.yml index aa2ac65b2..21bdb8520 100644 --- a/.github/workflows/benchmark_models.yml +++ b/.github/workflows/benchmark_models.yml @@ -1,7 +1,7 @@ # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions # https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables name: Test benchmark collection models -on: [push] +on: [push, pull_request, workflow_dispatch] jobs: container: runs-on: ubuntu-latest @@ -10,9 +10,9 @@ jobs: steps: - uses: actions/checkout@master - - run: echo "::set-env name=PARPE_BASE::$(pwd)" - - run: echo "::set-env name=PARPE_BUILD::${PARPE_BASE}/build" - - run: echo "::set-env name=AMICI_PATH::${PARPE_BASE}/deps/AMICI/" + - run: echo "PARPE_BASE=$(pwd)" >> $GITHUB_ENV + - run: echo "PARPE_BUILD=${PARPE_BASE}/build" >> $GITHUB_ENV + - run: echo "AMICI_PATH=${PARPE_BASE}/deps/AMICI/" >> $GITHUB_ENV # Build dependencies diff --git a/.github/workflows/deploy_dockerhub.yml b/.github/workflows/deploy_dockerhub.yml index c75f70b28..2891a70cb 100644 --- a/.github/workflows/deploy_dockerhub.yml +++ b/.github/workflows/deploy_dockerhub.yml @@ -1,6 +1,6 @@ # https://github.com/marketplace/actions/publish-docker name: Deploy to dockerhub -on: [push] +on: [push, workflow_dispatch] jobs: build: name: Deploy to dockerhub diff --git a/.github/workflows/parpe_tests.yml b/.github/workflows/parpe_tests.yml index be4f59a1f..73729cfdb 100644 --- a/.github/workflows/parpe_tests.yml +++ b/.github/workflows/parpe_tests.yml @@ -1,28 +1,32 @@ # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions # https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables name: parPE tests -on: [push] +on: [push, pull_request, workflow_dispatch] jobs: container: runs-on: ubuntu-latest container: dweindl/parpeci:1511078 name: parPE tests + env: + # mpiexec prefix for running tests + # If we are running in docker, we generally don't have SYS_PTRACE + # permissions and thus, cannot use vader. Also disable Infiniband. + PARPE_TESTS_MPIEXEC: mpiexec -n 5 --oversubscribe --allow-run-as-root --mca btl_vader_single_copy_mechanism none --mca btl ^openib --mca oob_tcp_if_include lo --mca btl_tcp_if_include lo --mca orte_base_help_aggregate 0 + steps: - uses: actions/checkout@master - with: - fetch-depth: 42 + - run: git fetch --prune --unshallow - - - run: echo "::set-env name=PARPE_BASE::$(pwd)" - - run: echo "::set-env name=PARPE_BUILD::${PARPE_BASE}/build" - - run: echo "::set-env name=AMICI_PATH::${PARPE_BASE}/deps/AMICI/" + - run: echo "PARPE_BASE=$(pwd)" >> $GITHUB_ENV + - run: echo "PARPE_BUILD=${PARPE_BASE}/build" >> $GITHUB_ENV + - run: echo "AMICI_PATH=${PARPE_BASE}/deps/AMICI/" >> $GITHUB_ENV # sonar cloud - - run: echo "::set-env name=SONAR_SCANNER_VERSION::4.2.0.1873" - - run: echo "::set-env name=SONAR_SCANNER_HOME::/root/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux" - - run: echo "::set-env name=SONAR_SCANNER_OPTS::-server" - - run: echo "::add-path::${SONAR_SCANNER_HOME}/bin" - - run: echo "::add-path::/root/.sonar/build-wrapper-linux-x86" + - run: echo "SONAR_SCANNER_VERSION=4.2.0.1873" >> $GITHUB_ENV + - run: echo "SONAR_SCANNER_HOME=/root/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux" >> $GITHUB_ENV + - run: echo "SONAR_SCANNER_OPTS=-server" >> $GITHUB_ENV + - run: echo "${SONAR_SCANNER_HOME}/bin" >> $GITHUB_PATH + - run: echo "/root/.sonar/build-wrapper-linux-x86" >> $GITHUB_PATH - name: Info run: lsb_release -a && printenv @@ -83,7 +87,7 @@ jobs: && $PARPE_BASE/misc/run_in_venv.sh $PARPE_BASE/build/venv \ pytest \ --cov-report=xml:$PARPE_BUILD/coverage_py.xml \ - --cov=./ \ + --cov=parpe --cov-append \ $PARPE_BASE/python/tests/ # Redundant with parpe_coverage_cobertura @@ -96,6 +100,13 @@ jobs: && CTEST_OUTPUT_ON_FAILURE=1 make parpe_coverage \ && make ExperimentalCoverage + - name: Cache sonar files + id: cache-sonar + uses: actions/cache@v1 + with: + path: sonar_cache + key: ${{ runner.os }}-sonar_cache + - name: Run sonar-scanner env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -104,6 +115,10 @@ jobs: -Dsonar.cfamily.build-wrapper-output=bw-output \ -Dsonar.projectVersion="$(git describe --abbrev=4 --dirty=-dirty --always --tags | tr -d '\n')" + - name: Run example notebooks + run: | + misc/run_notebook.sh examples/parpeamici/steadystate/parpeExampleSteadystateBasic.ipynb examples/parpeamici/steadystate/parpeExampleSteadystateHierarchical.ipynb + - name: Run valgrind run: | cd ${PARPE_BUILD} \ diff --git a/.github/workflows/petab_testsuite.yml b/.github/workflows/petab_testsuite.yml index fda6c7fa3..6c4c7ded0 100644 --- a/.github/workflows/petab_testsuite.yml +++ b/.github/workflows/petab_testsuite.yml @@ -2,7 +2,7 @@ # https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables name: PEtab test suite -on: [push] +on: [push, pull_request, workflow_dispatch] jobs: container: runs-on: ubuntu-latest @@ -11,9 +11,9 @@ jobs: steps: - uses: actions/checkout@master - - run: echo "::set-env name=PARPE_BASE::$(pwd)" - - run: echo "::set-env name=PARPE_BUILD::${PARPE_BASE}/build" - - run: echo "::set-env name=AMICI_PATH::${PARPE_BASE}/deps/AMICI/" + - run: echo "PARPE_BASE=$(pwd)" >> $GITHUB_ENV + - run: echo "PARPE_BUILD=${PARPE_BASE}/build" >> $GITHUB_ENV + - run: echo "AMICI_PATH=${PARPE_BASE}/deps/AMICI/" >> $GITHUB_ENV # Build dependencies diff --git a/.gitignore b/.gitignore index 6f22485a7..7eaf7174f 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,11 @@ python/test_*.png # breathe-generatd files doc/source/api/ + +# test files +tests/petab-test-suite/ test_*.png + +# containers +/container/charliecloud/parpe_base/parpe.tar.gz +*.sif diff --git a/CMakeLists.txt b/CMakeLists.txt index febec1e64..ec35454c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ project(parpe) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMakeModules/") -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) include(BuildType) # Ensure CMAKE_BUILD_TYPE is always set @@ -20,9 +20,9 @@ include(CTest) set(CMAKE_DEBUG_POSTFIX "-dbg") # -D_GNU_SOURCE for pthread recursive mutex set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} \ - -std=c99 -Wall -Wno-unused-function -fopenmp -D_GNU_SOURCE") + -std=c99 -Wall -Wno-unused-function -D_GNU_SOURCE") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \ - -std=c++11 -Wall -Wno-unused-function -fopenmp -D_GNU_SOURCE") + -Wall -Wno-unused-function -D_GNU_SOURCE") if(BUILD_PYTHON_MODULE) # Build PIC code to be used for swig/python module @@ -57,9 +57,6 @@ set(IPOPT_INCLUDE_DIRS "${IPOPT_DIR}/include/coin/" set(IPOPT_LIBRARIES "${IPOPT_DIR}/lib/libipopt.a" "${IPOPT_DIR}/lib/libcoinhsl.a" "gfortran" CACHE STRING "IpOpt library") -set(CERES_INCLUDE_DIRS "" "/usr/include/eigen3" - CACHE PATH "CERES include directories") -set(CERES_LIBRARIES "" CACHE STRING "CERES libraries") set(PARPE_ENABLE_IPOPT TRUE CACHE BOOL "Enable ipopt optimizer?") set(PARPE_ENABLE_CERES TRUE CACHE BOOL "Enable ceres optimizer?") set(PARPE_ENABLE_DLIB FALSE CACHE BOOL "Enable dlib optimizers?") @@ -68,6 +65,9 @@ set(PARPE_ENABLE_FSQP FALSE CACHE BOOL "Enable FSQP optimizer?") set(PARPE_EXPORT_PACKAGE FALSE CACHE BOOL "Export this build to CMake registry?") +# OpenMP? +find_package(OpenMP) + # Enable MPI? if(${PARPE_ENABLE_MPI}) find_package(MPI REQUIRED) @@ -97,6 +97,9 @@ set(HDF5_LIBRARIES # Guidelines Support Library (GSL-lite) directory set(GSL_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/ThirdParty/gsl") +# Throw on contract violation instead of terminate to get more meaningful +# message +add_definitions(-Dgsl_CONFIG_CONTRACT_VIOLATION_THROWS) # Build tests? if(${BUILD_TESTING}) diff --git a/CMakeModules/BuildOptimized.cmake b/CMakeModules/BuildOptimized.cmake index f5a746942..46a35d4d4 100644 --- a/CMakeModules/BuildOptimized.cmake +++ b/CMakeModules/BuildOptimized.cmake @@ -6,8 +6,7 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) if(COMPILER_SUPPORTS_XHOST) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -xHOST") - endif() - if(COMPILER_SUPPORTS_MARCHNATIVE) + elseif(COMPILER_SUPPORTS_MARCHNATIVE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") endif() endif() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..d97a84c9a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,47 @@ +# How to contribute + +We are happy about contributions to parPE in any form, be it new functionality, +documentation, bug reports, or anything else. + +When planning to contribute to parPE, it may be best to first create an issue +at [https://github.com/ICB-DCM/parPE/issues](https://github.com/ICB-DCM/parPE/issues) +to outline plans to avoid any redundant work. + +For any contribution, please create a pull request. By creating a pull request, +you agree on contributing your code/text/image/etc. under the license terms +stated in [https://github.com/ICB-DCM/parPE/blob/master/LICENSE](https://github.com/ICB-DCM/parPE/blob/master/LICENSE). + + +## Style guide + +For any code contributions, please follow the guidelines below. + + +### General + +* All files and functions should come with file-level and function-level + documentation. + +* All new functionality should be covered by unit or integration tests. Runtime + of those tests should be kept as short as possible. + + +### C++ + +* We use C++14 + +* New contributions should follow the + [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). + Existing code does not yet, but will be adapted accordingly. + + +### Python + +* We want to be compatible with Python 3.7 + +* For the Python code we want to follow + [PEP8](https://www.python.org/dev/peps/pep-0008/). Although this is not the + case for all existing code, any new contributions should do so. + +* We use Python [type hints](https://docs.python.org/3/library/typing.html) + for all functions. diff --git a/README.md b/README.md index 036f7a7c6..9b62eddeb 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ For full functionality, parPE requires the following libraries: * CBLAS compatible BLAS (libcblas, Intel MKL, ...) * [AMICI](https://github.com/ICB-DCM/AMICI) (included in this repository) (uses SuiteSparse, Sundials) -* C++14 compiler +* C++17 compiler * Python >= 3.6, including header files On Debian-based systems, dependencies can be installed via: diff --git a/ThirdParty/gsl/gsl/gsl-lite.hpp b/ThirdParty/gsl/gsl/gsl-lite.hpp index fdb774529..4956c040d 100644 --- a/ThirdParty/gsl/gsl/gsl-lite.hpp +++ b/ThirdParty/gsl/gsl/gsl-lite.hpp @@ -1,6 +1,6 @@ // -// gsl-lite is based on GSL: Guideline Support Library. -// For more information see https://github.com/martinmoene/gsl-lite +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite // // Copyright (c) 2015-2018 Martin Moene // Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. @@ -15,46 +15,68 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#pragma once - #ifndef GSL_GSL_LITE_HPP_INCLUDED #define GSL_GSL_LITE_HPP_INCLUDED -#include -#include -#include +#include // for swap() [pre-C++11], equal(), lexicographical_compare() +#include // for exception, terminate(), uncaught_exceptions() +#include // for data(), size(), reverse_iterator<>, iterator_traits<> #include -#include -#include -#include +#include // for addressof(), unique_ptr<>, shared_ptr<> +#include // for basic_ostream<> +#include // for ios_base, streamsize +#include // for logic_error #include -#include -#include +#include // for move(), forward<>(), swap() +#include // for size_t, ptrdiff_t, nullptr_t #define gsl_lite_MAJOR 0 -#define gsl_lite_MINOR 32 -#define gsl_lite_PATCH 0 +#define gsl_lite_MINOR 36 +#define gsl_lite_PATCH 1 + #define gsl_lite_VERSION gsl_STRINGIFY(gsl_lite_MAJOR) "." gsl_STRINGIFY(gsl_lite_MINOR) "." gsl_STRINGIFY(gsl_lite_PATCH) // gsl-lite backward compatibility: +#if !defined( gsl_CONFIG_DEFAULTS_VERSION ) +# define gsl_CONFIG_DEFAULTS_VERSION gsl_lite_MAJOR +#endif + #ifdef gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR # define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR -# pragma message ("gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR is deprecated since gsl-lite 0.7.0; replace with gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR, or consider span(with_container, cont).") +# pragma message ("gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR is deprecated since gsl-lite 0.7; replace with gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR, or consider span(with_container, cont).") +#endif + +#if defined( gsl_CONFIG_CONTRACT_LEVEL_ON ) +# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_ON is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_ON.") +# define gsl_CONFIG_CONTRACT_CHECKING_ON +#endif +#if defined( gsl_CONFIG_CONTRACT_LEVEL_OFF ) +# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_OFF is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_OFF.") +# define gsl_CONFIG_CONTRACT_CHECKING_OFF +#endif +#if defined( gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY ) +# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF.") +# define gsl_CONFIG_CONTRACT_CHECKING_ON +# define gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF +#elif defined( gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY ) +# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF.") +# define gsl_CONFIG_CONTRACT_CHECKING_ON +# define gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF #endif // M-GSL compatibility: #if defined( GSL_THROW_ON_CONTRACT_VIOLATION ) -# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS 1 +# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS #endif #if defined( GSL_TERMINATE_ON_CONTRACT_VIOLATION ) -# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS 0 +# define gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES #endif #if defined( GSL_UNENFORCED_ON_CONTRACT_VIOLATION ) -# define gsl_CONFIG_CONTRACT_LEVEL_OFF 1 +# define gsl_CONFIG_CONTRACT_CHECKING_OFF #endif // Configuration: Features @@ -71,40 +93,69 @@ # define gsl_FEATURE_BYTE_SPAN_TO_STD 99 #endif -#ifndef gsl_FEATURE_HAVE_IMPLICIT_MACRO -# define gsl_FEATURE_HAVE_IMPLICIT_MACRO 1 +#ifndef gsl_FEATURE_IMPLICIT_MACRO +# define gsl_FEATURE_IMPLICIT_MACRO 0 #endif -#ifndef gsl_FEATURE_HAVE_OWNER_MACRO -# define gsl_FEATURE_HAVE_OWNER_MACRO 1 +#ifndef gsl_FEATURE_OWNER_MACRO +# define gsl_FEATURE_OWNER_MACRO (gsl_CONFIG_DEFAULTS_VERSION == 0) #endif #ifndef gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD # define gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 0 #endif +#ifndef gsl_FEATURE_GSL_LITE_NAMESPACE +# define gsl_FEATURE_GSL_LITE_NAMESPACE (gsl_CONFIG_DEFAULTS_VERSION >= 1) +#endif + // Configuration: Other +#if defined( gsl_CONFIG_TRANSPARENT_NOT_NULL ) && gsl_CONFIG_TRANSPARENT_NOT_NULL && defined( gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF ) +# error configuration option gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF is meaningless if gsl_CONFIG_TRANSPARENT_NOT_NULL=1 +#endif + #ifndef gsl_CONFIG_DEPRECATE_TO_LEVEL -# define gsl_CONFIG_DEPRECATE_TO_LEVEL 0 +# if gsl_CONFIG_DEFAULTS_VERSION >= 1 +# define gsl_CONFIG_DEPRECATE_TO_LEVEL 6 +# else +# define gsl_CONFIG_DEPRECATE_TO_LEVEL 0 +# endif #endif #ifndef gsl_CONFIG_SPAN_INDEX_TYPE -# define gsl_CONFIG_SPAN_INDEX_TYPE size_t +# define gsl_CONFIG_SPAN_INDEX_TYPE std::size_t +#endif + +#ifndef gsl_CONFIG_INDEX_TYPE +# if gsl_CONFIG_DEFAULTS_VERSION >= 1 +// p0122r3 uses std::ptrdiff_t +# define gsl_CONFIG_INDEX_TYPE std::ptrdiff_t +# else +# define gsl_CONFIG_INDEX_TYPE gsl_CONFIG_SPAN_INDEX_TYPE +# endif #endif #ifndef gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR -# define gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR 0 +# define gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR (gsl_CONFIG_DEFAULTS_VERSION >= 1) #endif #ifndef gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF # define gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF 0 #endif +#ifndef gsl_CONFIG_TRANSPARENT_NOT_NULL +# define gsl_CONFIG_TRANSPARENT_NOT_NULL (gsl_CONFIG_DEFAULTS_VERSION >= 1) +#endif + #ifndef gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS # define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS 0 #endif +#ifndef gsl_CONFIG_ALLOWS_SPAN_COMPARISON +# define gsl_CONFIG_ALLOWS_SPAN_COMPARISON (gsl_CONFIG_DEFAULTS_VERSION == 0) +#endif + #ifndef gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON # define gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 1 #endif @@ -113,38 +164,29 @@ # define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR 0 #endif -#if defined( gsl_CONFIG_CONTRACT_LEVEL_ON ) -# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x11 -#elif defined( gsl_CONFIG_CONTRACT_LEVEL_OFF ) -# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x00 -#elif defined( gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY ) -# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x01 -#elif defined( gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY ) -# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x10 -#else -# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x11 -#endif - -#if !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && \ - !defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) -# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 0 -#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && \ - !defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) -# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 1 -#elif !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && \ - defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) -# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 0 -#else -# error only one of gsl_CONFIG_CONTRACT_VIOLATION_THROWS and gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES may be defined. +#ifndef gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION +# define gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION (gsl_CONFIG_DEFAULTS_VERSION >= 1) #endif -// Compiler detection (C++20 is speculative): +#if 1 < defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + defined( gsl_CONFIG_CONTRACT_CHECKING_ON ) + defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) +# error only one of gsl_CONFIG_CONTRACT_CHECKING_AUDIT, gsl_CONFIG_CONTRACT_CHECKING_ON, and gsl_CONFIG_CONTRACT_CHECKING_OFF may be defined +#endif +#if 1 < defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +# error only one of gsl_CONFIG_CONTRACT_VIOLATION_THROWS, gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES, and gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER may be defined +#endif +#if 1 < defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) + defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) +# error only one of gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME and gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE may be defined +#endif + +// C++ language version detection (C++20 is speculative): // Note: VC14.0/1900 (VS2015) lacks too much from C++14. -#if defined _MSVC_LANG -# define gsl_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) -#else -# define gsl_CPLUSPLUS __cplusplus +#ifndef gsl_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define gsl_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define gsl_CPLUSPLUS __cplusplus +# endif #endif #define gsl_CPP98_OR_GREATER ( gsl_CPLUSPLUS >= 199711L ) @@ -160,21 +202,63 @@ // half-open range [lo..hi): #define gsl_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) -#if defined( _MSC_VER ) && !defined( __clang__ ) -# define gsl_COMPILER_MSVC_VERSION ( _MSC_VER / 10 - 10 * ( 5 + ( _MSC_VER < 1900 ) ) ) +// Compiler versions: +// +// MSVC++ 6.0 _MSC_VER == 1200 gsl_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) +// MSVC++ 7.0 _MSC_VER == 1300 gsl_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) +// MSVC++ 7.1 _MSC_VER == 1310 gsl_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) +// MSVC++ 8.0 _MSC_VER == 1400 gsl_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) +// MSVC++ 9.0 _MSC_VER == 1500 gsl_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) +// MSVC++ 10.0 _MSC_VER == 1600 gsl_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) +// MSVC++ 11.0 _MSC_VER == 1700 gsl_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) +// MSVC++ 12.0 _MSC_VER == 1800 gsl_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) +// MSVC++ 14.0 _MSC_VER == 1900 gsl_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) +// MSVC++ 14.1 _MSC_VER >= 1910 gsl_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) +// MSVC++ 14.2 _MSC_VER >= 1920 gsl_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) +// +// AppleClang 7.0.0 __apple_build_version__ == 7000172 gsl_COMPILER_APPLECLANG_VERSION == 700 (Xcode 7.0, 7.0.1) (LLVM 3.7.0) +// AppleClang 7.0.0 __apple_build_version__ == 7000176 gsl_COMPILER_APPLECLANG_VERSION == 700 (Xcode 7.1) (LLVM 3.7.0) +// AppleClang 7.0.2 __apple_build_version__ == 7000181 gsl_COMPILER_APPLECLANG_VERSION == 702 (Xcode 7.2, 7.2.1) (LLVM 3.7.0) +// AppleClang 7.3.0 __apple_build_version__ == 7030029 gsl_COMPILER_APPLECLANG_VERSION == 730 (Xcode 7.3) (LLVM 3.8.0) +// AppleClang 7.3.0 __apple_build_version__ == 7030031 gsl_COMPILER_APPLECLANG_VERSION == 730 (Xcode 7.3.1) (LLVM 3.8.0) +// AppleClang 8.0.0 __apple_build_version__ == 8000038 gsl_COMPILER_APPLECLANG_VERSION == 800 (Xcode 8.0) (LLVM 3.9.0) +// AppleClang 8.0.0 __apple_build_version__ == 8000042 gsl_COMPILER_APPLECLANG_VERSION == 800 (Xcode 8.1, 8.2, 8.2.1) (LLVM 3.9.0) +// AppleClang 8.1.0 __apple_build_version__ == 8020038 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3) (LLVM 3.9.0) +// AppleClang 8.1.0 __apple_build_version__ == 8020041 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3.1) (LLVM 3.9.0) +// AppleClang 8.1.0 __apple_build_version__ == 8020042 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3.2, 8.3.3) (LLVM 3.9.0) +// AppleClang 9.0.0 __apple_build_version__ == 9000037 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.0) (LLVM 4.0.0?) +// AppleClang 9.0.0 __apple_build_version__ == 9000038 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.1) (LLVM 4.0.0?) +// AppleClang 9.0.0 __apple_build_version__ == 9000039 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.2) (LLVM 4.0.0?) +// AppleClang 9.1.0 __apple_build_version__ == 9020039 gsl_COMPILER_APPLECLANG_VERSION == 910 (Xcode 9.3, 9.3.1) (LLVM 5.0.2?) +// AppleClang 9.1.0 __apple_build_version__ == 9020039 gsl_COMPILER_APPLECLANG_VERSION == 910 (Xcode 9.4, 9.4.1) (LLVM 5.0.2?) +// AppleClang 10.0.0 __apple_build_version__ == 10001145 gsl_COMPILER_APPLECLANG_VERSION == 1000 (Xcode 10.0, 10.1) (LLVM 6.0.1?) +// AppleClang 10.0.1 __apple_build_version__ == 10010046 gsl_COMPILER_APPLECLANG_VERSION == 1001 (Xcode 10.2, 10.2.1, 10.3) (LLVM 7.0.0?) +// AppleClang 11.0.0 __apple_build_version__ == 11000033 gsl_COMPILER_APPLECLANG_VERSION == 1100 (Xcode 11.1, 11.2, 11.3) (LLVM 8.0.0?) + +#if defined(_MSC_VER ) && !defined(__clang__) +# define gsl_COMPILER_MSVC_VER (_MSC_VER ) +# define gsl_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) +# define gsl_COMPILER_MSVC_VERSION_FULL (_MSC_VER - 100 * ( 5 + (_MSC_VER < 1900 ) ) ) #else -# define gsl_COMPILER_MSVC_VERSION 0 +# define gsl_COMPILER_MSVC_VER 0 +# define gsl_COMPILER_MSVC_VERSION 0 +# define gsl_COMPILER_MSVC_VERSION_FULL 0 #endif #define gsl_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) -#if defined __clang__ +#if defined( __apple_build_version__ ) +# define gsl_COMPILER_APPLECLANG_VERSION gsl_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ ) +# define gsl_COMPILER_CLANG_VERSION 0 +#elif defined( __clang__ ) +# define gsl_COMPILER_APPLECLANG_VERSION 0 # define gsl_COMPILER_CLANG_VERSION gsl_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ ) #else +# define gsl_COMPILER_APPLECLANG_VERSION 0 # define gsl_COMPILER_CLANG_VERSION 0 #endif -#if defined __GNUC__ +#if defined(__GNUC__) && !defined(__clang__) # define gsl_COMPILER_GNUC_VERSION gsl_COMPILER_VERSION( __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ ) #else # define gsl_COMPILER_GNUC_VERSION 0 @@ -182,7 +266,7 @@ // Compiler non-strict aliasing: -#if defined __clang__ || defined __GNUC__ +#if defined(__clang__) || defined(__GNUC__) # define gsl_may_alias __attribute__((__may_alias__)) #else # define gsl_may_alias @@ -190,7 +274,7 @@ // Presence of gsl, language and library features: -#define gsl_IN_STD( v ) ( (v) == 98 || (v) >= gsl_CPLUSPLUS_V ) +#define gsl_IN_STD( v ) ( ((v) == 98 ? 3 : (v)) >= gsl_CPLUSPLUS_V ) #define gsl_DEPRECATE_TO_LEVEL( level ) ( level <= gsl_CONFIG_DEPRECATE_TO_LEVEL ) #define gsl_FEATURE_TO_STD( feature ) ( gsl_IN_STD( gsl_FEATURE( feature##_TO_STD ) ) ) @@ -208,31 +292,60 @@ // Presence of language & library features: +#if gsl_BETWEEN(gsl_COMPILER_GNUC_VERSION, 1, 500) || gsl_BETWEEN(gsl_COMPILER_CLANG_VERSION, 1, 360) || gsl_COMPILER_APPLECLANG_VERSION +# ifdef __EXCEPTIONS +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif // __EXCEPTIONS +#elif gsl_COMPILER_GNUC_VERSION >= 500 || gsl_COMPILER_CLANG_VERSION >= 500 +# ifdef __cpp_exceptions +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif // __cpp_exceptions +#elif gsl_COMPILER_MSVC_VERSION +# ifdef _CPPUNWIND +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif // _CPPUNWIND +#else +// For all other compilers, assume exceptions are always enabled. +# define gsl_HAVE_EXCEPTIONS 1 +#endif + +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && !gsl_HAVE( EXCEPTIONS ) +# error Cannot use gsl_CONFIG_CONTRACT_VIOLATION_THROWS if exceptions are disabled. +#endif // defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && !gsl_HAVE( EXCEPTIONS ) + #ifdef _HAS_CPP0X # define gsl_HAS_CPP0X _HAS_CPP0X #else # define gsl_HAS_CPP0X 0 #endif -#define gsl_CPP11_100 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 100) -#define gsl_CPP11_110 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 110) -#define gsl_CPP11_120 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120) -#define gsl_CPP11_140 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 140) +#define gsl_CPP11_100 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1600) +#define gsl_CPP11_110 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1700) +#define gsl_CPP11_120 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800) +#define gsl_CPP11_140 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) #define gsl_CPP14_000 (gsl_CPP14_OR_GREATER) -#define gsl_CPP14_120 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120) -#define gsl_CPP14_140 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 140) +#define gsl_CPP14_120 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800) +#define gsl_CPP14_140 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) #define gsl_CPP17_000 (gsl_CPP17_OR_GREATER) +#define gsl_CPP17_140 (gsl_CPP17_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) -#define gsl_CPP11_140_CPP0X_90 (gsl_CPP11_140 || (gsl_COMPILER_MSVC_VERSION >= 90 && gsl_HAS_CPP0X)) -#define gsl_CPP11_140_CPP0X_100 (gsl_CPP11_140 || (gsl_COMPILER_MSVC_VERSION >= 100 && gsl_HAS_CPP0X)) +#define gsl_CPP11_140_CPP0X_90 (gsl_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1500 && gsl_HAS_CPP0X)) +#define gsl_CPP11_140_CPP0X_100 (gsl_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1600 && gsl_HAS_CPP0X)) // Presence of C++11 language features: #define gsl_HAVE_AUTO gsl_CPP11_100 #define gsl_HAVE_NULLPTR gsl_CPP11_100 #define gsl_HAVE_RVALUE_REFERENCE gsl_CPP11_100 +#define gsl_HAVE_FUNCTION_REF_QUALIFIER ( gsl_CPP14_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 481 ) ) #define gsl_HAVE_ENUM_CLASS gsl_CPP11_110 @@ -240,11 +353,15 @@ #define gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG gsl_CPP11_120 #define gsl_HAVE_EXPLICIT gsl_CPP11_120 #define gsl_HAVE_INITIALIZER_LIST gsl_CPP11_120 +#define gsl_HAVE_VARIADIC_TEMPLATE gsl_CPP11_120 +#define gsl_HAVE_IS_DELETE gsl_CPP11_120 #define gsl_HAVE_CONSTEXPR_11 gsl_CPP11_140 #define gsl_HAVE_IS_DEFAULT gsl_CPP11_140 -#define gsl_HAVE_IS_DELETE gsl_CPP11_140 #define gsl_HAVE_NOEXCEPT gsl_CPP11_140 +#define gsl_HAVE_NORETURN ( gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 480 ) ) + +#define gsl_HAVE_EXPRESSION_SFINAE gsl_CPP11_140 #if gsl_CPP11_OR_GREATER // see above @@ -252,14 +369,21 @@ // Presence of C++14 language features: -#define gsl_HAVE_CONSTEXPR_14 gsl_CPP14_000 +#define gsl_HAVE_CONSTEXPR_14 ( gsl_CPP14_000 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 600 ) ) #define gsl_HAVE_DECLTYPE_AUTO gsl_CPP14_140 +#define gsl_HAVE_DEPRECATED ( gsl_CPP14_140 && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 142 ) ) // Presence of C++17 language features: // MSVC: template parameter deduction guides since Visual Studio 2017 v15.7 #define gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE gsl_CPP17_000 -#define gsl_HAVE_DEDUCTION_GUIDES (gsl_CPP17_000 && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 999 ) ) +#define gsl_HAVE_DEDUCTION_GUIDES ( gsl_CPP17_000 && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION_FULL, 1, 1414 ) ) +#define gsl_HAVE_NODISCARD gsl_CPP17_000 +#define gsl_HAVE_CONSTEXPR_17 gsl_CPP17_OR_GREATER + +// Presence of C++20 language features: + +#define gsl_HAVE_CONSTEXPR_20 gsl_CPP20_OR_GREATER // Presence of C++ library features: @@ -270,6 +394,7 @@ #define gsl_HAVE_CONTAINER_DATA_METHOD gsl_CPP11_140_CPP0X_90 #define gsl_HAVE_STD_DATA gsl_CPP17_000 +#define gsl_HAVE_STD_SSIZE ( gsl_COMPILER_GNUC_VERSION >= 1000 ) #define gsl_HAVE_SIZED_TYPES gsl_CPP11_140 @@ -279,18 +404,19 @@ #define gsl_HAVE_MAKE_UNIQUE gsl_CPP14_120 +#define gsl_HAVE_UNCAUGHT_EXCEPTIONS gsl_CPP17_140 + #define gsl_HAVE_ADD_CONST gsl_HAVE_TYPE_TRAITS #define gsl_HAVE_INTEGRAL_CONSTANT gsl_HAVE_TYPE_TRAITS #define gsl_HAVE_REMOVE_CONST gsl_HAVE_TYPE_TRAITS #define gsl_HAVE_REMOVE_REFERENCE gsl_HAVE_TYPE_TRAITS +#define gsl_HAVE_REMOVE_CVREF gsl_CPP20_OR_GREATER #define gsl_HAVE_TR1_ADD_CONST gsl_HAVE_TR1_TYPE_TRAITS #define gsl_HAVE_TR1_INTEGRAL_CONSTANT gsl_HAVE_TR1_TYPE_TRAITS #define gsl_HAVE_TR1_REMOVE_CONST gsl_HAVE_TR1_TYPE_TRAITS #define gsl_HAVE_TR1_REMOVE_REFERENCE gsl_HAVE_TR1_TYPE_TRAITS -// For the rest, consider VC12, VC14 as C++11 for GSL Lite. - // C++ feature usage: #if gsl_HAVE( ADDRESSOF ) @@ -311,13 +437,25 @@ # define gsl_constexpr14 /*constexpr*/ #endif +#if gsl_HAVE( CONSTEXPR_17 ) +# define gsl_constexpr17 constexpr +#else +# define gsl_constexpr17 /*constexpr*/ +#endif + +#if gsl_HAVE( CONSTEXPR_20 ) +# define gsl_constexpr20 constexpr +#else +# define gsl_constexpr20 /*constexpr*/ +#endif + #if gsl_HAVE( EXPLICIT ) # define gsl_explicit explicit #else # define gsl_explicit /*explicit*/ #endif -#if gsl_FEATURE( HAVE_IMPLICIT_MACRO ) +#if gsl_FEATURE( IMPLICIT_MACRO ) # define implicit /*implicit*/ #endif @@ -333,7 +471,7 @@ # define gsl_is_delete_access private #endif -#if !gsl_HAVE( NOEXCEPT ) || gsl_CONFIG( CONTRACT_VIOLATION_THROWS_V ) +#if !gsl_HAVE( NOEXCEPT ) || defined( gsl_TESTING_ ) # define gsl_noexcept /*noexcept*/ #else # define gsl_noexcept noexcept @@ -345,8 +483,168 @@ # define gsl_nullptr NULL #endif +#if gsl_HAVE( NODISCARD ) +# define gsl_NODISCARD [[nodiscard]] +#else +# define gsl_NODISCARD +#endif + +#if gsl_HAVE( NORETURN ) +# define gsl_NORETURN [[noreturn]] +#elif defined(_MSC_VER) +# define gsl_NORETURN __declspec(noreturn) +#else +# define gsl_NORETURN +#endif + +#if gsl_HAVE( DEPRECATED ) && !defined( gsl_TESTING_ ) +# define gsl_DEPRECATED [[deprecated]] +# define gsl_DEPRECATED_MSG( msg ) [[deprecated( msg )]] +#else +# define gsl_DEPRECATED +# define gsl_DEPRECATED_MSG( msg ) +#endif + +#if gsl_HAVE( TYPE_TRAITS ) + +#define gsl_DEFINE_ENUM_BITMASK_OPERATORS_( ENUM ) \ + gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ + operator~( ENUM val ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type::type U; \ + return ENUM( ~U( val ) ); \ + } \ + gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ + operator|( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type::type U; \ + return ENUM( U( lhs ) | U( rhs ) ); \ + } \ + gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ + operator&( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type::type U; \ + return ENUM( U( lhs ) & U( rhs ) ); \ + } \ + gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ + operator^( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type::type U; \ + return ENUM( U( lhs ) ^ U( rhs ) ); \ + } \ + gsl_api inline gsl_constexpr14 ENUM & \ + operator|=( ENUM & lhs, ENUM rhs ) gsl_noexcept \ + { \ + return lhs = lhs | rhs; \ + } \ + gsl_api inline gsl_constexpr14 ENUM & \ + operator&=( ENUM & lhs, ENUM rhs ) gsl_noexcept \ + { \ + return lhs = lhs & rhs; \ + } \ + gsl_api inline gsl_constexpr14 ENUM & \ + operator^=( ENUM & lhs, ENUM rhs ) gsl_noexcept \ + { \ + return lhs = lhs ^ rhs; \ + } + +#define gsl_DEFINE_ENUM_RELATIONAL_OPERATORS_( ENUM ) \ + gsl_NODISCARD gsl_api inline gsl_constexpr bool \ + operator<( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type::type U; \ + return U( lhs ) < U( rhs ); \ + } \ + gsl_NODISCARD gsl_api inline gsl_constexpr bool \ + operator>( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type::type U; \ + return U( lhs ) > U( rhs ); \ + } \ + gsl_NODISCARD gsl_api inline gsl_constexpr bool \ + operator<=( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type::type U; \ + return U( lhs ) <= U( rhs ); \ + } \ + gsl_NODISCARD gsl_api inline gsl_constexpr bool \ + operator>=( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type::type U; \ + return U( lhs ) >= U( rhs ); \ + } + +// +// Defines bitmask operators `|`, `&`, `^`, `~`, `|=`, `&=`, and `^=` for the given enum type. +//ᅟ +//ᅟ enum class Vegetables { +//ᅟ tomato = 0b001, +//ᅟ onion = 0b010, +//ᅟ eggplant = 0b100 +//ᅟ }; +//ᅟ gsl_DEFINE_ENUM_BITMASK_OPERATORS( Vegetables ) +// +#define gsl_DEFINE_ENUM_BITMASK_OPERATORS( ENUM ) gsl_DEFINE_ENUM_BITMASK_OPERATORS_( ENUM ) + +// +// Defines relational operators `<`, `>`, `<=`, `>=` for the given enum type. +//ᅟ +//ᅟ enum class OperatorPrecedence { +//ᅟ additive = 0, +//ᅟ multiplicative = 1, +//ᅟ power = 2 +//ᅟ }; +//ᅟ gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( OperatorPrecedence ) +// +#define gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( ENUM ) gsl_DEFINE_ENUM_RELATIONAL_OPERATORS_( ENUM ) + +#endif // gsl_HAVE( TYPE_TRAITS ) + #define gsl_DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) ) + +// Method enabling (C++98, VC120 (VS2013) cannot use __VA_ARGS__) + +// Guidelines for SFINAE in gsl-lite: +// +// The macros below are for conditional SFINAE, i.e. they apply SFINAE only if the necessary language support is available. +// Don't use these macros if language support can be assumed in the given context. +// +// For functions, prefer return-type SFINAE if possible. +// If return-type SFINAE is not applicable, use `gsl_REQUIRES_A_()` or `typename std::enable_if< VA, int >::type = 0` in the function template argument list. +// +// Use `gsl_REQUIRES_T_()` or `typename = typename std::enable_if< VA, ::gsl::detail::enabler >::type` in class template argument lists. + +#if gsl_HAVE( EXPRESSION_SFINAE ) +# define gsl_DECLTYPE_(T, EXPR) decltype( EXPR ) +#else +# define gsl_DECLTYPE_(T, EXPR) T +#endif + +#if gsl_HAVE( TYPE_TRAITS ) +# define gsl_REQUIRES_T_(VA) , typename = typename std::enable_if< ( VA ), ::gsl::detail::enabler >::type +#else +# define gsl_REQUIRES_T_(VA) +#endif + +#if gsl_HAVE( TYPE_TRAITS ) +# define gsl_REQUIRES_R_(R, VA) typename std::enable_if< ( VA ), R >::type +#else +# define gsl_REQUIRES_R_(R, VA) R +#endif + +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) +# if gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) +// VS 2013 and earlier seem to have trouble with SFINAE for default non-type arguments +# define gsl_REQUIRES_A_(VA) gsl_REQUIRES_T_(VA) +# else +# define gsl_REQUIRES_A_(VA) , typename std::enable_if< ( VA ), int >::type = 0 +# endif +#else +# define gsl_REQUIRES_A_(VA) +#endif + + // Other features: #define gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR \ @@ -358,6 +656,15 @@ // GSL API (e.g. for CUDA platform): +// Guidelines for using `gsl_api`: +// +// NVCC imposes the restriction that a function annotated `__host__ __device__` cannot call host-only or device-only functions. +// This makes `gsl_api` inappropriate for generic functions that call unknown code, e.g. the template constructors of `span<>` +// or functions like `finally()` which accept an arbitrary function object. +// It is often preferable to annotate functions only with `gsl_constexpr` or `gsl_constexpr14`. The "extended constexpr" mode +// of NVCC (currently an experimental feature) will implicitly consider constexpr functions `__host__ __device__` functions +// but tolerates calls to host-only or device-only functions. + #ifndef gsl_api # ifdef __CUDACC__ # define gsl_api __host__ __device__ @@ -372,24 +679,32 @@ # include #endif -#if gsl_HAVE( TYPE_TRAITS ) -# include -#elif gsl_HAVE( TR1_TYPE_TRAITS ) -# include +#if !gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || !gsl_HAVE( AUTO ) +# include +#endif + +#if gsl_HAVE( INITIALIZER_LIST ) +# include #endif -#if gsl_HAVE( SIZED_TYPES ) -# include +#if gsl_HAVE( TYPE_TRAITS ) +# include // for enable_if<>, + // add_const<>, add_pointer<>, common_type<>, make_signed<>, remove_cv<>, remove_const<>, remove_volatile<>, remove_reference<>, remove_cvref<>, remove_pointer<>, underlying_type<>, + // is_assignable<>, is_constructible<>, is_const<>, is_convertible<>, is_integral<>, is_pointer<>, is_signed<>, + // integral_constant<>, declval() +#elif gsl_HAVE( TR1_TYPE_TRAITS ) +# include // for add_const<>, remove_cv<>, remove_const<>, remove_volatile<>, remove_reference<>, integral_constant<> #endif // MSVC warning suppression macros: -#if gsl_COMPILER_MSVC_VERSION >= 140 +#if gsl_COMPILER_MSVC_VERSION >= 140 && !defined(__NVCC__) # define gsl_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]] # define gsl_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) ) # define gsl_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes)) # define gsl_RESTORE_MSVC_WARNINGS() __pragma(warning(pop )) #else +// TODO: define for Clang # define gsl_SUPPRESS_MSGSL_WARNING(expr) # define gsl_SUPPRESS_MSVC_WARNING(code, descr) # define gsl_DISABLE_MSVC_WARNINGS(codes) @@ -397,2358 +712,3437 @@ #endif // Suppress the following MSVC GSL warnings: -// - C26410: gsl::r.32: the parameter 'ptr' is a reference to const unique pointer, use const T* or const T& instead -// - C26415: gsl::r.30: smart pointer parameter 'ptr' is used only to access contained pointer. Use T* or T& instead -// - C26418: gsl::r.36: shared pointer parameter 'ptr' is not copied or moved. Use T* or T& instead -// - C26472, gsl::t.1 : don't use a static_cast for arithmetic conversions; -// use brace initialization, gsl::narrow_cast or gsl::narow -// - C26439, gsl::f.6 : special function 'function' can be declared 'noexcept' -// - C26440, gsl::f.6 : function 'function' can be declared 'noexcept' -// - C26473: gsl::t.1 : don't cast between pointer types where the source type and the target type are the same -// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead -// - C26482, gsl::b.2 : only index into arrays using constant expressions -// - C26490: gsl::t.1 : don't use reinterpret_cast +// - C26432: gsl::c.21 : if you define or delete any default operation in the type '...', define or delete them all +// - C26410: gsl::r.32 : the parameter 'ptr' is a reference to const unique pointer, use const T* or const T& instead +// - C26415: gsl::r.30 : smart pointer parameter 'ptr' is used only to access contained pointer. Use T* or T& instead +// - C26418: gsl::r.36 : shared pointer parameter 'ptr' is not copied or moved. Use T* or T& instead +// - C26472: gsl::t.1 : don't use a static_cast for arithmetic conversions; +// use brace initialization, gsl::narrow_cast or gsl::narrow +// - C26439: gsl::f.6 : special function 'function' can be declared 'noexcept' +// - C26440: gsl::f.6 : function 'function' can be declared 'noexcept' +// - C26455: gsl::f.6 : default constructor may not throw. Declare it 'noexcept' +// - C26473: gsl::t.1 : don't cast between pointer types where the source type and the target type are the same +// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead +// - C26482: gsl::b.2 : only index into arrays using constant expressions +// - C26446: gdl::b.4 : prefer to use gsl::at() instead of unchecked subscript operator +// - C26490: gsl::t.1 : don't use reinterpret_cast +// - C26487: gsl::l.4 : don't return a pointer '('s result)' that may be invalid -gsl_DISABLE_MSVC_WARNINGS( 26410 26415 26418 26472 26439 26440 26473 26481 26482 26490 ) +gsl_DISABLE_MSVC_WARNINGS( 26432 26410 26415 26418 26472 26439 26440 26455 26473 26481 26482 26446 26490 26487 ) -namespace gsl { + namespace gsl { -// forward declare span<>: + // forward declare span<>: -template< class T > -class span; + template< class T > + class span; -namespace details { + // C++11 emulation: -// C++11 emulation: + namespace std11 { #if gsl_HAVE( ADD_CONST ) -using std::add_const; + using std::add_const; #elif gsl_HAVE( TR1_ADD_CONST ) -using std::tr1::add_const; + using std::tr1::add_const; #else -template< class T > struct add_const { typedef const T type; }; + template< class T > struct add_const { typedef const T type; }; #endif // gsl_HAVE( ADD_CONST ) #if gsl_HAVE( REMOVE_CONST ) -using std::remove_cv; -using std::remove_const; -using std::remove_volatile; + using std::remove_cv; + using std::remove_const; + using std::remove_volatile; #elif gsl_HAVE( TR1_REMOVE_CONST ) -using std::tr1::remove_cv; -using std::tr1::remove_const; -using std::tr1::remove_volatile; + using std::tr1::remove_cv; + using std::tr1::remove_const; + using std::tr1::remove_volatile; #else -template< class T > struct remove_const { typedef T type; }; -template< class T > struct remove_const { typedef T type; }; + template< class T > struct remove_const { typedef T type; }; + template< class T > struct remove_const { typedef T type; }; -template< class T > struct remove_volatile { typedef T type; }; -template< class T > struct remove_volatile { typedef T type; }; + template< class T > struct remove_volatile { typedef T type; }; + template< class T > struct remove_volatile { typedef T type; }; -template< class T > -struct remove_cv -{ - typedef typename details::remove_volatile::type>::type type; -}; + template< class T > + struct remove_cv + { + typedef typename remove_volatile::type>::type type; + }; #endif // gsl_HAVE( REMOVE_CONST ) -#if gsl_HAVE( INTEGRAL_CONSTANT ) +#if gsl_HAVE( REMOVE_REFERENCE ) -using std::integral_constant; -using std::true_type; -using std::false_type; + using std::remove_reference; -#elif gsl_HAVE( TR1_INTEGRAL_CONSTANT ) +#elif gsl_HAVE( TR1_REMOVE_REFERENCE ) -using std::tr1::integral_constant; -using std::tr1::true_type; -using std::tr1::false_type; + using std::tr1::remove_reference; #else -template< int v > struct integral_constant { enum { value = v }; }; -typedef integral_constant< true > true_type; -typedef integral_constant< false > false_type; + template< class T > struct remove_reference { typedef T type; }; + template< class T > struct remove_reference { typedef T type; }; +# if gsl_HAVE( RVALUE_REFERENCE ) + template< class T > struct remove_reference { typedef T type; }; +# endif -#endif +#endif // gsl_HAVE( REMOVE_REFERENCE ) -#if gsl_HAVE( TYPE_TRAITS ) -template< class Q > -struct is_span_oracle : std::false_type{}; +#if gsl_HAVE( INTEGRAL_CONSTANT ) -template< class T> -struct is_span_oracle< span > : std::true_type{}; + using std::integral_constant; + using std::true_type; + using std::false_type; -template< class Q > -struct is_span : is_span_oracle< typename std::remove_cv::type >{}; +#elif gsl_HAVE( TR1_INTEGRAL_CONSTANT ) -template< class Q > -struct is_std_array_oracle : std::false_type{}; + using std::tr1::integral_constant; + using std::tr1::true_type; + using std::tr1::false_type; -#if gsl_HAVE( ARRAY ) +#else -template< class T, std::size_t Extent > -struct is_std_array_oracle< std::array > : std::true_type{}; + template< class T, T v > struct integral_constant { enum { value = v }; }; + typedef integral_constant< bool, true > true_type; + typedef integral_constant< bool, false > false_type; #endif -template< class Q > -struct is_std_array : is_std_array_oracle< typename std::remove_cv::type >{}; +#if gsl_HAVE( TYPE_TRAITS ) -template< class Q > -struct is_array : std::false_type {}; + using std::underlying_type; -template< class T > -struct is_array : std::true_type {}; +#elif gsl_HAVE( TR1_TYPE_TRAITS ) -template< class T, std::size_t N > -struct is_array : std::true_type {}; + using std::tr1::underlying_type; -#endif // gsl_HAVE( TYPE_TRAITS ) +#else -} // namespace details +// We could try to define `underlying_type<>` for pre-C++11 here, but let's not until someone actually needs it. -// -// GSL.util: utilities -// +#endif -// index type for all container indexes/subscripts/sizes -typedef gsl_CONFIG_SPAN_INDEX_TYPE index; // p0122r3 uses std::ptrdiff_t + } // namespace std11 -// -// GSL.owner: ownership pointers -// -#if gsl_HAVE( SHARED_PTR ) - using std::unique_ptr; - using std::shared_ptr; - using std::make_shared; -# if gsl_HAVE( MAKE_UNIQUE ) - using std::make_unique; -# endif -#endif + // C++14 emulation: -#if gsl_HAVE( ALIAS_TEMPLATE ) -# if gsl_HAVE( TYPE_TRAITS ) - template< class T, class = typename std::enable_if< std::is_pointer::value >::type > - using owner = T; -# else - template< class T > using owner = T; -# endif -#else - template< class T > struct owner { typedef T type; }; -#endif + namespace std14 { -#define gsl_HAVE_OWNER_TEMPLATE gsl_HAVE_ALIAS_TEMPLATE +#if gsl_HAVE( UNIQUE_PTR ) +# if gsl_HAVE( MAKE_UNIQUE ) -#if gsl_FEATURE( HAVE_OWNER_MACRO ) -# if gsl_HAVE( OWNER_TEMPLATE ) -# define Owner(t) ::gsl::owner -# else -# define Owner(t) ::gsl::owner::type -# endif -#endif + using std::make_unique; -// -// GSL.assert: assertions -// +# elif gsl_HAVE( VARIADIC_TEMPLATE ) -#define gsl_ELIDE_CONTRACT_EXPECTS ( 0 == ( gsl_CONFIG_CONTRACT_LEVEL_MASK & 0x01 ) ) -#define gsl_ELIDE_CONTRACT_ENSURES ( 0 == ( gsl_CONFIG_CONTRACT_LEVEL_MASK & 0x10 ) ) + template< class T, class... Args > + std::unique_ptr make_unique( Args &&... args ) + { + return std::unique_ptr( new T( std::forward( args )... ) ); + } -#if gsl_ELIDE_CONTRACT_EXPECTS -# define Expects( x ) /* Expects elided */ -#elif gsl_CONFIG( CONTRACT_VIOLATION_THROWS_V ) -# define Expects( x ) ::gsl::fail_fast_assert( (x), "GSL: Precondition failure at " __FILE__ ":" gsl_STRINGIFY(__LINE__) ); -#else -# define Expects( x ) ::gsl::fail_fast_assert( (x) ) -#endif +# endif // gsl_HAVE( MAKE_UNIQUE ), gsl_HAVE( VARIADIC_TEMPLATE ) +#endif // gsl_HAVE( UNIQUE_PTR ) -#if gsl_ELIDE_CONTRACT_ENSURES -# define Ensures( x ) /* Ensures elided */ -#elif gsl_CONFIG( CONTRACT_VIOLATION_THROWS_V ) -# define Ensures( x ) ::gsl::fail_fast_assert( (x), "GSL: Postcondition failure at " __FILE__ ":" gsl_STRINGIFY(__LINE__) ); -#else -# define Ensures( x ) ::gsl::fail_fast_assert( (x) ) -#endif + } // namespace std14 -#define gsl_STRINGIFY( x ) gsl_STRINGIFY_( x ) -#define gsl_STRINGIFY_( x ) #x + namespace detail { -struct fail_fast : public std::logic_error -{ - gsl_api explicit fail_fast( char const * const message ) - : std::logic_error( message ) {} -}; +#if gsl_HAVE( VARIADIC_TEMPLATE ) -// workaround for gcc 5 throw/terminate constexpr bug: + template < bool V0, class T0, class... Ts > struct conjunction_ { using type = T0; }; + template < class T0, class T1, class... Ts > struct conjunction_ : conjunction_ { }; + template < bool V0, class T0, class... Ts > struct disjunction_ { using type = T0; }; + template < class T0, class T1, class... Ts > struct disjunction_ : disjunction_ { }; -#if gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 430, 600 ) && gsl_HAVE( CONSTEXPR_14 ) +#endif -# if gsl_CONFIG( CONTRACT_VIOLATION_THROWS_V ) + } // namespace detail -gsl_api inline gsl_constexpr14 auto fail_fast_assert( bool cond, char const * const message ) -> void -{ - !cond ? throw fail_fast( message ) : 0; -} + // C++17 emulation: -# else + namespace std17 { -gsl_api inline gsl_constexpr14 auto fail_fast_assert( bool cond ) -> void -{ - struct F { static gsl_constexpr14 void f(){}; }; + template< bool v > struct bool_constant : std11::integral_constant{}; - !cond ? std::terminate() : F::f(); -} +#if gsl_CPP11_120 -# endif + template < class... Ts > struct conjunction; + template < > struct conjunction< > : std11::true_type { }; + template < class T0, class... Ts > struct conjunction : detail::conjunction_::type { }; + template < class... Ts > struct disjunction; + template < > struct disjunction< > : std11::false_type { }; + template < class T0, class... Ts > struct disjunction : detail::disjunction_::type { }; + template < class T > struct negation : std11::integral_constant { }; -#else // workaround +# if gsl_CPP14_OR_GREATER -# if gsl_CONFIG( CONTRACT_VIOLATION_THROWS_V ) + template < class... Ts > constexpr bool conjunction_v = conjunction::value; + template < class... Ts > constexpr bool disjunction_v = disjunction::value; + template < class T > constexpr bool negation_v = negation::value; -gsl_api inline gsl_constexpr14 void fail_fast_assert( bool cond, char const * const message ) -{ - if ( !cond ) - throw fail_fast( message ); -} +# endif // gsl_CPP14_OR_GREATER -# else + template< class... Ts > + struct make_void { typedef void type; }; -gsl_api inline gsl_constexpr14 void fail_fast_assert( bool cond ) gsl_noexcept -{ - if ( !cond ) - std::terminate(); -} + template< class... Ts > + using void_t = typename make_void< Ts... >::type; -# endif -#endif // workaround +#endif // gsl_CPP11_120 -// -// GSL.util: utilities -// +#if gsl_HAVE( STD_DATA ) -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 110 + using std::data; + using std::size; -template< class F > -class final_action -{ -public: - gsl_api explicit final_action( F action ) gsl_noexcept - : action_( std::move( action ) ) - , invoke_( true ) - {} +#elif gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) - gsl_api final_action( final_action && other ) gsl_noexcept - : action_( std::move( other.action_ ) ) - , invoke_( other.invoke_ ) + template< class T, size_t N > + gsl_api inline gsl_constexpr auto size( T const(&)[N] ) gsl_noexcept -> size_t { - other.invoke_ = false; + return N; } - gsl_api virtual ~final_action() gsl_noexcept + template< class C > + inline gsl_constexpr auto size( C const & cont ) -> decltype( cont.size() ) { - if ( invoke_ ) - action_(); + return cont.size(); } -gsl_is_delete_access: - gsl_api final_action( final_action const & ) gsl_is_delete; - gsl_api final_action & operator=( final_action const & ) gsl_is_delete; - gsl_api final_action & operator=( final_action && ) gsl_is_delete; - -protected: - gsl_api void dismiss() gsl_noexcept + template< class T, size_t N > + gsl_api inline gsl_constexpr auto data( T(&arr)[N] ) gsl_noexcept -> T* { - invoke_ = false; + return &arr[0]; } -#if gsl_CPP17_OR_GREATER - gsl_api int uncaught_exceptions() gsl_noexcept + template< class C > + inline gsl_constexpr auto data( C & cont ) -> decltype( cont.data() ) { - return std::uncaught_exceptions(); + return cont.data(); } -#else - gsl_api int uncaught_exceptions() + + template< class C > + inline gsl_constexpr auto data( C const & cont ) -> decltype( cont.data() ) { - return std::uncaught_exception() ? 1 : 0; + return cont.data(); } -#endif -private: - F action_; - bool invoke_; -}; + template< class E > + inline gsl_constexpr auto data( std::initializer_list il ) gsl_noexcept -> E const * + { + return il.begin(); + } -template< class F > -gsl_api inline final_action finally( F const & action ) gsl_noexcept -{ - return final_action( action ); -} +#endif // span_HAVE( DATA ) -template< class F > -gsl_api inline final_action finally( F && action ) gsl_noexcept -{ - return final_action( std::forward( action ) ); -} + } // namespace std17 -#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + // C++20 emulation: -template< class F > -class final_action_return : public final_action -{ -public: - gsl_api explicit final_action_return( F && action ) gsl_noexcept - : final_action( std::move( action ) ) - {} + namespace std20 { - gsl_api final_action_return( final_action_return && other ) gsl_noexcept - : final_action( std::move( other ) ) - {} +#if gsl_CPP11_100 - gsl_api ~final_action_return() override + struct identity { - if ( this->uncaught_exceptions() ) - this->dismiss(); - } + template < class T > + gsl_constexpr T && operator ()( T && arg ) const gsl_noexcept + { + return std::forward( arg ); + } + }; -gsl_is_delete_access: - gsl_api final_action_return( final_action_return const & ) gsl_is_delete; - gsl_api final_action_return & operator=( final_action_return const & ) gsl_is_delete; -}; +#endif // gsl_CPP11_100 -template< class F > -gsl_api inline final_action_return on_return( F const & action ) gsl_noexcept -{ - return final_action_return( action ); -} + template< class T > + struct type_identity + { + typedef T type; + }; +#if gsl_HAVE( ALIAS_TEMPLATE ) + template< class T > + using type_identity_t = typename type_identity::type; +#endif // gsl_HAVE( ALIAS_TEMPLATE ) -template< class F > -gsl_api inline final_action_return on_return( F && action ) gsl_noexcept -{ - return final_action_return( std::forward( action ) ); -} +#if gsl_HAVE( STD_SSIZE ) -template< class F > -class final_action_error : public final_action -{ -public: - gsl_api explicit final_action_error( F && action ) gsl_noexcept - : final_action( std::move( action ) ) - {} + using std::ssize; - gsl_api final_action_error( final_action_error && other ) gsl_noexcept - : final_action( std::move( other ) ) - {} +#elif gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) - gsl_api ~final_action_error() override + template < class C > + gsl_constexpr auto ssize( C const & c ) + -> typename std::common_type::type>::type { - if ( ! this->uncaught_exceptions() ) - this->dismiss(); + using R = typename std::common_type::type>::type; + return static_cast( c.size() ); } -gsl_is_delete_access: - gsl_api final_action_error( final_action_error const & ) gsl_is_delete; - gsl_api final_action_error & operator=( final_action_error const & ) gsl_is_delete; -}; + template + gsl_constexpr auto ssize( T const(&)[N] ) gsl_noexcept -> std::ptrdiff_t + { + return std::ptrdiff_t( N ); + } -template< class F > -gsl_api inline final_action_error on_error( F const & action ) gsl_noexcept -{ - return final_action_error( action ); -} +#endif // gsl_HAVE( STD_SSIZE ) -template< class F > -gsl_api inline final_action_error on_error( F && action ) gsl_noexcept -{ - return final_action_error( std::forward( action ) ); -} +#if gsl_HAVE( REMOVE_CVREF ) -#endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + using std::remove_cvref; -#else // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 110 +#else -class final_action -{ -public: - typedef void (*Action)(); + template< class T > struct remove_cvref { typedef typename std11::remove_cv< typename std11::remove_reference< T >::type >::type type; }; - gsl_api final_action( Action action ) - : action_( action ) - , invoke_( true ) - {} +#endif // gsl_HAVE( REMOVE_CVREF ) - gsl_api final_action( final_action const & other ) - : action_( other.action_ ) - , invoke_( other.invoke_ ) - { - other.invoke_ = false; - } + } // namespace std20 - gsl_api virtual ~final_action() - { - if ( invoke_ ) - action_(); - } + namespace detail { -protected: - gsl_api void dismiss() - { - invoke_ = false; - } + /// for nsel_REQUIRES_T - gsl_api int uncaught_exceptions() - { - return std::uncaught_exception() ? 1 : 0; - } + /*enum*/ class enabler{}; -private: - gsl_api final_action & operator=( final_action const & ); +#if gsl_HAVE( TYPE_TRAITS ) -private: - Action action_; - mutable bool invoke_; -}; + template< class Q > + struct is_span_oracle : std::false_type{}; -template< class F > -gsl_api inline final_action finally( F const & f ) -{ - return final_action(( f )); -} + template< class T> + struct is_span_oracle< span > : std::true_type{}; -#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + template< class Q > + struct is_span : is_span_oracle< typename std::remove_cv::type >{}; -class final_action_return : public final_action -{ -public: - gsl_api explicit final_action_return( Action action ) - : final_action( action ) - {} + template< class Q > + struct is_std_array_oracle : std::false_type{}; - gsl_api ~final_action_return() - { - if ( this->uncaught_exceptions() ) - this->dismiss(); - } +#if gsl_HAVE( ARRAY ) -private: - gsl_api final_action_return & operator=( final_action_return const & ); -}; + template< class T, std::size_t Extent > + struct is_std_array_oracle< std::array > : std::true_type{}; -template< class F > -gsl_api inline final_action_return on_return( F const & action ) -{ - return final_action_return( action ); -} +#endif -class final_action_error : public final_action -{ -public: - gsl_api explicit final_action_error( Action action ) - : final_action( action ) - {} + template< class Q > + struct is_std_array : is_std_array_oracle< typename std::remove_cv::type >{}; - gsl_api ~final_action_error() - { - if ( ! this->uncaught_exceptions() ) - this->dismiss(); - } + template< class Q > + struct is_array : std::false_type{}; -private: - gsl_api final_action_error & operator=( final_action_error const & ); -}; + template< class T > + struct is_array : std::true_type{}; -template< class F > -gsl_api inline final_action_error on_error( F const & action ) -{ - return final_action_error( action ); -} + template< class T, std::size_t N > + struct is_array : std::true_type{}; -#endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) +#if gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) -#endif // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION == 110 + template< class, class = void > + struct has_size_and_data : std::false_type{}; -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120 + template< class C > + struct has_size_and_data + < + C, std17::void_t< + decltype( std17::size(std::declval()) ), + decltype( std17::data(std::declval()) ) > + > : std::true_type{}; -template< class T, class U > -gsl_api inline gsl_constexpr T narrow_cast( U && u ) gsl_noexcept -{ - return static_cast( std::forward( u ) ); -} + template< class, class, class = void > + struct is_compatible_element : std::false_type {}; -#else + template< class C, class E > + struct is_compatible_element + < + C, E, std17::void_t< + decltype( std17::data(std::declval()) ), + typename std::remove_pointer() ) )>::type(*)[] > + > : std::is_convertible< typename std::remove_pointer() ) )>::type(*)[], E(*)[] >{}; -template< class T, class U > -gsl_api inline T narrow_cast( U u ) gsl_noexcept -{ - return static_cast( u ); -} + template< class C > + struct is_container : std17::bool_constant + < + ! is_span< C >::value + && ! is_array< C >::value + && ! is_std_array< C >::value + && has_size_and_data< C >::value + >{}; -#endif // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120 + template< class C, class E > + struct is_compatible_container : std17::bool_constant + < + is_container::value + && is_compatible_element::value + >{}; + +#else // gsl_CPP11_140 + + template< + class C, class E + , typename = typename std::enable_if< + ! is_span< C >::value + && ! is_array< C >::value + && ! is_std_array< C >::value + && ( std::is_convertible< typename std::remove_pointer() ) )>::type(*)[], E(*)[] >::value) + // && has_size_and_data< C >::value + , enabler>::type + , class = decltype( std17::size(std::declval()) ) + , class = decltype( std17::data(std::declval()) ) + > + struct is_compatible_container : std::true_type{}; + +#endif // gsl_CPP11_140 + +#endif // gsl_HAVE( TYPE_TRAITS ) + + } // namespace detail + + // + // GSL.util: utilities + // + + // Integer type for indices (e.g. in a loop). + typedef gsl_CONFIG_INDEX_TYPE index; + +// +// GSL.owner: ownership pointers +// +#if gsl_HAVE( SHARED_PTR ) + using std::unique_ptr; + using std::shared_ptr; + using std::make_shared; +# if gsl_HAVE( MAKE_UNIQUE ) || gsl_HAVE( VARIADIC_TEMPLATE ) + using std14::make_unique; +# endif +#endif -struct narrowing_error : public std::exception {}; +#if gsl_HAVE( ALIAS_TEMPLATE ) + template< class T + gsl_REQUIRES_T_( std::is_pointer::value ) + > + using owner = T; +#elif gsl_CONFIG_DEFAULTS_VERSION == 0 + // TODO vNext: remove + template< class T > struct owner { typedef T type; }; +#endif + +#define gsl_HAVE_OWNER_TEMPLATE gsl_HAVE_ALIAS_TEMPLATE + +// TODO vNext: remove +#if gsl_FEATURE( OWNER_MACRO ) +# if gsl_HAVE( OWNER_TEMPLATE ) +# define Owner(t) ::gsl::owner +# else +# define Owner(t) ::gsl::owner::type +# endif +#endif + +// +// GSL.assert: assertions +// #if gsl_HAVE( TYPE_TRAITS ) +# define gsl_ELIDE_CONTRACT_( x ) static_assert(::std::is_constructible::value, "argument of contract check must be convertible to bool") +#else +# define gsl_ELIDE_CONTRACT_( x ) +#endif -namespace details -{ - template< class T, class U > - struct is_same_signedness : public std::integral_constant::value == std::is_signed::value> - {}; -} +#if defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ) +# define gsl_ASSUME( x ) gsl_ELIDE_CONTRACT_( x ) /* there is no assume intrinsic in CUDA device code */ +#elif gsl_COMPILER_MSVC_VERSION +# define gsl_ASSUME( x ) __assume( x ) +#elif gsl_COMPILER_GNUC_VERSION +# define gsl_ASSUME( x ) (( x ) ? static_cast(0) : __builtin_unreachable()) +#elif defined(__has_builtin) +# if __has_builtin(__builtin_unreachable) +# define gsl_ASSUME( x ) (( x ) ? static_cast(0) : __builtin_unreachable()) +# endif +#else +# define gsl_ASSUME( x ) gsl_ELIDE_CONTRACT_( x ) /* unknown compiler; cannot rely on assume intrinsic */ #endif -template< class T, class U > -gsl_api inline T narrow( U u ) -{ - T t = narrow_cast( u ); +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast(0) : ::gsl::fail_fast_assert_handler( #x, "GSL: " str, __FILE__, __LINE__ ) ) +#elif defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ) +# define gsl_CONTRACT_CHECK_( str, x ) assert( ( x ) && str ) +#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) +# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast(0) : ::gsl::detail::fail_fast_throw( "GSL: " str " at " __FILE__ ":" gsl_STRINGIFY(__LINE__) ) ) +#else // defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) [default] +# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast(0) : ::gsl::detail::fail_fast_terminate() ) +#endif - if ( static_cast( t ) != u ) - { -#if gsl_CONFIG( CONTRACT_VIOLATION_THROWS_V ) - throw narrowing_error(); +#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) || defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) +# if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) +# define gsl_Expects( x ) gsl_ASSUME( x ) +# else // defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) [default] +# define gsl_Expects( x ) gsl_ELIDE_CONTRACT_( x ) +# endif #else - std::terminate(); +# define gsl_Expects( x ) gsl_CONTRACT_CHECK_( "Precondition failure", x ) #endif - } +#define Expects( x ) gsl_Expects( x ) -#if gsl_HAVE( TYPE_TRAITS ) -# if gsl_COMPILER_MSVC_VERSION - // Suppress MSVC level 4 warning C4127 (conditional expression is constant) - if ( 0, ! details::is_same_signedness::value && ( ( t < T() ) != ( u < U() ) ) ) -# else - if ( ! details::is_same_signedness::value && ( ( t < T() ) != ( u < U() ) ) ) +#if !defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) || defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) +# define gsl_ExpectsAudit( x ) gsl_ELIDE_CONTRACT_( x ) +#else +# define gsl_ExpectsAudit( x ) gsl_CONTRACT_CHECK_( "Precondition failure (audit)", x ) +#endif + +#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) || defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) +# if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) +# define gsl_Ensures( x ) gsl_ASSUME( x ) +# else // defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) [default] +# define gsl_Ensures( x ) gsl_ELIDE_CONTRACT_( x ) # endif #else - // Don't assume T() works: - if ( ( t < 0 ) != ( u < 0 ) ) +# define gsl_Ensures( x ) gsl_CONTRACT_CHECK_( "Postcondition failure", x ) #endif - { -#if gsl_CONFIG( CONTRACT_VIOLATION_THROWS_V ) - throw narrowing_error(); +#define Ensures( x ) gsl_Ensures( x ) + +#if !defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) || defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) +# define gsl_EnsuresAudit( x ) gsl_ELIDE_CONTRACT_( x ) #else - std::terminate(); +# define gsl_EnsuresAudit( x ) gsl_CONTRACT_CHECK_( "Postcondition failure (audit)", x ) #endif + +#define gsl_STRINGIFY( x ) gsl_STRINGIFY_( x ) +#define gsl_STRINGIFY_( x ) #x + + struct fail_fast : public std::logic_error + { + explicit fail_fast( char const * message ) + : std::logic_error( message ) {} + }; + + namespace detail { + + +#if gsl_HAVE( EXCEPTIONS ) + gsl_NORETURN inline void fail_fast_throw( char const * message ) + { + throw fail_fast( message ); + } +#endif // gsl_HAVE( EXCEPTIONS ) + gsl_NORETURN inline void fail_fast_terminate() gsl_noexcept + { + std::terminate(); } - return t; -} -// -// at() - Bounds-checked way of accessing static arrays, std::array, std::vector. -// + } // namespace detail -template< class T, size_t N > -gsl_api inline gsl_constexpr14 T & at( T(&arr)[N], size_t index ) -{ - Expects( index < N ); - return arr[index]; -} + // Should be defined by user + gsl_api void fail_fast_assert_handler( char const * const expression, char const * const message, char const * const file, int line ); -#if gsl_HAVE( ARRAY ) +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) -template< class T, size_t N > -gsl_api inline gsl_constexpr14 T & at( std::array & arr, size_t index ) -{ - Expects( index < N ); - return arr[index]; -} -#endif +# if gsl_HAVE( EXCEPTIONS ) + gsl_DEPRECATED_MSG("don't call gsl::fail_fast_assert() directly; use contract checking macros instead") + gsl_constexpr14 inline + void fail_fast_assert( bool cond, char const * const message ) + { + if ( !cond ) + throw fail_fast( message ); + } +# endif // gsl_HAVE( EXCEPTIONS ) -template< class Container > -gsl_api inline gsl_constexpr14 typename Container::value_type & at( Container & cont, size_t index ) -{ - Expects( index < cont.size() ); - return cont[index]; -} +#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) -#if gsl_HAVE( INITIALIZER_LIST ) + gsl_DEPRECATED_MSG("don't call gsl::fail_fast_assert() directly; use contract checking macros instead") + gsl_api gsl_constexpr14 inline + void fail_fast_assert( bool cond, char const * const expression, char const * const message, char const * const file, int line ) + { + if ( !cond ) + ::gsl::fail_fast_assert_handler( expression, message, file, line ); + } + +#else // defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) [default] + + gsl_DEPRECATED_MSG("don't call gsl::fail_fast_assert() directly; use contract checking macros instead") + gsl_constexpr14 inline + void fail_fast_assert( bool cond ) gsl_noexcept + { + if ( !cond ) + std::terminate(); + } -template< class T > -gsl_api inline const gsl_constexpr14 T & at( std::initializer_list cont, size_t index ) -{ - Expects( index < cont.size() ); - return *( cont.begin() + index ); -} #endif -template< class T > -gsl_api inline gsl_constexpr T & at( span s, size_t index ) -{ - return s.at( index ); -} // -// GSL.views: views +// GSL.util: utilities // -// -// not_null<> - Wrap any indirection and enforce non-null. -// -template< class T > -class not_null -{ -#if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) -# define gsl_not_null_explicit explicit -#else -# define gsl_not_null_explicit /*explicit*/ -#endif +#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) -#if gsl_CONFIG( NOT_NULL_GET_BY_CONST_REF ) - typedef T const & get_result_t; -#else - typedef T get_result_t; -#endif + // Add uncaught_exceptions for pre-2017 MSVC, GCC and Clang + // Return unsigned char to save stack space, uncaught_exceptions can only increase by 1 in a scope -public: -#if gsl_HAVE( TYPE_TRAITS ) - static_assert( std::is_assignable::value, "T cannot be assigned nullptr." ); -#endif + namespace detail { - template< class U -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - , class Dummy = typename std::enable_if::value>::type + gsl_api inline unsigned char to_uchar( unsigned x ) gsl_noexcept + { + return static_cast( x ); + } + + } // namespace detail + + namespace std11 { + +#if gsl_HAVE( UNCAUGHT_EXCEPTIONS ) + + inline unsigned char uncaught_exceptions() gsl_noexcept + { + return detail::to_uchar( std::uncaught_exceptions() ); + } + +#elif gsl_COMPILER_MSVC_VERSION + + extern "C" char * __cdecl _getptd(); + inline unsigned char uncaught_exceptions() gsl_noexcept + { + return detail::to_uchar( *reinterpret_cast(_getptd() + (sizeof(void*) == 8 ? 0x100 : 0x90) ) ); + } + +#elif gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_APPLECLANG_VERSION + + extern "C" char * __cxa_get_globals(); + inline unsigned char uncaught_exceptions() gsl_noexcept + { + return detail::to_uchar( *reinterpret_cast(__cxa_get_globals() + sizeof(void*) ) ); + } #endif - > - gsl_api gsl_constexpr14 gsl_not_null_explicit -#if gsl_HAVE( RVALUE_REFERENCE ) - not_null( U && u ) - : ptr_( std::forward( u ) ) -#else - not_null( U const & u ) - : ptr_( u ) + } // namespace std11 #endif + +#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 110 + + template< class F > + class final_action { - Expects( ptr_ != gsl_nullptr ); + public: + explicit final_action( F action ) gsl_noexcept + : action_( std::move( action ) ) + , invoke_( true ) + {} + + final_action( final_action && other ) gsl_noexcept + : action_( std::move( other.action_ ) ) + , invoke_( other.invoke_ ) + { + other.invoke_ = false; + } + + gsl_SUPPRESS_MSGSL_WARNING(f.6) + virtual ~final_action() gsl_noexcept + { + if ( invoke_ ) + action_(); + } + + gsl_is_delete_access: + final_action( final_action const & ) gsl_is_delete; + final_action & operator=( final_action const & ) gsl_is_delete; + final_action & operator=( final_action && ) gsl_is_delete; + + protected: + void dismiss() gsl_noexcept + { + invoke_ = false; + } + + private: + F action_; + bool invoke_; + }; + + template< class F > + inline final_action finally( F const & action ) gsl_noexcept + { + return final_action( action ); } -#undef gsl_not_null_explicit - -#if gsl_HAVE( IS_DEFAULT ) - gsl_api ~not_null() = default; - gsl_api gsl_constexpr not_null( not_null && other ) = default; - gsl_api gsl_constexpr not_null( not_null const & other ) = default; - gsl_api not_null & operator=( not_null && other ) = default; - gsl_api not_null & operator=( not_null const & other ) = default; -#else - gsl_api ~not_null() {}; - gsl_api gsl_constexpr not_null( not_null const & other ) : ptr_ ( other.ptr_ ) {} - gsl_api not_null & operator=( not_null const & other ) { ptr_ = other.ptr_; return *this; } -# if gsl_HAVE( RVALUE_REFERENCE ) - gsl_api gsl_constexpr not_null( not_null && other ) : ptr_( std::move( other.get() ) ) {} - gsl_api not_null & operator=( not_null && other ) { ptr_ = std::move( other.get() ); return *this; } -# endif -#endif - template< class U -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - , class Dummy = typename std::enable_if::value>::type -#endif - > - gsl_api gsl_constexpr not_null( not_null const & other ) - : ptr_( other.get() ) - {} + template< class F > + inline final_action finally( F && action ) gsl_noexcept + { + return final_action( std::forward( action ) ); + } + +#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + + template< class F > + class final_action_return : public final_action + { + public: + explicit final_action_return( F && action ) gsl_noexcept + : final_action( std::move( action ) ) + , exception_count( std11::uncaught_exceptions() ) + {} + + final_action_return( final_action_return && other ) gsl_noexcept + : final_action( std::move( other ) ) + , exception_count( std11::uncaught_exceptions() ) + {} + + ~final_action_return() override + { + if ( std11::uncaught_exceptions() != exception_count ) + this->dismiss(); + } + + gsl_is_delete_access: + final_action_return( final_action_return const & ) gsl_is_delete; + final_action_return & operator=( final_action_return const & ) gsl_is_delete; - gsl_api gsl_constexpr14 get_result_t get() const + private: + unsigned char exception_count; + }; + + template< class F > + inline final_action_return on_return( F const & action ) gsl_noexcept { - // Without cheating and changing ptr_ from the outside, this check is superfluous: - Ensures( ptr_ != gsl_nullptr ); - return ptr_; + return final_action_return( action ); } - gsl_api gsl_constexpr operator get_result_t () const { return get(); } - gsl_api gsl_constexpr get_result_t operator->() const { return get(); } + template< class F > + inline final_action_return on_return( F && action ) gsl_noexcept + { + return final_action_return( std::forward( action ) ); + } -#if gsl_HAVE( DECLTYPE_AUTO ) - gsl_api gsl_constexpr decltype(auto) operator*() const { return *get(); } -#endif + template< class F > + class final_action_error : public final_action + { + public: + explicit final_action_error( F && action ) gsl_noexcept + : final_action( std::move( action ) ) + , exception_count( std11::uncaught_exceptions() ) + {} + + final_action_error( final_action_error && other ) gsl_noexcept + : final_action( std::move( other ) ) + , exception_count( std11::uncaught_exceptions() ) + {} + + ~final_action_error() override + { + if ( std11::uncaught_exceptions() == exception_count ) + this->dismiss(); + } -gsl_is_delete_access: - // prevent compilation when initialized with a nullptr or literal 0: -#if gsl_HAVE( NULLPTR ) - gsl_api not_null( std::nullptr_t ) gsl_is_delete; - gsl_api not_null & operator=( std::nullptr_t ) gsl_is_delete; -#else - gsl_api not_null( int ) gsl_is_delete; - gsl_api not_null & operator=( int ) gsl_is_delete; -#endif - - // unwanted operators...pointers only point to single objects! - gsl_api not_null & operator++() gsl_is_delete; - gsl_api not_null & operator--() gsl_is_delete; - gsl_api not_null operator++( int ) gsl_is_delete; - gsl_api not_null operator--( int ) gsl_is_delete; - gsl_api not_null & operator+ ( size_t ) gsl_is_delete; - gsl_api not_null & operator+=( size_t ) gsl_is_delete; - gsl_api not_null & operator- ( size_t ) gsl_is_delete; - gsl_api not_null & operator-=( size_t ) gsl_is_delete; - gsl_api not_null & operator+=( std::ptrdiff_t ) gsl_is_delete; - gsl_api not_null & operator-=( std::ptrdiff_t ) gsl_is_delete; - gsl_api void operator[]( std::ptrdiff_t ) const gsl_is_delete; - -private: - T ptr_; -}; + gsl_is_delete_access: + final_action_error( final_action_error const & ) gsl_is_delete; + final_action_error & operator=( final_action_error const & ) gsl_is_delete; -// not_null with implicit constructor, allowing copy-initialization: + private: + unsigned char exception_count; + }; -template< class T > -class not_null_ic : public not_null -{ -public: - template< class U -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - , class Dummy = typename std::enable_if::value>::type -#endif - > - gsl_api gsl_constexpr14 -#if gsl_HAVE( RVALUE_REFERENCE ) - not_null_ic( U && u ) - : not_null( std::forward( u ) ) -#else - not_null_ic( U const & u ) - : not_null( u ) -#endif - {} -}; + template< class F > + inline final_action_error on_error( F const & action ) gsl_noexcept + { + return final_action_error( action ); + } -// more not_null unwanted operators + template< class F > + inline final_action_error on_error( F && action ) gsl_noexcept + { + return final_action_error( std::forward( action ) ); + } -template< class T, class U > -std::ptrdiff_t operator-( not_null const &, not_null const & ) gsl_is_delete; +#endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) -template< class T > -not_null operator-( not_null const &, std::ptrdiff_t ) gsl_is_delete; +#else // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 110 -template< class T > -not_null operator+( not_null const &, std::ptrdiff_t ) gsl_is_delete; + class final_action + { + public: + typedef void (*Action)(); -template< class T > -not_null operator+( std::ptrdiff_t, not_null const & ) gsl_is_delete; + final_action( Action action ) + : action_( action ) + , invoke_( true ) + {} -// not_null comparisons + final_action( final_action const & other ) + : action_( other.action_ ) + , invoke_( other.invoke_ ) + { + other.invoke_ = false; + } -template< class T, class U > -gsl_api inline gsl_constexpr bool operator==( not_null const & l, not_null const & r ) -{ - return l.get() == r.get(); -} + virtual ~final_action() + { + if ( invoke_ ) + action_(); + } -template< class T, class U > -gsl_api inline gsl_constexpr bool operator< ( not_null const & l, not_null const & r ) -{ - return l.get() < r.get(); -} + protected: + void dismiss() + { + invoke_ = false; + } -template< class T, class U > -gsl_api inline gsl_constexpr bool operator!=( not_null const & l, not_null const & r ) -{ - return !( l == r ); -} + private: + final_action & operator=( final_action const & ); -template< class T, class U > -gsl_api inline gsl_constexpr bool operator<=( not_null const & l, not_null const & r ) -{ - return !( r < l ); -} + private: + Action action_; + mutable bool invoke_; + }; -template< class T, class U > -gsl_api inline gsl_constexpr bool operator> ( not_null const & l, not_null const & r ) -{ - return ( r < l ); -} + template< class F > + inline final_action finally( F const & f ) + { + return final_action(( f )); + } -template< class T, class U > -gsl_api inline gsl_constexpr bool operator>=( not_null const & l, not_null const & r ) -{ - return !( l < r ); -} +#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) -// -// Byte-specific type. -// -#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - enum class gsl_may_alias byte : unsigned char {}; -#else - struct gsl_may_alias byte { typedef unsigned char type; type v; }; -#endif + class final_action_return : public final_action + { + public: + explicit final_action_return( Action action ) + : final_action( action ) + , exception_count( std11::uncaught_exceptions() ) + {} -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) -# define gsl_ENABLE_IF_INTEGRAL_T(T) \ - , class = typename std::enable_if::value>::type -#else -# define gsl_ENABLE_IF_INTEGRAL_T(T) -#endif + ~final_action_return() + { + if ( std11::uncaught_exceptions() != exception_count ) + this->dismiss(); + } -template< class T > -gsl_api inline gsl_constexpr byte to_byte( T v ) gsl_noexcept -{ -#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - return static_cast( v ); -#elif gsl_HAVE( CONSTEXPR_11 ) - return { static_cast( v ) }; -#else - byte b = { static_cast( v ) }; return b; -#endif -} + private: + final_action_return & operator=( final_action_return const & ); -template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > -gsl_api inline gsl_constexpr IntegerType to_integer( byte b ) gsl_noexcept -{ -#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - return static_cast::type>( b ); -#else - return b.v; -#endif -} + private: + unsigned char exception_count; + }; -gsl_api inline gsl_constexpr unsigned char to_uchar( byte b ) gsl_noexcept -{ - return to_integer( b ); -} + template< class F > + inline final_action_return on_return( F const & action ) + { + return final_action_return( action ); + } -gsl_api inline gsl_constexpr unsigned char to_uchar( int i ) gsl_noexcept -{ - return static_cast( i ); -} + class final_action_error : public final_action + { + public: + explicit final_action_error( Action action ) + : final_action( action ) + , exception_count( std11::uncaught_exceptions() ) + {} -#if ! gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + ~final_action_error() + { + if ( std11::uncaught_exceptions() == exception_count ) + this->dismiss(); + } -gsl_api inline gsl_constexpr bool operator==( byte l, byte r ) gsl_noexcept -{ - return l.v == r.v; -} + private: + final_action_error & operator=( final_action_error const & ); -gsl_api inline gsl_constexpr bool operator!=( byte l, byte r ) gsl_noexcept -{ - return !( l == r ); -} + private: + unsigned char exception_count; + }; -gsl_api inline gsl_constexpr bool operator< ( byte l, byte r ) gsl_noexcept -{ - return l.v < r.v; -} + template< class F > + inline final_action_error on_error( F const & action ) + { + return final_action_error( action ); + } -gsl_api inline gsl_constexpr bool operator<=( byte l, byte r ) gsl_noexcept -{ - return !( r < l ); -} +#endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) -gsl_api inline gsl_constexpr bool operator> ( byte l, byte r ) gsl_noexcept -{ - return ( r < l ); -} +#endif // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION == 110 + +#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120 + + template< class T, class U > + gsl_api inline gsl_constexpr T narrow_cast( U && u ) gsl_noexcept + { + return static_cast( std::forward( u ) ); + } + +#else + + template< class T, class U > + gsl_api inline T narrow_cast( U u ) gsl_noexcept + { + return static_cast( u ); + } + +#endif // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120 + + struct narrowing_error : public std::exception {}; + +#if gsl_HAVE( TYPE_TRAITS ) + + namespace detail { + + template< class T, class U > + struct is_same_signedness : public std::integral_constant::value == std::is_signed::value> + {}; + +# if defined( __NVCC__ ) + // We do this to circumvent NVCC warnings about pointless unsigned comparisons with 0. + template< class T > + gsl_constexpr gsl_api bool is_negative( T value, std::true_type /*isSigned*/ ) gsl_noexcept + { + return value < T(); + } + template< class T > + gsl_constexpr gsl_api bool is_negative( T /*value*/, std::false_type /*isUnsigned*/ ) gsl_noexcept + { + return false; + } + template< class T, class U > + gsl_constexpr gsl_api bool have_same_sign( T t, U u, std::true_type /*isSameSignedness*/ ) gsl_noexcept + { + return true; + } + template< class T, class U > + gsl_constexpr gsl_api bool have_same_sign( T t, U u, std::false_type /*isSameSignedness*/ ) gsl_noexcept + { + return detail::is_negative( t, std::is_signed() ) == detail::is_negative( u, std::is_signed() ); + } +# endif // defined( __NVCC__ ) + + } // namespace detail + +#endif + +#if gsl_HAVE( EXCEPTIONS ) || !gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION + template< class T, class U > +# if !gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION && !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + gsl_api +# endif // !gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION && !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + inline T narrow( U u ) + { + T t = static_cast( u ); + + if ( static_cast( t ) != u ) + { +# if gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION || defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + throw narrowing_error(); +# else + std::terminate(); +# endif + } + +# if gsl_HAVE( TYPE_TRAITS ) +# if defined( __NVCC__ ) + if ( ! detail::have_same_sign( t, u, detail::is_same_signedness() ) ) +# else + gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) + if ( ! detail::is_same_signedness::value && ( t < T() ) != ( u < U() ) ) +# endif +# else + // Don't assume T() works: + gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) + if ( ( t < 0 ) != ( u < 0 ) ) +# endif + { +# if gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION || defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + throw narrowing_error(); +# else + std::terminate(); +# endif + } + + return t; + } +#endif // gsl_HAVE( EXCEPTIONS ) || !gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION + + template< class T, class U > + gsl_api inline T narrow_failfast( U u ) + { + T t = static_cast( u ); + + gsl_Expects( static_cast( t ) == u ); + +#if gsl_HAVE( TYPE_TRAITS ) +# if defined( __NVCC__ ) + gsl_Expects( ::gsl::detail::have_same_sign( t, u, ::gsl::detail::is_same_signedness() ) ); +# else + gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) + gsl_Expects( ( ::gsl::detail::is_same_signedness::value || ( t < T() ) == ( u < U() ) ) ); +# endif +#else + // Don't assume T() works: + gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) + gsl_Expects( ( t < 0 ) == ( u < 0 ) ); +#endif + + return t; + } + + + // + // at() - Bounds-checked way of accessing static arrays, std::array, std::vector. + // + + template< class T, size_t N > + gsl_api inline gsl_constexpr14 T & at( T(&arr)[N], size_t pos ) + { + gsl_Expects( pos < N ); + return arr[pos]; + } + + template< class Container > + inline gsl_constexpr14 typename Container::value_type & at( Container & cont, size_t pos ) + { + gsl_Expects( pos < cont.size() ); + return cont[pos]; + } + + template< class Container > + inline gsl_constexpr14 typename Container::value_type const & at( Container const & cont, size_t pos ) + { + gsl_Expects( pos < cont.size() ); + return cont[pos]; + } + +#if gsl_HAVE( INITIALIZER_LIST ) + + template< class T > + inline const gsl_constexpr14 T at( std::initializer_list cont, size_t pos ) + { + gsl_Expects( pos < cont.size() ); + return *( cont.begin() + pos ); + } +#endif + + template< class T > + gsl_api inline gsl_constexpr14 T & at( span s, size_t pos ) + { + return s[ pos ]; + } + + // + // GSL.views: views + // + + // + // not_null<> - Wrap any indirection and enforce non-null. + // + + template< class T > + class not_null; + + namespace detail { + +// helper class to figure out the pointed-to type of a pointer +#if gsl_CPP11_OR_GREATER + template< class T, class E = void > + struct element_type_helper + { + // For types without a member element_type (this will handle raw pointers) + typedef typename std::remove_reference< decltype( *std::declval() ) >::type type; + }; + + template< class T > + struct element_type_helper< T, std17::void_t< typename T::element_type > > + { + // For types with a member element_type + typedef typename T::element_type type; + }; +#else + // Pre-C++11, we cannot have decltype, so we cannot handle types without a member element_type + template< class T, class E = void > + struct element_type_helper + { + typedef typename T::element_type type; + }; + + template< class T > + struct element_type_helper< T* > + { + typedef T type; + }; +#endif + + template< class T > + struct is_not_null_oracle : std11::false_type { }; + template< class T > + struct is_not_null_oracle< not_null > : std11::true_type { }; + + template< class T, bool IsCopyable = true > + struct not_null_data; +#if gsl_HAVE( RVALUE_REFERENCE ) && gsl_HAVE( TYPE_TRAITS ) + template< class T > + struct not_null_data< T, false > + { + T ptr_; + + gsl_constexpr14 not_null_data( T && _ptr ) gsl_noexcept + : ptr_( std::move( _ptr ) ) + { + } + + gsl_constexpr14 not_null_data( not_null_data && other ) gsl_noexcept + : ptr_( std::move( other.ptr_ ) ) + { + } + gsl_constexpr14 not_null_data & operator=( not_null_data && other ) gsl_noexcept + { + ptr_ = std::move( other.ptr_ ); + return *this; + } + + gsl_is_delete_access: + not_null_data( not_null_data const & other ) gsl_is_delete; + not_null_data & operator=( not_null_data const & other ) gsl_is_delete; + }; +#endif // gsl_HAVE( RVALUE_REFERENCE ) && gsl_HAVE( TYPE_TRAITS ) + template< class T > + struct not_null_data< T, true > + { + T ptr_; + + gsl_constexpr14 not_null_data( T const & _ptr ) gsl_noexcept + : ptr_( _ptr ) + { + } + +#if gsl_HAVE( RVALUE_REFERENCE ) + gsl_constexpr14 not_null_data( T && _ptr ) gsl_noexcept + : ptr_( std::move( _ptr ) ) + { + } + + gsl_constexpr14 not_null_data( not_null_data && other ) gsl_noexcept + : ptr_( std::move( other.ptr_ ) ) + { + } + gsl_constexpr14 not_null_data & operator=( not_null_data && other ) gsl_noexcept + { + ptr_ = std::move( other.ptr_ ); + return *this; + } +#endif // gsl_HAVE( RVALUE_REFERENCE ) + + gsl_constexpr14 not_null_data( not_null_data const & other ) + : ptr_( other.ptr_ ) + { + gsl_Expects( ptr_ != gsl_nullptr ); + } + gsl_constexpr14 not_null_data & operator=( not_null_data const & other ) + { + gsl_Expects( other.ptr_ != gsl_nullptr ); + ptr_ = other.ptr_; + return *this; + } + }; + + template< class T > + struct is_copyable +#if gsl_HAVE( TYPE_TRAITS ) + : std11::integral_constant< bool, std::is_copy_constructible::value && std::is_copy_assignable::value > +#else + : std11::true_type +#endif + { + }; +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( UNIQUE_PTR ) && gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + // Type traits are buggy in VC++ 2013, so we explicitly declare `unique_ptr<>` non-copyable. + template< class T, class Deleter > + struct is_copyable< std::unique_ptr< T, Deleter > > : std11::false_type + { + }; +#endif + + } // namespace detail + + template< class T > + class not_null + { + private: + detail::not_null_data< T, detail::is_copyable< T >::value > data_; + + // need to access `not_null::data_` + template< class U > + friend class not_null; + + public: + typedef typename detail::element_type_helper::type element_type; + +#if gsl_HAVE( TYPE_TRAITS ) + static_assert( std::is_assignable::value, "T cannot be assigned nullptr." ); +#endif + +#if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) +# if gsl_HAVE( RVALUE_REFERENCE ) + template< class U + // In Clang 3.x, `is_constructible>, unique_ptr>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. + // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. +# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< std::is_constructible::value, int >::type = 0 +# endif + > + gsl_constexpr14 explicit not_null( U other ) + : data_( T( std::move( other ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# else // a.k.a. !gsl_HAVE( RVALUE_REFERENCE ) + template< class U > + gsl_constexpr14 explicit not_null( U const& other ) + : data_( T( other ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# endif // gsl_HAVE( RVALUE_REFERENCE ) +#else // a.k.a. !gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) +# if gsl_HAVE( RVALUE_REFERENCE ) + // In Clang 3.x, `is_constructible>, unique_ptr>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. + // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. +# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< std::is_constructible::value && !std::is_convertible::value, int >::type = 0 + > + gsl_constexpr14 explicit not_null( U other ) + : data_( T( std::move( other ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + + template< class U + , typename std::enable_if< std::is_convertible::value, int >::type = 0 + > + gsl_constexpr14 not_null( U other ) + : data_( T( std::move( other ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# else // a.k.a. !( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + // If type_traits are not available, then we can't distinguish `is_convertible<>` and `is_constructible<>`, so we unconditionally permit implicit construction. + template< class U > + gsl_constexpr14 not_null( U other ) + : data_( T( std::move( other ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) +# else // a.k.a. !gsl_HAVE( RVALUE_REFERENCE ) + template< class U > + gsl_constexpr14 not_null( U const& other ) + : data_( T( other ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# endif // gsl_HAVE( RVALUE_REFERENCE ) +#endif // gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) + +# if gsl_HAVE( RVALUE_REFERENCE ) + // In Clang 3.x, `is_constructible>, unique_ptr>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. + // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. +# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< std::is_constructible::value && !std::is_convertible::value, int >::type = 0 + > + gsl_constexpr14 explicit not_null( not_null other ) + : data_( T( std::move( other.data_.ptr_ ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + + template< class U + , typename std::enable_if< std::is_convertible::value, int >::type = 0 + > + gsl_constexpr14 not_null( not_null other ) + : data_( T( std::move( other.data_.ptr_ ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# else // a.k.a. !( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + // If type_traits are not available, then we can't distinguish `is_convertible<>` and `is_constructible<>`, so we unconditionally permit implicit construction. + template< class U > + gsl_constexpr14 not_null( not_null other ) + : data_( T( std::move( other.data_.ptr_ ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + template< class U > + gsl_constexpr14 not_null& operator=( not_null other ) + { + gsl_Expects( other.data_.ptr_ != gsl_nullptr ); + data_.ptr_ = std::move( other.data_.ptr_ ); + return *this; + } +# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && !gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && !gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) +# else // a.k.a. !gsl_HAVE( RVALUE_REFERENCE ) + template< class U > + gsl_constexpr14 not_null( not_null const& other ) + : data_( T( other.data_.ptr_ ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + template< class U > + gsl_constexpr14 not_null& operator=( not_null const & other ) + { + gsl_Expects( other.data_.ptr_ != gsl_nullptr ); + data_.ptr_ = other.data_.ptr_; + return *this; + } +# endif // gsl_HAVE( RVALUE_REFERENCE ) + +#if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + gsl_constexpr14 element_type * + get() const + { + gsl_Ensures( data_.ptr_ != gsl_nullptr ); + return data_.ptr_.get(); + } +#else +# if gsl_CONFIG( NOT_NULL_GET_BY_CONST_REF ) + gsl_constexpr14 T const & get() const + { + gsl_Ensures( data_.ptr_ != gsl_nullptr ); + return data_.ptr_; + } +# else + gsl_constexpr14 T get() const + { + gsl_Ensures( data_.ptr_ != gsl_nullptr ); + return data_.ptr_; + } +# endif +#endif + + // We want an implicit conversion operator that can be used to convert from both lvalues (by + // const reference or by copy) and rvalues (by move). So it seems like we could define + // + // template< class U > + // operator U const &() const & { ... } + // template< class U > + // operator U &&() && { ... } + // + // However, having two conversion operators with different return types renders the assignment + // operator of the result type ambiguous: + // + // not_null> p( ... ); + // std::unique_ptr q; + // q = std::move( p ); // ambiguous + // + // To avoid this ambiguity, we have both overloads of the conversion operator return `U` + // rather than `U const &` or `U &&`. This implies that converting an lvalue always induces + // a copy, which can cause unnecessary copies or even fail to compile in some situations: + // + // not_null> sp( ... ); + // std::shared_ptr const & rs = sp; // unnecessary copy + // std::unique_ptr const & ru = p; // error: cannot copy `unique_ptr` + // + // However, these situations are rather unusual, and the following, more frequent situations + // remain unimpaired: + // + // std::shared_ptr vs = sp; // no extra copy + // std::unique_ptr vu = std::move( p ); + +#if gsl_HAVE( RVALUE_REFERENCE ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) + // explicit conversion operator + + template< class U + , typename std::enable_if< std::is_constructible::value && !std::is_convertible::value && !detail::is_not_null_oracle::value, int>::type = 0 + > + gsl_constexpr14 explicit + operator U() const +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + & +# endif + { + gsl_Ensures( data_.ptr_ != gsl_nullptr ); + return U( data_.ptr_ ); + } +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + template< class U + , typename std::enable_if< std::is_constructible::value && !std::is_convertible::value && !detail::is_not_null_oracle::value, int>::type = 0 + > + gsl_constexpr14 explicit + operator U() && + { + gsl_Ensures( data_.ptr_ != gsl_nullptr ); + return U( std::move( data_.ptr_ ) ); + } +# endif + + // implicit conversion operator + template< class U + , typename std::enable_if< std::is_constructible::value && std::is_convertible::value && !detail::is_not_null_oracle::value, int>::type = 0 + > + gsl_constexpr14 + operator U() const +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + & +# endif + { + gsl_Ensures( data_.ptr_ != gsl_nullptr ); + return data_.ptr_; + } +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + template< class U + , typename std::enable_if< std::is_convertible::value && !detail::is_not_null_oracle::value, int>::type = 0 + > + gsl_constexpr14 + operator U() && + { + gsl_Ensures( data_.ptr_ != gsl_nullptr ); + return std::move( data_.ptr_ ); + } +# endif +#else // a.k.a. #if !( gsl_HAVE( RVALUE_REFERENCE ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) ) + template< class U > + gsl_constexpr14 + operator U() const + { + gsl_Ensures( data_.ptr_ != gsl_nullptr ); + return data_.ptr_; + } +#endif // gsl_HAVE( RVALUE_REFERENCE ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) + + gsl_constexpr14 T const & + operator->() const + { + gsl_Ensures( data_.ptr_ != gsl_nullptr ); + return data_.ptr_; + } + + gsl_constexpr14 element_type & + operator*() const + { + gsl_Ensures( data_.ptr_ != gsl_nullptr ); + return *data_.ptr_; + } + +#if gsl_HAVE( RVALUE_REFERENCE ) + // Visual C++ 2013 doesn't generate default move constructors, so we declare them explicitly. + gsl_constexpr14 not_null( not_null && other ) gsl_noexcept + : data_( std::move( other.data_ ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + gsl_constexpr14 not_null & operator=( not_null && other ) gsl_noexcept + { + gsl_Expects( other.data_.ptr_ != gsl_nullptr ); + data_ = std::move( other.data_ ); + return *this; + } +#endif // gsl_HAVE( RVALUE_REFERENCE ) + +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr14 not_null( not_null const & other ) = default; + gsl_constexpr14 not_null & operator=( not_null const & other ) = default; +#endif + + gsl_is_delete_access: + not_null() gsl_is_delete; + // prevent compilation when initialized with a nullptr or literal 0: +#if gsl_HAVE( NULLPTR ) + not_null( std::nullptr_t ) gsl_is_delete; + not_null & operator=( std::nullptr_t ) gsl_is_delete; +#else + not_null( int ) gsl_is_delete; + not_null & operator=( int ) gsl_is_delete; +#endif + + // unwanted operators...pointers only point to single objects! + not_null & operator++() gsl_is_delete; + not_null & operator--() gsl_is_delete; + not_null operator++( int ) gsl_is_delete; + not_null operator--( int ) gsl_is_delete; + not_null & operator+ ( size_t ) gsl_is_delete; + not_null & operator+=( size_t ) gsl_is_delete; + not_null & operator- ( size_t ) gsl_is_delete; + not_null & operator-=( size_t ) gsl_is_delete; + not_null & operator+=( std::ptrdiff_t ) gsl_is_delete; + not_null & operator-=( std::ptrdiff_t ) gsl_is_delete; + void operator[]( std::ptrdiff_t ) const gsl_is_delete; + }; +#if gsl_HAVE( DEDUCTION_GUIDES ) + template< class U > + not_null( U ) -> not_null; + template< class U > + not_null( not_null ) -> not_null; +#endif + +#if gsl_HAVE( NULLPTR ) + void make_not_null( std::nullptr_t ) gsl_is_delete; +#endif // gsl_HAVE( NULLPTR ) +#if gsl_HAVE( RVALUE_REFERENCE ) + template< class U > + not_null make_not_null( U u ) + { + return not_null( std::move( u ) ); + } + template< class U > + not_null make_not_null( not_null u ) + { + return std::move( u ); + } +#else // a.k.a. !gsl_HAVE( RVALUE_REFERENCE ) + template< class U > + not_null make_not_null( U const & u ) + { + return not_null( u ); + } + template< class U > + not_null make_not_null( not_null const & u ) + { + return u; + } +#endif // gsl_HAVE( RVALUE_REFERENCE ) + + + // not_null with implicit constructor, allowing copy-initialization: + + template< class T > + class not_null_ic : public not_null + { + public: + template< class U + gsl_REQUIRES_A_(( std::is_constructible::value )) + > + gsl_constexpr14 +#if gsl_HAVE( RVALUE_REFERENCE ) + not_null_ic( U && u ) + : not_null( std::forward( u ) ) +#else + not_null_ic( U const & u ) + : not_null( u ) +#endif + {} + }; + + // more not_null unwanted operators + + template< class T, class U > + std::ptrdiff_t operator-( not_null const &, not_null const & ) gsl_is_delete; + + template< class T > + not_null operator-( not_null const &, std::ptrdiff_t ) gsl_is_delete; + + template< class T > + not_null operator+( not_null const &, std::ptrdiff_t ) gsl_is_delete; + + template< class T > + not_null operator+( std::ptrdiff_t, not_null const & ) gsl_is_delete; + + // not_null comparisons + + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() == std::declval() ) + operator==( not_null const & l, not_null const & r ) + { + return l.operator->() == r.operator->(); + } + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() == std::declval() ) + operator==( not_null const & l, U const & r ) + { + return l.operator->() == r; + } + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() == std::declval() ) + operator==( T const & l, not_null const & r ) + { + return l == r.operator->(); + } + + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() < std::declval() ) + operator<( not_null const & l, not_null const & r ) + { + return l.operator->() < r.operator->(); + } + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() < std::declval() ) + operator<( not_null const & l, U const & r ) + { + return l.operator->() < r; + } + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() < std::declval() ) + operator<( T const & l, not_null const & r ) + { + return l < r.operator->(); + } + + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() == std::declval() ) ) + operator!=( not_null const & l, not_null const & r ) + { + return !( l == r ); + } + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() == std::declval() ) ) + operator!=( not_null const & l, U const & r ) + { + return !( l == r ); + } + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() == std::declval() ) ) + operator!=( T const & l, not_null const & r ) + { + return !( l == r ); + } + + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() < std::declval() ) ) + operator<=( not_null const & l, not_null const & r ) + { + return !( r < l ); + } + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() < std::declval() ) ) + operator<=( not_null const & l, U const & r ) + { + return !( r < l ); + } + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() < std::declval() ) ) + operator<=( T const & l, not_null const & r ) + { + return !( r < l ); + } + + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() < std::declval() ) + operator>( not_null const & l, not_null const & r ) + { + return r < l; + } + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() < std::declval() ) + operator>( not_null const & l, U const & r ) + { + return r < l; + } + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, std::declval() < std::declval() ) + operator>( T const & l, not_null const & r ) + { + return r < l; + } + + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() < std::declval() ) ) + operator>=( not_null const & l, not_null const & r ) + { + return !( l < r ); + } + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() < std::declval() ) ) + operator>=( not_null const & l, U const & r ) + { + return !( l < r ); + } + template< class T, class U > + inline gsl_constexpr gsl_DECLTYPE_( bool, !( std::declval() < std::declval() ) ) + operator>=( T const & l, not_null const & r ) + { + return !( l < r ); + } + + // print not_null + + template< class CharType, class Traits, class T > + std::basic_ostream< CharType, Traits > & operator<<( std::basic_ostream< CharType, Traits > & os, not_null const & p ) + { + return os << p.operator->(); + } -gsl_api inline gsl_constexpr bool operator>=( byte l, byte r ) gsl_noexcept -{ - return !( l < r ); -} -#endif -template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > -gsl_api inline gsl_constexpr14 byte & operator<<=( byte & b, IntegerType shift ) gsl_noexcept -{ +// +// Byte-specific type. +// #if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - return b = to_byte( to_uchar( b ) << shift ); + enum class gsl_may_alias byte : unsigned char {}; #else - b.v = to_uchar( b.v << shift ); return b; + struct gsl_may_alias byte { typedef unsigned char type; type v; }; #endif -} -template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > -gsl_api inline gsl_constexpr byte operator<<( byte b, IntegerType shift ) gsl_noexcept -{ - return to_byte( to_uchar( b ) << shift ); -} + template< class T > + gsl_api inline gsl_constexpr byte to_byte( T v ) gsl_noexcept + { +#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + return static_cast( v ); +#elif gsl_HAVE( CONSTEXPR_11 ) + return { static_cast( v ) }; +#else + byte b = { static_cast( v ) }; return b; +#endif + } -template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > -gsl_api inline gsl_constexpr14 byte & operator>>=( byte & b, IntegerType shift ) gsl_noexcept -{ + template< class IntegerType gsl_REQUIRES_A_(( std::is_integral::value )) > + gsl_api inline gsl_constexpr IntegerType to_integer( byte b ) gsl_noexcept + { #if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - return b = to_byte( to_uchar( b ) >> shift ); + return static_cast::type>( b ); #else - b.v = to_uchar( b.v >> shift ); return b; + return b.v; #endif -} + } -template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > -gsl_api inline gsl_constexpr byte operator>>( byte b, IntegerType shift ) gsl_noexcept -{ - return to_byte( to_uchar( b ) >> shift ); -} + gsl_api inline gsl_constexpr unsigned char to_uchar( byte b ) gsl_noexcept + { + return to_integer( b ); + } -gsl_api inline gsl_constexpr14 byte & operator|=( byte & l, byte r ) gsl_noexcept -{ + gsl_api inline gsl_constexpr unsigned char to_uchar( int i ) gsl_noexcept + { + return static_cast( i ); + } + + template< class IntegerType gsl_REQUIRES_A_(( std::is_integral::value )) > + gsl_api inline gsl_constexpr14 byte & operator<<=( byte & b, IntegerType shift ) gsl_noexcept + { #if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - return l = to_byte( to_uchar( l ) | to_uchar( r ) ); + return b = ::gsl::to_byte( ::gsl::to_uchar( b ) << shift ); #else - l.v = to_uchar( l ) | to_uchar( r ); return l; + b.v = ::gsl::to_uchar( b.v << shift ); return b; #endif -} + } -gsl_api inline gsl_constexpr byte operator|( byte l, byte r ) gsl_noexcept -{ - return to_byte( to_uchar( l ) | to_uchar( r ) ); -} + template< class IntegerType gsl_REQUIRES_A_(( std::is_integral::value )) > + gsl_api inline gsl_constexpr byte operator<<( byte b, IntegerType shift ) gsl_noexcept + { + return ::gsl::to_byte( ::gsl::to_uchar( b ) << shift ); + } -gsl_api inline gsl_constexpr14 byte & operator&=( byte & l, byte r ) gsl_noexcept -{ + template< class IntegerType gsl_REQUIRES_A_(( std::is_integral::value )) > + gsl_api inline gsl_constexpr14 byte & operator>>=( byte & b, IntegerType shift ) gsl_noexcept + { #if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - return l = to_byte( to_uchar( l ) & to_uchar( r ) ); + return b = ::gsl::to_byte( ::gsl::to_uchar( b ) >> shift ); #else - l.v = to_uchar( l ) & to_uchar( r ); return l; + b.v = ::gsl::to_uchar( b.v >> shift ); return b; #endif -} + } -gsl_api inline gsl_constexpr byte operator&( byte l, byte r ) gsl_noexcept -{ - return to_byte( to_uchar( l ) & to_uchar( r ) ); -} + template< class IntegerType gsl_REQUIRES_A_(( std::is_integral::value )) > + gsl_api inline gsl_constexpr byte operator>>( byte b, IntegerType shift ) gsl_noexcept + { + return ::gsl::to_byte( ::gsl::to_uchar( b ) >> shift ); + } -gsl_api inline gsl_constexpr14 byte & operator^=( byte & l, byte r ) gsl_noexcept -{ #if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) - return l = to_byte( to_uchar( l ) ^ to_uchar (r ) ); -#else - l.v = to_uchar( l ) ^ to_uchar (r ); return l; -#endif -} + gsl_DEFINE_ENUM_BITMASK_OPERATORS( byte ) + gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( byte ) +#else // a.k.a. !gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + gsl_api inline gsl_constexpr bool operator==( byte l, byte r ) gsl_noexcept + { + return l.v == r.v; + } -gsl_api inline gsl_constexpr byte operator^( byte l, byte r ) gsl_noexcept -{ - return to_byte( to_uchar( l ) ^ to_uchar( r ) ); -} + gsl_api inline gsl_constexpr bool operator!=( byte l, byte r ) gsl_noexcept + { + return !( l == r ); + } -gsl_api inline gsl_constexpr byte operator~( byte b ) gsl_noexcept -{ - return to_byte( ~to_uchar( b ) ); -} + gsl_api inline gsl_constexpr bool operator< ( byte l, byte r ) gsl_noexcept + { + return l.v < r.v; + } -#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + gsl_api inline gsl_constexpr bool operator<=( byte l, byte r ) gsl_noexcept + { + return !( r < l ); + } + + gsl_api inline gsl_constexpr bool operator> ( byte l, byte r ) gsl_noexcept + { + return ( r < l ); + } + + gsl_api inline gsl_constexpr bool operator>=( byte l, byte r ) gsl_noexcept + { + return !( l < r ); + } -// Tag to select span constructor taking a container (prevent ms-gsl warning C26426): + gsl_api inline gsl_constexpr14 byte & operator|=( byte & l, byte r ) gsl_noexcept + { + l.v |= r.v; return l; + } -struct with_container_t { gsl_constexpr with_container_t() gsl_noexcept {} }; -const gsl_constexpr with_container_t with_container; + gsl_api inline gsl_constexpr byte operator|( byte l, byte r ) gsl_noexcept + { + return ::gsl::to_byte( l.v | r.v ); + } -#endif + gsl_api inline gsl_constexpr14 byte & operator&=( byte & l, byte r ) gsl_noexcept + { + l.v &= r.v; return l; + } -#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + gsl_api inline gsl_constexpr byte operator&( byte l, byte r ) gsl_noexcept + { + return ::gsl::to_byte( l.v & r.v ); + } + + gsl_api inline gsl_constexpr14 byte & operator^=( byte & l, byte r ) gsl_noexcept + { + l.v ^= r.v; return l; + } + + gsl_api inline gsl_constexpr byte operator^( byte l, byte r ) gsl_noexcept + { + return ::gsl::to_byte( l.v ^ r.v ); + } + + gsl_api inline gsl_constexpr byte operator~( byte b ) gsl_noexcept + { + return ::gsl::to_byte( ~b.v ); + } +#endif // gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) -namespace details { +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) -// Can construct from containers that: + // Tag to select span constructor taking a container: -template< - class Container, class ElementType - , class = typename std::enable_if< - ! details::is_span< Container >::value && - ! details::is_array< Container >::value && - ! details::is_std_array< Container >::value && - std::is_convertible().data())>::type(*)[], ElementType(*)[] >::value - >::type -#if gsl_HAVE( STD_DATA ) - // data(cont) and size(cont) well-formed: - , class = decltype( std::data( std::declval() ) ) - , class = decltype( std::size( std::declval() ) ) -#endif -> -struct can_construct_span_from : details::true_type{}; + struct with_container_t { gsl_constexpr with_container_t() gsl_noexcept {} }; + const gsl_constexpr with_container_t with_container; // TODO: this can lead to ODR violations because the symbol will be defined in multiple translation units -} // namespace details #endif -// -// span<> - A 1D view of contiguous T's, replace (*,len). -// -template< class T > -class span -{ - template< class U > friend class span; + // + // span<> - A 1D view of contiguous T's, replace (*,len). + // + template< class T > + class span + { + template< class U > friend class span; -public: - typedef index index_type; + public: + typedef gsl_CONFIG_SPAN_INDEX_TYPE index_type; - typedef T element_type; - typedef typename details::remove_cv< T >::type value_type; + typedef T element_type; + typedef typename std11::remove_cv< T >::type value_type; - typedef T & reference; - typedef T * pointer; - typedef T const * const_pointer; - typedef T const & const_reference; + typedef T & reference; + typedef T * pointer; + typedef T const * const_pointer; + typedef T const & const_reference; - typedef pointer iterator; - typedef const_pointer const_iterator; + typedef pointer iterator; + typedef const_pointer const_iterator; - typedef std::reverse_iterator< iterator > reverse_iterator; - typedef std::reverse_iterator< const_iterator > const_reverse_iterator; + typedef std::reverse_iterator< iterator > reverse_iterator; + typedef std::reverse_iterator< const_iterator > const_reverse_iterator; - typedef typename std::iterator_traits< iterator >::difference_type difference_type; + typedef typename std::iterator_traits< iterator >::difference_type difference_type; - // 26.7.3.2 Constructors, copy, and assignment [span.cons] + // 26.7.3.2 Constructors, copy, and assignment [span.cons] - gsl_api gsl_constexpr14 span() gsl_noexcept - : first_( gsl_nullptr ) - , last_ ( gsl_nullptr ) - { - Expects( size() == 0 ); - } + gsl_api gsl_constexpr14 span() gsl_noexcept + : first_( gsl_nullptr ) + , last_ ( gsl_nullptr ) + { + } #if ! gsl_DEPRECATE_TO_LEVEL( 5 ) #if gsl_HAVE( NULLPTR ) - gsl_api gsl_constexpr14 span( std::nullptr_t, index_type size_in ) - : first_( nullptr ) - , last_ ( nullptr ) - { - Expects( size_in == 0 ); - } + gsl_api gsl_constexpr14 span( std::nullptr_t, index_type size_in ) + : first_( nullptr ) + , last_ ( nullptr ) + { + gsl_Expects( size_in == 0 ); + } #endif #if gsl_HAVE( IS_DELETE ) - gsl_api gsl_constexpr span( reference data_in ) - : span( &data_in, 1 ) - {} + gsl_DEPRECATED + gsl_api gsl_constexpr span( reference data_in ) + : span( &data_in, 1 ) + {} - gsl_api gsl_constexpr span( element_type && ) = delete; + gsl_api gsl_constexpr span( element_type && ) = delete; #endif #endif // deprecate - gsl_api gsl_constexpr14 span( pointer data_in, index_type size_in ) - : first_( data_in ) - , last_ ( data_in + size_in ) - { - Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); - } + gsl_api gsl_constexpr14 span( pointer data_in, index_type size_in ) + : first_( data_in ) + , last_ ( data_in + size_in ) + { + gsl_Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); + } - gsl_api gsl_constexpr14 span( pointer first_in, pointer last_in ) - : first_( first_in ) - , last_ ( last_in ) - { - Expects( first_in <= last_in ); - } + gsl_api gsl_constexpr14 span( pointer first_in, pointer last_in ) + : first_( first_in ) + , last_ ( last_in ) + { + gsl_Expects( first_in <= last_in ); + } #if ! gsl_DEPRECATE_TO_LEVEL( 5 ) - template< class U > - gsl_api gsl_constexpr14 span( U * & data_in, index_type size_in ) - : first_( data_in ) - , last_ ( data_in + size_in ) - { - Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); - } - - template< class U > - gsl_api gsl_constexpr14 span( U * const & data_in, index_type size_in ) - : first_( data_in ) - , last_ ( data_in + size_in ) - { - Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); - } + template< class U > + gsl_api gsl_constexpr14 span( U * data_in, index_type size_in ) + : first_( data_in ) + , last_ ( data_in + size_in ) + { + gsl_Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); + } #endif // deprecate #if ! gsl_DEPRECATE_TO_LEVEL( 5 ) - template< class U, size_t N > - gsl_api gsl_constexpr span( U (&arr)[N] ) gsl_noexcept - : first_( gsl_ADDRESSOF( arr[0] ) ) - , last_ ( gsl_ADDRESSOF( arr[0] ) + N ) - {} + template< class U, size_t N > + gsl_api gsl_constexpr span( U (&arr)[N] ) gsl_noexcept + : first_( gsl_ADDRESSOF( arr[0] ) ) + , last_ ( gsl_ADDRESSOF( arr[0] ) + N ) + {} #else - template< size_t N -# if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - , class = typename std::enable_if< - std::is_convertible::value - >::type -# endif - > - gsl_api gsl_constexpr span( element_type (&arr)[N] ) gsl_noexcept - : first_( gsl_ADDRESSOF( arr[0] ) ) - , last_ ( gsl_ADDRESSOF( arr[0] ) + N ) - {} + template< size_t N + gsl_REQUIRES_A_(( std::is_convertible::value )) + > + gsl_api gsl_constexpr span( element_type (&arr)[N] ) gsl_noexcept + : first_( gsl_ADDRESSOF( arr[0] ) ) + , last_ ( gsl_ADDRESSOF( arr[0] ) + N ) + {} #endif // deprecate #if gsl_HAVE( ARRAY ) #if ! gsl_DEPRECATE_TO_LEVEL( 5 ) - template< class U, size_t N > - gsl_api gsl_constexpr span( std::array< U, N > & arr ) - : first_( arr.data() ) - , last_ ( arr.data() + N ) - {} + template< class U, size_t N > + gsl_constexpr span( std::array< U, N > & arr ) + : first_( arr.data() ) + , last_ ( arr.data() + N ) + {} - template< class U, size_t N > - gsl_api gsl_constexpr span( std::array< U, N > const & arr ) - : first_( arr.data() ) - , last_ ( arr.data() + N ) - {} + template< class U, size_t N > + gsl_constexpr span( std::array< U, N > const & arr ) + : first_( arr.data() ) + , last_ ( arr.data() + N ) + {} #else - template< size_t N -# if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - , class = typename std::enable_if< - std::is_convertible::value - >::type -# endif - > - gsl_api gsl_constexpr span( std::array< value_type, N > & arr ) - : first_( arr.data() ) - , last_ ( arr.data() + N ) - {} - - template< size_t N -# if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - , class = typename std::enable_if< - std::is_convertible::value - >::type -# endif - > - gsl_api gsl_constexpr span( std::array< value_type, N > const & arr ) - : first_( arr.data() ) - , last_ ( arr.data() + N ) - {} + template< size_t N + gsl_REQUIRES_A_(( std::is_convertible::value )) + > + gsl_constexpr span( std::array< value_type, N > & arr ) + : first_( arr.data() ) + , last_ ( arr.data() + N ) + {} + + template< size_t N + gsl_REQUIRES_A_(( std::is_convertible::value )) + > + gsl_constexpr span( std::array< value_type, N > const & arr ) + : first_( arr.data() ) + , last_ ( arr.data() + N ) + {} #endif // deprecate #endif // gsl_HAVE( ARRAY ) #if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) - template< class Container - , class = typename std::enable_if< - details::can_construct_span_from< Container, element_type >::value - >::type - > - gsl_api gsl_constexpr span( Container & cont ) - : first_( cont.data() ) - , last_ ( cont.data() + cont.size() ) - {} - - template< class Container - , class = typename std::enable_if< - std::is_const< element_type >::value && - details::can_construct_span_from< Container, element_type >::value - >::type - > - gsl_api gsl_constexpr span( Container const & cont ) - : first_( cont.data() ) - , last_ ( cont.data() + cont.size() ) - {} + template< class Container + gsl_REQUIRES_A_(( detail::is_compatible_container< Container, element_type >::value )) + > + gsl_constexpr span( Container & cont ) gsl_noexcept + : first_( std17::data( cont ) ) + , last_ ( std17::data( cont ) + std17::size( cont ) ) + {} + + template< class Container + gsl_REQUIRES_A_(( + std::is_const< element_type >::value + && detail::is_compatible_container< Container, element_type >::value + )) + > + gsl_constexpr span( Container const & cont ) gsl_noexcept + : first_( std17::data( cont ) ) + , last_ ( std17::data( cont ) + std17::size( cont ) ) + {} #elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) - template< class Container > - gsl_api gsl_constexpr span( Container & cont ) - : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) - , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) - {} + template< class Container > + gsl_constexpr span( Container & cont ) + : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) + , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) + {} - template< class Container > - gsl_api gsl_constexpr span( Container const & cont ) - : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) - , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) - {} + template< class Container > + gsl_constexpr span( Container const & cont ) + : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) + , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) + {} #endif #if gsl_FEATURE_TO_STD( WITH_CONTAINER ) - template< class Container > - gsl_api gsl_constexpr span( with_container_t, Container & cont ) - : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) - , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) - {} - - template< class Container > - gsl_api gsl_constexpr span( with_container_t, Container const & cont ) - : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) - , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) - {} - -#endif + template< class Container > + gsl_constexpr span( with_container_t, Container & cont ) gsl_noexcept + : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) + , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) + {} -#if ! gsl_DEPRECATE_TO_LEVEL( 4 ) - // constructor taking shared_ptr deprecated since 0.29.0 + template< class Container > + gsl_constexpr span( with_container_t, Container const & cont ) gsl_noexcept + : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) + , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) + {} -#if gsl_HAVE( SHARED_PTR ) - gsl_api gsl_constexpr span( shared_ptr const & ptr ) - : first_( ptr.get() ) - , last_ ( ptr.get() ? ptr.get() + 1 : 0 ) - {} #endif - // constructors taking unique_ptr deprecated since 0.29.0 +#if !gsl_DEPRECATE_TO_LEVEL( 4 ) + // constructor taking shared_ptr deprecated since 0.29.0 -#if gsl_HAVE( UNIQUE_PTR ) -# if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - template< class ArrayElementType = typename std::add_pointer::type > -# else - template< class ArrayElementType > +# if gsl_HAVE( SHARED_PTR ) + gsl_DEPRECATED + gsl_constexpr span( shared_ptr const & ptr ) + : first_( ptr.get() ) + , last_ ( ptr.get() ? ptr.get() + 1 : gsl_nullptr ) + {} # endif - gsl_api gsl_constexpr span( unique_ptr const & ptr, index_type count ) - : first_( ptr.get() ) - , last_ ( ptr.get() + count ) - {} - gsl_api gsl_constexpr span( unique_ptr const & ptr ) - : first_( ptr.get() ) - , last_ ( ptr.get() ? ptr.get() + 1 : 0 ) - {} -#endif + // constructors taking unique_ptr deprecated since 0.29.0 + +# if gsl_HAVE( UNIQUE_PTR ) +# if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + template< class ArrayElementType = typename std::add_pointer::type > +# else + template< class ArrayElementType > +# endif + gsl_DEPRECATED + gsl_constexpr span( unique_ptr const & ptr, index_type count ) + : first_( ptr.get() ) + , last_ ( ptr.get() + count ) + {} + + gsl_DEPRECATED + gsl_constexpr span( unique_ptr const & ptr ) + : first_( ptr.get() ) + , last_ ( ptr.get() ? ptr.get() + 1 : gsl_nullptr ) + {} +# endif #endif // deprecate shared_ptr, unique_ptr #if gsl_HAVE( IS_DEFAULT ) && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 430, 600) - gsl_api gsl_constexpr span( span && ) gsl_noexcept = default; - gsl_api gsl_constexpr span( span const & ) = default; + gsl_constexpr span( span && ) gsl_noexcept = default; + gsl_constexpr span( span const & ) = default; #else - gsl_api gsl_constexpr span( span const & other ) - : first_( other.begin() ) - , last_ ( other.end() ) - {} + gsl_api gsl_constexpr span( span const & other ) + : first_( other.begin() ) + , last_ ( other.end() ) + {} #endif #if gsl_HAVE( IS_DEFAULT ) - ~span() = default; + gsl_constexpr14 span & operator=( span && ) gsl_noexcept = default; + gsl_constexpr14 span & operator=( span const & ) gsl_noexcept = default; #else - ~span() {} + gsl_constexpr14 span & operator=( span other ) gsl_noexcept + { + first_ = other.first_; + last_ = other.last_; + return *this; + } #endif -#if gsl_HAVE( IS_DEFAULT ) - gsl_api gsl_constexpr14 span & operator=( span && ) gsl_noexcept = default; - gsl_api gsl_constexpr14 span & operator=( span const & ) gsl_noexcept = default; + template< class U + gsl_REQUIRES_A_(( std::is_convertible::value )) + > + gsl_api gsl_constexpr span( span const & other ) + : first_( other.begin() ) + , last_ ( other.end() ) + {} + +#if 0 + // Converting from other span ? + template< class U > operator=(); +#endif + + // 26.7.3.3 Subviews [span.sub] + + gsl_api gsl_constexpr14 span first( index_type count ) const + { + gsl_Expects( std::size_t( count ) <= std::size_t( this->size() ) ); + return span( this->data(), count ); + } + + gsl_api gsl_constexpr14 span last( index_type count ) const + { + gsl_Expects( std::size_t( count ) <= std::size_t( this->size() ) ); + return span( this->data() + this->size() - count, count ); + } + + gsl_api gsl_constexpr14 span subspan( index_type offset ) const + { + gsl_Expects( std::size_t( offset ) <= std::size_t( this->size() ) ); + return span( this->data() + offset, this->size() - offset ); + } + + gsl_api gsl_constexpr14 span subspan( index_type offset, index_type count ) const + { + gsl_Expects( + std::size_t( offset ) <= std::size_t( this->size() ) && + std::size_t( count ) <= std::size_t( this->size() - offset ) ); + return span( this->data() + offset, count ); + } + + // 26.7.3.4 Observers [span.obs] + + gsl_api gsl_constexpr index_type size() const gsl_noexcept + { + return narrow_cast( last_ - first_ ); + } + + gsl_api gsl_constexpr std::ptrdiff_t ssize() const gsl_noexcept + { + return narrow_cast( last_ - first_ ); + } + + gsl_api gsl_constexpr index_type size_bytes() const gsl_noexcept + { + return size() * narrow_cast( sizeof( element_type ) ); + } + + gsl_api gsl_constexpr bool empty() const gsl_noexcept + { + return size() == 0; + } + + // 26.7.3.5 Element access [span.elem] + + gsl_api gsl_constexpr14 reference operator[]( index_type pos ) const + { + gsl_Expects( pos < size() ); + return first_[ pos ]; + } + +#if ! gsl_DEPRECATE_TO_LEVEL( 6 ) + gsl_DEPRECATED_MSG("use subscript indexing instead") + gsl_api gsl_constexpr14 reference operator()( index_type pos ) const + { + return (*this)[ pos ]; + } + + gsl_DEPRECATED_MSG("use subscript indexing instead") + gsl_api gsl_constexpr14 reference at( index_type pos ) const + { + return (*this)[ pos ]; + } +#endif // deprecate + + gsl_api gsl_constexpr14 reference front() const + { + gsl_Expects( first_ != last_ ); + return *first_; + } + + gsl_api gsl_constexpr14 reference back() const + { + gsl_Expects( first_ != last_ ); + return *(last_ - 1); + } + + gsl_api gsl_constexpr pointer data() const gsl_noexcept + { + return first_; + } + + // 26.7.3.6 Iterator support [span.iterators] + + gsl_api gsl_constexpr iterator begin() const gsl_noexcept + { + return iterator( first_ ); + } + + gsl_api gsl_constexpr iterator end() const gsl_noexcept + { + return iterator( last_ ); + } + + gsl_api gsl_constexpr const_iterator cbegin() const gsl_noexcept + { +#if gsl_CPP11_OR_GREATER + return { begin() }; #else - gsl_api span & operator=( span other ) gsl_noexcept - { - other.swap( *this ); - return *this; - } + return const_iterator( begin() ); +#endif + } + + gsl_api gsl_constexpr const_iterator cend() const gsl_noexcept + { +#if gsl_CPP11_OR_GREATER + return { end() }; +#else + return const_iterator( end() ); #endif + } + + gsl_constexpr17 reverse_iterator rbegin() const gsl_noexcept + { + return reverse_iterator( end() ); + } + + gsl_constexpr17 reverse_iterator rend() const gsl_noexcept + { + return reverse_iterator( begin() ); + } + + gsl_constexpr17 const_reverse_iterator crbegin() const gsl_noexcept + { + return const_reverse_iterator( cend() ); + } + + gsl_constexpr17 const_reverse_iterator crend() const gsl_noexcept + { + return const_reverse_iterator( cbegin() ); + } + + gsl_constexpr14 void swap( span & other ) gsl_noexcept + { + std::swap( first_, other.first_ ); + std::swap( last_ , other.last_ ); + } + +#if ! gsl_DEPRECATE_TO_LEVEL( 3 ) + // member length() deprecated since 0.29.0 + + gsl_DEPRECATED_MSG("use size() instead") + gsl_api gsl_constexpr index_type length() const gsl_noexcept + { + return size(); + } + + // member length_bytes() deprecated since 0.29.0 + + gsl_DEPRECATED_MSG("use size_bytes() instead") + gsl_api gsl_constexpr index_type length_bytes() const gsl_noexcept + { + return size_bytes(); + } +#endif + +#if ! gsl_DEPRECATE_TO_LEVEL( 2 ) + // member as_bytes(), as_writeable_bytes deprecated since 0.17.0 + + gsl_DEPRECATED_MSG("use free function gsl::as_bytes() instead") + gsl_api span< const byte > as_bytes() const gsl_noexcept + { + return span< const byte >( reinterpret_cast( data() ), size_bytes() ); // NOLINT + } + + gsl_DEPRECATED_MSG("use free function gsl::as_writable_bytes() instead") + gsl_api span< byte > as_writeable_bytes() const gsl_noexcept + { + return span< byte >( reinterpret_cast( data() ), size_bytes() ); // NOLINT + } - template< class U -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - , class = typename std::enable_if< - std::is_convertible::value - >::type #endif - > - gsl_api gsl_constexpr span( span const & other ) - : first_( other.begin() ) - , last_ ( other.end() ) - {} -#if 0 - // Converting from other span ? - template< class U > operator=(); -#endif + template< class U > + gsl_api span< U > as_span() const + { + gsl_Expects( ( this->size_bytes() % sizeof(U) ) == 0 ); + return span< U >( reinterpret_cast( this->data() ), this->size_bytes() / sizeof( U ) ); // NOLINT + } + + private: + pointer first_; + pointer last_; + }; + +// class template argument deduction guides: + +#if gsl_HAVE( DEDUCTION_GUIDES ) // gsl_CPP17_OR_GREATER + + template< class T, size_t N > + span( T (&)[N] ) -> span; + + template< class T, size_t N > + span( std::array & ) -> span; + + template< class T, size_t N > + span( std::array const & ) -> span; + + template< class Container > + span( Container& ) -> span; + + template< class Container > + span( Container const & ) -> span; + +#endif // gsl_HAVE( DEDUCTION_GUIDES ) + +// 26.7.3.7 Comparison operators [span.comparison] - // 26.7.3.3 Subviews [span.sub] +#if gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) +# if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - gsl_api gsl_constexpr14 span first( index_type count ) const gsl_noexcept + template< class T, class U > + gsl_SUPPRESS_MSGSL_WARNING(stl.1) + inline gsl_constexpr bool operator==( span const & l, span const & r ) { - Expects( 0 <= count && count <= this->size() ); - return span( this->data(), count ); + return l.size() == r.size() + && (l.begin() == r.begin() || std::equal( l.begin(), l.end(), r.begin() ) ); } - gsl_api gsl_constexpr14 span last( index_type count ) const gsl_noexcept + template< class T, class U > + gsl_SUPPRESS_MSGSL_WARNING(stl.1) + inline gsl_constexpr bool operator< ( span const & l, span const & r ) { - Expects( 0 <= count && count <= this->size() ); - return span( this->data() + this->size() - count, count ); + return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); } - gsl_api gsl_constexpr14 span subspan( index_type offset ) const gsl_noexcept - { - Expects( 0 <= offset && offset <= this->size() ); - return span( this->data() + offset, this->size() - offset ); - } +# else // a.k.a. !gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - gsl_api gsl_constexpr14 span subspan( index_type offset, index_type count ) const gsl_noexcept + template< class T > + gsl_SUPPRESS_MSGSL_WARNING(stl.1) + inline gsl_constexpr bool operator==( span const & l, span const & r ) { - Expects( - 0 <= offset && offset <= this->size() && - 0 <= count && count + offset <= this->size() ); - return span( this->data() + offset, count ); + return l.size() == r.size() + && (l.begin() == r.begin() || std::equal( l.begin(), l.end(), r.begin() ) ); } - // 26.7.3.4 Observers [span.obs] - - gsl_api gsl_constexpr index_type size() const gsl_noexcept + template< class T > + gsl_SUPPRESS_MSGSL_WARNING(stl.1) + inline gsl_constexpr bool operator< ( span const & l, span const & r ) { - return narrow_cast( last_ - first_ ); + return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); } +# endif // gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - gsl_api gsl_constexpr index_type size_bytes() const gsl_noexcept + template< class T, class U > + inline gsl_constexpr bool operator!=( span const & l, span const & r ) { - return size() * narrow_cast( sizeof( element_type ) ); + return !( l == r ); } - gsl_api gsl_constexpr bool empty() const gsl_noexcept + template< class T, class U > + inline gsl_constexpr bool operator<=( span const & l, span const & r ) { - return size() == 0; + return !( r < l ); } - // 26.7.3.5 Element access [span.elem] - - gsl_api gsl_constexpr reference operator[]( index_type index ) const + template< class T, class U > + inline gsl_constexpr bool operator> ( span const & l, span const & r ) { - return at( index ); + return ( r < l ); } - gsl_api gsl_constexpr reference operator()( index_type index ) const + template< class T, class U > + inline gsl_constexpr bool operator>=( span const & l, span const & r ) { - return at( index ); + return !( l < r ); } +#endif // gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) - gsl_api gsl_constexpr14 reference at( index_type index ) const + // span algorithms + + template< class T > + gsl_api inline gsl_constexpr std::size_t size( span const & spn ) { - Expects( index < size() ); - return first_[ index ]; + return static_cast( spn.size() ); } - gsl_api gsl_constexpr pointer data() const gsl_noexcept + template< class T > + gsl_api inline gsl_constexpr std::ptrdiff_t ssize( span const & spn ) { - return first_; + return spn.ssize(); } - // 26.7.3.6 Iterator support [span.iterators] + namespace detail { - gsl_api gsl_constexpr iterator begin() const gsl_noexcept + template< class II, class N, class OI > + gsl_api gsl_constexpr14 inline OI copy_n( II first, N count, OI result ) { - return iterator( first_ ); + if ( count > 0 ) + { + *result++ = *first; + for ( N i = 1; i < count; ++i ) + { + *result++ = *++first; + } + } + return result; } - - gsl_api gsl_constexpr iterator end() const gsl_noexcept - { - return iterator( last_ ); } - gsl_api gsl_constexpr const_iterator cbegin() const gsl_noexcept + template< class T, class U > + gsl_api gsl_constexpr14 inline void copy( span src, span dest ) { -#if gsl_CPP11_OR_GREATER - return { begin() }; -#else - return const_iterator( begin() ); +#if gsl_CPP14_OR_GREATER // gsl_HAVE( TYPE_TRAITS ) (circumvent Travis clang 3.4) + static_assert( std::is_assignable::value, "Cannot assign elements of source span to elements of destination span" ); #endif + gsl_Expects( dest.size() >= src.size() ); + detail::copy_n( src.data(), src.size(), dest.data() ); } - gsl_api gsl_constexpr const_iterator cend() const gsl_noexcept + // span creator functions (see ctors) + + template< class T > + gsl_api inline span< const byte > as_bytes( span spn ) gsl_noexcept { -#if gsl_CPP11_OR_GREATER - return { end() }; -#else - return const_iterator( end() ); -#endif + return span< const byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT } - gsl_api gsl_constexpr reverse_iterator rbegin() const gsl_noexcept + template< class T> + gsl_api inline span< byte > as_writable_bytes( span spn ) gsl_noexcept { - return reverse_iterator( end() ); + return span< byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT } - gsl_api gsl_constexpr reverse_iterator rend() const gsl_noexcept +#if ! gsl_DEPRECATE_TO_LEVEL( 6 ) + template< class T> + gsl_DEPRECATED_MSG("use as_writable_bytes() (different spelling) instead") + gsl_api inline span< byte > as_writeable_bytes( span spn ) gsl_noexcept { - return reverse_iterator( begin() ); + return span< byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT } +#endif // deprecate + +#if gsl_FEATURE_TO_STD( MAKE_SPAN ) - gsl_api gsl_constexpr const_reverse_iterator crbegin() const gsl_noexcept + template< class T > + gsl_api inline gsl_constexpr span + make_span( T * ptr, typename span::index_type count ) { - return const_reverse_iterator( cend() ); + return span( ptr, count ); } - gsl_api gsl_constexpr const_reverse_iterator crend() const gsl_noexcept + template< class T > + gsl_api inline gsl_constexpr span + make_span( T * first, T * last ) { - return const_reverse_iterator( cbegin() ); + return span( first, last ); } - gsl_api void swap( span & other ) gsl_noexcept + template< class T, size_t N > + gsl_api inline gsl_constexpr span + make_span( T (&arr)[N] ) { - using std::swap; - swap( first_, other.first_ ); - swap( last_ , other.last_ ); + return span( gsl_ADDRESSOF( arr[0] ), N ); } -#if ! gsl_DEPRECATE_TO_LEVEL( 3 ) - // member length() deprecated since 0.29.0 +#if gsl_HAVE( ARRAY ) - gsl_api gsl_constexpr index_type length() const gsl_noexcept + template< class T, size_t N > + inline gsl_constexpr span + make_span( std::array & arr ) { - return size(); + return span( arr ); } - // member length_bytes() deprecated since 0.29.0 - - gsl_api gsl_constexpr index_type length_bytes() const gsl_noexcept + template< class T, size_t N > + inline gsl_constexpr span + make_span( std::array const & arr ) { - return size_bytes(); + return span( arr ); } #endif -#if ! gsl_DEPRECATE_TO_LEVEL( 2 ) - // member as_bytes(), as_writeable_bytes deprecated since 0.17.0 +#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) && gsl_HAVE( AUTO ) - gsl_api span< const byte > as_bytes() const gsl_noexcept + template< class Container, class EP = decltype( std17::data(std::declval())) > + inline gsl_constexpr auto + make_span( Container & cont ) -> span< typename std::remove_pointer::type > { - return span< const byte >( reinterpret_cast( data() ), size_bytes() ); // NOLINT + return span< typename std::remove_pointer::type >( cont ); } - gsl_api span< byte > as_writeable_bytes() const gsl_noexcept + template< class Container, class EP = decltype( std17::data(std::declval())) > + inline gsl_constexpr auto + make_span( Container const & cont ) -> span< const typename std::remove_pointer::type > { - return span< byte >( reinterpret_cast( data() ), size_bytes() ); // NOLINT + return span< const typename std::remove_pointer::type >( cont ); } -#endif +#else - template< class U > - gsl_api span< U > as_span() const gsl_noexcept + template< class T > + inline span + make_span( std::vector & cont ) { - Expects( ( this->size_bytes() % sizeof(U) ) == 0 ); - return span< U >( reinterpret_cast( this->data() ), this->size_bytes() / sizeof( U ) ); // NOLINT + return span( with_container, cont ); } -private: - pointer first_; - pointer last_; -}; - -// class template argument deduction guides: - -#if gsl_HAVE( DEDUCTION_GUIDES ) // gsl_CPP17_OR_GREATER - -template< class T, size_t N > -span( T (&)[N] ) -> span; - -template< class T, size_t N > -span( std::array & ) -> span; + template< class T > + inline span + make_span( std::vector const & cont ) + { + return span( with_container, cont ); + } +#endif -template< class T, size_t N > -span( std::array const & ) -> span; +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) -template< class Container > -span( Container& ) -> span; + template< class Container > + inline gsl_constexpr span + make_span( with_container_t, Container & cont ) gsl_noexcept + { + return span< typename Container::value_type >( with_container, cont ); + } -template< class Container > -span( Container const & ) -> span; + template< class Container > + inline gsl_constexpr span + make_span( with_container_t, Container const & cont ) gsl_noexcept + { + return span< const typename Container::value_type >( with_container, cont ); + } -#endif // gsl_HAVE( DEDUCTION_GUIDES ) +#endif // gsl_FEATURE_TO_STD( WITH_CONTAINER ) -// 26.7.3.7 Comparison operators [span.comparison] +#if !gsl_DEPRECATE_TO_LEVEL( 4 ) + template< class Ptr > + gsl_DEPRECATED + inline span + make_span( Ptr & ptr ) + { + return span( ptr ); + } +#endif // !gsl_DEPRECATE_TO_LEVEL( 4 ) -#if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + template< class Ptr > + gsl_DEPRECATED + inline span + make_span( Ptr & ptr, typename span::index_type count ) + { + return span( ptr, count ); + } -template< class T, class U > -gsl_api inline gsl_constexpr bool operator==( span const & l, span const & r ) -{ - return l.size() == r.size() - && (l.begin() == r.begin() || std::equal( l.begin(), l.end(), r.begin() ) ); -} +#endif // gsl_FEATURE_TO_STD( MAKE_SPAN ) -template< class T, class U > -gsl_api inline gsl_constexpr bool operator< ( span const & l, span const & r ) -{ - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} +#if gsl_FEATURE_TO_STD( BYTE_SPAN ) -#else + template< class T > + gsl_api inline gsl_constexpr span + byte_span( T & t ) gsl_noexcept + { + return span( reinterpret_cast( &t ), sizeof(T) ); + } -template< class T > -gsl_api inline gsl_constexpr bool operator==( span const & l, span const & r ) -{ - return l.size() == r.size() - && (l.begin() == r.begin() || std::equal( l.begin(), l.end(), r.begin() ) ); -} + template< class T > + gsl_api inline gsl_constexpr span + byte_span( T const & t ) gsl_noexcept + { + return span( reinterpret_cast( &t ), sizeof(T) ); + } -template< class T > -gsl_api inline gsl_constexpr bool operator< ( span const & l, span const & r ) -{ - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} -#endif +#endif // gsl_FEATURE_TO_STD( BYTE_SPAN ) -template< class T, class U > -gsl_api inline gsl_constexpr bool operator!=( span const & l, span const & r ) -{ - return !( l == r ); -} + // + // basic_string_span: + // -template< class T, class U > -gsl_api inline gsl_constexpr bool operator<=( span const & l, span const & r ) -{ - return !( r < l ); -} + template< class T > + class basic_string_span; -template< class T, class U > -gsl_api inline gsl_constexpr bool operator> ( span const & l, span const & r ) -{ - return ( r < l ); -} + namespace detail { -template< class T, class U > -gsl_api inline gsl_constexpr bool operator>=( span const & l, span const & r ) -{ - return !( l < r ); -} + template< class T > + struct is_basic_string_span_oracle : std11::false_type {}; -// span algorithms + template< class T > + struct is_basic_string_span_oracle< basic_string_span > : std11::true_type {}; -namespace details { + template< class T > + struct is_basic_string_span : is_basic_string_span_oracle< typename std11::remove_cv::type > {}; -template< class II, class N, class OI > -gsl_api inline OI copy_n( II first, N count, OI result ) -{ - if ( count > 0 ) + template< class T > + gsl_api inline gsl_constexpr14 std::size_t string_length( T * ptr, std::size_t max ) { - *result++ = *first; - for ( N i = 1; i < count; ++i ) - { - *result++ = *++first; - } - } - return result; -} -} - -template< class T, class U > -gsl_api inline void copy( span src, span dest ) -{ -#if gsl_CPP14_OR_GREATER // gsl_HAVE( TYPE_TRAITS ) (circumvent Travis clang 3.4) - static_assert( std::is_assignable::value, "Cannot assign elements of source span to elements of destination span" ); -#endif - Expects( dest.size() >= src.size() ); - details::copy_n( src.data(), src.size(), dest.data() ); -} - -// span creator functions (see ctors) - -template< class T > -gsl_api inline span< const byte > as_bytes( span spn ) gsl_noexcept -{ - return span< const byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT -} - -template< class T> -gsl_api inline span< byte > as_writeable_bytes( span spn ) gsl_noexcept -{ - return span< byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT -} - -#if gsl_FEATURE_TO_STD( MAKE_SPAN ) - -template< class T > -gsl_api inline gsl_constexpr span -make_span( T * ptr, typename span::index_type count ) -{ - return span( ptr, count ); -} + if ( ptr == gsl_nullptr || max <= 0 ) + return 0; -template< class T > -gsl_api inline gsl_constexpr span -make_span( T * first, T * last ) -{ - return span( first, last ); -} + std::size_t len = 0; + while ( len < max && ptr[len] ) // NOLINT + ++len; -template< class T, size_t N > -gsl_api inline gsl_constexpr span -make_span( T (&arr)[N] ) -{ - return span( gsl_ADDRESSOF( arr[0] ), N ); -} + return len; + } -#if gsl_HAVE( ARRAY ) + } // namespace detail -template< class T, size_t N > -gsl_api inline gsl_constexpr span -make_span( std::array & arr ) -{ - return span( arr ); -} + // + // basic_string_span<> - A view of contiguous characters, replace (*,len). + // + template< class T > + class basic_string_span + { + public: + typedef T element_type; + typedef span span_type; -template< class T, size_t N > -gsl_api inline gsl_constexpr span -make_span( std::array const & arr ) -{ - return span( arr ); -} -#endif + typedef typename span_type::index_type index_type; + typedef typename span_type::difference_type difference_type; -#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) && gsl_HAVE( AUTO ) + typedef typename span_type::pointer pointer ; + typedef typename span_type::reference reference ; -template< class Container, class = decltype(std::declval().data()) > -gsl_api inline gsl_constexpr auto -make_span( Container & cont ) -> span< typename Container::value_type > -{ - return span< typename Container::value_type >( cont ); -} + typedef typename span_type::iterator iterator ; + typedef typename span_type::const_iterator const_iterator ; + typedef typename span_type::reverse_iterator reverse_iterator; + typedef typename span_type::const_reverse_iterator const_reverse_iterator; -template< class Container, class = decltype(std::declval().data()) > -gsl_api inline gsl_constexpr auto -make_span( Container const & cont ) -> span< const typename Container::value_type > -{ - return span< const typename Container::value_type >( cont ); -} + // construction: +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr basic_string_span() gsl_noexcept = default; #else + gsl_api gsl_constexpr basic_string_span() gsl_noexcept {} +#endif -template< class T > -gsl_api inline span -make_span( std::vector & cont ) -{ - return span( with_container, cont ); -} - -template< class T > -gsl_api inline span -make_span( std::vector const & cont ) -{ - return span( with_container, cont ); -} +#if gsl_HAVE( NULLPTR ) + gsl_api gsl_constexpr basic_string_span( std::nullptr_t ) gsl_noexcept + : span_( nullptr, static_cast( 0 ) ) + {} #endif -#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) +#ifdef __CUDACC_RELAXED_CONSTEXPR__ + gsl_api +#endif // __CUDACC_RELAXED_CONSTEXPR__ + gsl_constexpr basic_string_span( pointer ptr ) + : span_( remove_z( ptr, (std::numeric_limits::max)() ) ) + {} -template< class Container > -gsl_api inline gsl_constexpr span -make_span( with_container_t, Container & cont ) gsl_noexcept -{ - return span< typename Container::value_type >( with_container, cont ); -} + gsl_api gsl_constexpr basic_string_span( pointer ptr, index_type count ) + : span_( ptr, count ) + {} -template< class Container > -gsl_api inline gsl_constexpr span -make_span( with_container_t, Container const & cont ) gsl_noexcept -{ - return span< const typename Container::value_type >( with_container, cont ); -} + gsl_api gsl_constexpr basic_string_span( pointer firstElem, pointer lastElem ) + : span_( firstElem, lastElem ) + {} -#endif // gsl_FEATURE_TO_STD( WITH_CONTAINER ) + template< std::size_t N > + gsl_api gsl_constexpr basic_string_span( element_type (&arr)[N] ) + : span_( remove_z( gsl_ADDRESSOF( arr[0] ), N ) ) + {} -template< class Ptr > -gsl_api inline span -make_span( Ptr & ptr ) -{ - return span( ptr ); -} +#if gsl_HAVE( ARRAY ) -template< class Ptr > -gsl_api inline span -make_span( Ptr & ptr, typename span::index_type count ) -{ - return span( ptr, count); -} + template< std::size_t N > + gsl_constexpr basic_string_span( std::array< typename std11::remove_const::type, N> & arr ) + : span_( remove_z( arr ) ) + {} -#endif // gsl_FEATURE_TO_STD( MAKE_SPAN ) + template< std::size_t N > + gsl_constexpr basic_string_span( std::array< typename std11::remove_const::type, N> const & arr ) + : span_( remove_z( arr ) ) + {} -#if gsl_FEATURE_TO_STD( BYTE_SPAN ) +#endif -template< class T > -gsl_api inline gsl_constexpr span -byte_span( T & t ) gsl_noexcept -{ - return span( reinterpret_cast( &t ), sizeof(T) ); -} +#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) -template< class T > -gsl_api inline gsl_constexpr span -byte_span( T const & t ) gsl_noexcept -{ - return span( reinterpret_cast( &t ), sizeof(T) ); -} + // Exclude: array, [basic_string,] basic_string_span + + template< class Container + gsl_REQUIRES_A_(( + ! detail::is_std_array< Container >::value + && ! detail::is_basic_string_span< Container >::value + && std::is_convertible< typename Container::pointer, pointer >::value + && std::is_convertible< typename Container::pointer, decltype(std::declval().data()) >::value + )) + > + gsl_constexpr basic_string_span( Container & cont ) + : span_( ( cont ) ) + {} + + // Exclude: array, [basic_string,] basic_string_span + + template< class Container + gsl_REQUIRES_A_(( + ! detail::is_std_array< Container >::value + && ! detail::is_basic_string_span< Container >::value + && std::is_convertible< typename Container::pointer, pointer >::value + && std::is_convertible< typename Container::pointer, decltype(std::declval().data()) >::value + )) + > + gsl_constexpr basic_string_span( Container const & cont ) + : span_( ( cont ) ) + {} -#endif // gsl_FEATURE_TO_STD( BYTE_SPAN ) +#elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) -// -// basic_string_span: -// + template< class Container > + gsl_constexpr basic_string_span( Container & cont ) + : span_( cont ) + {} -template< class T > -class basic_string_span; + template< class Container > + gsl_constexpr basic_string_span( Container const & cont ) + : span_( cont ) + {} -namespace details { +#else -template< class T > -struct is_basic_string_span_oracle : false_type {}; + template< class U > + gsl_api gsl_constexpr basic_string_span( span const & rhs ) + : span_( rhs ) + {} -template< class T > -struct is_basic_string_span_oracle< basic_string_span > : true_type {}; +#endif -template< class T > -struct is_basic_string_span : is_basic_string_span_oracle< typename remove_cv::type > {}; +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) -template< class T > -gsl_api inline gsl_constexpr14 std::size_t string_length( T * ptr, std::size_t max ) -{ - if ( ptr == gsl_nullptr || max <= 0 ) - return 0; + template< class Container > + gsl_constexpr basic_string_span( with_container_t, Container & cont ) + : span_( with_container, cont ) + {} +#endif - std::size_t len = 0; - while ( len < max && ptr[len] ) // NOLINT - ++len; +#if gsl_HAVE( IS_DEFAULT ) +# if gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 440, 600 ) + gsl_constexpr basic_string_span( basic_string_span const & rhs ) = default; - return len; -} + gsl_constexpr basic_string_span( basic_string_span && rhs ) = default; +# else + gsl_constexpr basic_string_span( basic_string_span const & rhs ) gsl_noexcept = default; -} // namespace details + gsl_constexpr basic_string_span( basic_string_span && rhs ) gsl_noexcept = default; +# endif +#endif -// -// basic_string_span<> - A view of contiguous characters, replace (*,len). -// -template< class T > -class basic_string_span -{ -public: - typedef T element_type; - typedef span span_type; + template< class U + gsl_REQUIRES_A_(( std::is_convertible::pointer, pointer>::value )) + > + gsl_api gsl_constexpr basic_string_span( basic_string_span const & rhs ) + : span_( reinterpret_cast( rhs.data() ), rhs.length() ) // NOLINT + {} - typedef typename span_type::index_type index_type; - typedef typename span_type::difference_type difference_type; +#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120 + template< class U + gsl_REQUIRES_A_(( std::is_convertible::pointer, pointer>::value )) + > + gsl_api gsl_constexpr basic_string_span( basic_string_span && rhs ) + : span_( reinterpret_cast( rhs.data() ), rhs.length() ) // NOLINT + {} +#endif - typedef typename span_type::pointer pointer ; - typedef typename span_type::reference reference ; + template< class CharTraits, class Allocator > + gsl_constexpr basic_string_span( + std::basic_string< typename std11::remove_const::type, CharTraits, Allocator > & str ) + : span_( gsl_ADDRESSOF( str[0] ), str.length() ) + {} - typedef typename span_type::iterator iterator ; - typedef typename span_type::const_iterator const_iterator ; - typedef typename span_type::reverse_iterator reverse_iterator; - typedef typename span_type::const_reverse_iterator const_reverse_iterator; + template< class CharTraits, class Allocator > + gsl_constexpr basic_string_span( + std::basic_string< typename std11::remove_const::type, CharTraits, Allocator > const & str ) + : span_( gsl_ADDRESSOF( str[0] ), str.length() ) + {} - // construction: + // assignment: #if gsl_HAVE( IS_DEFAULT ) - gsl_api gsl_constexpr basic_string_span() gsl_noexcept = default; -#else - gsl_api gsl_constexpr basic_string_span() gsl_noexcept {} -#endif + gsl_constexpr14 basic_string_span & operator=( basic_string_span const & rhs ) gsl_noexcept = default; -#if gsl_HAVE( NULLPTR ) - gsl_api gsl_constexpr basic_string_span( std::nullptr_t ptr ) gsl_noexcept - : span_( ptr, index_type( 0 ) ) - {} + gsl_constexpr14 basic_string_span & operator=( basic_string_span && rhs ) gsl_noexcept = default; #endif - gsl_api gsl_constexpr basic_string_span( pointer ptr ) - : span_( remove_z( ptr, std::numeric_limits::max() ) ) - {} - - gsl_api gsl_constexpr basic_string_span( pointer ptr, index_type count ) - : span_( ptr, count ) - {} + // sub span: - gsl_api gsl_constexpr basic_string_span( pointer firstElem, pointer lastElem ) - : span_( firstElem, lastElem ) - {} - - template< std::size_t N > - gsl_api gsl_constexpr basic_string_span( element_type (&arr)[N] ) - : span_( remove_z( gsl_ADDRESSOF( arr[0] ), N ) ) - {} - -#if gsl_HAVE( ARRAY ) + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_constexpr14 basic_string_span first( index_type count ) const + { + return span_.first( count ); + } - template< std::size_t N > - gsl_api gsl_constexpr basic_string_span( std::array< typename details::remove_const::type, N> & arr ) - : span_( remove_z( arr ) ) - {} + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_constexpr14 basic_string_span last( index_type count ) const + { + return span_.last( count ); + } - template< std::size_t N > - gsl_api gsl_constexpr basic_string_span( std::array< typename details::remove_const::type, N> const & arr ) - : span_( remove_z( arr ) ) - {} + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_constexpr14 basic_string_span subspan( index_type offset ) const + { + return span_.subspan( offset ); + } -#endif + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_constexpr14 basic_string_span subspan( index_type offset, index_type count ) const + { + return span_.subspan( offset, count ); + } -#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + // observers: - // Exclude: array, [basic_string,] basic_string_span + gsl_api gsl_constexpr index_type length() const gsl_noexcept + { + return span_.size(); + } - template< - class Container, - class = typename std::enable_if< - ! details::is_std_array< Container >::value - && ! details::is_basic_string_span< Container >::value - && std::is_convertible< typename Container::pointer, pointer >::value - && std::is_convertible< typename Container::pointer, decltype(std::declval().data()) >::value - >::type - > - gsl_api gsl_constexpr basic_string_span( Container & cont ) - : span_( ( cont ) ) - {} - - // Exclude: array, [basic_string,] basic_string_span + gsl_api gsl_constexpr index_type size() const gsl_noexcept + { + return span_.size(); + } - template< - class Container, - class = typename std::enable_if< - ! details::is_std_array< Container >::value - && ! details::is_basic_string_span< Container >::value - && std::is_convertible< typename Container::pointer, pointer >::value - && std::is_convertible< typename Container::pointer, decltype(std::declval().data()) >::value - >::type - > - gsl_api gsl_constexpr basic_string_span( Container const & cont ) - : span_( ( cont ) ) - {} + gsl_api gsl_constexpr index_type length_bytes() const gsl_noexcept + { + return span_.size_bytes(); + } -#elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + gsl_api gsl_constexpr index_type size_bytes() const gsl_noexcept + { + return span_.size_bytes(); + } - template< class Container > - gsl_api gsl_constexpr basic_string_span( Container & cont ) - : span_( cont ) - {} + gsl_api gsl_constexpr bool empty() const gsl_noexcept + { + return size() == 0; + } - template< class Container > - gsl_api gsl_constexpr basic_string_span( Container const & cont ) - : span_( cont ) - {} + gsl_api gsl_constexpr14 reference operator[]( index_type idx ) const + { + return span_[idx]; + } -#else +#if ! gsl_DEPRECATE_TO_LEVEL( 6 ) + gsl_DEPRECATED_MSG("use subscript indexing instead") + gsl_api gsl_constexpr14 reference operator()( index_type idx ) const + { + return span_[idx]; + } +#endif // deprecate - template< class U > - gsl_api gsl_constexpr basic_string_span( span const & rhs ) - : span_( rhs ) - {} + gsl_api gsl_constexpr14 reference front() const + { + return span_.front(); + } -#endif + gsl_api gsl_constexpr14 reference back() const + { + return span_.back(); + } -#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + gsl_api gsl_constexpr pointer data() const gsl_noexcept + { + return span_.data(); + } - template< class Container > - gsl_api gsl_constexpr basic_string_span( with_container_t, Container & cont ) - : span_( with_container, cont ) - {} -#endif + gsl_api gsl_constexpr iterator begin() const gsl_noexcept + { + return span_.begin(); + } -#if gsl_HAVE( IS_DEFAULT ) -# if gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 440, 600 ) - gsl_api gsl_constexpr basic_string_span( basic_string_span const & rhs ) = default; + gsl_api gsl_constexpr iterator end() const gsl_noexcept + { + return span_.end(); + } - gsl_api gsl_constexpr basic_string_span( basic_string_span && rhs ) = default; -# else - gsl_api gsl_constexpr basic_string_span( basic_string_span const & rhs ) gsl_noexcept = default; + gsl_constexpr17 reverse_iterator rbegin() const gsl_noexcept + { + return span_.rbegin(); + } - gsl_api gsl_constexpr basic_string_span( basic_string_span && rhs ) gsl_noexcept = default; -# endif -#endif + gsl_constexpr17 reverse_iterator rend() const gsl_noexcept + { + return span_.rend(); + } - template< class U -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - , class = typename std::enable_if< std::is_convertible::pointer, pointer>::value >::type -#endif - > - gsl_api gsl_constexpr basic_string_span( basic_string_span const & rhs ) - : span_( reinterpret_cast( rhs.data() ), rhs.length() ) // NOLINT - {} + // const version not in p0123r2: -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120 - template< class U - , class = typename std::enable_if< std::is_convertible::pointer, pointer>::value >::type - > - gsl_api gsl_constexpr basic_string_span( basic_string_span && rhs ) - : span_( reinterpret_cast( rhs.data() ), rhs.length() ) // NOLINT - {} -#endif + gsl_api gsl_constexpr const_iterator cbegin() const gsl_noexcept + { + return span_.cbegin(); + } - template< class CharTraits, class Allocator > - gsl_api gsl_constexpr basic_string_span( - std::basic_string< typename details::remove_const::type, CharTraits, Allocator > & str ) - : span_( gsl_ADDRESSOF( str[0] ), str.length() ) - {} + gsl_api gsl_constexpr const_iterator cend() const gsl_noexcept + { + return span_.cend(); + } - template< class CharTraits, class Allocator > - gsl_api gsl_constexpr basic_string_span( - std::basic_string< typename details::remove_const::type, CharTraits, Allocator > const & str ) - : span_( gsl_ADDRESSOF( str[0] ), str.length() ) - {} + gsl_constexpr17 const_reverse_iterator crbegin() const gsl_noexcept + { + return span_.crbegin(); + } - // destruction, assignment: + gsl_constexpr17 const_reverse_iterator crend() const gsl_noexcept + { + return span_.crend(); + } -#if gsl_HAVE( IS_DEFAULT ) - gsl_api ~basic_string_span() gsl_noexcept = default; + private: + gsl_api static gsl_constexpr14 span_type remove_z( pointer const & sz, std::size_t max ) + { + return span_type( sz, detail::string_length( sz, max ) ); + } - gsl_api basic_string_span & operator=( basic_string_span const & rhs ) gsl_noexcept = default; +#if gsl_HAVE( ARRAY ) + template< size_t N > + static gsl_constexpr14 span_type remove_z( std::array::type, N> & arr ) + { + return remove_z( gsl_ADDRESSOF( arr[0] ), narrow_cast< std::size_t >( N ) ); + } - gsl_api basic_string_span & operator=( basic_string_span && rhs ) gsl_noexcept = default; + template< size_t N > + static gsl_constexpr14 span_type remove_z( std::array::type, N> const & arr ) + { + return remove_z( gsl_ADDRESSOF( arr[0] ), narrow_cast< std::size_t >( N ) ); + } #endif - // sub span: + private: + span_type span_; + }; - gsl_api gsl_constexpr basic_string_span first( index_type count ) const - { - return span_.first( count ); - } +// basic_string_span comparison functions: - gsl_api gsl_constexpr basic_string_span last( index_type count ) const - { - return span_.last( count ); - } +#if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - gsl_api gsl_constexpr basic_string_span subspan( index_type offset ) const + template< class T, class U > + gsl_SUPPRESS_MSGSL_WARNING(stl.1) + inline gsl_constexpr14 bool operator==( basic_string_span const & l, U const & u ) gsl_noexcept { - return span_.subspan( offset ); + const basic_string_span< typename std11::add_const::type > r( u ); + + return l.size() == r.size() + && std::equal( l.begin(), l.end(), r.begin() ); } - gsl_api gsl_constexpr basic_string_span subspan( index_type offset, index_type count ) const + template< class T, class U > + gsl_SUPPRESS_MSGSL_WARNING(stl.1) + inline gsl_constexpr14 bool operator<( basic_string_span const & l, U const & u ) gsl_noexcept { - return span_.subspan( offset, count ); + const basic_string_span< typename std11::add_const::type > r( u ); + + return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); } - // observers: +#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - gsl_api gsl_constexpr index_type length() const gsl_noexcept + template< class T, class U + gsl_REQUIRES_A_(( !detail::is_basic_string_span::value )) + > + gsl_SUPPRESS_MSGSL_WARNING(stl.1) + inline gsl_constexpr14 bool operator==( U const & u, basic_string_span const & r ) gsl_noexcept { - return span_.size(); - } + const basic_string_span< typename std11::add_const::type > l( u ); - gsl_api gsl_constexpr index_type size() const gsl_noexcept - { - return span_.size(); + return l.size() == r.size() + && std::equal( l.begin(), l.end(), r.begin() ); } - gsl_api gsl_constexpr index_type length_bytes() const gsl_noexcept + template< class T, class U + gsl_REQUIRES_A_(( !detail::is_basic_string_span::value )) + > + gsl_SUPPRESS_MSGSL_WARNING(stl.1) + inline gsl_constexpr14 bool operator<( U const & u, basic_string_span const & r ) gsl_noexcept { - return span_.size_bytes(); - } + const basic_string_span< typename std11::add_const::type > l( u ); - gsl_api gsl_constexpr index_type size_bytes() const gsl_noexcept - { - return span_.size_bytes(); + return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); } +#endif - gsl_api gsl_constexpr bool empty() const gsl_noexcept - { - return size() == 0; - } +#else //gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - gsl_api gsl_constexpr reference operator[]( index_type idx ) const + template< class T > + gsl_SUPPRESS_MSGSL_WARNING(stl.1) + inline gsl_constexpr14 bool operator==( basic_string_span const & l, basic_string_span const & r ) gsl_noexcept { - return span_[idx]; + return l.size() == r.size() + && std::equal( l.begin(), l.end(), r.begin() ); } - gsl_api gsl_constexpr reference operator()( index_type idx ) const + template< class T > + gsl_SUPPRESS_MSGSL_WARNING(stl.1) + inline gsl_constexpr14 bool operator<( basic_string_span const & l, basic_string_span const & r ) gsl_noexcept { - return span_[idx]; + return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); } - gsl_api gsl_constexpr pointer data() const gsl_noexcept - { - return span_.data(); - } +#endif // gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - gsl_api iterator begin() const gsl_noexcept + template< class T, class U > + inline gsl_constexpr14 bool operator!=( basic_string_span const & l, U const & r ) gsl_noexcept { - return span_.begin(); + return !( l == r ); } - gsl_api iterator end() const gsl_noexcept + template< class T, class U > + inline gsl_constexpr14 bool operator<=( basic_string_span const & l, U const & r ) gsl_noexcept { - return span_.end(); +#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) || ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + return !( r < l ); +#else + basic_string_span< typename std11::add_const::type > rr( r ); + return !( rr < l ); +#endif } - gsl_api reverse_iterator rbegin() const gsl_noexcept + template< class T, class U > + inline gsl_constexpr14 bool operator>( basic_string_span const & l, U const & r ) gsl_noexcept { - return span_.rbegin(); +#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) || ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + return ( r < l ); +#else + basic_string_span< typename std11::add_const::type > rr( r ); + return ( rr < l ); +#endif } - gsl_api reverse_iterator rend() const gsl_noexcept + template< class T, class U > + inline gsl_constexpr14 bool operator>=( basic_string_span const & l, U const & r ) gsl_noexcept { - return span_.rend(); + return !( l < r ); } - // const version not in p0123r2: +#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) - gsl_api const_iterator cbegin() const gsl_noexcept + template< class T, class U + gsl_REQUIRES_A_(( !detail::is_basic_string_span::value )) + > + inline gsl_constexpr14 bool operator!=( U const & l, basic_string_span const & r ) gsl_noexcept { - return span_.cbegin(); + return !( l == r ); } - gsl_api const_iterator cend() const gsl_noexcept + template< class T, class U + gsl_REQUIRES_A_(( !detail::is_basic_string_span::value )) + > + inline gsl_constexpr14 bool operator<=( U const & l, basic_string_span const & r ) gsl_noexcept { - return span_.cend(); + return !( r < l ); } - gsl_api const_reverse_iterator crbegin() const gsl_noexcept + template< class T, class U + gsl_REQUIRES_A_(( !detail::is_basic_string_span::value )) + > + inline gsl_constexpr14 bool operator>( U const & l, basic_string_span const & r ) gsl_noexcept { - return span_.crbegin(); + return ( r < l ); } - gsl_api const_reverse_iterator crend() const gsl_noexcept + template< class T, class U + gsl_REQUIRES_A_(( !detail::is_basic_string_span::value )) + > + inline gsl_constexpr14 bool operator>=( U const & l, basic_string_span const & r ) gsl_noexcept { - return span_.crend(); + return !( l < r ); } -private: - gsl_api static gsl_constexpr14 span_type remove_z( pointer const & sz, std::size_t max ) - { - return span_type( sz, details::string_length( sz, max ) ); - } +#endif // gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) -#if gsl_HAVE( ARRAY ) - template< size_t N > - gsl_api static gsl_constexpr14 span_type remove_z( std::array::type, N> & arr ) - { - return remove_z( gsl_ADDRESSOF( arr[0] ), narrow_cast< std::size_t >( N ) ); - } + // convert basic_string_span to byte span: - template< size_t N > - gsl_api static gsl_constexpr14 span_type remove_z( std::array::type, N> const & arr ) + template< class T > + gsl_api inline span< const byte > as_bytes( basic_string_span spn ) gsl_noexcept { - return remove_z( gsl_ADDRESSOF( arr[0] ), narrow_cast< std::size_t >( N ) ); + return span< const byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT } -#endif - -private: - span_type span_; -}; -// basic_string_span comparison functions: + // + // String types: + // -#if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + typedef char * zstring; + typedef const char * czstring; -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator==( basic_string_span const & l, U const & u ) gsl_noexcept -{ - const basic_string_span< typename details::add_const::type > r( u ); +#if gsl_HAVE( WCHAR ) + typedef wchar_t * wzstring; + typedef const wchar_t * cwzstring; +#endif - return l.size() == r.size() - && std::equal( l.begin(), l.end(), r.begin() ); -} + typedef basic_string_span< char > string_span; + typedef basic_string_span< char const > cstring_span; -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator<( basic_string_span const & l, U const & u ) gsl_noexcept -{ - const basic_string_span< typename details::add_const::type > r( u ); +#if gsl_HAVE( WCHAR ) + typedef basic_string_span< wchar_t > wstring_span; + typedef basic_string_span< wchar_t const > cwstring_span; +#endif - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} +// to_string() allow (explicit) conversions from string_span to string -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) +#if 0 -template< class T, class U, - class = typename std::enable_if::value >::type > -gsl_api inline gsl_constexpr14 bool operator==( U const & u, basic_string_span const & r ) gsl_noexcept +template< class T > +inline std::basic_string< typename std::remove_const::type > to_string( basic_string_span spn ) { - const basic_string_span< typename details::add_const::type > l( u ); - - return l.size() == r.size() - && std::equal( l.begin(), l.end(), r.begin() ); + std::string( spn.data(), spn.length() ); } -template< class T, class U, - class = typename std::enable_if::value >::type > -gsl_api inline gsl_constexpr14 bool operator<( U const & u, basic_string_span const & r ) gsl_noexcept -{ - const basic_string_span< typename details::add_const::type > l( u ); +#else - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} -#endif + inline std::string to_string( string_span const & spn ) + { + return std::string( spn.data(), spn.length() ); + } -#else //gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + inline std::string to_string( cstring_span const & spn ) + { + return std::string( spn.data(), spn.length() ); + } -template< class T > -gsl_api inline gsl_constexpr14 bool operator==( basic_string_span const & l, basic_string_span const & r ) gsl_noexcept -{ - return l.size() == r.size() - && std::equal( l.begin(), l.end(), r.begin() ); -} +#if gsl_HAVE( WCHAR ) -template< class T > -gsl_api inline gsl_constexpr14 bool operator<( basic_string_span const & l, basic_string_span const & r ) gsl_noexcept -{ - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} + inline std::wstring to_string( wstring_span const & spn ) + { + return std::wstring( spn.data(), spn.length() ); + } -#endif // gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + inline std::wstring to_string( cwstring_span const & spn ) + { + return std::wstring( spn.data(), spn.length() ); + } -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator!=( basic_string_span const & l, U const & r ) gsl_noexcept -{ - return !( l == r ); -} +#endif // gsl_HAVE( WCHAR ) +#endif // to_string() -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator<=( basic_string_span const & l, U const & r ) gsl_noexcept -{ -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) || ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - return !( r < l ); -#else - basic_string_span< typename details::add_const::type > rr( r ); - return !( rr < l ); -#endif -} + // + // Stream output for string_span types + // -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator>( basic_string_span const & l, U const & r ) gsl_noexcept -{ -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) || ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) - return ( r < l ); -#else - basic_string_span< typename details::add_const::type > rr( r ); - return ( rr < l ); -#endif -} + namespace detail { -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator>=( basic_string_span const & l, U const & r ) gsl_noexcept -{ - return !( l < r ); -} + template< class Stream > + void write_padding( Stream & os, std::streamsize n ) + { + for ( std::streamsize i = 0; i < n; ++i ) + os.rdbuf()->sputc( os.fill() ); + } -#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + template< class Stream, class Span > + Stream & write_to_stream( Stream & os, Span const & spn ) + { + typename Stream::sentry sentry( os ); -template< class T, class U, - class = typename std::enable_if::value >::type > -gsl_api inline gsl_constexpr14 bool operator!=( U const & l, basic_string_span const & r ) gsl_noexcept -{ - return !( l == r ); -} + if ( !os ) + return os; -template< class T, class U, - class = typename std::enable_if::value >::type > -gsl_api inline gsl_constexpr14 bool operator<=( U const & l, basic_string_span const & r ) gsl_noexcept -{ - return !( r < l ); -} + const std::streamsize length = narrow( spn.length() ); -template< class T, class U, - class = typename std::enable_if::value >::type > -gsl_api inline gsl_constexpr14 bool operator>( U const & l, basic_string_span const & r ) gsl_noexcept -{ - return ( r < l ); -} + // Whether, and how, to pad + const bool pad = ( length < os.width() ); + const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right; -template< class T, class U, - class = typename std::enable_if::value >::type > -gsl_api inline gsl_constexpr14 bool operator>=( U const & l, basic_string_span const & r ) gsl_noexcept -{ - return !( l < r ); -} + if ( left_pad ) + write_padding( os, os.width() - length ); -#endif // gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + // Write span characters + os.rdbuf()->sputn( spn.begin(), length ); -// convert basic_string_span to byte span: + if ( pad && !left_pad ) + write_padding( os, os.width() - length ); -template< class T > -gsl_api inline span< const byte > as_bytes( basic_string_span spn ) gsl_noexcept -{ - return span< const byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT -} + // Reset output stream width + os.width(0); -// -// String types: -// + return os; + } -typedef char * zstring; -typedef const char * czstring; + } // namespace detail -#if gsl_HAVE( WCHAR ) -typedef wchar_t * zwstring; -typedef const wchar_t * cwzstring; -#endif + template< typename Traits > + std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, string_span const & spn ) + { + return detail::write_to_stream( os, spn ); + } -typedef basic_string_span< char > string_span; -typedef basic_string_span< char const > cstring_span; + template< typename Traits > + std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, cstring_span const & spn ) + { + return detail::write_to_stream( os, spn ); + } #if gsl_HAVE( WCHAR ) -typedef basic_string_span< wchar_t > wstring_span; -typedef basic_string_span< wchar_t const > cwstring_span; -#endif -// to_string() allow (explicit) conversions from string_span to string + template< typename Traits > + std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, wstring_span const & spn ) + { + return detail::write_to_stream( os, spn ); + } -#if 0 + template< typename Traits > + std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, cwstring_span const & spn ) + { + return detail::write_to_stream( os, spn ); + } -template< class T > -gsl_api inline std::basic_string< typename std::remove_const::type > to_string( basic_string_span spn ) -{ - std::string( spn.data(), spn.length() ); -} +#endif // gsl_HAVE( WCHAR ) -#else + // + // ensure_sentinel() + // + // Provides a way to obtain a span from a contiguous sequence + // that ends with a (non-inclusive) sentinel value. + // + // Will fail-fast if sentinel cannot be found before max elements are examined. + // + namespace detail { + + template< class T, class SizeType, const T Sentinel > + gsl_api static span ensure_sentinel( T * seq, SizeType max = (std::numeric_limits::max)() ) + { + typedef T * pointer; -gsl_api inline std::string to_string( string_span const & spn ) -{ - return std::string( spn.data(), spn.length() ); -} + gsl_SUPPRESS_MSVC_WARNING( 26429, "f.23: symbol 'cur' is never tested for nullness, it can be marked as not_null" ) + pointer cur = seq; -gsl_api inline std::string to_string( cstring_span const & spn ) -{ - return std::string( spn.data(), spn.length() ); -} + while ( static_cast( cur - seq ) < max && *cur != Sentinel ) + ++cur; -#if gsl_HAVE( WCHAR ) + gsl_Expects( *cur == Sentinel ); -gsl_api inline std::wstring to_string( wstring_span const & spn ) -{ - return std::wstring( spn.data(), spn.length() ); -} + return span( seq, narrow_cast< typename span::index_type >( cur - seq ) ); + } + } // namespace detail -gsl_api inline std::wstring to_string( cwstring_span const & spn ) -{ - return std::wstring( spn.data(), spn.length() ); -} + // + // ensure_z - creates a string_span for a czstring or cwzstring. + // Will fail fast if a null-terminator cannot be found before + // the limit of size_type. + // -#endif // gsl_HAVE( WCHAR ) -#endif // to_string() + template< class T > + gsl_api inline span ensure_z( T * const & sz, size_t max = (std::numeric_limits::max)() ) + { + return detail::ensure_sentinel( sz, max ); + } -// -// Stream output for string_span types -// + template< class T, size_t N > + gsl_api inline span ensure_z( T (&sz)[N] ) + { + return ::gsl::ensure_z( gsl_ADDRESSOF( sz[0] ), N ); + } -namespace details { +# if gsl_HAVE( TYPE_TRAITS ) -template< class Stream > -gsl_api void write_padding( Stream & os, std::streamsize n ) -{ - for ( std::streamsize i = 0; i < n; ++i ) - os.rdbuf()->sputc( os.fill() ); -} + template< class Container > + inline span< typename std::remove_pointer::type > + ensure_z( Container & cont ) + { + return ::gsl::ensure_z( cont.data(), cont.length() ); + } +# endif -template< class Stream, class Span > -gsl_api Stream & write_to_stream( Stream & os, Span const & spn ) -{ - typename Stream::sentry sentry( os ); + // + // basic_zstring_span<> - A view of contiguous null-terminated characters, replace (*,len). + // - if ( !os ) - return os; + template + class basic_zstring_span + { + public: + typedef T element_type; + typedef span span_type; - const std::streamsize length = narrow( spn.length() ); + typedef typename span_type::index_type index_type; + typedef typename span_type::difference_type difference_type; - // Whether, and how, to pad - const bool pad = ( length < os.width() ); - const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right; + typedef element_type * czstring_type; + typedef basic_string_span string_span_type; - if ( left_pad ) - write_padding( os, os.width() - length ); + gsl_api gsl_constexpr14 basic_zstring_span( span_type s ) + : span_( s ) + { + // expects a zero-terminated span + gsl_Expects( s[s.size() - 1] == '\0'); + } - // Write span characters - os.rdbuf()->sputn( spn.begin(), length ); +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr basic_zstring_span( basic_zstring_span const & other ) = default; + gsl_constexpr basic_zstring_span( basic_zstring_span && other ) = default; + gsl_constexpr14 basic_zstring_span & operator=( basic_zstring_span const & other ) = default; + gsl_constexpr14 basic_zstring_span & operator=( basic_zstring_span && other ) = default; +#else + gsl_api gsl_constexpr basic_zstring_span( basic_zstring_span const & other) : span_ ( other.span_ ) {} + gsl_api gsl_constexpr basic_zstring_span & operator=( basic_zstring_span const & other ) { span_ = other.span_; return *this; } +#endif - if ( pad && !left_pad ) - write_padding( os, os.width() - length ); + gsl_api gsl_constexpr bool empty() const gsl_noexcept + { + return span_.size() == 0; + } - // Reset output stream width - os.width(0); + gsl_api gsl_constexpr string_span_type as_string_span() const gsl_noexcept + { + return string_span_type( span_.data(), span_.size() > 1 ? span_.size() - 1 : 0 ); + } - return os; -} + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_constexpr string_span_type ensure_z() const + { + return ::gsl::ensure_z(span_.data(), span_.size()); + } -} // namespace details + gsl_api gsl_constexpr czstring_type assume_z() const gsl_noexcept + { + return span_.data(); + } -template< typename Traits > -gsl_api std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, string_span const & spn ) -{ - return details::write_to_stream( os, spn ); -} + private: + span_type span_; + }; -template< typename Traits > -gsl_api std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, cstring_span const & spn ) -{ - return details::write_to_stream( os, spn ); -} + // + // zString types: + // + + typedef basic_zstring_span< char > zstring_span; + typedef basic_zstring_span< char const > czstring_span; #if gsl_HAVE( WCHAR ) + typedef basic_zstring_span< wchar_t > wzstring_span; + typedef basic_zstring_span< wchar_t const > cwzstring_span; +#endif -template< typename Traits > -gsl_api std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, wstring_span const & spn ) -{ - return details::write_to_stream( os, spn ); -} +} // namespace gsl + +#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120 + +namespace std { -template< typename Traits > -gsl_api std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, cwstring_span const & spn ) +template<> +struct hash< ::gsl::byte > { - return details::write_to_stream( os, spn ); -} + public: + gsl_constexpr std::size_t operator()( ::gsl::byte v ) const gsl_noexcept + { + return ::gsl::to_integer( v ); + } +}; -#endif // gsl_HAVE( WCHAR ) +} // namespace std + +#endif + +#if gsl_FEATURE_GSL_LITE_NAMESPACE +// gsl_lite namespace: + +// gsl-lite currently keeps all symbols in the namespace `gsl`. The `gsl_lite` namespace contains all the symbols in the +// `gsl` namespace, plus some extensions that are not specified in the Core Guidelines. // -// ensure_sentinel() +// Going forward, we want to support coexistence of gsl-lite with M-GSL, so we want to encourage using the `gsl_lite` +// namespace when consuming gsl-lite. Typical use in library code would be: // -// Provides a way to obtain a span from a contiguous sequence -// that ends with a (non-inclusive) sentinel value. +// #include // instead of // -// Will fail-fast if sentinel cannot be found before max elements are examined. +// namespace foo { +// namespace gsl = ::gsl_lite; // convenience alias +// double mean(gsl::span elements) { +// gsl_Expects(!elements.empty()); // instead of Expects() +// ... +// } +// } // namespace foo // -namespace details { +// In a future version, the new header will only define the `gsl_lite` namespace and no +// unprefixed `Expects()` and `Ensures()` macros to avoid collision with M-GSL. To ensure backward compatibility, the +// old header will keep defining the `gsl` namespace and the `Expects()` and `Ensures()` macros. -template< class T, class SizeType, const T Sentinel > -gsl_api static span ensure_sentinel( T * seq, SizeType max = std::numeric_limits::max() ) +namespace gsl_lite { - typedef T * pointer; - gsl_SUPPRESS_MSVC_WARNING( 26429, "f.23: symbol 'cur' is never tested for nullness, it can be marked as not_null" ) +namespace std11 = ::gsl::std11; +namespace std14 = ::gsl::std14; +namespace std17 = ::gsl::std17; +namespace std20 = ::gsl::std20; - pointer cur = seq; +using namespace std11; +using namespace std14; +using namespace std17; +using namespace std20; - while ( static_cast( cur - seq ) < max && *cur != Sentinel ) - ++cur; +#if gsl_HAVE( SHARED_PTR ) +using std::unique_ptr; +using std::shared_ptr; +using std::make_shared; +#endif - Expects( *cur == Sentinel ); +using ::gsl::index; - return span( seq, narrow_cast< typename span::index_type >( cur - seq ) ); -} -} // namespace details +// Integer type for dimensions. +typedef gsl_CONFIG_INDEX_TYPE dim; -// -// ensure_z - creates a string_span for a czstring or cwzstring. -// Will fail fast if a null-terminator cannot be found before -// the limit of size_type. -// +// Integer type for array strides. +typedef gsl_CONFIG_INDEX_TYPE stride; -template< class T > -gsl_api inline span ensure_z( T * const & sz, size_t max = std::numeric_limits::max() ) -{ - return details::ensure_sentinel( sz, max ); -} +// Integer type for pointer, iterator, or index differences. +typedef gsl_CONFIG_INDEX_TYPE diff; -template< class T, size_t N > -gsl_api inline span ensure_z( T (&sz)[N] ) -{ - return ensure_z( gsl_ADDRESSOF( sz[0] ), N ); -} +#if gsl_HAVE( ALIAS_TEMPLATE ) +using ::gsl::owner; +#endif -# if gsl_HAVE( TYPE_TRAITS ) +using ::gsl::fail_fast; -template< class Container > -gsl_api inline span< typename std::remove_pointer::type > -ensure_z( Container & cont ) -{ - return ensure_z( cont.data(), cont.length() ); -} -# endif +using ::gsl::finally; +#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) +using ::gsl::on_return; +using ::gsl::on_error; +#endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) -} // namespace gsl +using ::gsl::narrow_cast; +using ::gsl::narrowing_error; +using ::gsl::narrow; +using ::gsl::narrow_failfast; -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 120 -namespace std { +using ::gsl::at; -template<> -struct hash< gsl::byte > -{ -public: - std::size_t operator()( gsl::byte v ) const gsl_noexcept - { - return gsl::to_integer( v ); - } -}; +using ::gsl::not_null; +using ::gsl::make_not_null; -} // namespace std +using ::gsl::byte; +using ::gsl::with_container_t; +using ::gsl::with_container; + +using ::gsl::span; +using ::gsl::make_span; +using ::gsl::byte_span; +using ::gsl::copy; +using ::gsl::as_bytes; +using ::gsl::as_writable_bytes; +#if ! gsl_DEPRECATE_TO_LEVEL( 6 ) +using ::gsl::as_writeable_bytes; #endif +using ::gsl::basic_string_span; +using ::gsl::string_span; +using ::gsl::cstring_span; + +using ::gsl::basic_zstring_span; +using ::gsl::zstring_span; +using ::gsl::czstring_span; + +using ::gsl::zstring; +using ::gsl::czstring; + +#if gsl_HAVE( WCHAR ) +using ::gsl::wzstring; +using ::gsl::cwzstring; + +using ::gsl::wzstring_span; +using ::gsl::cwzstring_span; +#endif // gsl_HAVE( WCHAR ) + +} // namespace gsl_lite + +#endif // gsl_FEATURE_GSL_LITE_NAMESPACE + gsl_RESTORE_MSVC_WARNINGS() #endif // GSL_GSL_LITE_HPP_INCLUDED -// end of file + // end of file diff --git a/ThirdParty/installCBLAS.sh b/ThirdParty/installCBLAS.sh index 1ab906502..49fdf449d 100755 --- a/ThirdParty/installCBLAS.sh +++ b/ThirdParty/installCBLAS.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Install CBLAS set -euo pipefail diff --git a/ThirdParty/installCeres.sh b/ThirdParty/installCeres.sh index 340873513..d58ae552b 100755 --- a/ThirdParty/installCeres.sh +++ b/ThirdParty/installCeres.sh @@ -1,4 +1,6 @@ -#!/bin/bash +#!/usr/bin/env bash +# Install Ceres solver and Eigen lib + set -euo pipefail set -x script_dir=$(dirname "$0") diff --git a/ThirdParty/installDeps.sh b/ThirdParty/installDeps.sh index c1863ec79..bc587a86a 100755 --- a/ThirdParty/installDeps.sh +++ b/ThirdParty/installDeps.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # build parPE dependencies script_dir=$(dirname "$0") diff --git a/ThirdParty/installDlib.sh b/ThirdParty/installDlib.sh index 884f91141..f02d822d0 100755 --- a/ThirdParty/installDlib.sh +++ b/ThirdParty/installDlib.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # build DLIB set -euo pipefail diff --git a/ThirdParty/installGoogleTest.sh b/ThirdParty/installGoogleTest.sh index 54b7a096e..270a99363 100755 --- a/ThirdParty/installGoogleTest.sh +++ b/ThirdParty/installGoogleTest.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Download and build googletest set -euo pipefail diff --git a/ThirdParty/installIpopt.sh b/ThirdParty/installIpopt.sh index 1d23c448c..98d2e80a2 100755 --- a/ThirdParty/installIpopt.sh +++ b/ThirdParty/installIpopt.sh @@ -1,5 +1,6 @@ -#!/bin/bash +#!/usr/bin/env bash # build Ipopt + set -euo pipefail script_dir=$(dirname "$0") script_dir=$(cd "${script_dir}" && pwd ) diff --git a/ThirdParty/installToms611.sh b/ThirdParty/installToms611.sh index 8bded95da..7b9472379 100755 --- a/ThirdParty/installToms611.sh +++ b/ThirdParty/installToms611.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # build f2c set -euo pipefail diff --git a/codacy.yml b/codacy.yml deleted file mode 100644 index 588fcc2a7..000000000 --- a/codacy.yml +++ /dev/null @@ -1,5 +0,0 @@ -engines: - prospector: - enabled: true - python_version: 3 - diff --git a/container/charliecloud/parpe_base/Dockerfile b/container/charliecloud/parpe_base/Dockerfile index 148aa6068..f16047484 100644 --- a/container/charliecloud/parpe_base/Dockerfile +++ b/container/charliecloud/parpe_base/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:19.04 +FROM ubuntu:19.10 COPY . /u18 diff --git a/container/charliecloud/parpe_base/install_parpe.sh b/container/charliecloud/parpe_base/install_parpe.sh index 30e9dc371..decee1f0b 100755 --- a/container/charliecloud/parpe_base/install_parpe.sh +++ b/container/charliecloud/parpe_base/install_parpe.sh @@ -63,6 +63,9 @@ CC=mpicc CXX=mpiCC cmake \ .. make -j12 VERBOSE=1 +# MPI settings for python tests +export PARPE_TESTS_MPIEXEC="mpiexec -n 5 --oversubscribe --allow-run-as-root --mca btl_vader_single_copy_mechanism none --mca btl ^openib --mca oob_tcp_if_include lo --mca btl_tcp_if_include lo --mca orte_base_help_aggregate 0" + # run tests cd "${PARPE_BASE}"/build && CTEST_OUTPUT_ON_FAILURE=1 make test diff --git a/deps/AMICI/.github/workflows/deploy_sdist.yml b/deps/AMICI/.github/workflows/deploy_sdist.yml index c5c8e5efe..dd68fa57c 100644 --- a/deps/AMICI/.github/workflows/deploy_sdist.yml +++ b/deps/AMICI/.github/workflows/deploy_sdist.yml @@ -26,7 +26,7 @@ jobs: run: | cd python/sdist && /usr/bin/python3 setup.py sdist - - name: Archive sdist + - name: "Upload artifact: sdist" uses: actions/upload-artifact@v1 with: name: sdist diff --git a/deps/AMICI/.github/workflows/sbml-semantic-test-suite.yml b/deps/AMICI/.github/workflows/sbml-semantic-test-suite.yml index 2d4af5139..c9dd31400 100644 --- a/deps/AMICI/.github/workflows/sbml-semantic-test-suite.yml +++ b/deps/AMICI/.github/workflows/sbml-semantic-test-suite.yml @@ -5,8 +5,14 @@ on: - develop - master pull_request: - branches: - - master + paths: + - .github/workflows/sbml-semantic-test-suite.yml + - python/amici/ode_export.py + - python/amici/sbml_import.py + - scripts/run-SBMLTestsuite.sh + - tests/testSBMLSuite.py + check_suite: + types: [requested] jobs: build: @@ -25,3 +31,9 @@ jobs: && sudo ln -s /usr/bin/swig3.0 /usr/bin/swig - run: AMICI_PARALLEL_COMPILE=2 ./scripts/installAmiciSource.sh - run: AMICI_PARALLEL_COMPILE=2 ./scripts/run-SBMLTestsuite.sh + + - name: "Upload artifact: SBML semantic test suite results" + uses: actions/upload-artifact@v1 + with: + name: amici-semantic-results + path: tests/amici-semantic-results diff --git a/deps/AMICI/.github/workflows/test-large-model.yml b/deps/AMICI/.github/workflows/test-large-model.yml index d5f82c622..4d7f5e2ff 100644 --- a/deps/AMICI/.github/workflows/test-large-model.yml +++ b/deps/AMICI/.github/workflows/test-large-model.yml @@ -58,6 +58,12 @@ jobs: -y 'FroehlichKes2018/PEtab/FroehlichKes2018.yaml' \ --no-compile + - name: "Upload artifact: CS_Signalling_ERBB_RAS_AKT_petab" + uses: actions/upload-artifact@v1 + with: + name: CS_Signalling_ERBB_RAS_AKT + path: CS_Signalling_ERBB_RAS_AKT/CS_Signalling_ERBB_RAS_AKT_petab + # install model package - name: Install test model run: | diff --git a/deps/AMICI/.github/workflows/test_cplusplus.yml b/deps/AMICI/.github/workflows/test_cplusplus.yml new file mode 100644 index 000000000..0d62b539f --- /dev/null +++ b/deps/AMICI/.github/workflows/test_cplusplus.yml @@ -0,0 +1,107 @@ +name: C++ testsuite / Ubuntu +on: [push] + +jobs: + build: + name: _ + + # TODO: prepare image with more deps preinstalled + runs-on: ubuntu-latest + + env: + ENABLE_GCOV_COVERAGE: TRUE + CI_SONARCLOUD: TRUE + + steps: + - uses: actions/checkout@master + - run: git fetch --prune --unshallow + + - run: echo "::set-env name=AMICI_DIR::$(pwd)" + - run: echo "::set-env name=BNGPATH::${AMICI_DIR}/ThirdParty/BioNetGen-2.3.2" + + # sonar cloud + - run: echo "::set-env name=SONAR_SCANNER_VERSION::4.2.0.1873" + - run: echo "::set-env name=SONAR_SCANNER_HOME::$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux" + - run: echo "::set-env name=SONAR_SCANNER_OPTS::-server" + - run: echo "::add-path::${SONAR_SCANNER_HOME}/bin" + - run: echo "::add-path::$HOME/.sonar/build-wrapper-linux-x86" + + # TODO: add to ci image + - name: Install sonarcloud tools + run: | + sudo apt install nodejs curl unzip \ + && curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip \ + https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux.zip \ + && unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/ \ + && curl --create-dirs -sSLo $HOME/.sonar/build-wrapper-linux-x86.zip \ + https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip \ + && unzip -o $HOME/.sonar/build-wrapper-linux-x86.zip -d $HOME/.sonar/ \ + + # install amici dependencies + - name: apt + run: | + sudo apt-get update \ + && sudo apt-get install -y \ + cmake \ + g++ \ + libatlas-base-dev \ + libboost-serialization-dev \ + libhdf5-serial-dev \ + python3-dev \ + swig + + - name: Build suitesparse + run: | + scripts/buildSuiteSparse.sh + + - name: Build sundials + run: | + scripts/buildSundials.sh + + - name: Build cpputest + run: | + scripts/buildCpputest.sh + + - name: Build cpputest + run: | + scripts/buildBNGL.sh + + - name: Build AMICI + run: | + CI_SONARCLOUD=TRUE scripts/buildAmici.sh + + - name: Cache sonar files + id: cache-sonar + uses: actions/cache@v1 + with: + path: sonar_cache + key: ${{ runner.os }}-sonar_cache + + - name: C++ tests + run: | + scripts/run-cpputest.sh + + - name: gcov + run: cd build && gcov CMakeFiles/amici.dir/src/*.o + + - name: Install python package + run: scripts/installAmiciSource.sh + + - name: Python tests + run: | + source build/venv/bin/activate \ + && pip3 install coverage pytest pytest-cov \ + && pytest \ + --ignore-glob=*petab* \ + --cov=amici \ + --cov-report=xml:"${AMICI_DIR}/build/coverage_py.xml" \ + --cov-append \ + ${AMICI_DIR}/python/tests + + - name: Run sonar-scanner + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sonar-scanner \ + -Dsonar.cfamily.build-wrapper-output=bw-output \ + -Dsonar.projectVersion="$(git describe --abbrev=4 --dirty=-dirty --always --tags | tr -d '\n')" diff --git a/deps/AMICI/.github/workflows/test_cplusplus_osx.yml b/deps/AMICI/.github/workflows/test_cplusplus_osx.yml new file mode 100644 index 000000000..362398a7c --- /dev/null +++ b/deps/AMICI/.github/workflows/test_cplusplus_osx.yml @@ -0,0 +1,72 @@ +name: C++ testsuite / OSX +on: [push] + +jobs: + build: + name: tests_osx + + runs-on: macos-latest + + env: + ENABLE_GCOV_COVERAGE: FALSE + CI_SONARCLOUD: FALSE + + steps: + - uses: actions/checkout@master + - run: git fetch --prune --unshallow + + - run: echo "::set-env name=AMICI_DIR::$(pwd)" + - run: echo "::set-env name=BNGPATH::${AMICI_DIR}/ThirdParty/BioNetGen-2.3.2" + + # install amici dependencies + - name: homebrew + run: | + brew install hdf5 swig gcc cppcheck libomp + + - name: Build suitesparse + run: | + scripts/buildSuiteSparse.sh + + - name: Build sundials + run: | + scripts/buildSundials.sh + + - name: Build cpputest + run: | + scripts/buildCpputest.sh + + - name: Build cpputest + run: | + scripts/buildBNGL.sh + + - name: Build AMICI + run: | + scripts/buildAmici.sh + + - name: Install python archive + run: | + scripts/installAmiciArchive.sh + + - name: Install python package + run: | + scripts/installAmiciSource.sh + + - name: cppcheck + run: | + scripts/run-cppcheck.sh + + - name: notebooks + run: | + scripts/runNotebook.sh python/examples/example_*/ + + - name: Python tests + run: | + scripts/run-python-tests.sh + + - name: C++ tests + run: | + scripts/run-cpputest.sh + + - name: sphinx + run: | + scripts/run-sphinx.sh diff --git a/deps/AMICI/.github/workflows/test_cplusplus_valgrind.yml b/deps/AMICI/.github/workflows/test_cplusplus_valgrind.yml new file mode 100644 index 000000000..5152e3212 --- /dev/null +++ b/deps/AMICI/.github/workflows/test_cplusplus_valgrind.yml @@ -0,0 +1,52 @@ +name: C++ testsuite / Valgrind / Ubuntu +on: + push: + branches: + - develop + - master + +jobs: + build: + name: _ + + # TODO: prepare image with more deps preinstalled + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@master + - run: git fetch --prune --unshallow + + # install amici dependencies + - name: apt + run: | + sudo apt-get update \ + && sudo apt-get install -y \ + cmake \ + g++ \ + libatlas-base-dev \ + libboost-serialization-dev \ + libhdf5-serial-dev \ + swig \ + valgrind + + - name: Build suitesparse + run: | + scripts/buildSuiteSparse.sh + + - name: Build sundials + run: | + scripts/buildSundials.sh + + - name: Build cpputest + run: | + scripts/buildCpputest.sh + + - name: Build AMICI + # TODO: should get rid of having to install numpy before + run: | + pip3 install numpy \ + && scripts/buildAmici.sh + + - name: C++ tests / Valgrind + run: | + scripts/run-valgrind.sh diff --git a/deps/AMICI/.gitignore b/deps/AMICI/.gitignore index 0f855b720..f4474b419 100644 --- a/deps/AMICI/.gitignore +++ b/deps/AMICI/.gitignore @@ -108,6 +108,8 @@ tests/test/* */tests/test_model_presimulation/* */tests/test_model_presimulation_pysb/* */tests/test_model_presimulation_sbml/* +*/tests/model_constant_species_cl/* +*/tests/model_constant_species/* */tests/test_likelihoods/* */tests/bax_pore_sequential_amici/* */tests/bax_pore_amici/* @@ -136,11 +138,14 @@ tests/sedml-test-suite/ tests/SBMLTestModels/ tests/benchmark-models/test_bmc tests/petab_test_suite +petab_test_suite /python/test/amici-SBMLTest*/ python/examples/example_steadystate/model_steadystate_scaled/* python/examples/example_presimulation/model_presimulation/* python/examples/example_presimulation/model_presimulation_re/* +python/examples/example_constant_species/model_constant_species_reduced/* +python/examples/example_constant_species/model_constant_species/* python/sdist/amici.egg-info/* python/sdist/amici/version.txt diff --git a/deps/AMICI/.gitrepo b/deps/AMICI/.gitrepo index a60dbaa7a..92351b227 100644 --- a/deps/AMICI/.gitrepo +++ b/deps/AMICI/.gitrepo @@ -5,8 +5,8 @@ ; [subrepo] remote = git@github.com:ICB-DCM/AMICI.git - branch = v0.10.21 - commit = 390305f98c96ea505cf52884991774e7dfefdeff - parent = da14c219af1e41d53e72017e8a48d171c9d25d88 + branch = develop + commit = d220128f262747ad9f15db83377e4f8a5d2006d3 + parent = da7afe19a3b70b511bcbbc9eb45457fc616cfac4 cmdver = 0.4.1 method = merge diff --git a/deps/AMICI/.travis.yml b/deps/AMICI/.travis.yml index 168f8c084..7c461d8de 100644 --- a/deps/AMICI/.travis.yml +++ b/deps/AMICI/.travis.yml @@ -32,8 +32,6 @@ matrix: - CI_PYTHON=TRUE - CI_ARCHIVE=TRUE - CI_NOTEBOOK=TRUE - before_install: - - ./scripts/buildValgrind.sh after_script: # cpputest coverage cpp - lcov --compat-libtool --no-external --directory ${BASE_DIR}/build/CMakeFiles/amici.dir/src --base-directory ${BASE_DIR} --capture --output-file coverage_cpp.info @@ -71,33 +69,6 @@ matrix: - CI_PYTHON=TRUE - CI_NOTEBOOK=TRUE - - os: osx - osx_image: xcode11 - language: minimal - compiler: clang - env: - - CI_BUILD=TRUE - - CI_CPPUTEST=TRUE - - CI_ARCHIVE=TRUE - - CI_CPPCHECK=TRUE - - CI_PYTHON=TRUE - - CI_NOTEBOOK=TRUE - addons: - homebrew: - packages: - - hdf5 - - swig - - gcc - - cppcheck - update: true - before_install: - - travis_wait brew link --overwrite gcc # fix linker warning regarding /usr/local/include/c++ - - brew link --overwrite python # https://github.com/ICB-DCM/AMICI/issues/894 - - export -f travis_fold travis_nanoseconds travis_time_start travis_time_finish - - pip3 install --user -U numpy - after_success: - - cd $BASE_DIR # cd to base dir for correct relative path in deploy - - os: osx osx_image: xcode11 language: minimal @@ -149,7 +120,6 @@ matrix: - choco install python --version 3.7.5 - choco install swig - python -m pip install --upgrade pip - - pip install --user -U numpy - git clone -c core.symlinks=true https://github.com/ICB-DCM/AMICI.git && cd AMICI - if [[ "$TRAVIS_PULL_REQUEST" == "false" ]]; then git checkout -qf $TRAVIS_COMMIT; elif [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then git fetch --update-head-ok origin pull/$TRAVIS_PULL_REQUEST/head:$TRAVIS_BRANCH && git checkout $TRAVIS_BRANCH; fi # run BLAS installation script @@ -184,8 +154,7 @@ script: - if [[ "$CI_PYTHON" == "TRUE" ]] && [[ "$ENABLE_GCOV_COVERAGE" == "TRUE" ]]; then $FOLD codecov ./scripts/run-codecov.sh; fi - if [[ "$CI_PYTHON" == "TRUE" ]] && [[ "$ENABLE_GCOV_COVERAGE" != "TRUE" ]]; then $FOLD python-tests ./scripts/run-python-tests.sh; fi # needs to be run after python tests - - if [[ "$CI_CPPUTEST" == "TRUE" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then $FOLD valgrind ./scripts/run-valgrind.sh; fi - - if [[ "$CI_CPPUTEST" == "TRUE" ]] && [[ "$TRAVIS_OS_NAME" != "linux" ]]; then $FOLD cpputest ./scripts/run-cpputest.sh; fi + - if [[ "$CI_CPPUTEST" == "TRUE" ]]; then $FOLD cpputest ./scripts/run-cpputest.sh; fi - if [[ "$CI_DOC" == "TRUE" ]]; then $FOLD doxygen ./scripts/run-doxygen.sh; fi - if [[ "$CI_PYTHON" == "TRUE" ]]; then $FOLD sphinx ./scripts/run-sphinx.sh; fi diff --git a/deps/AMICI/CMakeLists.txt b/deps/AMICI/CMakeLists.txt index a427873fe..2bd7bbd71 100644 --- a/deps/AMICI/CMakeLists.txt +++ b/deps/AMICI/CMakeLists.txt @@ -170,7 +170,10 @@ target_link_libraries(${PROJECT_NAME} # For matlab interface add_custom_target(matlabInterface - SOURCES src/interface_matlab.cpp src/returndata_matlab.cpp) + SOURCES + src/interface_matlab.cpp + src/returndata_matlab.cpp + include/amici/interface_matlab.h) set_target_properties(matlabInterface PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/include/") find_package(Matlab) @@ -189,6 +192,7 @@ add_custom_target( src/CMakeLists.template.cmake src/main.template.cpp src/model_header.ODE_template.h + src/model.ODE_template.cpp src/wrapfunctions.ODE_template.h src/wrapfunctions.template.cpp swig/CMakeLists_model.cmake diff --git a/deps/AMICI/README.md b/deps/AMICI/README.md index cf9087135..07d275eaa 100644 --- a/deps/AMICI/README.md +++ b/deps/AMICI/README.md @@ -37,8 +37,8 @@ constrained optimization problems. - - + + @@ -130,7 +130,7 @@ When presenting work that employs AMICI, feel free to use one of the icons in ## Status of SBML support in Python-AMICI -Python-AMICI currently passes 500 out of the 1780 (~28%) test cases from +Python-AMICI currently passes 696 out of the 1780 (~39%) test cases from the semantic [SBML Test Suite](https://github.com/sbmlteam/sbml-test-suite/) ([current status](https://github.com/ICB-DCM/AMICI/actions)). @@ -139,10 +139,7 @@ In addition, we currently plan to add support for the following features (see corresponding issues for details and progress): - Events (currently Matlab-only) -- Rate rules - Algebraic rules -- Species assignment rules -- Compartment assignment rules - Models without species contributions are welcome. diff --git a/deps/AMICI/ThirdParty/SuiteSparse/AMD/Doc/License.txt b/deps/AMICI/ThirdParty/SuiteSparse/AMD/Doc/License.txt index 05f154c83..7a2bce91e 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/AMD/Doc/License.txt +++ b/deps/AMICI/ThirdParty/SuiteSparse/AMD/Doc/License.txt @@ -1,37 +1,14 @@ AMD, Copyright (c), 1996-2015, Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. -AMD License: At the user's option, you may use AMD under either the LGPL -version 2.1 license, or the BSD 3-clause license. You may not use both -licenses, nor may you mix-and-match clauses from each license. To use a -license, in the documentation for your application simply state either of the -following, replacing with the name of your application: - - AMD, Copyright (c), 1996-2015, Timothy A. Davis, - Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. - Used in under the BSD 3-clause license. - -or - - AMD, Copyright (c), 1996-2015, Timothy A. Davis, - Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. - Used in under the LGPL v2.1 license. - -In the event that your package includes another package by another -author, and and use AMD under different licenses, you may select -one license to apply to both uses of AMD in the combined application. - Availability: http://www.suitesparse.com ------------------------------------------------------------------------------- -BSD 3-clause: +AMD License: BSD 3-clause: ------------------------------------------------------------------------------- - Copyright (c), 1996-2015, Timothy A. Davis, - Patrick R. Amestoy, and Iain S. Duff. 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 @@ -56,36 +33,3 @@ BSD 3-clause: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -LGPL version 2.1: -------------------------------------------------------------------------------- - - Your use or distribution of AMD or any modified version of - AMD implies that you agree to this License. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - USA - - Permission is hereby granted to use or copy this program under the - terms of the GNU LGPL, provided that the Copyright, this License, - and the Availability of the original version is retained on all copies. - User documentation of any code that uses this code or any modified - version of this code must cite the Copyright, this License, the - Availability note, and "Used by permission." Permission to modify - the code and to distribute modified code is granted, provided the - Copyright, this License, and the Availability note are retained, - and a notice that the code was modified is included. - -------------------------------------------------------------------------------- diff --git a/deps/AMICI/ThirdParty/SuiteSparse/AMD/Doc/Makefile b/deps/AMICI/ThirdParty/SuiteSparse/AMD/Doc/Makefile index e90536a28..4769bf1af 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/AMD/Doc/Makefile +++ b/deps/AMICI/ThirdParty/SuiteSparse/AMD/Doc/Makefile @@ -23,9 +23,9 @@ distclean: clean #------------------------------------------------------------------------------ AMD_UserGuide.pdf: AMD_UserGuide.tex AMD_UserGuide.bib ../Include/amd.h - echo '\begin{verbatim}' > amd_h.tex + echo '\\begin{verbatim}' > amd_h.tex expand -8 ../Include/amd.h >> amd_h.tex - echo '\end{verbatim}' >> amd_h.tex + echo '\\end{verbatim}' >> amd_h.tex pdflatex AMD_UserGuide bibtex AMD_UserGuide pdflatex AMD_UserGuide diff --git a/deps/AMICI/ThirdParty/SuiteSparse/CAMD/Doc/License.txt b/deps/AMICI/ThirdParty/SuiteSparse/CAMD/Doc/License.txt index 9f3faa0cd..5329cec2b 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/CAMD/Doc/License.txt +++ b/deps/AMICI/ThirdParty/SuiteSparse/CAMD/Doc/License.txt @@ -3,38 +3,33 @@ Yanqing Chen, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. CAMD is available under alternate licenses, contact T. Davis for details. -CAMD License: - - Your use or distribution of CAMD or any modified version of - CAMD implies that you agree to this License. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - USA - - Permission is hereby granted to use or copy this program under the - terms of the GNU LGPL, provided that the Copyright, this License, - and the Availability of the original version is retained on all copies. - User documentation of any code that uses this code or any modified - version of this code must cite the Copyright, this License, the - Availability note, and "Used by permission." Permission to modify - the code and to distribute modified code is granted, provided the - Copyright, this License, and the Availability note are retained, - and a notice that the code was modified is included. +CAMD License: BSD 3-clause + + 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 organizations to which the authors are + affiliated, 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 HOLDERS 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. Availability: http://www.suitesparse.com -------------------------------------------------------------------------------- diff --git a/deps/AMICI/ThirdParty/SuiteSparse/CAMD/Doc/Makefile b/deps/AMICI/ThirdParty/SuiteSparse/CAMD/Doc/Makefile index 3ce39e362..8d177e61e 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/CAMD/Doc/Makefile +++ b/deps/AMICI/ThirdParty/SuiteSparse/CAMD/Doc/Makefile @@ -23,9 +23,9 @@ distclean: clean #------------------------------------------------------------------------------ CAMD_UserGuide.pdf: CAMD_UserGuide.tex CAMD_UserGuide.bib ../Include/camd.h - echo '\begin{verbatim}' > camd_h.tex + echo '\\begin{verbatim}' > camd_h.tex expand -8 ../Include/camd.h >> camd_h.tex - echo '\end{verbatim}' >> camd_h.tex + echo '\\end{verbatim}' >> camd_h.tex pdflatex CAMD_UserGuide bibtex CAMD_UserGuide pdflatex CAMD_UserGuide diff --git a/deps/AMICI/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_example.out b/deps/AMICI/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_example.out index 67faf7565..a2b6b0ae8 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_example.out +++ b/deps/AMICI/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_example.out @@ -15,7 +15,7 @@ Column 3, with 2 entries: row 1 row 3 -colamd version 2.9, Apr 1, 2016: OK. +colamd version 2.9, May 4, 2016: OK. colamd: number of dense or empty rows ignored: 0 colamd: number of dense or empty columns ignored: 0 colamd: number of garbage collections performed: 0 @@ -38,7 +38,7 @@ Column 3, with 1 entries: row 4 Column 4, with 0 entries: -symamd version 2.9, Apr 1, 2016: OK. +symamd version 2.9, May 4, 2016: OK. symamd: number of dense or empty rows ignored: 0 symamd: number of dense or empty columns ignored: 0 symamd: number of garbage collections performed: 0 diff --git a/deps/AMICI/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_l_example.out b/deps/AMICI/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_l_example.out index 45632dab3..2f1035c5c 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_l_example.out +++ b/deps/AMICI/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_l_example.out @@ -15,7 +15,7 @@ Column 3, with 2 entries: row 1 row 3 -colamd version 2.9, Apr 1, 2016: OK. +colamd version 2.9, May 4, 2016: OK. colamd: number of dense or empty rows ignored: 0 colamd: number of dense or empty columns ignored: 0 colamd: number of garbage collections performed: 0 @@ -38,7 +38,7 @@ Column 3, with 1 entries: row 4 Column 4, with 0 entries: -symamd version 2.9, Apr 1, 2016: OK. +symamd version 2.9, May 4, 2016: OK. symamd: number of dense or empty rows ignored: 0 symamd: number of dense or empty columns ignored: 0 symamd: number of garbage collections performed: 0 diff --git a/deps/AMICI/ThirdParty/SuiteSparse/COLAMD/Doc/License.txt b/deps/AMICI/ThirdParty/SuiteSparse/COLAMD/Doc/License.txt index 07bde42fe..4fff9e977 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/COLAMD/Doc/License.txt +++ b/deps/AMICI/ThirdParty/SuiteSparse/COLAMD/Doc/License.txt @@ -3,16 +3,28 @@ http://www.suitesparse.com -------------------------------------------------------------------------------- -COLAMD is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. +COLAMD License: BSD 3-clause -COLAMD is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. + 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 organizations to which the authors are + affiliated, nor the names of its contributors may be used to endorse + or promote products derived from this software without specific prior + written permission. -You should have received a copy of the GNU Lesser General Public -License along with this Module; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + 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 HOLDERS 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. diff --git a/deps/AMICI/ThirdParty/SuiteSparse/CONTRIBUTOR-LICENSE.txt b/deps/AMICI/ThirdParty/SuiteSparse/CONTRIBUTOR-LICENSE.txt new file mode 100644 index 000000000..cc0fe876c --- /dev/null +++ b/deps/AMICI/ThirdParty/SuiteSparse/CONTRIBUTOR-LICENSE.txt @@ -0,0 +1,166 @@ +SuiteSparse Individual Contributor License Agreement + +Thank you for your interest in contributing to SuiteSparse ("We" or "Us"). + +This contributor agreement ("Agreement") documents the rights granted by +contributors to Us. To make this document effective, please sign it and send it +to Us by electronic submission. This is a legally binding document, so please +read it carefully before agreeing to it. The Agreement may cover more than one +software project managed by Us. + +1. Definitions + + "You" means the individual who Submits a Contribution to Us. + + "Contribution" means any work of authorship that is Submitted by You to Us + in which You own or assert ownership of the Copyright. + + "Copyright" means all rights protecting works of authorship owned or + controlled by You, including copyright, moral and neighboring rights, as + appropriate, for the full term of their existence including any extensions + by You. + + "Material" means the work of authorship which is made available by Us to + third parties. When this Agreement covers more than one software project, + the Material means the work of authorship to which the Contribution was + Submitted. After You Submit the Contribution, it may be included in the + Material. + + "Submit" means any form of electronic, verbal, or written communication + sent to Us or our representatives, including but not limited to electronic + mailing lists, source code control systems, and issue tracking systems that + are managed by, or on behalf of, Us for the purpose of discussing and + improving the Material, but excluding communication that is conspicuously + marked or otherwise designated in writing by You as "Not a Contribution." + + "Submission Date" means the date on which You Submit a Contribution to Us. + + "Effective Date" means the date You execute this Agreement or the date You + first Submit a Contribution to Us, whichever is earlier. + +2. Grant of Rights + + 2.1 Copyright License + + (a) You retain ownership of the Copyright in Your Contribution and have + the same rights to use or license the Contribution which You would have + had without entering into the Agreement. + + (b) To the maximum extent permitted by the relevant law, You grant to + Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, + irrevocable license under the Copyright covering the Contribution, with + the right to sublicense such rights through multiple tiers of + sublicensees, to reproduce, modify, display, perform and distribute the + Contribution as part of the Material; provided that this license is + conditioned upon compliance with Section 2.3. + + 2.2 Patent License + + For patent claims including, without limitation, method, process, and + apparatus claims which You own, control or have the right to grant, now + or in the future, You grant to Us a perpetual, worldwide, + non-exclusive, transferable, royalty-free, irrevocable patent license, + with the right to sublicense these rights to multiple tiers of + sublicensees, to make, have made, use, sell, offer for sale, import and + otherwise transfer the Contribution and the Contribution in combination + with the Material (and portions of such combination). This license is + granted only to the extent that the exercise of the licensed rights + infringes such patent claims; and provided that this license is + conditioned upon compliance with Section 2.3. + + 2.3 Outbound License + + Based on the grant of rights in Sections 2.1 and 2.2, if We include + Your Contribution in a Material, We may license the Contribution under + any license, including copyleft, permissive, commercial, or proprietary + licenses. + + 2.4 Moral Rights. + + If moral rights apply to the Contribution, to the maximum extent + permitted by law, You waive and agree not to assert such moral rights + against Us or our successors in interest, or any of our licensees, + either direct or indirect. + + 2.5 Our Rights. + + You acknowledge that We are not obligated to use Your Contribution as + part of the Material and may decide to include any Contribution We + consider appropriate. + + 2.6 Reservation of Rights. + + Any rights not expressly licensed under this section are expressly + reserved by You. + +3. Agreement + + You confirm that: + + (a) You have the legal authority to enter into this Agreement. + + (b) You own the Copyright and patent claims covering the Contribution which + are required to grant the rights under Section 2. + + (c) The grant of rights under Section 2 does not violate any grant of + rights which You have made to third parties, including Your employer. If + You are an employee, You have had Your employer approve this Agreement or + sign the Entity version of this document. If You are less than eighteen + years old, please have Your parents or guardian sign the Agreement. + +4. Disclaimer + + EXCEPT FOR THE EXPRESS WARRANTIES IN SECTION 3, THE CONTRIBUTION IS + PROVIDED "AS IS". MORE PARTICULARLY, ALL EXPRESS OR IMPLIED WARRANTIES + INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY + DISCLAIMED BY YOU TO US. TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE + DISCLAIMED, SUCH WARRANTY IS LIMITED IN DURATION TO THE MINIMUM PERIOD + PERMITTED BY LAW. + +5. Consequential Damage Waiver + + TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU BE + LIABLE FOR ANY LOSS OF PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA, + INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY DAMAGES ARISING + OUT OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY + (CONTRACT, TORT OR OTHERWISE) UPON WHICH THE CLAIM IS BASED. + +6. Miscellaneous + + 6.1 This Agreement will be governed by and construed in accordance with the + laws of the State of Texas excluding its conflicts of law provisions. Under + certain circumstances, the governing law in this section might be + superseded by the United Nations Convention on Contracts for the + International Sale of Goods ("UN Convention") and the parties intend to + avoid the application of the UN Convention to this Agreement and, thus, + exclude the application of the UN Convention in its entirety to this + Agreement. + + 6.2 This Agreement sets out the entire agreement between You and Us for + Your Contributions to Us and overrides all other agreements or + understandings. + + 6.3 If You or We assign the rights or obligations received through this + Agreement to a third party, as a condition of the assignment, that third + party must agree in writing to abide by all the rights and obligations in + the Agreement. + + 6.4 The failure of either party to require performance by the other party + of any provision of this Agreement in one situation shall not affect the + right of a party to require such performance at any time in the future. A + waiver of performance under a provision in one situation shall not be + considered a waiver of the performance of the provision in the future or a + waiver of the provision in its entirety. + + 6.5 If any provision of this Agreement is found void and unenforceable, + such provision will be replaced to the extent possible with a provision + that comes closest to the meaning of the original provision and which is + enforceable. The terms and conditions set forth in this Agreement shall + apply notwithstanding any failure of essential purpose of this Agreement or + any limited remedy to the maximum extent possible under law. + +Us +Timothy A. Davis, and all SuiteSparse co-authors (varies according to +the SuiteSparse package) + diff --git a/deps/AMICI/ThirdParty/SuiteSparse/ChangeLog b/deps/AMICI/ThirdParty/SuiteSparse/ChangeLog index 331a34e15..854681298 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/ChangeLog +++ b/deps/AMICI/ThirdParty/SuiteSparse/ChangeLog @@ -1,3 +1,75 @@ +Dec 28, 2018: SuiteSparse 5.4.0 + + * GraphBLAS 2.2.2: many upgrades and new features, a few bug fixes + * CHOLMOD 3.0.13: fix to cholmod_core.h (for latest CUDA) + * SPQR 2.0.9: fix to SuiteSparseQR.hpp (for latest CUDA) + * UMFPACK 5.7.8: minor change to umf_analyze.h (not a bug, but the + parameter names in the *.h did not match the *.c. + * ssget: new matrices + * Mongoose 2.0.3: simpler cmake + * SuiteSparse_config: added JOBS option for parallel make, also added to + GraphBLAS, CHOLMOD, SPQR, UMFPACK, Mongoose, and metis-5.1.0 + +July 5, 2018: SuiteSparse 5.3.0 + + * GraphBLAS 2.0.3: bug fix to GxB_resize, better cmake script + * new package: Mongoose (version 2.0.2) + * fixed metis gk_arch.h for Windows + * UMFPACK 5.7.7: modified comments in umfpack*symbolic.h + * added contributor license for all of SuiteSparse + * updated and renamed MATLAB_Tools/UFcollection to SuiteSparseCollection + +Mar 15, 2018: SuiteSparse 5.2.0 + + * GraphBLAS 2.0.1: bug fix to GxB_kron + * SuiteSparse_config: corrected back to SO_VERSION 5 + +Mar 12, 2018: + + * GraphBLAS 2.0.0: with changes to API to conform to the latest + specification. The SO_VERSION of GraphBLAS must change, + as a result, since this affects both the ABI and API interface. + * CHOLMOD 3.1.12: bug fix (no change to the CHOLMOD ABI or API) + * KLU 1.3.9: minor edit, not a bug fix, but code is more clear now + +Dec 28, 2017: SuiteSparse 5.1.2 + + * improved build process for GraphBLAS + * minor change to CSparse/Lib/Makefile, no change in CSparse version + +Dec 17, 2017: SuiteSparse 5.1.1 + + * GraphBLAS added to top-level SuiteSparse/Makefile + * GraphBLAS 1.1.1: bug fix to *assign, split AxB for faster compile, + added memory usage statistics, AxB performance improvment + * minor update to [AMD CAMD KLU]/Doc/Makefile's, no change to + version numbers of AMD, CAMD, or KLU + +Dec 1, 2017: SuiteSparse 5.1.0 + + * GraphBLAS 1.1.0 + * minor update to SPQR Makefile (version remains unchanged; + no change to source) + +Nov 25, 2017: SuiteSparse 5.0.0 + + * added GraphBLAS Version 1.0.0 + * replaced UFget with ssget + +Oct 3, 2017: SuiteSparse 4.5.6 + + * changed COLAMD, CAMD, and CCOLAMD to BSD 3-clause, + to match AMD. No other changes; version numbers of + packages unchanged. + +Apr 17, 2017: SuiteSparse 4.5.5 + + * minor fix to SuiteSparse/Makefile for 'make install' + +Dec 8, 2016: SuiteSparse 4.5.4 + + * minor update to SPQR for ACM TOMS submission + May 4, 2016: SuiteSparse 4.5.3 * minor changes to Makefiles diff --git a/deps/AMICI/ThirdParty/SuiteSparse/Contents.m b/deps/AMICI/ThirdParty/SuiteSparse/Contents.m index 8d2902b3e..af9e7978a 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/Contents.m +++ b/deps/AMICI/ThirdParty/SuiteSparse/Contents.m @@ -7,7 +7,7 @@ % compiles and installs all of SuiteSparse, and runs several demos and tests. % %------------------------------------------------------------------------------- -% Ordering methods: +% Ordering methods and graph partitioners: %------------------------------------------------------------------------------- % % amd2 - approximate minimum degree ordering. @@ -16,6 +16,7 @@ % camd - constrained amd. % ccolamd - constrained colamd. % csymamd - constrained symamd. +% edgecut - Mongoose graph partitioner % %------------------------------------------------------------------------------- % CHOLMOD: a sparse supernodal Cholesky update/downdate package: @@ -134,16 +135,17 @@ % sparseinv sparse inverse subset % spqr_rank toolbox for sparse rank-deficient matrices % -% UFcollection for managing the UF Sparse Matrix Collection +% SuiteSparseCollection for managing the SuiteSparse Matrix Collection % RBio for reading/writing Rutherford/Boeing sparse matrices -% UFget MATLAB interface to the UF Sparse Matrix Collection, -% located in C*Sparse*/MATLAB +% ssget MATLAB interface to the SuiteSparse Matrix Collection +% GraphBLAS graph algorithms via sparse linear algebra (graphblas.org), +% does not yet have a MATLAB interface % %------------------------------------------------------------------------------- % % For help on compiling SuiteSparse or the demos, testing functions, etc., % please see the help for each individual package. % -% Copyright 2014, Timothy A. Davis, http://www.suitesparse.com. +% Copyright 2018, Timothy A. Davis, http://www.suitesparse.com. help SuiteSparse diff --git a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/ChangeLog b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/ChangeLog index a98c9d33b..70a1b4f97 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/ChangeLog +++ b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/ChangeLog @@ -1,3 +1,7 @@ +Mar 12, 2018: version 1.3.9 + + * swapped arguments for KLU_malloc; not a bug, just more readable now + May 4, 2016: version 1.3.8 * minor changes to Makefile diff --git a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/KLU_UserGuide.pdf b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/KLU_UserGuide.pdf index f169aa5fa..d5ae2f2a2 100644 Binary files a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/KLU_UserGuide.pdf and b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/KLU_UserGuide.pdf differ diff --git a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/KLU_UserGuide.tex b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/KLU_UserGuide.tex index 4dbcd5eb8..7ec756ed7 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/KLU_UserGuide.tex +++ b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/KLU_UserGuide.tex @@ -26,7 +26,7 @@ } \and Eka Palamadai Natarajan} -\date{VERSION 1.3.8, May 4, 2016} +\date{VERSION 1.3.9, Mar 12, 2018} \maketitle %------------------------------------------------------------------------------ diff --git a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/Makefile b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/Makefile index 8d7e7492d..a275b4be5 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/Makefile +++ b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Doc/Makefile @@ -24,15 +24,15 @@ distclean: clean KLU_UserGuide.pdf: KLU_UserGuide.tex KLU_UserGuide.bib \ ../Include/klu.h ../../BTF/Include/btf.h Makefile - echo '\begin{verbatim}' > klu_h.tex + echo '\\begin{verbatim}' > klu_h.tex expand -8 ../Include/klu.h >> klu_h.tex - echo '\end{verbatim}' >> klu_h.tex - echo '\begin{verbatim}' > btf_h.tex + echo '\\end{verbatim}' >> klu_h.tex + echo '\\begin{verbatim}' > btf_h.tex expand -8 ../../BTF/Include/btf.h >> btf_h.tex - echo '\end{verbatim}' >> btf_h.tex - echo '\begin{verbatim}' > klu_simple_c.tex + echo '\\end{verbatim}' >> btf_h.tex + echo '\\begin{verbatim}' > klu_simple_c.tex expand -8 ../Demo/klu_simple.c >> klu_simple_c.tex - echo '\end{verbatim}' >> klu_simple_c.tex + echo '\\end{verbatim}' >> klu_simple_c.tex pdflatex KLU_UserGuide bibtex KLU_UserGuide pdflatex KLU_UserGuide diff --git a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Include/klu.h b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Include/klu.h index 2da483b06..07611f72d 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Include/klu.h +++ b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Include/klu.h @@ -819,11 +819,11 @@ void *klu_l_realloc (size_t, size_t, size_t, void *, klu_l_common *) ; * #endif */ -#define KLU_DATE "May 4, 2016" +#define KLU_DATE "Mar 12, 2018" #define KLU_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) #define KLU_MAIN_VERSION 1 #define KLU_SUB_VERSION 3 -#define KLU_SUBSUB_VERSION 8 +#define KLU_SUBSUB_VERSION 9 #define KLU_VERSION KLU_VERSION_CODE(KLU_MAIN_VERSION,KLU_SUB_VERSION) #ifdef __cplusplus diff --git a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Source/klu_analyze_given.c b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Source/klu_analyze_given.c index bee547345..348c011b3 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Source/klu_analyze_given.c +++ b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Source/klu_analyze_given.c @@ -96,7 +96,7 @@ KLU_symbolic *KLU_alloc_symbolic /* allocate the Symbolic object */ /* ---------------------------------------------------------------------- */ - Symbolic = KLU_malloc (sizeof (KLU_symbolic), 1, Common) ; + Symbolic = KLU_malloc (1, sizeof (KLU_symbolic), Common) ; if (Common->status < KLU_OK) { /* out of memory */ diff --git a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Source/klu_factor.c b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Source/klu_factor.c index 8a410e717..d651f49e1 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/KLU/Source/klu_factor.c +++ b/deps/AMICI/ThirdParty/SuiteSparse/KLU/Source/klu_factor.c @@ -441,7 +441,7 @@ KLU_numeric *KLU_factor /* returns NULL if error, or a valid n1 = ((size_t) n) + 1 ; nzoff1 = ((size_t) nzoff) + 1 ; - Numeric = KLU_malloc (sizeof (KLU_numeric), 1, Common) ; + Numeric = KLU_malloc (1, sizeof (KLU_numeric), Common) ; if (Common->status < KLU_OK) { /* out of memory */ diff --git a/deps/AMICI/ThirdParty/SuiteSparse/LICENSE.txt b/deps/AMICI/ThirdParty/SuiteSparse/LICENSE.txt index 101db2442..445759392 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/LICENSE.txt +++ b/deps/AMICI/ThirdParty/SuiteSparse/LICENSE.txt @@ -1,38 +1,16 @@ ==> AMD/Doc/License.txt <== + AMD, Copyright (c), 1996-2015, Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. - AMD License: At the user's option, you may use AMD under either the LGPL - version 2.1 license, or the BSD 3-clause license. You may not use both - licenses, nor may you mix-and-match clauses from each license. To use a - license, in the documentation for your application simply state either of the - following, replacing with the name of your application: - - AMD, Copyright (c), 1996-2015, Timothy A. Davis, - Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. - Used in under the BSD 3-clause license. - - or - - AMD, Copyright (c), 1996-2015, Timothy A. Davis, - Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. - Used in under the LGPL v2.1 license. - - In the event that your package includes another package by another - author, and and use AMD under different licenses, you may select - one license to apply to both uses of AMD in the combined application. - Availability: http://www.suitesparse.com ------------------------------------------------------------------------------- - BSD 3-clause: + AMD License: BSD 3-clause: ------------------------------------------------------------------------------- - Copyright (c), 1996-2015, Timothy A. Davis, - Patrick R. Amestoy, and Iain S. Duff. 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 @@ -57,40 +35,6 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------- - LGPL version 2.1: - ------------------------------------------------------------------------------- - - Your use or distribution of AMD or any modified version of - AMD implies that you agree to this License. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - USA - - Permission is hereby granted to use or copy this program under the - terms of the GNU LGPL, provided that the Copyright, this License, - and the Availability of the original version is retained on all copies. - User documentation of any code that uses this code or any modified - version of this code must cite the Copyright, this License, the - Availability note, and "Used by permission." Permission to modify - the code and to distribute modified code is granted, provided the - Copyright, this License, and the Availability note are retained, - and a notice that the code was modified is included. - - ------------------------------------------------------------------------------- - ==> BTF/Doc/License.txt <== BTF, Copyright (C) 2004-2013, University of Florida by Timothy A. Davis and Ekanathan Palamadai. @@ -114,48 +58,44 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ==> CAMD/Doc/License.txt <== + CAMD, Copyright (c) by Timothy A. Davis, Yanqing Chen, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. CAMD is available under alternate licenses, contact T. Davis for details. - CAMD License: - - Your use or distribution of CAMD or any modified version of - CAMD implies that you agree to this License. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + CAMD License: BSD 3-clause - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - USA + 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 organizations to which the authors are + affiliated, nor the names of its contributors may be used to endorse + or promote products derived from this software without specific prior + written permission. - Permission is hereby granted to use or copy this program under the - terms of the GNU LGPL, provided that the Copyright, this License, - and the Availability of the original version is retained on all copies. - User documentation of any code that uses this code or any modified - version of this code must cite the Copyright, this License, the - Availability note, and "Used by permission." Permission to modify - the code and to distribute modified code is granted, provided the - Copyright, this License, and the Availability note are retained, - and a notice that the code was modified is included. + 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 HOLDERS 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. Availability: http://www.suitesparse.com - ------------------------------------------------------------------------------- - ==> CCOLAMD/Doc/License.txt <== + CCOLAMD: constrained column approximate minimum degree ordering Copyright (C) 2005-2016, Univ. of Florida. Authors: Timothy A. Davis, Sivasankaran Rajamanickam, and Stefan Larimore. Closely based on COLAMD by @@ -164,19 +104,33 @@ -------------------------------------------------------------------------------- - CCOLAMD is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + CCOLAMD license: BSD 3-clause: - CCOLAMD is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + 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 organizations to which the authors are + affiliated, nor the names of its contributors may be used to endorse + or promote products derived from this software without specific prior + written permission. - You should have received a copy of the GNU Lesser General Public - License along with this Module; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + 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 HOLDERS 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. + + -------------------------------------------------------------------------------- ==> CHOLMOD/Doc/License.txt <== -------------------------------------------------------------------------------- @@ -530,21 +484,31 @@ COLAMD, Copyright 1998-2016, Timothy A. Davis. http://www.suitesparse.com http://www.suitesparse.com - -------------------------------------------------------------------------------- + COLAMD License: BSD 3-clause - COLAMD is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - COLAMD is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + 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 organizations to which the authors are + affiliated, nor the names of its contributors may be used to endorse + or promote products derived from this software without specific prior + written permission. - You should have received a copy of the GNU Lesser General Public - License along with this Module; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + 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 HOLDERS 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. ==> CSparse/Doc/License.txt <== CSparse: a Concise Sparse matrix package. @@ -681,7 +645,7 @@ Contact the authors for details. -------------------------------------------------------------------------------- - MATLAB_Tools License, with the exception of SSMULT and UFcollection: + MATLAB_Tools License, with the exception of SSMULT and SuiteSparseCollection: -------------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -709,15 +673,15 @@ DAMAGE. -------------------------------------------------------------------------------- - UFcollection License: + SuiteSparseCollection License: -------------------------------------------------------------------------------- - UFcollection is free software; you can redistribute it and/or + SuiteSparseCollection is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - UFcollection is distributed in the hope that it will be useful, + SuiteSparseCollection is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -830,7 +794,7 @@ this Module; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -==> UFget/Doc/License.txt <== +==> ssget/Doc/License.txt <== Copyright (c), 2009-2016, Timothy A. Davis, All Rights Reserved. Redistribution and use in source and binary forms, with or without @@ -898,7 +862,7 @@ http://www.suitesparse.com -==> CSparse/MATLAB/UFget/Doc/License.txt <== +==> CSparse/MATLAB/ssget/Doc/License.txt <== Copyright (c), 2009-2016, Timothy A. Davis, All Rights Reserved. Redistribution and use in source and binary forms, with or without @@ -926,7 +890,7 @@ DAMAGE. -==> CXSparse/MATLAB/UFget/Doc/License.txt <== +==> CXSparse/MATLAB/ssget/Doc/License.txt <== Copyright (c), 2009-2016, Timothy A. Davis, All Rights Reserved. Redistribution and use in source and binary forms, with or without @@ -953,3 +917,24 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==> GraphBLAS/Doc/License.txt <== + SuiteSparse:GraphBLAS, Copyright 2017, Timothy A. Davis + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use SuiteSparse:GraphBLAS except in compliance with the + License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +==> Mongoose License <== + Mongoose, Copyright 2018, Timothy A. Davis, Scott P. Kolodziej, + William W. Hager, S. Nuri Yeralan + Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3, 29 June 2007 + + diff --git a/deps/AMICI/ThirdParty/SuiteSparse/Makefile b/deps/AMICI/ThirdParty/SuiteSparse/Makefile index 9d3ceb1c0..7d7d12d66 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/Makefile +++ b/deps/AMICI/ThirdParty/SuiteSparse/Makefile @@ -12,6 +12,8 @@ include SuiteSparse_config/SuiteSparse_config.mk # Compile the default rules for each package go: metis ( cd SuiteSparse_config && $(MAKE) ) + ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' ) + ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' ) ( cd AMD && $(MAKE) ) ( cd BTF && $(MAKE) ) ( cd CAMD && $(MAKE) ) @@ -34,8 +36,10 @@ endif # install all packages in /usr/local/lib and /usr/local/include # (note that CSparse is not installed; CXSparse is installed instead) -install: metis +install: metisinstall ( cd SuiteSparse_config && $(MAKE) install ) + ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' install ) + ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' install ) ( cd AMD && $(MAKE) install ) ( cd BTF && $(MAKE) install ) ( cd CAMD && $(MAKE) install ) @@ -56,8 +60,13 @@ endif # ( cd SKYLINE_SVD && $(MAKE) install ) $(CP) README.txt $(INSTALL_DOC)/SuiteSparse_README.txt chmod 644 $(INSTALL_DOC)/SuiteSparse_README.txt + +metisinstall: metis ifeq (,$(MY_METIS_LIB)) # install METIS from SuiteSparse/metis-5.1.0 + @mkdir -p $(INSTALL_LIB) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) - $(CP) lib/libmetis.* $(INSTALL_LIB) - $(CP) metis-5.1.0/manual/manual.pdf $(INSTALL_DOC)/METIS_manual.pdf - $(CP) metis-5.1.0/README.txt $(INSTALL_DOC)/METIS_README.txt @@ -75,6 +84,8 @@ uninstall: $(RM) $(INSTALL_DOC)/SuiteSparse_README.txt ( cd SuiteSparse_config && $(MAKE) uninstall ) - ( cd metis-5.1.0 && $(MAKE) uninstall ) + - ( cd GraphBLAS && $(MAKE) uninstall ) + - ( cd Mongoose && $(MAKE) uninstall ) ( cd AMD && $(MAKE) uninstall ) ( cd CAMD && $(MAKE) uninstall ) ( cd COLAMD && $(MAKE) uninstall ) @@ -101,9 +112,12 @@ ifeq (,$(MY_METIS_LIB)) endif $(RM) -r $(INSTALL_DOC) -# compile the dynamic libraries +# compile the dynamic libraries. For GraphBLAS and Mongoose, this also builds +# the static library library: metis ( cd SuiteSparse_config && $(MAKE) ) + ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' library ) + ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' library ) ( cd AMD && $(MAKE) library ) ( cd BTF && $(MAKE) library ) ( cd CAMD && $(MAKE) library ) @@ -124,9 +138,13 @@ endif # ( cd PIRO_BAND && $(MAKE) library ) # ( cd SKYLINE_SVD && $(MAKE) library ) -# compile the static libraries (except for metis, which is only dynamic) +# compile the static libraries (except for metis, GraphBLAS, and Mongoose). +# metis is only dynamic, and the 'make static' for GraphBLAS and Mongoose makes +# both the dynamic and static libraries. static: metis ( cd SuiteSparse_config && $(MAKE) static ) + ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' static ) + ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' static ) ( cd AMD && $(MAKE) static ) ( cd BTF && $(MAKE) static ) ( cd CAMD && $(MAKE) static ) @@ -152,6 +170,8 @@ purge: - ( cd SuiteSparse_config && $(MAKE) purge ) - ( cd metis-5.1.0 && $(MAKE) distclean ) - ( cd AMD && $(MAKE) purge ) + - ( cd GraphBLAS && $(MAKE) purge ) + - ( cd Mongoose && $(MAKE) purge ) - ( cd CAMD && $(MAKE) purge ) - ( cd COLAMD && $(MAKE) purge ) - ( cd BTF && $(MAKE) purge ) @@ -163,7 +183,7 @@ purge: - ( cd CSparse && $(MAKE) purge ) - ( cd CXSparse && $(MAKE) purge ) - ( cd RBio && $(MAKE) purge ) - - ( cd MATLAB_Tools/UFcollection && $(RM) *.mex* ) + - ( cd MATLAB_Tools/SuiteSparseCollection && $(RM) *.mex* ) - ( cd MATLAB_Tools/SSMULT && $(RM) *.mex* ) - ( cd SuiteSparse_GPURuntime && $(MAKE) purge ) - ( cd GPUQREngine && $(MAKE) purge ) @@ -177,6 +197,8 @@ purge: clean: - ( cd SuiteSparse_config && $(MAKE) clean ) - ( cd metis-5.1.0 && $(MAKE) clean ) + - ( cd GraphBLAS && $(MAKE) clean ) + - ( cd Mongoose && $(MAKE) clean ) - ( cd AMD && $(MAKE) clean ) - ( cd CAMD && $(MAKE) clean ) - ( cd COLAMD && $(MAKE) clean ) @@ -197,6 +219,8 @@ clean: # Create the PDF documentation docs: + ( cd GraphBLAS && $(MAKE) docs ) + ( cd Mongoose && $(MAKE) docs ) ( cd AMD && $(MAKE) docs ) ( cd CAMD && $(MAKE) docs ) ( cd KLU && $(MAKE) docs ) @@ -242,7 +266,7 @@ metis: include/metis.h # hardcoded below. include/metis.h: ifeq (,$(MY_METIS_LIB)) - - ( cd metis-5.1.0 && $(MAKE) config shared=1 prefix=$(SUITESPARSE) ) + - ( cd metis-5.1.0 && $(MAKE) config shared=1 prefix=$(SUITESPARSE) cc=$(CC) ) - ( cd metis-5.1.0 && $(MAKE) ) - ( cd metis-5.1.0 && $(MAKE) install ) - $(SO_INSTALL_NAME) $(SUITESPARSE)/lib/libmetis.dylib \ @@ -251,3 +275,13 @@ else @echo 'Using pre-installed METIS 5.1.0 library at ' '[$(MY_METIS_LIB)]' endif +# just compile GraphBLAS +gb: + echo $(CMAKE_OPTIONS) + ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' ) + +# just install GraphBLAS +gbinstall: + echo $(CMAKE_OPTIONS) + ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' install ) + diff --git a/deps/AMICI/ThirdParty/SuiteSparse/README.txt b/deps/AMICI/ThirdParty/SuiteSparse/README.txt index 08c2313ab..6678053b3 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/README.txt +++ b/deps/AMICI/ThirdParty/SuiteSparse/README.txt @@ -1,6 +1,22 @@ SuiteSparse: A Suite of Sparse matrix packages at http://www.suitesparse.com -May 4, 2016. SuiteSparse VERSION 4.5.3 +Dec 20, 2018. SuiteSparse VERSION 5.4.0 + +Now includes GraphBLAS and a new interface to the SuiteSparse Matrix +Collection (ssget), via MATLAB and a Java GUI, to http://sparse.tamu.edu. + +Primary author of SuiteSparse (codes and algorithms, excl. METIS): Tim Davis + +Code co-authors, in alphabetical order (not including METIS): + + Patrick Amestoy, David Bateman, Yanqing Chen, Iain Duff, Les Foster, + William Hager, Scott Kolodziej, Stefan Larimore, Ekanathan Palamadai, + Sivasankaran Rajamanickam, Sanjay Ranka, Wissam Sid-Lakhdar, Nuri Yeralan. + +Additional algorithm designers: Esmond Ng and John Gilbert. + +Refer to each package for license, copyright, and author information. All +codes are authored or co-authored by Timothy A. Davis. ------------------ SuiteSparse/README @@ -10,16 +26,29 @@ SuiteSparse/README Packages in SuiteSparse, and files in this directory: ================================================================================ + GraphBLAS graph algorithms in the language of linear algebra. + https://graphblas.org + A stand-alone package that uses cmake to compile; see + GraphBLAS/README.txt. The rest of SuiteSparse still uses + 'make'. A cmake setup for all of SuiteSparse is in progress. + author: Tim Davis + AMD approximate minimum degree ordering. This is the built-in AMD function in MATLAB. + authors: Tim Davis, Patrick Amestoy, Iain Duff bin where the metis-5.1.0 programs are placed when METIS is compiled BTF permutation to block triangular form + authors: Tim Davis, Ekanathan Palamadai CAMD constrained approximate minimum degree ordering + authors: Tim Davis, Patrick Amestoy, Iain Duff, Yanqing Chen CCOLAMD constrained column approximate minimum degree ordering + authors: Tim Davis, Sivasankaran Rajamanickam, Stefan Larimore. + Algorithm design collaborators: Esmond Ng, John Gilbert + (for COLAMD) ChangeLog a summary of changes to SuiteSparse. See */Doc/ChangeLog for details for each package. @@ -27,9 +56,13 @@ Packages in SuiteSparse, and files in this directory: CHOLMOD sparse Cholesky factorization. Requires AMD, COLAMD, CCOLAMD, the BLAS, and LAPACK. Optionally uses METIS. This is chol and x=A\b in MATLAB. + author for all modules: Tim Davis + CHOLMOD/Modify module authors: Tim Davis and William W. Hager COLAMD column approximate minimum degree ordering. This is the built-in COLAMD function in MATLAB. + authors (of the code): Tim Davis and Stefan Larimore + Algorithm design collaborators: Esmond Ng, John Gilbert Contents.m a list of contents for 'help SuiteSparse' in MATLAB. @@ -41,10 +74,12 @@ Packages in SuiteSparse, and files in this directory: have the same include filename: cs.h. This package is used for the built-in DMPERM in MATLAB. + author: Tim Davis CSparse_to_CXSparse a Perl script to create CXSparse from CSparse and CXSparse_newfiles + author: David Bateman, Motorola CXSparse CSparse Extended. Includes support for complex matrices and both int or long integers. Use this instead of CSparse @@ -52,25 +87,31 @@ Packages in SuiteSparse, and files in this directory: the Mac) with the same name as CSparse. It is a superset of CSparse. Any code that links against CSparse should also be able to link against CXSparse instead. + author: Tim Davis, David Bateman CXSparse_newfiles Files unique to CXSparse + author: Tim Davis, David Bateman share 'make' places documentation for each package here GPUQREngine GPU support package for SPQR (not built into MATLAB, however) + authors: Tim Davis, Nuri Yeralan, Sanjay Ranka, + Wissam Sid-Lakhdar include 'make' places user-visible include fomes for each package here KLU sparse LU factorization, primarily for circuit simulation. Requires AMD, COLAMD, and BTF. Optionally uses CHOLMOD, CAMD, CCOLAMD, and METIS. + authors: Tim Davis, Ekanathan Palamadai LDL a very concise LDL' factorization package + author: Tim Davis lib 'make' places shared libraries for each package here - Makefile to compile all of SuiteSparse: + Makefile to compile all of SuiteSparse (except GraphBLAS) make compiles SuiteSparse libraries and runs demos make install compiles SuiteSparse and installs in /usr/local make uninstall undoes 'make install' @@ -94,6 +135,8 @@ Packages in SuiteSparse, and files in this directory: make metis compiles METIS (also done by 'make') MATLAB_Tools various m-files for use in MATLAB + author: Tim Davis (all parts) + for spqr_rank: author Les Foster and Tim Davis Contents.m list of contents dimacs10 loads matrices for DIMACS10 collection @@ -115,26 +158,38 @@ Packages in SuiteSparse, and files in this directory: reliable factorizations, etc. With Leslie Foster, San Jose State Univ. SSMULT C=A*B where A and B are both sparse - UFcollection maitains the SuiteSparse matrix collection + SuiteSparseCollection maitains the SuiteSparse Matrix Collection waitmex waitbar for use inside a mexFunction The SSMULT and SFMULT functions are the basis for the built-in C=A*B functions in MATLAB. + Mongoose graph partitioning. + authors: Nuri Yeralan, Scott Kolodziej, William Hager, Tim Davis + metis-5.1.0 a modified version of METIS. See the README.txt files for details. + author: George Karypis; not an integral component of + SuiteSparse, however. This is just a copy included with + SuiteSparse via the open-source license provided by + George Karypis RBio read/write sparse matrices in Rutherford/Boeing format + author: Tim Davis README.txt this file SPQR sparse QR factorization. This the built-in qr and x=A\b in MATLAB. + author of the CPU code: Tim Davis + author of GPU modules: Tim Davis, Nuri Yeralan, + Wissam Sid-Lakhdar, Sanjay Ranka SuiteSparse_config configuration file for all the above packages. The SuiteSparse_config/SuiteSparse_config.mk is included in the Makefile's of all packages. CSparse and MATLAB_Tools do not use SuiteSparse_config. + author: Tim Davis SuiteSparse_GPURuntime GPU support package for SPQR (not builtin to MATLAB, however). @@ -143,11 +198,15 @@ Packages in SuiteSparse, and files in this directory: SuiteSparse_test.m exhaustive test for SuiteSparse in MATLAB - UFget MATLAB interface to the SuiteSparse Matrix Collection + ssget MATLAB interface to the SuiteSparse Matrix Collection (formerly called the UF Sparse Matrix Collection). + Includes a UFget function for backward compatibility. + author: Tim Davis UMFPACK sparse LU factorization. Requires AMD and the BLAS. This is the built-in lu and x=A\b in MATLAB. + author: Tim Davis + algorithm design collaboration: Iain Duff Some codes optionally use METIS 5.1.0. This package is located in SuiteSparse in the metis-5.1.0 directory. Its use is optional, so you can remove it before @@ -182,18 +241,20 @@ PACKAGENAME/Doc/License.txt: KLU/Doc/License.txt LDL/Doc/License.txt MATLAB_Tools/Doc/License.txt + Mongoose/Doc/License.txt RBio/Doc/License.txt SPQR/Doc/License.txt SuiteSparse_GPURuntime/Doc/License.txt - UFget/Doc/License.txt + ssget/Doc/License.txt UMFPACK/Doc/License.txt + GraphBLAS/Doc/License.txt These files are also present, but they are simply copies of the above license -files for CXSparse and UFget: +files for CXSparse and ssget: CXSparse_newfiles/Doc/License.txt - CSparse/MATLAB/UFget/Doc/License.txt - CXSparse/MATLAB/UFget/Doc/License.txt + CSparse/MATLAB/ssget/Doc/License.txt + CXSparse/MATLAB/ssget/Doc/License.txt METIS 5.0.1 is distributed with SuiteSparse, and is Copyright (c) by George Karypis. Please refer to that package for its License. @@ -208,10 +269,27 @@ will be run. To run a (long!) exhaustive test, do SuiteSparse_test. ================================================================================ -QUICK START FOR THE C/C++ LIBRARIES: Just type 'make' in this directory. All -libraries will be created and copied into SuiteSparse/lib. All include files -need by the applications that use SuiteSparse are copied into -SuiteSparse/include. All user documenation is copied into SuiteSparse/doc. +QUICK START FOR THE C/C++ LIBRARIES: + +For just GraphBLAS, do this: + + cd GraphBLAS/build ; cmake .. ; make ; cd ../Demo ; ./demo + cd ../build ; sudo make install + +For all other packages, type 'make' in this directory. All libraries will be +created and copied into SuiteSparse/lib. All include files need by the +applications that use SuiteSparse are copied into SuiteSparse/include. All +user documenation is copied into SuiteSparse/share/doc. + +When compiling the libraries, do NOT use the INSTALL=... options for +installing. Just do: + + make + +or to compile just the libraries without running the demos, do: + + make library + Any program that uses SuiteSparse can thus use a simpler rule as compared to earlier versions of SuiteSparse. If you add /home/myself/SuiteSparse/lib to your library search patch, you can do the following (for example): @@ -219,6 +297,17 @@ your library search patch, you can do the following (for example): S = /home/myself/SuiteSparse cc myprogram.c -I$(S)/include -lumfpack -lamd -lcholmod -lsuitesparseconfig -lm +To change the C and C++ compilers, and to compile in parallel use: + + AUTOCC=no CC=gcc CX=g++ JOBS=32 make + +for example, which changes the compiler to gcc and g++, and runs make with +'make -j32', in parallel with 32 jobs. + +Now you can install the libraries, if you wish, in a location other than +SuiteSparse/lib, SuiteSparse/include, and SuiteSparse/share/doc, using +'make install INSTALL=...' + Do 'make install' if you want to install the libraries and include files in SuiteSparse/lib and SuiteSparse/include, and the documentation in SuiteSparse/doc/suitesparse-VERSION. @@ -302,6 +391,8 @@ Step-by-step details: and the compiled libraries are copied into SuiteSparse/lib. Documentation is copied into SuiteSparse/doc. + The GraphBLAS libraries are created by cmake and placed in GraphBLAS/build. + NOTE: on Linux, you may see some errors when you compile METIS ('make: *** No rule to make target 'w'.). You can safely ignore those errors. diff --git a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/Makefile b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/Makefile index 188d076da..695a327a4 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/Makefile +++ b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/Makefile @@ -7,8 +7,8 @@ export SUITESPARSE # version of SuiteSparse_config is also version of SuiteSparse meta-package LIBRARY = libsuitesparseconfig -VERSION = 4.5.3 -SO_VERSION = 4 +VERSION = 5.4.0 +SO_VERSION = 5 default: library diff --git a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/README.txt b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/README.txt index a76a5fab6..8555cc459 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/README.txt +++ b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/README.txt @@ -1,4 +1,4 @@ -SuiteSparse_config, 2016, Timothy A. Davis, http://www.suitesparse.com +SuiteSparse_config, 2018, Timothy A. Davis, http://www.suitesparse.com (formerly the UFconfig package) This directory contains a default SuiteSparse_config.mk file. It tries to @@ -37,6 +37,7 @@ SuiteSparse_config is not required by these packages: CSparse a Concise Sparse matrix package MATLAB_Tools toolboxes for use in MATLAB + GraphBLAS graph algorithms in the language of linear algebra In addition, the xerbla/ directory contains Fortan and C versions of the BLAS/LAPACK xerbla routine, which is called when an invalid input is passed to diff --git a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c index b491539fe..595e46781 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c +++ b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c @@ -4,7 +4,7 @@ /* SuiteSparse configuration : memory manager and printf functions. */ -/* Copyright (c) 2013, Timothy A. Davis. No licensing restrictions +/* Copyright (c) 2013-2018, Timothy A. Davis. No licensing restrictions * apply to this file or to the SuiteSparse_config directory. * Author: Timothy A. Davis. */ diff --git a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.h b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.h index 6d1bc2dbe..9e28c0530 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.h +++ b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.h @@ -177,38 +177,7 @@ int SuiteSparse_divcomplex /* SuiteSparse is not a package itself, but a collection of packages, some of * which must be used together (UMFPACK requires AMD, CHOLMOD requires AMD, * COLAMD, CAMD, and CCOLAMD, etc). A version number is provided here for the - * collection itself. The versions of packages within each version of - * SuiteSparse are meant to work together. Combining one package from one - * version of SuiteSparse, with another package from another version of - * SuiteSparse, may or may not work. - * - * SuiteSparse contains the following packages: - * - * SuiteSparse_config version 4.5.3 (version always the same as SuiteSparse) - * AMD version 2.4.6 - * BTF version 1.2.6 - * CAMD version 2.4.6 - * CCOLAMD version 2.9.6 - * CHOLMOD version 3.0.11 - * COLAMD version 2.9.6 - * CSparse version 3.1.9 - * CXSparse version 3.1.9 - * GPUQREngine version 1.0.5 - * KLU version 1.3.8 - * LDL version 2.2.6 - * RBio version 2.2.6 - * SPQR version 2.0.7 - * SuiteSparse_GPURuntime version 1.0.5 - * UMFPACK version 5.7.6 - * MATLAB_Tools various packages & M-files - * xerbla version 1.0.3 - * - * Other package dependencies: - * BLAS required by CHOLMOD and UMFPACK - * LAPACK required by CHOLMOD - * METIS 5.1.0 required by CHOLMOD (optional) and KLU (optional) - * CUBLAS, CUDART NVIDIA libraries required by CHOLMOD and SPQR when - * they are compiled with GPU acceleration. + * collection itself, which is also the version number of SuiteSparse_config. */ int SuiteSparse_version /* returns SUITESPARSE_VERSION */ @@ -233,11 +202,11 @@ int SuiteSparse_version /* returns SUITESPARSE_VERSION */ */ #define SUITESPARSE_HAS_VERSION_FUNCTION -#define SUITESPARSE_DATE "May 4, 2016" +#define SUITESPARSE_DATE "Dec 28, 2018" #define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub)) -#define SUITESPARSE_MAIN_VERSION 4 -#define SUITESPARSE_SUB_VERSION 5 -#define SUITESPARSE_SUBSUB_VERSION 3 +#define SUITESPARSE_MAIN_VERSION 5 +#define SUITESPARSE_SUB_VERSION 4 +#define SUITESPARSE_SUBSUB_VERSION 0 #define SUITESPARSE_VERSION \ SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION) diff --git a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.mk b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.mk index 67894c373..19a39032a 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.mk +++ b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.mk @@ -3,9 +3,11 @@ #=============================================================================== # This file contains all configuration settings for all packages in SuiteSparse, -# except for CSparse (which is stand-alone) and the packages in MATLAB_Tools. +# except for CSparse (which is stand-alone), the packages in MATLAB_Tools, +# and GraphBLAS. The configuration settings for GraphBLAS are determined by +# GraphBLAS/CMakeLists.txt -SUITESPARSE_VERSION = 4.5.3 +SUITESPARSE_VERSION = 5.4.0 #=============================================================================== # Options you can change without editing this file: @@ -57,6 +59,15 @@ SUITESPARSE_VERSION = 4.5.3 INSTALL_INCLUDE ?= $(INSTALL)/include INSTALL_DOC ?= $(INSTALL)/share/doc/suitesparse-$(SUITESPARSE_VERSION) + CMAKE_OPTIONS ?= -DCMAKE_INSTALL_PREFIX=$(INSTALL) + + #--------------------------------------------------------------------------- + # parallel make + #--------------------------------------------------------------------------- + + # sequential make's by default + JOBS ?= 1 + #--------------------------------------------------------------------------- # optimization level #--------------------------------------------------------------------------- @@ -78,19 +89,11 @@ SUITESPARSE_VERSION = 4.5.3 CXX = g++ BLAS = -lrefblas -lgfortran -lstdc++ LAPACK = -llapack - CFLAGS += --coverage - OPTIMIZATION = -g - LDFLAGS += --coverage + CFLAGS += --coverage + OPTIMIZATION = -g + LDFLAGS += --coverage endif - #--------------------------------------------------------------------------- - # CFLAGS for the C/C++ compiler - #--------------------------------------------------------------------------- - - # The CF macro is used by SuiteSparse Makefiles as a combination of - # CFLAGS, CPPFLAGS, TARGET_ARCH, and system-dependent settings. - CF ?= $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) $(OPTIMIZATION) -fexceptions -fPIC - #--------------------------------------------------------------------------- # OpenMP is used in CHOLMOD #--------------------------------------------------------------------------- @@ -112,9 +115,12 @@ SUITESPARSE_VERSION = 4.5.3 ifneq ($(AUTOCC),no) ifneq ($(shell which icc 2>/dev/null),) # use the Intel icc compiler for C codes, and -qopenmp for OpenMP - CC = icc -D_GNU_SOURCE - CXX = $(CC) + CC = icc + CFLAGS += -D_GNU_SOURCE + CXX = icpc CFOPENMP = -qopenmp -I$(MKLROOT)/include + LDFLAGS += -qopenmp + LDLIBS += -lm -lirc endif ifneq ($(shell which ifort 2>/dev/null),) # use the Intel ifort compiler for Fortran codes @@ -122,8 +128,18 @@ SUITESPARSE_VERSION = 4.5.3 endif endif + CMAKE_OPTIONS += -DCMAKE_CXX_COMPILER=$(CXX) -DCMAKE_C_COMPILER=$(CC) + + #--------------------------------------------------------------------------- + # CFLAGS for the C/C++ compiler + #--------------------------------------------------------------------------- + + # The CF macro is used by SuiteSparse Makefiles as a combination of + # CFLAGS, CPPFLAGS, TARGET_ARCH, and system-dependent settings. + CF ?= $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) $(OPTIMIZATION) -fexceptions -fPIC + #--------------------------------------------------------------------------- - # code formatting (for Tcov only) + # code formatting (for Tcov on Linux only) #--------------------------------------------------------------------------- PRETTY ?= grep -v "^\#" | indent -bl -nce -bli0 -i4 -sob -l120 @@ -156,7 +172,7 @@ SUITESPARSE_VERSION = 4.5.3 # $(MKLROOT)/lib/intel64/libmkl_intel_thread.a \ # -Wl,--end-group -lpthread -lm # using dynamic linking: - BLAS = -lmkl_intel_lp64 -lmkl_core -lmkl_intel_thread -lpthread -lm + BLAS = -lmkl_intel_lp64 -lmkl_core -lmkl_intel_thread -liomp5 -lpthread -lm LAPACK = else # use the OpenBLAS at http://www.openblas.net @@ -222,13 +238,16 @@ SUITESPARSE_VERSION = 4.5.3 CUBLAS_LIB = $(CUDA_PATH)/lib64/libcublas.so CUDA_INC_PATH = $(CUDA_PATH)/include/ CUDA_INC = -I$(CUDA_INC_PATH) + MAGMA_INC = -I/opt/magma-2.4.0/include/ + MAGMA_LIB = -L/opt/magma-2.4.0/lib/ -lmagma NVCC = $(CUDA_PATH)/bin/nvcc NVCCFLAGS = -Xcompiler -fPIC -O3 \ - -gencode=arch=compute_20,code=sm_20 \ -gencode=arch=compute_30,code=sm_30 \ -gencode=arch=compute_35,code=sm_35 \ -gencode=arch=compute_50,code=sm_50 \ - -gencode=arch=compute_50,code=compute_50 + -gencode=arch=compute_53,code=sm_53 \ + -gencode=arch=compute_53,code=sm_53 \ + -gencode=arch=compute_60,code=compute_60 endif #--------------------------------------------------------------------------- @@ -305,8 +324,9 @@ SUITESPARSE_VERSION = 4.5.3 SPQR_CONFIG ?= $(GPU_CONFIG) - # to compile with Intel's TBB, use TBB=-ltbb SPQR_CONFIG=-DHAVE_TBB + # to compile with Intel's TBB, use TBB=-ltbb -DSPQR_CONFIG=-DHAVE_TBB TBB ?= + # TBB = -ltbb -DSPQR_CONFIG=-DHAVE_TBB # TODO: this *mk file should auto-detect the presence of Intel's TBB, # and set the compiler flags accordingly. @@ -432,8 +452,6 @@ ifeq ($(UNAME),Windows) SO_PLAIN = $(LIBRARY).dll SO_MAIN = $(LIBRARY).$(SO_VERSION).dll SO_TARGET = $(LIBRARY).$(VERSION).dll - SO_OPTS += -shared \ - -L$(SUITESPARSE)/lib SO_INSTALL_NAME = echo else # Mac or Linux/Unix @@ -556,6 +574,7 @@ config: @echo 'Install include files in: INSTALL_INCLUDE=' '$(INSTALL_INCLUDE)' @echo 'Install documentation in: INSTALL_DOC= ' '$(INSTALL_DOC)' @echo 'Optimization level: OPTIMIZATION= ' '$(OPTIMIZATION)' + @echo 'parallel make jobs: JOBS= ' '$(JOBS)' @echo 'BLAS library: BLAS= ' '$(BLAS)' @echo 'LAPACK library: LAPACK= ' '$(LAPACK)' @echo 'Intel TBB library: TBB= ' '$(TBB)' diff --git a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_demo.m b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_demo.m index 2dd77e264..b5fce6ad1 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_demo.m +++ b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_demo.m @@ -5,9 +5,9 @@ function SuiteSparse_demo (matrixpath, dopause) % SuiteSparse_demo % % See also umfpack, cholmod, amd, camd, colamd, ccolamd, btf, klu, spqr, -% CSparse, CXSparse, ldlsparse +% CSparse, CXSparse, ldlsparse, mongoose -% Copyright 2015, Timothy A. Davis, http://www.suitesparse.com. +% Copyright 2016, Timothy A. Davis, http://www.suitesparse.com. if (nargin < 1 || isempty (matrixpath) || ~ischar (matrixpath)) try @@ -187,4 +187,26 @@ function SuiteSparse_demo (matrixpath, dopause) fprintf ('spqr_rank demo failed\n' ) end +if (dopause) + input ('Hit enter to run the Mongoose demo: ', 's') ; +end +try + mongoose_demo +catch me + disp (me.message) ; + fprintf ('Mongoose demo failed\n' ) +end + +%{ +if (dopause) + input ('Hit enter to run the piro_band demo: ', 's') ; +end +try + piro_band_demo +catch me + disp (me.message) ; + fprintf ('piro_band_demo failed\n' ) +end +%} + fprintf ('\n\n---- SuiteSparse demos complete\n') ; diff --git a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_install.m b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_install.m index 4a5cdda4c..630854975 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_install.m +++ b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_install.m @@ -4,6 +4,9 @@ function SuiteSparse_install (do_demo) % % Packages in SuiteSparse: % +% GraphBLAS graph algorithms via sparse linear algebra (graphblas.org) +% (does not yet have a MATLAB interface) +% Mongoose graph partitioner % UMFPACK sparse LU factorization (multifrontal) % CHOLMOD sparse Cholesky factorization, and many other operations % AMD sparse symmetric approximate minimum degree ordering @@ -12,11 +15,11 @@ function SuiteSparse_install (do_demo) % CCOLAMD constrained COLAMD % CSparse a Concise Sparse matrix package (32-bit or 64-bit, real only) % CXSparse extended version of CSparse (32-bit/64-bit/real/complex) -% UFget interface to UF Sparse Matrix Collection (MATLAB 7.0 or later) +% ssget interface to SuiteSparse Matrix Collection % KLU sparse LU factorization (left-looking) % BTF permutation to block triangular form (like dmperm) % LDL sparse LDL' factorization -% UFcollection tools for managing the UF Sparse Matrix Collection +% SuiteSparseCollection tools for managing the SuiteSparse Matrix Collection % RBio read/write Rutherford/Boeing files % SSMULT sparse matrix times sparse matrix % MESHND 2D and 3D regular mesh generation and nested dissection @@ -33,15 +36,17 @@ function SuiteSparse_install (do_demo) % help SuiteSparse % for more details % % See also AMD, COLAMD, CAMD, CCOLAMD, CHOLMOD, UMFPACK, CSPARSE, CXSPARSE, -% UFget, RBio, UFcollection, KLU, BTF, MESHND, SSMULT, LINFACTOR, SPOK, -% SPQR_RANK, SuiteSparse, SPQR, PATHTOOL, PATH, FACTORIZE, SPARSEINV. +% ssget, RBio, SuiteSparseCollection, KLU, BTF, MESHND, SSMULT, LINFACTOR, +% SPOK, SPQR_RANK, SuiteSparse, SPQR, PATHTOOL, PATH, FACTORIZE, +% SPARSEINV, Mongoose. % % This script installs the full-featured CXSparse rather than CSparse. % -% Copyright 1990-2015, Timothy A. Davis, http://www.suitesparse.com. -% In collaboration with Patrick Amestoy, Yanqing Chen, Iain Duff, John Gilbert, -% Steve Hadfield, William Hager, Stefan Larimore, Leslie Foster, Eka Palamadai -% Natarajan, Esmond Ng, Siva Rajamanickam, Nuri Yeralan, and Sanjay Ranka. +% Copyright 1990-2018, Timothy A. Davis, http://www.suitesparse.com. +% In collaboration with (in alphabetical order): Patrick Amestoy, David +% Bateman, Yanqing Chen, Iain Duff, Les Foster, William Hager, Scott Kolodziej, +% Stefan Larimore, Ekanathan Palamadai Natarajan, Sivasankaran Rajamanickam, +% Sanjay Ranka, Wissam Sid-Lakhdar, and Nuri Yeralan. %------------------------------------------------------------------------------- % initializations @@ -120,23 +125,23 @@ function SuiteSparse_install (do_demo) fprintf ('CAMD not installed\n') ; end -% install UFget, unless it's already in the path +% install ssget, unless it's already in the path try - % if this fails, then UFget is not yet installed - index = UFget ; - fprintf ('UFget already installed:\n') ; - which UFget + % if this fails, then ssget is not yet installed + index = ssget ; + fprintf ('ssget already installed:\n') ; + which ssget catch index = [ ] ; end if (isempty (index)) - % UFget is not installed. Use SuiteSparse/UFget - fprintf ('Installing SuiteSparse/UFget\n') ; + % ssget is not installed. Use SuiteSparse/ssget + fprintf ('Installing SuiteSparse/ssget\n') ; try - paths = add_to_path (paths, [SuiteSparse '/UFget']) ; + paths = add_to_path (paths, [SuiteSparse '/ssget']) ; catch me disp (me.message) ; - fprintf ('UFget not installed\n') ; + fprintf ('ssget not installed\n') ; end end @@ -223,14 +228,14 @@ function SuiteSparse_install (do_demo) fprintf ('MATLAB_Tools not installed\n') ; end -% compile and install UFcollection +% compile and install SuiteSparseCollection try % do not try to compile with large-file I/O for MATLAB 6.5 or earlier - paths = add_to_path (paths, [SuiteSparse '/MATLAB_Tools/UFcollection']) ; - UFcollection_install (verLessThan ('matlab', '7.0')) ; + paths = add_to_path (paths, [SuiteSparse '/MATLAB_Tools/SuiteSparseCollection']) ; + ss_install (verLessThan ('matlab', '7.0')) ; catch me disp (me.message) ; - fprintf ('UFcollection not installed\n') ; + fprintf ('SuiteSparseCollection not installed\n') ; end % compile and install SSMULT @@ -260,6 +265,17 @@ function SuiteSparse_install (do_demo) fprintf ('MATLAB_Tools/spok not installed\n') ; end +%{ +% compile and install PIRO_BAND +try + paths = add_to_path (paths, [SuiteSparse '/PIRO_BAND/MATLAB']) ; + piro_band_make ; +catch me + disp (me.message) ; + fprintf ('PIRO_BAND not installed\n') ; +end +%} + % compile and install sparsinv try paths = add_to_path (paths, [SuiteSparse '/MATLAB_Tools/sparseinv']) ; @@ -269,6 +285,15 @@ function SuiteSparse_install (do_demo) fprintf ('MATLAB_Tools/sparseinv not installed\n') ; end +% compile and install Mongoose +try + paths = add_to_path (paths, [SuiteSparse '/Mongoose/MATLAB']) ; + mongoose_make (0) ; +catch me + disp (me.message) ; + fprintf ('Mongoose not installed\n') ; +end + %------------------------------------------------------------------------------- % post-install wrapup %------------------------------------------------------------------------------- @@ -316,4 +341,4 @@ function SuiteSparse_install (do_demo) % add a path cd (newpath) ; addpath (newpath) ; -paths = [paths { newpath } ] ; %#ok +paths = [paths { newpath } ] ; diff --git a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_test.m b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_test.m index f277b764d..24d22fa29 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_test.m +++ b/deps/AMICI/ThirdParty/SuiteSparse/SuiteSparse_test.m @@ -14,7 +14,7 @@ help SuiteSparse_test -npackages = 18 ; +npackages = 19 ; h = waitbar (0, 'SuiteSparse test:') ; SuiteSparse = pwd ; package = 0 ; @@ -38,7 +38,7 @@ % uninstall CSparse by removing it from path rmpath ([SuiteSparse '/CSparse/MATLAB/CSparse']) ; rmpath ([SuiteSparse '/CSparse/MATLAB/Demo']) ; - rmpath ([SuiteSparse '/CSparse/MATLAB/UFget']) ; + rmpath ([SuiteSparse '/CSparse/MATLAB/ssget']) ; %--------------------------------------------------------------------------- % CXSparse @@ -192,12 +192,30 @@ demo_spqr_rank ; %--------------------------------------------------------------------------- - % AMD, CAMD, UFcollection, UFget + % Mongoose + %--------------------------------------------------------------------------- + + package = package + 1 ; + waitbar (package/(npackages+1), h, 'SuiteSparse test: mongoose') ; + cd ([SuiteSparse '/Mongoose/MATLAB']) ; + mongoose_test ; + + %--------------------------------------------------------------------------- + % PIRO_BAND + %--------------------------------------------------------------------------- + +% package = package + 1 ; +% waitbar (package/(npackages+1), h, 'SuiteSparse test: PIRO_BAND') ; +% cd ([SuiteSparse '/PIRO_BAND/MATLAB/Test']) ; +% demo_spqr_rank ; + + %--------------------------------------------------------------------------- + % AMD, CAMD, SuiteSparseCollection, ssget %--------------------------------------------------------------------------- % no exhaustive tests; tested via other packages -catch %#ok +catch %--------------------------------------------------------------------------- % test failure diff --git a/deps/AMICI/ThirdParty/SuiteSparse/include/SuiteSparse_config.h b/deps/AMICI/ThirdParty/SuiteSparse/include/SuiteSparse_config.h index 6d1bc2dbe..9e28c0530 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/include/SuiteSparse_config.h +++ b/deps/AMICI/ThirdParty/SuiteSparse/include/SuiteSparse_config.h @@ -177,38 +177,7 @@ int SuiteSparse_divcomplex /* SuiteSparse is not a package itself, but a collection of packages, some of * which must be used together (UMFPACK requires AMD, CHOLMOD requires AMD, * COLAMD, CAMD, and CCOLAMD, etc). A version number is provided here for the - * collection itself. The versions of packages within each version of - * SuiteSparse are meant to work together. Combining one package from one - * version of SuiteSparse, with another package from another version of - * SuiteSparse, may or may not work. - * - * SuiteSparse contains the following packages: - * - * SuiteSparse_config version 4.5.3 (version always the same as SuiteSparse) - * AMD version 2.4.6 - * BTF version 1.2.6 - * CAMD version 2.4.6 - * CCOLAMD version 2.9.6 - * CHOLMOD version 3.0.11 - * COLAMD version 2.9.6 - * CSparse version 3.1.9 - * CXSparse version 3.1.9 - * GPUQREngine version 1.0.5 - * KLU version 1.3.8 - * LDL version 2.2.6 - * RBio version 2.2.6 - * SPQR version 2.0.7 - * SuiteSparse_GPURuntime version 1.0.5 - * UMFPACK version 5.7.6 - * MATLAB_Tools various packages & M-files - * xerbla version 1.0.3 - * - * Other package dependencies: - * BLAS required by CHOLMOD and UMFPACK - * LAPACK required by CHOLMOD - * METIS 5.1.0 required by CHOLMOD (optional) and KLU (optional) - * CUBLAS, CUDART NVIDIA libraries required by CHOLMOD and SPQR when - * they are compiled with GPU acceleration. + * collection itself, which is also the version number of SuiteSparse_config. */ int SuiteSparse_version /* returns SUITESPARSE_VERSION */ @@ -233,11 +202,11 @@ int SuiteSparse_version /* returns SUITESPARSE_VERSION */ */ #define SUITESPARSE_HAS_VERSION_FUNCTION -#define SUITESPARSE_DATE "May 4, 2016" +#define SUITESPARSE_DATE "Dec 28, 2018" #define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub)) -#define SUITESPARSE_MAIN_VERSION 4 -#define SUITESPARSE_SUB_VERSION 5 -#define SUITESPARSE_SUBSUB_VERSION 3 +#define SUITESPARSE_MAIN_VERSION 5 +#define SUITESPARSE_SUB_VERSION 4 +#define SUITESPARSE_SUBSUB_VERSION 0 #define SUITESPARSE_VERSION \ SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION) diff --git a/deps/AMICI/ThirdParty/SuiteSparse/include/klu.h b/deps/AMICI/ThirdParty/SuiteSparse/include/klu.h index 2da483b06..07611f72d 100644 --- a/deps/AMICI/ThirdParty/SuiteSparse/include/klu.h +++ b/deps/AMICI/ThirdParty/SuiteSparse/include/klu.h @@ -819,11 +819,11 @@ void *klu_l_realloc (size_t, size_t, size_t, void *, klu_l_common *) ; * #endif */ -#define KLU_DATE "May 4, 2016" +#define KLU_DATE "Mar 12, 2018" #define KLU_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) #define KLU_MAIN_VERSION 1 #define KLU_SUB_VERSION 3 -#define KLU_SUBSUB_VERSION 8 +#define KLU_SUBSUB_VERSION 9 #define KLU_VERSION KLU_VERSION_CODE(KLU_MAIN_VERSION,KLU_SUB_VERSION) #ifdef __cplusplus diff --git a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode.h b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode.h index 00a10fe12..e61cbcf00 100644 --- a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode.h +++ b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -40,58 +40,81 @@ extern "C" { * ARKode Constants * ----------------- */ -/* itask */ +/* usage modes (itask) */ #define ARK_NORMAL 1 #define ARK_ONE_STEP 2 + +/* interpolation module flags */ + +/* max allowed degree */ +#define ARK_INTERP_MAX_DEGREE 5 + +/* interpolation module types */ +#define ARK_INTERP_HERMITE 0 +#define ARK_INTERP_LAGRANGE 1 + + /* return values */ -#define ARK_SUCCESS 0 -#define ARK_TSTOP_RETURN 1 -#define ARK_ROOT_RETURN 2 - -#define ARK_WARNING 99 - -#define ARK_TOO_MUCH_WORK -1 -#define ARK_TOO_MUCH_ACC -2 -#define ARK_ERR_FAILURE -3 -#define ARK_CONV_FAILURE -4 - -#define ARK_LINIT_FAIL -5 -#define ARK_LSETUP_FAIL -6 -#define ARK_LSOLVE_FAIL -7 -#define ARK_RHSFUNC_FAIL -8 -#define ARK_FIRST_RHSFUNC_ERR -9 -#define ARK_REPTD_RHSFUNC_ERR -10 -#define ARK_UNREC_RHSFUNC_ERR -11 -#define ARK_RTFUNC_FAIL -12 -#define ARK_LFREE_FAIL -13 -#define ARK_MASSINIT_FAIL -14 -#define ARK_MASSSETUP_FAIL -15 -#define ARK_MASSSOLVE_FAIL -16 -#define ARK_MASSFREE_FAIL -17 -#define ARK_MASSMULT_FAIL -18 - -#define ARK_MEM_FAIL -20 -#define ARK_MEM_NULL -21 -#define ARK_ILL_INPUT -22 -#define ARK_NO_MALLOC -23 -#define ARK_BAD_K -24 -#define ARK_BAD_T -25 -#define ARK_BAD_DKY -26 -#define ARK_TOO_CLOSE -27 - -#define ARK_POSTPROCESS_FAIL -28 -#define ARK_VECTOROP_ERR -29 - -#define ARK_NLS_INIT_FAIL -30 -#define ARK_NLS_SETUP_FAIL -31 -#define ARK_NLS_SETUP_RECVR -32 -#define ARK_NLS_OP_ERR -33 - -#define ARK_INNERSTEP_FAIL -34 - -#define ARK_UNRECOGNIZED_ERROR -99 +#define ARK_SUCCESS 0 +#define ARK_TSTOP_RETURN 1 +#define ARK_ROOT_RETURN 2 + +#define ARK_WARNING 99 + +#define ARK_TOO_MUCH_WORK -1 +#define ARK_TOO_MUCH_ACC -2 +#define ARK_ERR_FAILURE -3 +#define ARK_CONV_FAILURE -4 + +#define ARK_LINIT_FAIL -5 +#define ARK_LSETUP_FAIL -6 +#define ARK_LSOLVE_FAIL -7 +#define ARK_RHSFUNC_FAIL -8 +#define ARK_FIRST_RHSFUNC_ERR -9 +#define ARK_REPTD_RHSFUNC_ERR -10 +#define ARK_UNREC_RHSFUNC_ERR -11 +#define ARK_RTFUNC_FAIL -12 +#define ARK_LFREE_FAIL -13 +#define ARK_MASSINIT_FAIL -14 +#define ARK_MASSSETUP_FAIL -15 +#define ARK_MASSSOLVE_FAIL -16 +#define ARK_MASSFREE_FAIL -17 +#define ARK_MASSMULT_FAIL -18 + +#define ARK_CONSTR_FAIL -19 +#define ARK_MEM_FAIL -20 +#define ARK_MEM_NULL -21 +#define ARK_ILL_INPUT -22 +#define ARK_NO_MALLOC -23 +#define ARK_BAD_K -24 +#define ARK_BAD_T -25 +#define ARK_BAD_DKY -26 +#define ARK_TOO_CLOSE -27 + +#define ARK_VECTOROP_ERR -28 + +#define ARK_NLS_INIT_FAIL -29 +#define ARK_NLS_SETUP_FAIL -30 +#define ARK_NLS_SETUP_RECVR -31 +#define ARK_NLS_OP_ERR -32 + +#define ARK_INNERSTEP_ATTACH_ERR -33 +#define ARK_INNERSTEP_FAIL -34 +#define ARK_OUTERTOINNER_FAIL -35 +#define ARK_INNERTOOUTER_FAIL -36 + +/* ARK_POSTPROCESS_FAIL equals ARK_POSTPROCESS_STEP_FAIL + for backwards compatibility */ +#define ARK_POSTPROCESS_FAIL -37 +#define ARK_POSTPROCESS_STEP_FAIL -37 +#define ARK_POSTPROCESS_STAGE_FAIL -38 + +#define ARK_USER_PREDICT_FAIL -39 +#define ARK_INTERP_FAIL -40 + +#define ARK_UNRECOGNIZED_ERROR -99 /* ------------------------------ * User-Supplied Function Types @@ -123,10 +146,14 @@ typedef int (*ARKExpStabFn)(N_Vector y, realtype t, typedef int (*ARKVecResizeFn)(N_Vector y, N_Vector ytemplate, void *user_data); +typedef int (*ARKPostProcessFn)(realtype t, N_Vector y, + void *user_data); + +/* ARKPostProcessStepFn is now deprecated and will be removed in future + releases. It has be replaced with ARKPostProcessFn. */ typedef int (*ARKPostProcessStepFn)(realtype t, N_Vector y, void *user_data); - #ifdef __cplusplus } #endif diff --git a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_arkstep.h b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_arkstep.h index e622b0165..7bc7ac3cd 100644 --- a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_arkstep.h +++ b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_arkstep.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -58,6 +58,13 @@ extern "C" { #define DEFAULT_ARK_ITABLE_5 ARK548L2SA_DIRK_8_4_5 +/* ------------------------------ + * User-Supplied Function Types + * ------------------------------ */ + +typedef int (*ARKStepStagePredictFn)(realtype t, N_Vector zpred, + void *user_data); + /* ------------------- * Exported Functions * ------------------- */ @@ -110,6 +117,8 @@ SUNDIALS_EXPORT int ARKStepRootInit(void *arkode_mem, int nrtfn, SUNDIALS_EXPORT int ARKStepSetDefaults(void* arkode_mem); SUNDIALS_EXPORT int ARKStepSetOptimalParams(void *arkode_mem); SUNDIALS_EXPORT int ARKStepSetOrder(void *arkode_mem, int maxord); +SUNDIALS_EXPORT int ARKStepSetInterpolantType(void *arkode_mem, int itype); +SUNDIALS_EXPORT int ARKStepSetInterpolantDegree(void *arkode_mem, int degree); SUNDIALS_EXPORT int ARKStepSetDenseOrder(void *arkode_mem, int dord); SUNDIALS_EXPORT int ARKStepSetNonlinearSolver(void *arkode_mem, SUNNonlinearSolver NLS); @@ -136,7 +145,7 @@ SUNDIALS_EXPORT int ARKStepSetFixedStepBounds(void *arkode_mem, SUNDIALS_EXPORT int ARKStepSetAdaptivityMethod(void *arkode_mem, int imethod, int idefault, int pq, - realtype *adapt_params); + realtype adapt_params[3]); SUNDIALS_EXPORT int ARKStepSetAdaptivityFn(void *arkode_mem, ARKAdaptFn hfun, void *h_data); @@ -169,6 +178,8 @@ SUNDIALS_EXPORT int ARKStepSetMaxConvFails(void *arkode_mem, int maxncf); SUNDIALS_EXPORT int ARKStepSetNonlinConvCoef(void *arkode_mem, realtype nlscoef); +SUNDIALS_EXPORT int ARKStepSetConstraints(void *arkode_mem, + N_Vector constraints); SUNDIALS_EXPORT int ARKStepSetMaxNumSteps(void *arkode_mem, long int mxsteps); SUNDIALS_EXPORT int ARKStepSetMaxHnilWarns(void *arkode_mem, @@ -183,6 +194,8 @@ SUNDIALS_EXPORT int ARKStepSetStopTime(void *arkode_mem, realtype tstop); SUNDIALS_EXPORT int ARKStepSetFixedStep(void *arkode_mem, realtype hfixed); +SUNDIALS_EXPORT int ARKStepSetMaxNumConstrFails(void *arkode_mem, + int maxfails); SUNDIALS_EXPORT int ARKStepSetRootDirection(void *arkode_mem, int *rootdir); @@ -199,7 +212,11 @@ SUNDIALS_EXPORT int ARKStepSetDiagnostics(void *arkode_mem, FILE *diagfp); SUNDIALS_EXPORT int ARKStepSetPostprocessStepFn(void *arkode_mem, - ARKPostProcessStepFn ProcessStep); + ARKPostProcessFn ProcessStep); +SUNDIALS_EXPORT int ARKStepSetPostprocessStageFn(void *arkode_mem, + ARKPostProcessFn ProcessStage); +SUNDIALS_EXPORT int ARKStepSetStagePredictFn(void *arkode_mem, + ARKStepStagePredictFn PredictStage); /* Linear solver interface optional input functions -- must be called AFTER ARKStepSetLinearSolver and/or ARKStepSetMassLinearSolver */ @@ -207,6 +224,8 @@ SUNDIALS_EXPORT int ARKStepSetJacFn(void *arkode_mem, ARKLsJacFn jac); SUNDIALS_EXPORT int ARKStepSetMassFn(void *arkode_mem, ARKLsMassFn mass); SUNDIALS_EXPORT int ARKStepSetMaxStepsBetweenJac(void *arkode_mem, long int msbj); +SUNDIALS_EXPORT int ARKStepSetLinearSolutionScaling(void *arkode_mem, + booleantype onoff); SUNDIALS_EXPORT int ARKStepSetEpsLin(void *arkode_mem, realtype eplifac); SUNDIALS_EXPORT int ARKStepSetMassEpsLin(void *arkode_mem, realtype eplifac); SUNDIALS_EXPORT int ARKStepSetPreconditioner(void *arkode_mem, @@ -222,6 +241,7 @@ SUNDIALS_EXPORT int ARKStepSetMassTimes(void *arkode_mem, ARKLsMassTimesSetupFn msetup, ARKLsMassTimesVecFn mtimes, void *mtimes_data); +SUNDIALS_EXPORT int ARKStepSetLinSysFn(void *arkode_mem, ARKLsLinSysFn linsys); /* Integrate the ODE over an interval in t */ SUNDIALS_EXPORT int ARKStepEvolve(void *arkode_mem, realtype tout, @@ -264,6 +284,10 @@ SUNDIALS_EXPORT int ARKStepGetCurrentStep(void *arkode_mem, realtype *hcur); SUNDIALS_EXPORT int ARKStepGetCurrentTime(void *arkode_mem, realtype *tcur); +SUNDIALS_EXPORT int ARKStepGetCurrentState(void *arkode_mem, + N_Vector *ycur); +SUNDIALS_EXPORT int ARKStepGetCurrentGamma(void *arkode_mem, + realtype *gamma); SUNDIALS_EXPORT int ARKStepGetTolScaleFactor(void *arkode_mem, realtype *tolsfac); SUNDIALS_EXPORT int ARKStepGetErrWeights(void *arkode_mem, @@ -274,6 +298,8 @@ SUNDIALS_EXPORT int ARKStepGetNumGEvals(void *arkode_mem, long int *ngevals); SUNDIALS_EXPORT int ARKStepGetRootInfo(void *arkode_mem, int *rootsfound); +SUNDIALS_EXPORT int ARKStepGetNumConstrFails(void *arkode_mem, + long int *nconstrfails); SUNDIALS_EXPORT char *ARKStepGetReturnFlagName(long int flag); SUNDIALS_EXPORT int ARKStepWriteParameters(void *arkode_mem, FILE *fp); @@ -334,6 +360,8 @@ SUNDIALS_EXPORT int ARKStepGetMassWorkSpace(void *arkode_mem, long int *leniwMLS); SUNDIALS_EXPORT int ARKStepGetNumMassSetups(void *arkode_mem, long int *nmsetups); +SUNDIALS_EXPORT int ARKStepGetNumMassMultSetups(void *arkode_mem, + long int *nmvsetups); SUNDIALS_EXPORT int ARKStepGetNumMassMult(void *arkode_mem, long int *nmvevals); SUNDIALS_EXPORT int ARKStepGetNumMassSolves(void *arkode_mem, diff --git a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_bandpre.h b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_bandpre.h index ebcb38c90..a268804f9 100644 --- a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_bandpre.h +++ b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_bandpre.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_bbdpre.h b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_bbdpre.h index 1594cf614..bfa153cc8 100644 --- a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_bbdpre.h +++ b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_bbdpre.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_butcher.h b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_butcher.h index d4432e916..2dd275ad2 100644 --- a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_butcher.h +++ b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_butcher.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -27,7 +27,7 @@ extern "C" { /*--------------------------------------------------------------- Types : struct ARKodeButcherTableMem, ARKodeButcherTable ---------------------------------------------------------------*/ -typedef struct ARKodeButcherTableMem { +struct ARKodeButcherTableMem { int q; /* method order of accuracy */ int p; /* embedding order of accuracy */ @@ -37,7 +37,10 @@ typedef struct ARKodeButcherTableMem { realtype *b; /* root node coefficients */ realtype *d; /* embedding coefficients */ -} *ARKodeButcherTable; +}; + + +typedef _SUNDIALS_STRUCT_ ARKodeButcherTableMem *ARKodeButcherTable; /* Utility routines to allocate/free/output Butcher table structures */ diff --git a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_butcher_dirk.h b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_butcher_dirk.h index 8b907cec2..e7ff08f08 100644 --- a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_butcher_dirk.h +++ b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_butcher_dirk.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -39,10 +39,12 @@ extern "C" { #define ARK436L2SA_DIRK_6_3_4 109 #define KVAERNO_7_4_5 110 #define ARK548L2SA_DIRK_8_4_5 111 +#define ARK437L2SA_DIRK_7_3_4 112 +#define ARK548L2SAb_DIRK_8_4_5 113 /* Utility #defines to ensure valid input IDs for DIRK tables */ #define MIN_DIRK_NUM 100 -#define MAX_DIRK_NUM 111 +#define MAX_DIRK_NUM 113 /* Accessor routine to load built-in DIRK table */ SUNDIALS_EXPORT ARKodeButcherTable ARKodeButcherTable_LoadDIRK(int imethod); diff --git a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_butcher_erk.h b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_butcher_erk.h index d4f4dee66..61a056549 100644 --- a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_butcher_erk.h +++ b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_butcher_erk.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -40,10 +40,12 @@ extern "C" { #define VERNER_8_5_6 10 #define FEHLBERG_13_7_8 11 #define KNOTH_WOLKE_3_3 12 +#define ARK437L2SA_ERK_7_3_4 13 +#define ARK548L2SAb_ERK_8_4_5 14 /* Utility #defines to ensure valid input IDs for ERK tables */ #define MIN_ERK_NUM 0 -#define MAX_ERK_NUM 12 +#define MAX_ERK_NUM 14 /* Accessor routine to load built-in ERK table */ SUNDIALS_EXPORT ARKodeButcherTable ARKodeButcherTable_LoadERK(int imethod); diff --git a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_erkstep.h b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_erkstep.h index f339d741c..2431b7be6 100644 --- a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_erkstep.h +++ b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_erkstep.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -72,6 +72,8 @@ SUNDIALS_EXPORT int ERKStepRootInit(void *arkode_mem, int nrtfn, /* Optional input functions -- must be called AFTER ERKStepCreate */ SUNDIALS_EXPORT int ERKStepSetDefaults(void* arkode_mem); SUNDIALS_EXPORT int ERKStepSetOrder(void *arkode_mem, int maxord); +SUNDIALS_EXPORT int ERKStepSetInterpolantType(void *arkode_mem, int itype); +SUNDIALS_EXPORT int ERKStepSetInterpolantDegree(void *arkode_mem, int degree); SUNDIALS_EXPORT int ERKStepSetDenseOrder(void *arkode_mem, int dord); SUNDIALS_EXPORT int ERKStepSetTable(void *arkode_mem, ARKodeButcherTable B); @@ -89,7 +91,7 @@ SUNDIALS_EXPORT int ERKStepSetFixedStepBounds(void *arkode_mem, SUNDIALS_EXPORT int ERKStepSetAdaptivityMethod(void *arkode_mem, int imethod, int idefault, int pq, - realtype *adapt_params); + realtype adapt_params[3]); SUNDIALS_EXPORT int ERKStepSetAdaptivityFn(void *arkode_mem, ARKAdaptFn hfun, void *h_data); @@ -104,6 +106,8 @@ SUNDIALS_EXPORT int ERKStepSetStabilityFn(void *arkode_mem, void *estab_data); SUNDIALS_EXPORT int ERKStepSetMaxErrTestFails(void *arkode_mem, int maxnef); +SUNDIALS_EXPORT int ERKStepSetConstraints(void *arkode_mem, + N_Vector constraints); SUNDIALS_EXPORT int ERKStepSetMaxNumSteps(void *arkode_mem, long int mxsteps); SUNDIALS_EXPORT int ERKStepSetMaxHnilWarns(void *arkode_mem, @@ -118,6 +122,8 @@ SUNDIALS_EXPORT int ERKStepSetStopTime(void *arkode_mem, realtype tstop); SUNDIALS_EXPORT int ERKStepSetFixedStep(void *arkode_mem, realtype hfixed); +SUNDIALS_EXPORT int ERKStepSetMaxNumConstrFails(void *arkode_mem, + int maxfails); SUNDIALS_EXPORT int ERKStepSetRootDirection(void *arkode_mem, int *rootdir); @@ -134,7 +140,9 @@ SUNDIALS_EXPORT int ERKStepSetDiagnostics(void *arkode_mem, FILE *diagfp); SUNDIALS_EXPORT int ERKStepSetPostprocessStepFn(void *arkode_mem, - ARKPostProcessStepFn ProcessStep); + ARKPostProcessFn ProcessStep); +SUNDIALS_EXPORT int ERKStepSetPostprocessStageFn(void *arkode_mem, + ARKPostProcessFn ProcessStage); /* Integrate the ODE over an interval in t */ @@ -182,6 +190,8 @@ SUNDIALS_EXPORT int ERKStepGetNumGEvals(void *arkode_mem, long int *ngevals); SUNDIALS_EXPORT int ERKStepGetRootInfo(void *arkode_mem, int *rootsfound); +SUNDIALS_EXPORT int ERKStepGetNumConstrFails(void *arkode_mem, + long int *nconstrfails); SUNDIALS_EXPORT char *ERKStepGetReturnFlagName(long int flag); SUNDIALS_EXPORT int ERKStepWriteParameters(void *arkode_mem, FILE *fp); diff --git a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_ls.h b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_ls.h index 8cbac5c1b..2f6113e92 100644 --- a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_ls.h +++ b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_ls.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ---------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -77,6 +77,11 @@ typedef int (*ARKLsJacTimesVecFn)(N_Vector v, N_Vector Jv, N_Vector fy, void *user_data, N_Vector tmp); +typedef int (*ARKLsLinSysFn)(realtype t, N_Vector y, N_Vector fy, SUNMatrix A, + SUNMatrix M, booleantype jok, booleantype *jcur, + realtype gamma, void *user_data, N_Vector tmp1, + N_Vector tmp2, N_Vector tmp3); + typedef int (*ARKLsMassTimesSetupFn)(realtype t, void *mtimes_data); diff --git a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_mristep.h b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_mristep.h index fde224291..a0aef2eeb 100644 --- a/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_mristep.h +++ b/deps/AMICI/ThirdParty/sundials/include/arkode/arkode_mristep.h @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -29,26 +29,38 @@ extern "C" { * MRIStep Constants * ----------------- */ -/* Default Butcher tables for each order */ +/* Inner stepper module identifiers */ +typedef enum { + MRISTEP_ARKSTEP +} MRISTEP_ID; -#define DEFAULT_MRI_STABLE_3 KNOTH_WOLKE_3_3 -#define DEFAULT_MRI_FTABLE_3 KNOTH_WOLKE_3_3 +/* Default slow (outer) Butcher tables for each order */ +#define DEFAULT_MRI_TABLE_3 KNOTH_WOLKE_3_3 +/* ------------------------------ + * User-Supplied Function Types + * ------------------------------ */ + +typedef int (*MRIStepPreInnerFn)(realtype t, N_Vector *f, int nvecs, + void *user_data); + +typedef int (*MRIStepPostInnerFn)(realtype t, N_Vector y, void *user_data); /* ------------------- * Exported Functions * ------------------- */ /* Create, Resize, and Reinitialization functions */ -SUNDIALS_EXPORT void* MRIStepCreate(ARKRhsFn fs, ARKRhsFn ff, - realtype t0, N_Vector y0); +SUNDIALS_EXPORT void* MRIStepCreate(ARKRhsFn fs, realtype t0, N_Vector y0, + MRISTEP_ID inner_step_id, + void* inner_step_mem); SUNDIALS_EXPORT int MRIStepResize(void *arkode_mem, N_Vector ynew, realtype t0, ARKVecResizeFn resize, void *resize_data); -SUNDIALS_EXPORT int MRIStepReInit(void* arkode_mem, ARKRhsFn fs, ARKRhsFn ff, - realtype t0, N_Vector y0); +SUNDIALS_EXPORT int MRIStepReInit(void* arkode_mem, ARKRhsFn fs, realtype t0, + N_Vector y0); /* Rootfinding initialization */ SUNDIALS_EXPORT int MRIStepRootInit(void *arkode_mem, int nrtfn, @@ -56,13 +68,13 @@ SUNDIALS_EXPORT int MRIStepRootInit(void *arkode_mem, int nrtfn, /* Optional input functions -- must be called AFTER MRIStepCreate */ SUNDIALS_EXPORT int MRIStepSetDefaults(void* arkode_mem); +SUNDIALS_EXPORT int MRIStepSetInterpolantType(void *arkode_mem, int itype); +SUNDIALS_EXPORT int MRIStepSetInterpolantDegree(void *arkode_mem, int degree); SUNDIALS_EXPORT int MRIStepSetDenseOrder(void *arkode_mem, int dord); -SUNDIALS_EXPORT int MRIStepSetTables(void *arkode_mem, - int q, - ARKodeButcherTable Bs, - ARKodeButcherTable Bf); -SUNDIALS_EXPORT int MRIStepSetTableNum(void *arkode_mem, int istable, - int iftable); +SUNDIALS_EXPORT int MRIStepSetTable(void *arkode_mem, int q, + ARKodeButcherTable B); +SUNDIALS_EXPORT int MRIStepSetTableNum(void *arkode_mem, + int itable); SUNDIALS_EXPORT int MRIStepSetMaxNumSteps(void *arkode_mem, long int mxsteps); SUNDIALS_EXPORT int MRIStepSetMaxHnilWarns(void *arkode_mem, @@ -70,8 +82,7 @@ SUNDIALS_EXPORT int MRIStepSetMaxHnilWarns(void *arkode_mem, SUNDIALS_EXPORT int MRIStepSetStopTime(void *arkode_mem, realtype tstop); SUNDIALS_EXPORT int MRIStepSetFixedStep(void *arkode_mem, - realtype hsfixed, - realtype hffixed); + realtype hsfixed); SUNDIALS_EXPORT int MRIStepSetRootDirection(void *arkode_mem, int *rootdir); SUNDIALS_EXPORT int MRIStepSetNoInactiveRootWarn(void *arkode_mem); @@ -85,7 +96,13 @@ SUNDIALS_EXPORT int MRIStepSetUserData(void *arkode_mem, SUNDIALS_EXPORT int MRIStepSetDiagnostics(void *arkode_mem, FILE *diagfp); SUNDIALS_EXPORT int MRIStepSetPostprocessStepFn(void *arkode_mem, - ARKPostProcessStepFn ProcessStep); + ARKPostProcessFn ProcessStep); +SUNDIALS_EXPORT int MRIStepSetPostprocessStageFn(void *arkode_mem, + ARKPostProcessFn ProcessStage); +SUNDIALS_EXPORT int MRIStepSetPreInnerFn(void *arkode_mem, + MRIStepPreInnerFn prefn); +SUNDIALS_EXPORT int MRIStepSetPostInnerFn(void *arkode_mem, + MRIStepPostInnerFn postfn); /* Integrate the ODE over an interval in t */ @@ -99,20 +116,20 @@ SUNDIALS_EXPORT int MRIStepGetDky(void *arkode_mem, realtype t, /* Optional output functions */ SUNDIALS_EXPORT int MRIStepGetNumRhsEvals(void *arkode_mem, - long int *nfs_evals, - long int *nff_evals); + long int *nfs_evals); SUNDIALS_EXPORT int MRIStepGetCurrentButcherTables(void *arkode_mem, - ARKodeButcherTable *Bs, - ARKodeButcherTable *Bf); + ARKodeButcherTable *B); SUNDIALS_EXPORT int MRIStepGetWorkSpace(void *arkode_mem, long int *lenrw, long int *leniw); SUNDIALS_EXPORT int MRIStepGetNumSteps(void *arkode_mem, - long int *nssteps, long int *nfsteps); + long int *nssteps); SUNDIALS_EXPORT int MRIStepGetLastStep(void *arkode_mem, realtype *hlast); SUNDIALS_EXPORT int MRIStepGetCurrentTime(void *arkode_mem, realtype *tcur); +SUNDIALS_EXPORT int MRIStepGetCurrentState(void *arkode_mem, + N_Vector *ycur); SUNDIALS_EXPORT int MRIStepGetNumGEvals(void *arkode_mem, long int *ngevals); SUNDIALS_EXPORT int MRIStepGetRootInfo(void *arkode_mem, diff --git a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode.h b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode.h index 48f7c824e..77d32d8e7 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode.h @@ -3,7 +3,7 @@ * and Dan Shumaker @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -64,6 +64,7 @@ extern "C" { #define CV_NLS_INIT_FAIL -13 #define CV_NLS_SETUP_FAIL -14 #define CV_CONSTR_FAIL -15 +#define CV_NLS_FAIL -16 #define CV_MEM_FAIL -20 #define CV_MEM_NULL -21 @@ -75,6 +76,9 @@ extern "C" { #define CV_TOO_CLOSE -27 #define CV_VECTOROP_ERR -28 +#define CV_UNRECOGNIZED_ERR -99 + + /* ------------------------------ * User-Supplied Function Types * ------------------------------ */ @@ -157,11 +161,13 @@ SUNDIALS_EXPORT int CVodeGetNumErrTestFails(void *cvode_mem, long int *netfails); SUNDIALS_EXPORT int CVodeGetLastOrder(void *cvode_mem, int *qlast); SUNDIALS_EXPORT int CVodeGetCurrentOrder(void *cvode_mem, int *qcur); +SUNDIALS_EXPORT int CVodeGetCurrentGamma(void *cvode_mem, realtype *gamma); SUNDIALS_EXPORT int CVodeGetNumStabLimOrderReds(void *cvode_mem, long int *nslred); SUNDIALS_EXPORT int CVodeGetActualInitStep(void *cvode_mem, realtype *hinused); SUNDIALS_EXPORT int CVodeGetLastStep(void *cvode_mem, realtype *hlast); SUNDIALS_EXPORT int CVodeGetCurrentStep(void *cvode_mem, realtype *hcur); +SUNDIALS_EXPORT int CVodeGetCurrentState(void *cvode_mem, N_Vector *y); SUNDIALS_EXPORT int CVodeGetCurrentTime(void *cvode_mem, realtype *tcur); SUNDIALS_EXPORT int CVodeGetTolScaleFactor(void *cvode_mem, realtype *tolsfac); SUNDIALS_EXPORT int CVodeGetErrWeights(void *cvode_mem, N_Vector eweight); diff --git a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_bandpre.h b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_bandpre.h index a75b0ab46..f732fb475 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_bandpre.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_bandpre.h @@ -3,7 +3,7 @@ * Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_bbdpre.h b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_bbdpre.h index 7d606184b..94ecb1334 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_bbdpre.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_bbdpre.h @@ -4,7 +4,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_diag.h b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_diag.h index 2575e84e0..4a5be54e2 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_diag.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_diag.h @@ -3,7 +3,7 @@ * Radu Serban @ LLNL * --------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_direct.h b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_direct.h index 95aa8e127..f0dcc0d81 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_direct.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_direct.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -36,21 +36,21 @@ typedef CVLsJacFn CVDlsJacFn; Exported Functions (wrappers for equivalent routines in cvode_ls.h) ===================================================================*/ -int CVDlsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, - SUNMatrix A); +SUNDIALS_EXPORT int CVDlsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, + SUNMatrix A); -int CVDlsSetJacFn(void *cvode_mem, CVDlsJacFn jac); +SUNDIALS_EXPORT int CVDlsSetJacFn(void *cvode_mem, CVDlsJacFn jac); -int CVDlsGetWorkSpace(void *cvode_mem, long int *lenrwLS, - long int *leniwLS); +SUNDIALS_EXPORT int CVDlsGetWorkSpace(void *cvode_mem, long int *lenrwLS, + long int *leniwLS); -int CVDlsGetNumJacEvals(void *cvode_mem, long int *njevals); +SUNDIALS_EXPORT int CVDlsGetNumJacEvals(void *cvode_mem, long int *njevals); -int CVDlsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); +SUNDIALS_EXPORT int CVDlsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); -int CVDlsGetLastFlag(void *cvode_mem, long int *flag); +SUNDIALS_EXPORT int CVDlsGetLastFlag(void *cvode_mem, long int *flag); -char *CVDlsGetReturnFlagName(long int flag); +SUNDIALS_EXPORT char *CVDlsGetReturnFlagName(long int flag); #ifdef __cplusplus diff --git a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_ls.h b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_ls.h index 94d1d786a..31e51019e 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_ls.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_ls.h @@ -4,7 +4,7 @@ * Radu Serban @ LLNL * ---------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -69,6 +69,10 @@ typedef int (*CVLsJacTimesVecFn)(N_Vector v, N_Vector Jv, realtype t, N_Vector y, N_Vector fy, void *user_data, N_Vector tmp); +typedef int (*CVLsLinSysFn)(realtype t, N_Vector y, N_Vector fy, SUNMatrix A, + booleantype jok, booleantype *jcur, realtype gamma, + void *user_data, N_Vector tmp1, N_Vector tmp2, + N_Vector tmp3); /*================================================================= CVLS Exported functions @@ -86,6 +90,8 @@ SUNDIALS_EXPORT int CVodeSetLinearSolver(void *cvode_mem, SUNDIALS_EXPORT int CVodeSetJacFn(void *cvode_mem, CVLsJacFn jac); SUNDIALS_EXPORT int CVodeSetMaxStepsBetweenJac(void *cvode_mem, long int msbj); +SUNDIALS_EXPORT int CVodeSetLinearSolutionScaling(void *cvode_mem, + booleantype onoff); SUNDIALS_EXPORT int CVodeSetEpsLin(void *cvode_mem, realtype eplifac); SUNDIALS_EXPORT int CVodeSetPreconditioner(void *cvode_mem, CVLsPrecSetupFn pset, @@ -93,6 +99,7 @@ SUNDIALS_EXPORT int CVodeSetPreconditioner(void *cvode_mem, SUNDIALS_EXPORT int CVodeSetJacTimes(void *cvode_mem, CVLsJacTimesSetupFn jtsetup, CVLsJacTimesVecFn jtimes); +SUNDIALS_EXPORT int CVodeSetLinSysFn(void *cvode_mem, CVLsLinSysFn linsys); /*----------------------------------------------------------------- Optional outputs from the CVLS linear solver interface diff --git a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_spils.h b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_spils.h index 0d4e044a7..7f10fcf0c 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_spils.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvode/cvode_spils.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -39,36 +39,36 @@ typedef CVLsJacTimesVecFn CVSpilsJacTimesVecFn; Exported Functions (wrappers for equivalent routines in cvode_ls.h) ====================================================================*/ -int CVSpilsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS); +SUNDIALS_EXPORT int CVSpilsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS); -int CVSpilsSetEpsLin(void *cvode_mem, realtype eplifac); +SUNDIALS_EXPORT int CVSpilsSetEpsLin(void *cvode_mem, realtype eplifac); -int CVSpilsSetPreconditioner(void *cvode_mem, CVSpilsPrecSetupFn pset, +SUNDIALS_EXPORT int CVSpilsSetPreconditioner(void *cvode_mem, CVSpilsPrecSetupFn pset, CVSpilsPrecSolveFn psolve); -int CVSpilsSetJacTimes(void *cvode_mem, CVSpilsJacTimesSetupFn jtsetup, +SUNDIALS_EXPORT int CVSpilsSetJacTimes(void *cvode_mem, CVSpilsJacTimesSetupFn jtsetup, CVSpilsJacTimesVecFn jtimes); -int CVSpilsGetWorkSpace(void *cvode_mem, long int *lenrwLS, +SUNDIALS_EXPORT int CVSpilsGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS); -int CVSpilsGetNumPrecEvals(void *cvode_mem, long int *npevals); +SUNDIALS_EXPORT int CVSpilsGetNumPrecEvals(void *cvode_mem, long int *npevals); -int CVSpilsGetNumPrecSolves(void *cvode_mem, long int *npsolves); +SUNDIALS_EXPORT int CVSpilsGetNumPrecSolves(void *cvode_mem, long int *npsolves); -int CVSpilsGetNumLinIters(void *cvode_mem, long int *nliters); +SUNDIALS_EXPORT int CVSpilsGetNumLinIters(void *cvode_mem, long int *nliters); -int CVSpilsGetNumConvFails(void *cvode_mem, long int *nlcfails); +SUNDIALS_EXPORT int CVSpilsGetNumConvFails(void *cvode_mem, long int *nlcfails); -int CVSpilsGetNumJTSetupEvals(void *cvode_mem, long int *njtsetups); +SUNDIALS_EXPORT int CVSpilsGetNumJTSetupEvals(void *cvode_mem, long int *njtsetups); -int CVSpilsGetNumJtimesEvals(void *cvode_mem, long int *njvevals); +SUNDIALS_EXPORT int CVSpilsGetNumJtimesEvals(void *cvode_mem, long int *njvevals); -int CVSpilsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); +SUNDIALS_EXPORT int CVSpilsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); -int CVSpilsGetLastFlag(void *cvode_mem, long int *flag); +SUNDIALS_EXPORT int CVSpilsGetLastFlag(void *cvode_mem, long int *flag); -char *CVSpilsGetReturnFlagName(long int flag); +SUNDIALS_EXPORT char *CVSpilsGetReturnFlagName(long int flag); #ifdef __cplusplus diff --git a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes.h b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes.h index 194fb0808..29e294b7b 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes.h @@ -2,7 +2,7 @@ * Programmer(s): Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -75,6 +75,7 @@ extern "C" { #define CV_NLS_INIT_FAIL -13 #define CV_NLS_SETUP_FAIL -14 #define CV_CONSTR_FAIL -15 +#define CV_NLS_FAIL -16 #define CV_MEM_FAIL -20 #define CV_MEM_NULL -21 @@ -106,6 +107,9 @@ extern "C" { #define CV_REPTD_QSRHSFUNC_ERR -53 #define CV_UNREC_QSRHSFUNC_ERR -54 + +#define CV_UNRECOGNIZED_ERR -99 + /* adjoint return values */ #define CV_NO_ADJ -101 @@ -233,11 +237,15 @@ SUNDIALS_EXPORT int CVodeGetNumErrTestFails(void *cvode_mem, long int *netfails); SUNDIALS_EXPORT int CVodeGetLastOrder(void *cvode_mem, int *qlast); SUNDIALS_EXPORT int CVodeGetCurrentOrder(void *cvode_mem, int *qcur); +SUNDIALS_EXPORT int CVodeGetCurrentGamma(void *cvode_mem, realtype *gamma); SUNDIALS_EXPORT int CVodeGetNumStabLimOrderReds(void *cvode_mem, long int *nslred); SUNDIALS_EXPORT int CVodeGetActualInitStep(void *cvode_mem, realtype *hinused); SUNDIALS_EXPORT int CVodeGetLastStep(void *cvode_mem, realtype *hlast); SUNDIALS_EXPORT int CVodeGetCurrentStep(void *cvode_mem, realtype *hcur); +SUNDIALS_EXPORT int CVodeGetCurrentState(void *cvode_mem, N_Vector *y); +SUNDIALS_EXPORT int CVodeGetCurrentStateSens(void *cvode_mem, N_Vector **yS); +SUNDIALS_EXPORT int CVodeGetCurrentSensSolveIndex(void *cvode_mem, int *index); SUNDIALS_EXPORT int CVodeGetCurrentTime(void *cvode_mem, realtype *tcur); SUNDIALS_EXPORT int CVodeGetTolScaleFactor(void *cvode_mem, realtype *tolsfac); SUNDIALS_EXPORT int CVodeGetErrWeights(void *cvode_mem, N_Vector eweight); diff --git a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_bandpre.h b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_bandpre.h index aec8709a2..1b89979ae 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_bandpre.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_bandpre.h @@ -3,7 +3,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_bbdpre.h b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_bbdpre.h index 13dea8db4..6532b5c85 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_bbdpre.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_bbdpre.h @@ -3,7 +3,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_diag.h b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_diag.h index b98e3416b..8a628eca7 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_diag.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_diag.h @@ -2,7 +2,7 @@ * Programmer(s): Radu Serban @ LLNL * --------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_direct.h b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_direct.h index cef57b0c4..be79c107a 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_direct.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_direct.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -38,28 +38,28 @@ typedef CVLsJacFnBS CVDlsJacFnBS; Exported Functions (wrappers for equivalent routines in cvodes_ls.h) ====================================================================*/ -int CVDlsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, - SUNMatrix A); +SUNDIALS_EXPORT int CVDlsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, + SUNMatrix A); -int CVDlsSetJacFn(void *cvode_mem, CVDlsJacFn jac); +SUNDIALS_EXPORT int CVDlsSetJacFn(void *cvode_mem, CVDlsJacFn jac); -int CVDlsGetWorkSpace(void *cvode_mem, long int *lenrwLS, - long int *leniwLS); +SUNDIALS_EXPORT int CVDlsGetWorkSpace(void *cvode_mem, long int *lenrwLS, + long int *leniwLS); -int CVDlsGetNumJacEvals(void *cvode_mem, long int *njevals); +SUNDIALS_EXPORT int CVDlsGetNumJacEvals(void *cvode_mem, long int *njevals); -int CVDlsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); +SUNDIALS_EXPORT int CVDlsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); -int CVDlsGetLastFlag(void *cvode_mem, long int *flag); +SUNDIALS_EXPORT int CVDlsGetLastFlag(void *cvode_mem, long int *flag); -char *CVDlsGetReturnFlagName(long int flag); +SUNDIALS_EXPORT char *CVDlsGetReturnFlagName(long int flag); -int CVDlsSetLinearSolverB(void *cvode_mem, int which, - SUNLinearSolver LS, SUNMatrix A); +SUNDIALS_EXPORT int CVDlsSetLinearSolverB(void *cvode_mem, int which, + SUNLinearSolver LS, SUNMatrix A); -int CVDlsSetJacFnB(void *cvode_mem, int which, CVDlsJacFnB jacB); +SUNDIALS_EXPORT int CVDlsSetJacFnB(void *cvode_mem, int which, CVDlsJacFnB jacB); -int CVDlsSetJacFnBS(void *cvode_mem, int which, CVDlsJacFnBS jacBS); +SUNDIALS_EXPORT int CVDlsSetJacFnBS(void *cvode_mem, int which, CVDlsJacFnBS jacBS); #ifdef __cplusplus diff --git a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_ls.h b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_ls.h index fb8e9f0f8..1e2ac9802 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_ls.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_ls.h @@ -3,7 +3,7 @@ * Radu Serban @ LLNL * ---------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -77,6 +77,10 @@ typedef int (*CVLsJacTimesVecFn)(N_Vector v, N_Vector Jv, realtype t, N_Vector y, N_Vector fy, void *user_data, N_Vector tmp); +typedef int (*CVLsLinSysFn)(realtype t, N_Vector y, N_Vector fy, SUNMatrix A, + booleantype jok, booleantype *jcur, realtype gamma, + void *user_data, N_Vector tmp1, N_Vector tmp2, + N_Vector tmp3); /*================================================================= CVLS Exported functions @@ -94,6 +98,8 @@ SUNDIALS_EXPORT int CVodeSetLinearSolver(void *cvode_mem, SUNDIALS_EXPORT int CVodeSetJacFn(void *cvode_mem, CVLsJacFn jac); SUNDIALS_EXPORT int CVodeSetMaxStepsBetweenJac(void *cvode_mem, long int msbj); +SUNDIALS_EXPORT int CVodeSetLinearSolutionScaling(void *cvode_mem, + booleantype onoff); SUNDIALS_EXPORT int CVodeSetEpsLin(void *cvode_mem, realtype eplifac); SUNDIALS_EXPORT int CVodeSetPreconditioner(void *cvode_mem, CVLsPrecSetupFn pset, @@ -101,6 +107,7 @@ SUNDIALS_EXPORT int CVodeSetPreconditioner(void *cvode_mem, SUNDIALS_EXPORT int CVodeSetJacTimes(void *cvode_mem, CVLsJacTimesSetupFn jtsetup, CVLsJacTimesVecFn jtimes); +SUNDIALS_EXPORT int CVodeSetLinSysFn(void *cvode_mem, CVLsLinSysFn linsys); /*----------------------------------------------------------------- Optional outputs from the CVLS linear solver interface @@ -187,6 +194,16 @@ typedef int (*CVLsJacTimesVecFnBS)(N_Vector vB, N_Vector JvB, N_Vector yB, N_Vector fyB, void *jac_dataB, N_Vector tmpB); +typedef int (*CVLsLinSysFnB)(realtype t, N_Vector y, N_Vector yB, N_Vector fyB, + SUNMatrix AB, booleantype jokB, booleantype *jcurB, + realtype gammaB, void *user_dataB, N_Vector tmp1B, + N_Vector tmp2B, N_Vector tmp3B); + +typedef int (*CVLsLinSysFnBS)(realtype t, N_Vector y, N_Vector* yS, + N_Vector yB, N_Vector fyB, SUNMatrix AB, + booleantype jokB, booleantype *jcurB, + realtype gammaB, void *user_dataB, N_Vector tmp1B, + N_Vector tmp2B, N_Vector tmp3B); /*================================================================= CVLS Exported functions @@ -212,6 +229,9 @@ SUNDIALS_EXPORT int CVodeSetJacFnBS(void *cvode_mem, int which, SUNDIALS_EXPORT int CVodeSetEpsLinB(void *cvode_mem, int which, realtype eplifacB); +SUNDIALS_EXPORT int CVodeSetLinearSolutionScalingB(void *cvode_mem, int which, + booleantype onoffB); + SUNDIALS_EXPORT int CVodeSetPreconditionerB(void *cvode_mem, int which, CVLsPrecSetupFnB psetB, CVLsPrecSolveFnB psolveB); @@ -226,6 +246,11 @@ SUNDIALS_EXPORT int CVodeSetJacTimesBS(void *cvode_mem, int which, CVLsJacTimesSetupFnBS jtsetupBS, CVLsJacTimesVecFnBS jtimesBS); +SUNDIALS_EXPORT int CVodeSetLinSysFnB(void *cvode_mem, int which, + CVLsLinSysFnB linsys); +SUNDIALS_EXPORT int CVodeSetLinSysFnBS(void *cvode_mem, int which, + CVLsLinSysFnBS linsys); + #ifdef __cplusplus } diff --git a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_spils.h b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_spils.h index da3bc7123..a509dcf84 100644 --- a/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_spils.h +++ b/deps/AMICI/ThirdParty/sundials/include/cvodes/cvodes_spils.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -47,55 +47,55 @@ typedef CVLsJacTimesVecFnBS CVSpilsJacTimesVecFnBS; Exported Functions (wrappers for equivalent routines in cvodes_ls.h) ====================================================================*/ -int CVSpilsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS); +SUNDIALS_EXPORT int CVSpilsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS); -int CVSpilsSetEpsLin(void *cvode_mem, realtype eplifac); +SUNDIALS_EXPORT int CVSpilsSetEpsLin(void *cvode_mem, realtype eplifac); -int CVSpilsSetPreconditioner(void *cvode_mem, CVSpilsPrecSetupFn pset, +SUNDIALS_EXPORT int CVSpilsSetPreconditioner(void *cvode_mem, CVSpilsPrecSetupFn pset, CVSpilsPrecSolveFn psolve); -int CVSpilsSetJacTimes(void *cvode_mem, CVSpilsJacTimesSetupFn jtsetup, +SUNDIALS_EXPORT int CVSpilsSetJacTimes(void *cvode_mem, CVSpilsJacTimesSetupFn jtsetup, CVSpilsJacTimesVecFn jtimes); -int CVSpilsGetWorkSpace(void *cvode_mem, long int *lenrwLS, +SUNDIALS_EXPORT int CVSpilsGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS); -int CVSpilsGetNumPrecEvals(void *cvode_mem, long int *npevals); +SUNDIALS_EXPORT int CVSpilsGetNumPrecEvals(void *cvode_mem, long int *npevals); -int CVSpilsGetNumPrecSolves(void *cvode_mem, long int *npsolves); +SUNDIALS_EXPORT int CVSpilsGetNumPrecSolves(void *cvode_mem, long int *npsolves); -int CVSpilsGetNumLinIters(void *cvode_mem, long int *nliters); +SUNDIALS_EXPORT int CVSpilsGetNumLinIters(void *cvode_mem, long int *nliters); -int CVSpilsGetNumConvFails(void *cvode_mem, long int *nlcfails); +SUNDIALS_EXPORT int CVSpilsGetNumConvFails(void *cvode_mem, long int *nlcfails); -int CVSpilsGetNumJTSetupEvals(void *cvode_mem, long int *njtsetups); +SUNDIALS_EXPORT int CVSpilsGetNumJTSetupEvals(void *cvode_mem, long int *njtsetups); -int CVSpilsGetNumJtimesEvals(void *cvode_mem, long int *njvevals); +SUNDIALS_EXPORT int CVSpilsGetNumJtimesEvals(void *cvode_mem, long int *njvevals); -int CVSpilsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); +SUNDIALS_EXPORT int CVSpilsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); -int CVSpilsGetLastFlag(void *cvode_mem, long int *flag); +SUNDIALS_EXPORT int CVSpilsGetLastFlag(void *cvode_mem, long int *flag); -char *CVSpilsGetReturnFlagName(long int flag); +SUNDIALS_EXPORT char *CVSpilsGetReturnFlagName(long int flag); -int CVSpilsSetLinearSolverB(void *cvode_mem, int which, +SUNDIALS_EXPORT int CVSpilsSetLinearSolverB(void *cvode_mem, int which, SUNLinearSolver LS); -int CVSpilsSetEpsLinB(void *cvode_mem, int which, realtype eplifacB); +SUNDIALS_EXPORT int CVSpilsSetEpsLinB(void *cvode_mem, int which, realtype eplifacB); -int CVSpilsSetPreconditionerB(void *cvode_mem, int which, +SUNDIALS_EXPORT int CVSpilsSetPreconditionerB(void *cvode_mem, int which, CVSpilsPrecSetupFnB psetB, CVSpilsPrecSolveFnB psolveB); -int CVSpilsSetPreconditionerBS(void *cvode_mem, int which, +SUNDIALS_EXPORT int CVSpilsSetPreconditionerBS(void *cvode_mem, int which, CVSpilsPrecSetupFnBS psetBS, CVSpilsPrecSolveFnBS psolveBS); -int CVSpilsSetJacTimesB(void *cvode_mem, int which, +SUNDIALS_EXPORT int CVSpilsSetJacTimesB(void *cvode_mem, int which, CVSpilsJacTimesSetupFnB jtsetupB, CVSpilsJacTimesVecFnB jtimesB); -int CVSpilsSetJacTimesBS(void *cvode_mem, int which, +SUNDIALS_EXPORT int CVSpilsSetJacTimesBS(void *cvode_mem, int which, CVSpilsJacTimesSetupFnBS jtsetupBS, CVSpilsJacTimesVecFnBS jtimesBS); diff --git a/deps/AMICI/ThirdParty/sundials/include/ida/ida.h b/deps/AMICI/ThirdParty/sundials/include/ida/ida.h index bdfa9efc1..e34054369 100644 --- a/deps/AMICI/ThirdParty/sundials/include/ida/ida.h +++ b/deps/AMICI/ThirdParty/sundials/include/ida/ida.h @@ -3,7 +3,7 @@ * and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -65,6 +65,7 @@ extern "C" { #define IDA_NO_RECOVERY -14 #define IDA_NLS_INIT_FAIL -15 #define IDA_NLS_SETUP_FAIL -16 +#define IDA_NLS_FAIL -17 #define IDA_MEM_NULL -20 #define IDA_MEM_FAIL -21 @@ -158,6 +159,10 @@ SUNDIALS_EXPORT int IDASetNoInactiveRootWarn(void *ida_mem); SUNDIALS_EXPORT int IDASolve(void *ida_mem, realtype tout, realtype *tret, N_Vector yret, N_Vector ypret, int itask); +/* Utility functions to update/compute y and yp based on ycor */ +SUNDIALS_EXPORT int IDAComputeY(void *ida_mem, N_Vector ycor, N_Vector y); +SUNDIALS_EXPORT int IDAComputeYp(void *ida_mem, N_Vector ycor, N_Vector yp); + /* Dense output function */ SUNDIALS_EXPORT int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky); @@ -173,6 +178,9 @@ SUNDIALS_EXPORT int IDAGetConsistentIC(void *ida_mem, N_Vector yy0_mod, N_Vector yp0_mod); SUNDIALS_EXPORT int IDAGetLastOrder(void *ida_mem, int *klast); SUNDIALS_EXPORT int IDAGetCurrentOrder(void *ida_mem, int *kcur); +SUNDIALS_EXPORT int IDAGetCurrentCj(void *ida_mem, realtype *cj); +SUNDIALS_EXPORT int IDAGetCurrentY(void *ida_mem, N_Vector *ycur); +SUNDIALS_EXPORT int IDAGetCurrentYp(void *ida_mem, N_Vector *ypcur); SUNDIALS_EXPORT int IDAGetActualInitStep(void *ida_mem, realtype *hinused); SUNDIALS_EXPORT int IDAGetLastStep(void *ida_mem, realtype *hlast); SUNDIALS_EXPORT int IDAGetCurrentStep(void *ida_mem, realtype *hcur); diff --git a/deps/AMICI/ThirdParty/sundials/include/ida/ida_bbdpre.h b/deps/AMICI/ThirdParty/sundials/include/ida/ida_bbdpre.h index 0c99d1c02..e59a07d1f 100644 --- a/deps/AMICI/ThirdParty/sundials/include/ida/ida_bbdpre.h +++ b/deps/AMICI/ThirdParty/sundials/include/ida/ida_bbdpre.h @@ -3,7 +3,7 @@ * Alan C. Hindmarsh, Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/ida/ida_direct.h b/deps/AMICI/ThirdParty/sundials/include/ida/ida_direct.h index 25455836a..db2880eca 100644 --- a/deps/AMICI/ThirdParty/sundials/include/ida/ida_direct.h +++ b/deps/AMICI/ThirdParty/sundials/include/ida/ida_direct.h @@ -3,7 +3,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -37,21 +37,21 @@ typedef IDALsJacFn IDADlsJacFn; Exported Functions (wrappers for equivalent routines in ida_ls.h) ===================================================================*/ -int IDADlsSetLinearSolver(void *ida_mem, SUNLinearSolver LS, - SUNMatrix A); +SUNDIALS_EXPORT int IDADlsSetLinearSolver(void *ida_mem, SUNLinearSolver LS, + SUNMatrix A); -int IDADlsSetJacFn(void *ida_mem, IDADlsJacFn jac); +SUNDIALS_EXPORT int IDADlsSetJacFn(void *ida_mem, IDADlsJacFn jac); -int IDADlsGetWorkSpace(void *ida_mem, long int *lenrwLS, - long int *leniwLS); +SUNDIALS_EXPORT int IDADlsGetWorkSpace(void *ida_mem, long int *lenrwLS, + long int *leniwLS); -int IDADlsGetNumJacEvals(void *ida_mem, long int *njevals); +SUNDIALS_EXPORT int IDADlsGetNumJacEvals(void *ida_mem, long int *njevals); -int IDADlsGetNumResEvals(void *ida_mem, long int *nrevalsLS); +SUNDIALS_EXPORT int IDADlsGetNumResEvals(void *ida_mem, long int *nrevalsLS); -int IDADlsGetLastFlag(void *ida_mem, long int *flag); +SUNDIALS_EXPORT int IDADlsGetLastFlag(void *ida_mem, long int *flag); -char *IDADlsGetReturnFlagName(long int flag); +SUNDIALS_EXPORT char *IDADlsGetReturnFlagName(long int flag); #ifdef __cplusplus diff --git a/deps/AMICI/ThirdParty/sundials/include/ida/ida_ls.h b/deps/AMICI/ThirdParty/sundials/include/ida/ida_ls.h index 3255b2d7b..5630533d5 100644 --- a/deps/AMICI/ThirdParty/sundials/include/ida/ida_ls.h +++ b/deps/AMICI/ThirdParty/sundials/include/ida/ida_ls.h @@ -4,7 +4,7 @@ * Aaron Collier @ LLNL * ---------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -97,6 +97,8 @@ SUNDIALS_EXPORT int IDASetJacTimes(void *ida_mem, IDALsJacTimesSetupFn jtsetup, IDALsJacTimesVecFn jtimes); SUNDIALS_EXPORT int IDASetEpsLin(void *ida_mem, realtype eplifac); +SUNDIALS_EXPORT int IDASetLinearSolutionScaling(void *ida_mem, + booleantype onoff); SUNDIALS_EXPORT int IDASetIncrementFactor(void *ida_mem, realtype dqincfac); diff --git a/deps/AMICI/ThirdParty/sundials/include/ida/ida_spils.h b/deps/AMICI/ThirdParty/sundials/include/ida/ida_spils.h index 2ec98da78..68a2c1032 100644 --- a/deps/AMICI/ThirdParty/sundials/include/ida/ida_spils.h +++ b/deps/AMICI/ThirdParty/sundials/include/ida/ida_spils.h @@ -3,7 +3,7 @@ * Alan Hindmarsh, Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -40,37 +40,37 @@ typedef IDALsJacTimesVecFn IDASpilsJacTimesVecFn; Exported Functions (wrappers for equivalent routines in ida_ls.h) ====================================================================*/ -int IDASpilsSetLinearSolver(void *ida_mem, SUNLinearSolver LS); +SUNDIALS_EXPORT int IDASpilsSetLinearSolver(void *ida_mem, SUNLinearSolver LS); -int IDASpilsSetPreconditioner(void *ida_mem, IDASpilsPrecSetupFn pset, - IDASpilsPrecSolveFn psolve); +SUNDIALS_EXPORT int IDASpilsSetPreconditioner(void *ida_mem, IDASpilsPrecSetupFn pset, + IDASpilsPrecSolveFn psolve); -int IDASpilsSetJacTimes(void *ida_mem, IDASpilsJacTimesSetupFn jtsetup, - IDASpilsJacTimesVecFn jtimes); +SUNDIALS_EXPORT int IDASpilsSetJacTimes(void *ida_mem, IDASpilsJacTimesSetupFn jtsetup, + IDASpilsJacTimesVecFn jtimes); -int IDASpilsSetEpsLin(void *ida_mem, realtype eplifac); +SUNDIALS_EXPORT int IDASpilsSetEpsLin(void *ida_mem, realtype eplifac); -int IDASpilsSetIncrementFactor(void *ida_mem, realtype dqincfac); +SUNDIALS_EXPORT int IDASpilsSetIncrementFactor(void *ida_mem, realtype dqincfac); -int IDASpilsGetWorkSpace(void *ida_mem, long int *lenrwLS, long int *leniwLS); +SUNDIALS_EXPORT int IDASpilsGetWorkSpace(void *ida_mem, long int *lenrwLS, long int *leniwLS); -int IDASpilsGetNumPrecEvals(void *ida_mem, long int *npevals); +SUNDIALS_EXPORT int IDASpilsGetNumPrecEvals(void *ida_mem, long int *npevals); -int IDASpilsGetNumPrecSolves(void *ida_mem, long int *npsolves); +SUNDIALS_EXPORT int IDASpilsGetNumPrecSolves(void *ida_mem, long int *npsolves); -int IDASpilsGetNumLinIters(void *ida_mem, long int *nliters); +SUNDIALS_EXPORT int IDASpilsGetNumLinIters(void *ida_mem, long int *nliters); -int IDASpilsGetNumConvFails(void *ida_mem, long int *nlcfails); +SUNDIALS_EXPORT int IDASpilsGetNumConvFails(void *ida_mem, long int *nlcfails); -int IDASpilsGetNumJTSetupEvals(void *ida_mem, long int *njtsetups); +SUNDIALS_EXPORT int IDASpilsGetNumJTSetupEvals(void *ida_mem, long int *njtsetups); -int IDASpilsGetNumJtimesEvals(void *ida_mem, long int *njvevals); +SUNDIALS_EXPORT int IDASpilsGetNumJtimesEvals(void *ida_mem, long int *njvevals); -int IDASpilsGetNumResEvals(void *ida_mem, long int *nrevalsLS); +SUNDIALS_EXPORT int IDASpilsGetNumResEvals(void *ida_mem, long int *nrevalsLS); -int IDASpilsGetLastFlag(void *ida_mem, long int *flag); +SUNDIALS_EXPORT int IDASpilsGetLastFlag(void *ida_mem, long int *flag); -char *IDASpilsGetReturnFlagName(long int flag); +SUNDIALS_EXPORT char *IDASpilsGetReturnFlagName(long int flag); #ifdef __cplusplus diff --git a/deps/AMICI/ThirdParty/sundials/include/idas/idas.h b/deps/AMICI/ThirdParty/sundials/include/idas/idas.h index af33c8d61..a0c59809c 100644 --- a/deps/AMICI/ThirdParty/sundials/include/idas/idas.h +++ b/deps/AMICI/ThirdParty/sundials/include/idas/idas.h @@ -2,7 +2,7 @@ * Programmer(s): Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -76,6 +76,7 @@ extern "C" { #define IDA_NO_RECOVERY -14 #define IDA_NLS_INIT_FAIL -15 #define IDA_NLS_SETUP_FAIL -16 +#define IDA_NLS_FAIL -17 #define IDA_MEM_NULL -20 #define IDA_MEM_FAIL -21 @@ -232,6 +233,12 @@ SUNDIALS_EXPORT int IDASetNoInactiveRootWarn(void *ida_mem); SUNDIALS_EXPORT int IDASolve(void *ida_mem, realtype tout, realtype *tret, N_Vector yret, N_Vector ypret, int itask); +/* Utility functions to update/compute y and yp based on ycor */ +SUNDIALS_EXPORT int IDAComputeY(void *ida_mem, N_Vector ycor, N_Vector y); +SUNDIALS_EXPORT int IDAComputeYp(void *ida_mem, N_Vector ycor, N_Vector yp); +SUNDIALS_EXPORT int IDAComputeYSens(void *ida_mem, N_Vector *ycor, N_Vector *yyS); +SUNDIALS_EXPORT int IDAComputeYpSens(void *ida_mem, N_Vector *ycor, N_Vector *ypS); + /* Dense output function */ SUNDIALS_EXPORT int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky); @@ -247,6 +254,11 @@ SUNDIALS_EXPORT int IDAGetConsistentIC(void *ida_mem, N_Vector yy0_mod, N_Vector yp0_mod); SUNDIALS_EXPORT int IDAGetLastOrder(void *ida_mem, int *klast); SUNDIALS_EXPORT int IDAGetCurrentOrder(void *ida_mem, int *kcur); +SUNDIALS_EXPORT int IDAGetCurrentCj(void *ida_mem, realtype *cj); +SUNDIALS_EXPORT int IDAGetCurrentY(void *ida_mem, N_Vector *ycur); +SUNDIALS_EXPORT int IDAGetCurrentYSens(void *ida_mem, N_Vector **yS); +SUNDIALS_EXPORT int IDAGetCurrentYp(void *ida_mem, N_Vector *ypcur); +SUNDIALS_EXPORT int IDAGetCurrentYpSens(void *ida_mem, N_Vector **ypS); SUNDIALS_EXPORT int IDAGetActualInitStep(void *ida_mem, realtype *hinused); SUNDIALS_EXPORT int IDAGetLastStep(void *ida_mem, realtype *hlast); SUNDIALS_EXPORT int IDAGetCurrentStep(void *ida_mem, realtype *hcur); diff --git a/deps/AMICI/ThirdParty/sundials/include/idas/idas_bbdpre.h b/deps/AMICI/ThirdParty/sundials/include/idas/idas_bbdpre.h index 3e956c068..ea597773e 100644 --- a/deps/AMICI/ThirdParty/sundials/include/idas/idas_bbdpre.h +++ b/deps/AMICI/ThirdParty/sundials/include/idas/idas_bbdpre.h @@ -3,7 +3,7 @@ * Alan C. Hindmarsh, Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/idas/idas_direct.h b/deps/AMICI/ThirdParty/sundials/include/idas/idas_direct.h index 74df9ed9d..0b519cf7f 100644 --- a/deps/AMICI/ThirdParty/sundials/include/idas/idas_direct.h +++ b/deps/AMICI/ThirdParty/sundials/include/idas/idas_direct.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -38,28 +38,28 @@ typedef IDALsJacFnBS IDADlsJacFnBS; Exported Functions (wrappers for equivalent routines in idas_ls.h) ===================================================================*/ -int IDADlsSetLinearSolver(void *ida_mem, SUNLinearSolver LS, - SUNMatrix A); +SUNDIALS_EXPORT int IDADlsSetLinearSolver(void *ida_mem, SUNLinearSolver LS, + SUNMatrix A); -int IDADlsSetJacFn(void *ida_mem, IDADlsJacFn jac); +SUNDIALS_EXPORT int IDADlsSetJacFn(void *ida_mem, IDADlsJacFn jac); -int IDADlsGetWorkSpace(void *ida_mem, long int *lenrwLS, - long int *leniwLS); +SUNDIALS_EXPORT int IDADlsGetWorkSpace(void *ida_mem, long int *lenrwLS, + long int *leniwLS); -int IDADlsGetNumJacEvals(void *ida_mem, long int *njevals); +SUNDIALS_EXPORT int IDADlsGetNumJacEvals(void *ida_mem, long int *njevals); -int IDADlsGetNumResEvals(void *ida_mem, long int *nrevalsLS); +SUNDIALS_EXPORT int IDADlsGetNumResEvals(void *ida_mem, long int *nrevalsLS); -int IDADlsGetLastFlag(void *ida_mem, long int *flag); +SUNDIALS_EXPORT int IDADlsGetLastFlag(void *ida_mem, long int *flag); char *IDADlsGetReturnFlagName(long int flag); -int IDADlsSetLinearSolverB(void *ida_mem, int which, - SUNLinearSolver LS, SUNMatrix A); +SUNDIALS_EXPORT int IDADlsSetLinearSolverB(void *ida_mem, int which, + SUNLinearSolver LS, SUNMatrix A); -int IDADlsSetJacFnB(void *ida_mem, int which, IDADlsJacFnB jacB); +SUNDIALS_EXPORT int IDADlsSetJacFnB(void *ida_mem, int which, IDADlsJacFnB jacB); -int IDADlsSetJacFnBS(void *ida_mem, int which, IDADlsJacFnBS jacBS); +SUNDIALS_EXPORT int IDADlsSetJacFnBS(void *ida_mem, int which, IDADlsJacFnBS jacBS); diff --git a/deps/AMICI/ThirdParty/sundials/include/idas/idas_ls.h b/deps/AMICI/ThirdParty/sundials/include/idas/idas_ls.h index eed5c1917..e3948112b 100644 --- a/deps/AMICI/ThirdParty/sundials/include/idas/idas_ls.h +++ b/deps/AMICI/ThirdParty/sundials/include/idas/idas_ls.h @@ -3,7 +3,7 @@ * Radu Serban @ LLNL * ---------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -104,6 +104,8 @@ SUNDIALS_EXPORT int IDASetJacTimes(void *ida_mem, IDALsJacTimesSetupFn jtsetup, IDALsJacTimesVecFn jtimes); SUNDIALS_EXPORT int IDASetEpsLin(void *ida_mem, realtype eplifac); +SUNDIALS_EXPORT int IDASetLinearSolutionScaling(void *ida_mem, + booleantype onoff); SUNDIALS_EXPORT int IDASetIncrementFactor(void *ida_mem, realtype dqincfac); @@ -232,6 +234,8 @@ SUNDIALS_EXPORT int IDASetJacFnBS(void *ida_mem, int which, SUNDIALS_EXPORT int IDASetEpsLinB(void *ida_mem, int which, realtype eplifacB); +SUNDIALS_EXPORT int IDASetLinearSolutionScalingB(void *ida_mem, int which, + booleantype onoffB); SUNDIALS_EXPORT int IDASetIncrementFactorB(void *ida_mem, int which, realtype dqincfacB); SUNDIALS_EXPORT int IDASetPreconditionerB(void *ida_mem, int which, diff --git a/deps/AMICI/ThirdParty/sundials/include/idas/idas_spils.h b/deps/AMICI/ThirdParty/sundials/include/idas/idas_spils.h index e7ef52ed1..487bb5be2 100644 --- a/deps/AMICI/ThirdParty/sundials/include/idas/idas_spils.h +++ b/deps/AMICI/ThirdParty/sundials/include/idas/idas_spils.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -47,61 +47,61 @@ typedef IDALsJacTimesVecFnBS IDASpilsJacTimesVecFnBS; Exported Functions (wrappers for equivalent routines in idas_ls.h) ====================================================================*/ -int IDASpilsSetLinearSolver(void *ida_mem, SUNLinearSolver LS); +SUNDIALS_EXPORT int IDASpilsSetLinearSolver(void *ida_mem, SUNLinearSolver LS); -int IDASpilsSetPreconditioner(void *ida_mem, IDASpilsPrecSetupFn pset, - IDASpilsPrecSolveFn psolve); +SUNDIALS_EXPORT int IDASpilsSetPreconditioner(void *ida_mem, IDASpilsPrecSetupFn pset, + IDASpilsPrecSolveFn psolve); -int IDASpilsSetJacTimes(void *ida_mem, IDASpilsJacTimesSetupFn jtsetup, - IDASpilsJacTimesVecFn jtimes); +SUNDIALS_EXPORT int IDASpilsSetJacTimes(void *ida_mem, IDASpilsJacTimesSetupFn jtsetup, + IDASpilsJacTimesVecFn jtimes); -int IDASpilsSetEpsLin(void *ida_mem, realtype eplifac); +SUNDIALS_EXPORT int IDASpilsSetEpsLin(void *ida_mem, realtype eplifac); -int IDASpilsSetIncrementFactor(void *ida_mem, realtype dqincfac); +SUNDIALS_EXPORT int IDASpilsSetIncrementFactor(void *ida_mem, realtype dqincfac); -int IDASpilsGetWorkSpace(void *ida_mem, long int *lenrwLS, long int *leniwLS); +SUNDIALS_EXPORT int IDASpilsGetWorkSpace(void *ida_mem, long int *lenrwLS, long int *leniwLS); -int IDASpilsGetNumPrecEvals(void *ida_mem, long int *npevals); +SUNDIALS_EXPORT int IDASpilsGetNumPrecEvals(void *ida_mem, long int *npevals); -int IDASpilsGetNumPrecSolves(void *ida_mem, long int *npsolves); +SUNDIALS_EXPORT int IDASpilsGetNumPrecSolves(void *ida_mem, long int *npsolves); -int IDASpilsGetNumLinIters(void *ida_mem, long int *nliters); +SUNDIALS_EXPORT int IDASpilsGetNumLinIters(void *ida_mem, long int *nliters); -int IDASpilsGetNumConvFails(void *ida_mem, long int *nlcfails); +SUNDIALS_EXPORT int IDASpilsGetNumConvFails(void *ida_mem, long int *nlcfails); -int IDASpilsGetNumJTSetupEvals(void *ida_mem, long int *njtsetups); +SUNDIALS_EXPORT int IDASpilsGetNumJTSetupEvals(void *ida_mem, long int *njtsetups); -int IDASpilsGetNumJtimesEvals(void *ida_mem, long int *njvevals); +SUNDIALS_EXPORT int IDASpilsGetNumJtimesEvals(void *ida_mem, long int *njvevals); -int IDASpilsGetNumResEvals(void *ida_mem, long int *nrevalsLS); +SUNDIALS_EXPORT int IDASpilsGetNumResEvals(void *ida_mem, long int *nrevalsLS); -int IDASpilsGetLastFlag(void *ida_mem, long int *flag); +SUNDIALS_EXPORT int IDASpilsGetLastFlag(void *ida_mem, long int *flag); -char *IDASpilsGetReturnFlagName(long int flag); +SUNDIALS_EXPORT char *IDASpilsGetReturnFlagName(long int flag); -int IDASpilsSetLinearSolverB(void *ida_mem, int which, - SUNLinearSolver LS); +SUNDIALS_EXPORT int IDASpilsSetLinearSolverB(void *ida_mem, int which, + SUNLinearSolver LS); -int IDASpilsSetEpsLinB(void *ida_mem, int which, realtype eplifacB); +SUNDIALS_EXPORT int IDASpilsSetEpsLinB(void *ida_mem, int which, realtype eplifacB); -int IDASpilsSetIncrementFactorB(void *ida_mem, int which, - realtype dqincfacB); +SUNDIALS_EXPORT int IDASpilsSetIncrementFactorB(void *ida_mem, int which, + realtype dqincfacB); -int IDASpilsSetPreconditionerB(void *ida_mem, int which, - IDASpilsPrecSetupFnB psetB, - IDASpilsPrecSolveFnB psolveB); +SUNDIALS_EXPORT int IDASpilsSetPreconditionerB(void *ida_mem, int which, + IDASpilsPrecSetupFnB psetB, + IDASpilsPrecSolveFnB psolveB); -int IDASpilsSetPreconditionerBS(void *ida_mem, int which, - IDASpilsPrecSetupFnBS psetBS, - IDASpilsPrecSolveFnBS psolveBS); +SUNDIALS_EXPORT int IDASpilsSetPreconditionerBS(void *ida_mem, int which, + IDASpilsPrecSetupFnBS psetBS, + IDASpilsPrecSolveFnBS psolveBS); -int IDASpilsSetJacTimesB(void *ida_mem, int which, - IDASpilsJacTimesSetupFnB jtsetupB, - IDASpilsJacTimesVecFnB jtimesB); +SUNDIALS_EXPORT int IDASpilsSetJacTimesB(void *ida_mem, int which, + IDASpilsJacTimesSetupFnB jtsetupB, + IDASpilsJacTimesVecFnB jtimesB); -int IDASpilsSetJacTimesBS(void *ida_mem, int which, - IDASpilsJacTimesSetupFnBS jtsetupBS, - IDASpilsJacTimesVecFnBS jtimesBS); +SUNDIALS_EXPORT int IDASpilsSetJacTimesBS(void *ida_mem, int which, + IDASpilsJacTimesSetupFnBS jtsetupBS, + IDASpilsJacTimesVecFnBS jtimesBS); #ifdef __cplusplus diff --git a/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol.h b/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol.h index fa8a372a0..10ac581c7 100644 --- a/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol.h +++ b/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol.h @@ -3,7 +3,7 @@ * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -105,6 +105,7 @@ SUNDIALS_EXPORT int KINSetInfoFile(void *kinmem, FILE *infofp); SUNDIALS_EXPORT int KINSetUserData(void *kinmem, void *user_data); SUNDIALS_EXPORT int KINSetPrintLevel(void *kinmemm, int printfl); SUNDIALS_EXPORT int KINSetMAA(void *kinmem, long int maa); +SUNDIALS_EXPORT int KINSetDampingAA(void *kinmem, realtype beta); SUNDIALS_EXPORT int KINSetNumMaxIters(void *kinmem, long int mxiter); SUNDIALS_EXPORT int KINSetNoInitSetup(void *kinmem, booleantype noInitSetup); SUNDIALS_EXPORT int KINSetNoResMon(void *kinmem, booleantype noNNIResMon); diff --git a/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_bbdpre.h b/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_bbdpre.h index bbc6910ad..2d91769ac 100644 --- a/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_bbdpre.h +++ b/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_bbdpre.h @@ -4,7 +4,7 @@ * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_direct.h b/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_direct.h index c7e1ce7bb..91dd42143 100644 --- a/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_direct.h +++ b/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_direct.h @@ -3,7 +3,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -37,19 +37,19 @@ typedef KINLsJacFn KINDlsJacFn; Exported Functions (wrappers for equivalent routines in kinsol_ls.h) ===================================================================*/ -int KINDlsSetLinearSolver(void *kinmem, SUNLinearSolver LS, SUNMatrix A); +SUNDIALS_EXPORT int KINDlsSetLinearSolver(void *kinmem, SUNLinearSolver LS, SUNMatrix A); -int KINDlsSetJacFn(void *kinmem, KINDlsJacFn jac); +SUNDIALS_EXPORT int KINDlsSetJacFn(void *kinmem, KINDlsJacFn jac); -int KINDlsGetWorkSpace(void *kinmem, long int *lenrw, long int *leniw); +SUNDIALS_EXPORT int KINDlsGetWorkSpace(void *kinmem, long int *lenrw, long int *leniw); -int KINDlsGetNumJacEvals(void *kinmem, long int *njevals); +SUNDIALS_EXPORT int KINDlsGetNumJacEvals(void *kinmem, long int *njevals); -int KINDlsGetNumFuncEvals(void *kinmem, long int *nfevals); +SUNDIALS_EXPORT int KINDlsGetNumFuncEvals(void *kinmem, long int *nfevals); -int KINDlsGetLastFlag(void *kinmem, long int *flag); +SUNDIALS_EXPORT int KINDlsGetLastFlag(void *kinmem, long int *flag); -char *KINDlsGetReturnFlagName(long int flag); +SUNDIALS_EXPORT char *KINDlsGetReturnFlagName(long int flag); #ifdef __cplusplus diff --git a/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_ls.h b/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_ls.h index 27a8ea4e5..d0a177756 100644 --- a/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_ls.h +++ b/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_ls.h @@ -4,7 +4,7 @@ * Aaron Collier @ LLNL * ---------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -105,8 +105,6 @@ SUNDIALS_EXPORT int KINGetNumLinConvFails(void *kinmem, long int *nlcfails); SUNDIALS_EXPORT int KINGetNumJtimesEvals(void *kinmem, long int *njvevals); -SUNDIALS_EXPORT int KINGetNumLinFuncEvals(void *kinmem, - long int *nfevals); SUNDIALS_EXPORT int KINGetLastLinFlag(void *kinmem, long int *flag); SUNDIALS_EXPORT char *KINGetLinReturnFlagName(long int flag); diff --git a/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_spils.h b/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_spils.h index a20731d63..f6dc9de0a 100644 --- a/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_spils.h +++ b/deps/AMICI/ThirdParty/sundials/include/kinsol/kinsol_spils.h @@ -4,7 +4,7 @@ * and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -40,30 +40,30 @@ typedef KINLsJacTimesVecFn KINSpilsJacTimesVecFn; Exported Functions (wrappers for equivalent routines in kinsol_ls.h) ====================================================================*/ -int KINSpilsSetLinearSolver(void *kinmem, SUNLinearSolver LS); +SUNDIALS_EXPORT int KINSpilsSetLinearSolver(void *kinmem, SUNLinearSolver LS); -int KINSpilsSetPreconditioner(void *kinmem, KINSpilsPrecSetupFn psetup, - KINSpilsPrecSolveFn psolve); +SUNDIALS_EXPORT int KINSpilsSetPreconditioner(void *kinmem, KINSpilsPrecSetupFn psetup, + KINSpilsPrecSolveFn psolve); -int KINSpilsSetJacTimesVecFn(void *kinmem, KINSpilsJacTimesVecFn jtv); +SUNDIALS_EXPORT int KINSpilsSetJacTimesVecFn(void *kinmem, KINSpilsJacTimesVecFn jtv); -int KINSpilsGetWorkSpace(void *kinmem, long int *lenrwLS, long int *leniwLS); +SUNDIALS_EXPORT int KINSpilsGetWorkSpace(void *kinmem, long int *lenrwLS, long int *leniwLS); -int KINSpilsGetNumPrecEvals(void *kinmem, long int *npevals); +SUNDIALS_EXPORT int KINSpilsGetNumPrecEvals(void *kinmem, long int *npevals); -int KINSpilsGetNumPrecSolves(void *kinmem, long int *npsolves); +SUNDIALS_EXPORT int KINSpilsGetNumPrecSolves(void *kinmem, long int *npsolves); -int KINSpilsGetNumLinIters(void *kinmem, long int *nliters); +SUNDIALS_EXPORT int KINSpilsGetNumLinIters(void *kinmem, long int *nliters); -int KINSpilsGetNumConvFails(void *kinmem, long int *nlcfails); +SUNDIALS_EXPORT int KINSpilsGetNumConvFails(void *kinmem, long int *nlcfails); -int KINSpilsGetNumJtimesEvals(void *kinmem, long int *njvevals); +SUNDIALS_EXPORT int KINSpilsGetNumJtimesEvals(void *kinmem, long int *njvevals); -int KINSpilsGetNumFuncEvals(void *kinmem, long int *nfevals); +SUNDIALS_EXPORT int KINSpilsGetNumFuncEvals(void *kinmem, long int *nfevals); -int KINSpilsGetLastFlag(void *kinmem, long int *flag); +SUNDIALS_EXPORT int KINSpilsGetLastFlag(void *kinmem, long int *flag); -char *KINSpilsGetReturnFlagName(long int flag); +SUNDIALS_EXPORT char *KINSpilsGetReturnFlagName(long int flag); #ifdef __cplusplus diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/cuda/ThreadPartitioning.hpp b/deps/AMICI/ThirdParty/sundials/include/nvector/cuda/ThreadPartitioning.hpp index 10a8c72fd..4e830ac51 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/cuda/ThreadPartitioning.hpp +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/cuda/ThreadPartitioning.hpp @@ -3,7 +3,7 @@ * Programmer(s): Slaven Peles @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -22,12 +22,18 @@ #include #include +#include + namespace suncudavec { + +using SUNAllocFn = void* (*)(size_t); +using SUNFreeFn = void (*)(void*); template class ThreadPartitioning { + public: ThreadPartitioning() : block_(1), @@ -35,25 +41,35 @@ class ThreadPartitioning shMemSize_(0), stream_(0), bufferSize_(0), + allocfn_(nullptr), + freefn_(nullptr), d_buffer_(nullptr), - h_buffer_(nullptr) + h_buffer_(nullptr), + ownBuffer_(true) {} - ThreadPartitioning(unsigned block) + ThreadPartitioning(unsigned block, + SUNAllocFn allocfn = nullptr, + SUNFreeFn freefn = nullptr) : block_(block), grid_(1), shMemSize_(0), stream_(0), bufferSize_(0), + allocfn_(allocfn), + freefn_(freefn), d_buffer_(nullptr), - h_buffer_(nullptr) + h_buffer_(nullptr), + ownBuffer_(true) {} - + explicit ThreadPartitioning(ThreadPartitioning& p) : block_(p.block_), grid_(p.grid_), shMemSize_(p.shMemSize_), - stream_(p.stream_) + stream_(p.stream_), + allocfn_(p.allocfn_), + freefn_(p.freefn_) {} virtual ~ThreadPartitioning(){} @@ -78,7 +94,7 @@ class ThreadPartitioning return stream_; } - unsigned int buffSize() + unsigned int bufferSize() { return bufferSize_; } @@ -110,51 +126,14 @@ class ThreadPartitioning virtual void copyFromDevBuffer(unsigned int n) const { - std::cerr << "Trying to copy buffer from base class!\n"; - } - - virtual int setPartitioning(I N, unsigned& grid, unsigned& block, unsigned& shMemSize, - cudaStream_t& stream) - { - block = 1; - grid = 1; - shMemSize = 0; - stream = 0; - std::cerr << "Trying to set partitioning from base class!\n"; - - return 0; + std::cerr << "Trying to copy buffer from base class in " + << "suncudavec::ThreadPartitioning::copyFromDevBuffer\n"; } - virtual int setPartitioning(I N, unsigned& grid, unsigned& block, unsigned& shMemSize) - { - block = 1; - grid = 1; - shMemSize = 0; - std::cerr << "Trying to set partitioning from base class!\n"; - - return 0; - } - - virtual int setPartitioning(I N, unsigned& grid, unsigned& block, cudaStream_t& stream) - { - block = 1; - grid = 1; - stream = 0; - std::cerr << "Trying to set partitioning from base class!\n"; - - return 0; - } + /* pure virtual functions to get the relevant partitioning information */ + virtual int calcPartitioning(I N, unsigned& grid, unsigned& block, unsigned& shMemSize, cudaStream_t& stream) = 0; + virtual int calcPartitioning(I N, unsigned& grid, unsigned& block, unsigned& shMemSize) = 0; - virtual int setPartitioning(I N, unsigned& grid, unsigned& block) - { - block = 1; - grid = 1; - std::cerr << "Trying to set partitioning from base class!\n"; - - return 0; - } - - protected: unsigned block_; unsigned grid_; @@ -163,6 +142,11 @@ class ThreadPartitioning cudaStream_t stream_; T* d_buffer_; T* h_buffer_; + bool ownBuffer_; + + /* custom allocators for the internal buffers */ + SUNAllocFn allocfn_; + SUNFreeFn freefn_; }; // class ThreadPartitioning @@ -194,8 +178,8 @@ class StreamPartitioning : public ThreadPartitioning { } - virtual int setPartitioning(I N, unsigned& grid, unsigned& block, unsigned& shMemSize, - cudaStream_t& stream) + virtual int calcPartitioning(I N, unsigned& grid, unsigned& block, unsigned& shMemSize, + cudaStream_t& stream) { block = block_; grid = (N + block_ - 1) / block_; @@ -205,7 +189,7 @@ class StreamPartitioning : public ThreadPartitioning return 0; } - virtual int setPartitioning(I N, unsigned& grid, unsigned& block, unsigned& shMemSize) + virtual int calcPartitioning(I N, unsigned& grid, unsigned& block, unsigned& shMemSize) { block = block_; grid = (N + block_ - 1) / block_; @@ -214,23 +198,6 @@ class StreamPartitioning : public ThreadPartitioning return 0; } - virtual int setPartitioning(I N, unsigned& grid, unsigned& block, cudaStream_t& stream) - { - block = block_; - grid = (N + block_ - 1) / block_; - stream = stream_; - - return 0; - } - - virtual int setPartitioning(I N, unsigned& grid, unsigned& block) - { - block = block_; - grid = (N + block_ - 1) / block_; - - return 0; - } - }; // class StreamPartitioning @@ -244,47 +211,84 @@ class ReducePartitioning : public ThreadPartitioning using ThreadPartitioning::bufferSize_; using ThreadPartitioning::d_buffer_; using ThreadPartitioning::h_buffer_; + using ThreadPartitioning::ownBuffer_; + using ThreadPartitioning::allocfn_; + using ThreadPartitioning::freefn_; public: - ReducePartitioning(I N, unsigned block, cudaStream_t stream) - : ThreadPartitioning(block) + ReducePartitioning(I N, unsigned block, + SUNAllocFn allocfn = nullptr, SUNFreeFn freefn = nullptr) + : ThreadPartitioning(block, allocfn, freefn) + { + grid_ = (N + (block_ * 2 - 1)) / (block_ * 2); + shMemSize_ = block_*sizeof(T); + allocateBuffer(false, allocfn != nullptr); + } + + ReducePartitioning(I N, unsigned block, cudaStream_t stream, + SUNAllocFn allocfn = nullptr, SUNFreeFn freefn = nullptr) + : ThreadPartitioning(block, allocfn, freefn) { grid_ = (N + (block_ * 2 - 1)) / (block_ * 2); shMemSize_ = block_*sizeof(T); stream_ = stream; - allocateBuffer(); + allocateBuffer(false, allocfn != nullptr); } - ReducePartitioning(I N, unsigned block) + ReducePartitioning(T *h_buffer, T *d_buffer, I N, unsigned block, cudaStream_t stream = 0) : ThreadPartitioning(block) { grid_ = (N + (block_ * 2 - 1)) / (block_ * 2); shMemSize_ = block_*sizeof(T); - allocateBuffer(); + stream_ = stream; + h_buffer_ = h_buffer; + d_buffer_ = d_buffer; + ownBuffer_ = false; } - + explicit ReducePartitioning(ReducePartitioning& p) : ThreadPartitioning(p) { shMemSize_ = p.shMemSize_; - allocateBuffer(); + /* if device buffer and host buffer are the same, then assume managed memory */ + allocateBuffer(p.d_buffer_ == p.h_buffer_, p.allocfn_ != nullptr); } ~ReducePartitioning() { cudaError_t err; - if (bufferSize_ > 0) - free(h_buffer_); - if (bufferSize_ > 0) - { - err = cudaFree(d_buffer_); - if(err != cudaSuccess) - std::cerr << "Failed to free device vector (error code " << err << ")!\n"; + + if (ownBuffer_ && bufferSize_ > 0) { + + if (d_buffer_ == h_buffer_) { + /* managed memory */ + if (freefn_) { + freefn_(d_buffer_); + } else { + err = cudaFree(d_buffer_); + if(err != cudaSuccess) + std::cerr << "Failed to free device vector " + << "in suncudavec::ReducePartitioning::~ReducePartitioning " + << "(CUDA error code " << err << ")\n"; + } + d_buffer_ = h_buffer_ = nullptr; + } else { + /* unmanaged memory */ + err = cudaFree(d_buffer_); + if(err != cudaSuccess) + std::cerr << "Failed to free device vector " + << "in suncudavec::ReducePartitioning::~ReducePartitioning " + << "(CUDA error code " << err << ")\n"; + free(h_buffer_); + d_buffer_ = nullptr; + h_buffer_ = nullptr; + } + } } - virtual int setPartitioning(I N, unsigned& grid, unsigned& block, unsigned& shMemSize, - cudaStream_t& stream) + virtual int calcPartitioning(I N, unsigned& grid, unsigned& block, unsigned& shMemSize, + cudaStream_t& stream) { block = block_; grid = (N + (block_ * 2 - 1)) / (block_ * 2); @@ -294,7 +298,7 @@ class ReducePartitioning : public ThreadPartitioning return 0; } - virtual int setPartitioning(I N, unsigned& grid, unsigned& block, unsigned& shMemSize) + virtual int calcPartitioning(I N, unsigned& grid, unsigned& block, unsigned& shMemSize) { block = block_; grid = (N + (block_ * 2 - 1)) / (block_ * 2); @@ -303,42 +307,73 @@ class ReducePartitioning : public ThreadPartitioning return 0; } - virtual int setPartitioning(I N, unsigned& grid, unsigned& block, cudaStream_t& stream) - { - block = block_; - grid = (N + (block_ * 2 - 1)) / (block_ * 2); - stream = stream_; - - return 0; - } - - virtual int setPartitioning(I N, unsigned& grid, unsigned& block) + virtual void copyFromDevBuffer(unsigned int n) const { - block = block_; - grid = (N + (block_ * 2 - 1)) / (block_ * 2); + cudaError_t err; - return 0; + /* If the host and device pointers are the same, then we don't need + to do a copy (this happens in the managed memory case), but we + still need to synchronize the device to adhere to the unified + memory access rules. */ + if (h_buffer_ == d_buffer_) { + err = cudaStreamSynchronize(stream_); + if(err != cudaSuccess) + std::cerr << "Failed to synchronize stream in " + << "suncudavec::ReducePartitioning::copyFromDevBuffer " + << "(CUDA error code " << err << ")\n"; + } else { + err = cudaMemcpyAsync(h_buffer_, d_buffer_, n*sizeof(T), cudaMemcpyDeviceToHost, + stream_); + if(err != cudaSuccess) + std::cerr << "Failed to copy vector from device to host in " + << "suncudavec::ReducePartitioning::copyFromDevBuffer " + << "(CUDA error code " << err << ")\n"; + } } - virtual void copyFromDevBuffer(unsigned int n) const + static unsigned calcBufferSize(I N, unsigned block) { - cudaError_t err = cudaMemcpy(h_buffer_, d_buffer_, n*sizeof(T), cudaMemcpyDeviceToHost); - if(err != cudaSuccess) - std::cerr << "Failed to copy vector from device to host (error code " << err << ")!\n"; + return (N + (block * 2 - 1)) / (block * 2) * sizeof(T); } private: - int allocateBuffer() + int allocateBuffer(bool use_managed_memory = false, bool custom_allocator = false) { + cudaError_t err; + bufferSize_ = grid_ * sizeof(T); - h_buffer_ = static_cast(malloc(bufferSize_)); - if(h_buffer_ == NULL) - std::cerr << "Failed to allocate host vector!\n"; + if (bufferSize_ == 0) return 0; - cudaError_t err; - err = cudaMalloc((void**) &d_buffer_, bufferSize_); - if(err != cudaSuccess) - std::cerr << "Failed to allocate device vector (error code " << err << ")!\n"; + if (custom_allocator) { + + d_buffer_ = static_cast(allocfn_(bufferSize_)); + if(d_buffer_ == NULL) + std::cerr << "Failed to allocate managed buffer with custom allocator in " + << "suncudavec::ReducePartitioning::allocateBuffer\n"; + h_buffer_ = d_buffer_; + + } else if (use_managed_memory) { + + err = cudaMallocManaged((void**) &d_buffer_, bufferSize_); + if(err != cudaSuccess) + std::cerr << "Failed to allocate internal managed buffer in " + << "suncudavec::ReducePartitioning::allocateBuffer " + << "(CUDA error code " << err << ")\n"; + h_buffer_ = d_buffer_; + + } else { + + h_buffer_ = static_cast(malloc(bufferSize_)); + if(h_buffer_ == NULL) + std::cerr << "Failed to allocate internal host buffer in " + << "suncudavec::ReducePartitioning::allocateBuffer\n"; + err = cudaMalloc((void**) &d_buffer_, bufferSize_); + if(err != cudaSuccess) + std::cerr << "Failed to allocate internal device buffer " + << "in suncudavec::ReducePartitioning::allocateBuffer " + << "(CUDA error code " << err << ")\n"; + + } return 0; } diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/cuda/Vector.hpp b/deps/AMICI/ThirdParty/sundials/include/nvector/cuda/Vector.hpp index e46973ea6..2d3f9aaa9 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/cuda/Vector.hpp +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/cuda/Vector.hpp @@ -3,7 +3,7 @@ * Programmer(s): Slaven Peles, and Cody J. Balos @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -31,14 +31,8 @@ #include #include "ThreadPartitioning.hpp" -#include -#include - -#if SUNDIALS_MPI_ENABLED -#include -#else #include -#endif +#include namespace suncudavec { @@ -46,17 +40,20 @@ namespace suncudavec template class Vector : public _N_VectorContent_Cuda { + public: - Vector(I N, bool use_managed_memory = false, bool allocate_data = true, T* const h_vec = nullptr, T* const d_vec = nullptr) + Vector(I N, + bool use_managed_memory = false, bool allocate_data = true, + T* const h_vec = nullptr, T* const d_vec = nullptr) : size_(N), mem_size_(N*sizeof(T)), - global_size_(N), ownPartitioning_(true), ownData_(allocate_data), managed_mem_(use_managed_memory), + allocfn_(nullptr), + freefn_(nullptr), h_vec_(h_vec), - d_vec_(d_vec), - comm_(0) + d_vec_(d_vec) { // Set partitioning partStream_ = new StreamPartitioning(N, 256); @@ -68,16 +65,17 @@ class Vector : public _N_VectorContent_Cuda } Vector(I N, cudaStream_t stream, - bool use_managed_memory = false, bool allocate_data = true, T* const h_vec = nullptr, T* const d_vec = nullptr) + bool use_managed_memory = false, bool allocate_data = true, + T* const h_vec = nullptr, T* const d_vec = nullptr) : size_(N), mem_size_(N*sizeof(T)), - global_size_(N), ownPartitioning_(true), ownData_(allocate_data), managed_mem_(use_managed_memory), + allocfn_(nullptr), + freefn_(nullptr), h_vec_(h_vec), - d_vec_(d_vec), - comm_(0) + d_vec_(d_vec) { // Set partitioning partStream_ = new StreamPartitioning(N, 256, stream); @@ -87,62 +85,64 @@ class Vector : public _N_VectorContent_Cuda if (allocate_data) allocate(); } - - Vector(SUNMPI_Comm comm, I N, I Nglobal, - bool use_managed_memory = false, bool allocate_data = true, T* const h_vec = nullptr, T* const d_vec = nullptr) + + Vector(I N, + SUNAllocFn allocfn, SUNFreeFn freefn, + bool allocate_data = true) : size_(N), mem_size_(N*sizeof(T)), - global_size_(Nglobal), ownPartitioning_(true), ownData_(allocate_data), - managed_mem_(use_managed_memory), - h_vec_(h_vec), - d_vec_(d_vec), - comm_(comm) + managed_mem_(true), + allocfn_(allocfn), + freefn_(freefn), + h_vec_(nullptr), + d_vec_(nullptr) { // Set partitioning partStream_ = new StreamPartitioning(N, 256); - partReduce_ = new ReducePartitioning(N, 256); + partReduce_ = new ReducePartitioning(N, 256, allocfn, freefn); // Allocate data arrays if (allocate_data) allocate(); } - Vector(SUNMPI_Comm comm, I N, I Nglobal, cudaStream_t stream, - bool use_managed_memory = false, bool allocate_data = true, T* const h_vec = nullptr, T* const d_vec = nullptr) + Vector(I N, cudaStream_t stream, + SUNAllocFn allocfn, SUNFreeFn freefn, + bool allocate_data = true) : size_(N), mem_size_(N*sizeof(T)), - global_size_(Nglobal), ownPartitioning_(true), ownData_(allocate_data), - managed_mem_(use_managed_memory), - h_vec_(h_vec), - d_vec_(d_vec), - comm_(comm) + managed_mem_(true), + allocfn_(allocfn), + freefn_(freefn), + h_vec_(nullptr), + d_vec_(nullptr) { // Set partitioning partStream_ = new StreamPartitioning(N, 256, stream); - partReduce_ = new ReducePartitioning(N, 256, stream); + partReduce_ = new ReducePartitioning(N, 256, stream, allocfn, freefn); // Allocate data arrays if (allocate_data) allocate(); } - + // Copy constructor does not copy data array values explicit Vector(const Vector& v) : size_(v.size()), mem_size_(size_*sizeof(T)), - global_size_(v.global_size_), partStream_(v.partStream_), partReduce_(v.partReduce_), ownPartitioning_(false), ownData_(true), managed_mem_(v.managed_mem_), + allocfn_(v.allocfn_), + freefn_(v.freefn_), h_vec_(nullptr), - d_vec_(nullptr), - comm_(v.comm_) + d_vec_(nullptr) { allocate(); } @@ -150,28 +150,36 @@ class Vector : public _N_VectorContent_Cuda ~Vector() { cudaError_t err; - + if (ownPartitioning_) { delete partReduce_; delete partStream_; } - + if (ownData_) { - if (!managed_mem_) - free(h_vec_); - - err = cudaFree(d_vec_); - if(err != cudaSuccess) - std::cerr << "Failed to free device vector (error code " << err << ")!\n"; - - d_vec_ = nullptr; - h_vec_ = nullptr; + if (freefn_) { + freefn_(d_vec_); + d_vec_ = nullptr; + h_vec_ = nullptr; + } else { + if (!managed_mem_) + free(h_vec_); + err = cudaFree(d_vec_); + if(err != cudaSuccess) + std::cerr << "Failed to free device vector " + << "in suncudavec::Vector::~Vector " + << "(error code " << err << ")\n"; + d_vec_ = nullptr; + h_vec_ = nullptr; + } } } void allocate() { - if (managed_mem_) { + if (allocfn_) { + allocateCustom(); + } else if (managed_mem_) { allocateManaged(); } else { allocateUnmanaged(); @@ -183,55 +191,84 @@ class Vector : public _N_VectorContent_Cuda cudaError_t err; err = cudaMallocManaged((void**) &d_vec_, mem_size_); if (err != cudaSuccess) - std::cerr << "Failed to allocate managed vector (error code " << err << ")!\n"; + std::cerr << "Failed to allocate managed vector " + << "in suncudavec::Vector::allocateManaged " + << "(error code " << err << ")\n"; h_vec_ = d_vec_; } void allocateUnmanaged() { cudaError_t err; - + h_vec_ = static_cast(malloc(mem_size_)); if(h_vec_ == nullptr) - std::cerr << "Failed to allocate host vector!\n"; - + std::cerr << "Failed to allocate host vector " + << "in suncudavec::Vector::allocateUnmanaged\n"; + err = cudaMalloc((void**) &d_vec_, mem_size_); if(err != cudaSuccess) - std::cerr << "Failed to allocate device vector (error code " << err << ")!\n"; - } - - int size() const - { - return size_; + std::cerr << "Failed to allocate device vector " + << "in suncudavec::Vector::allocateUnmanaged " + << "(error code " << err << ")\n"; } - int sizeGlobal() const + void allocateCustom() { - return global_size_; + /* We assume managed memory when a custom allocator is provided */ + d_vec_ = (realtype *) allocfn_(mem_size_); + if (d_vec_ == nullptr) + std::cerr << "Failed to allocate vector with user-provied allocator " + << "in suncudavec::Vector::allocateCustom()\n"; + h_vec_ = d_vec_; } - SUNMPI_Comm comm() const + int size() const { - return comm_; + return size_; } T* host() { + // If the vector is using managed memory, and a user + // is accessing a data array, then we need to synchronzie + // to ensure all kernels have completed since a memcpy + // won't have to happen. + if (managed_mem_) + cudaStreamSynchronize(partReduce_->stream()); return h_vec_; } const T* host() const { + // If the vector is using managed memory, and a user + // is accessing a data array, then we need to synchronzie + // to ensure all kernels have completed since a memcpy + // won't have to happen. + if (managed_mem_) + cudaStreamSynchronize(partReduce_->stream()); return h_vec_; } T* device() { + // If the vector is using managed memory, and a user + // is accessing a data array, then we need to synchronzie + // to ensure all kernels have completed since a memcpy + // won't have to happen. + if (managed_mem_) + cudaStreamSynchronize(partReduce_->stream()); return d_vec_; } const T* device() const { + // If the vector is using managed memory, and a user + // is accessing a data array, then we need to synchronzie + // to ensure all kernels have completed since a memcpy + // won't have to happen. + if (managed_mem_) + cudaStreamSynchronize(partReduce_->stream()); return d_vec_; } @@ -242,16 +279,61 @@ class Vector : public _N_VectorContent_Cuda void copyToDev() { - cudaError_t err = cudaMemcpy(d_vec_, h_vec_, mem_size_, cudaMemcpyHostToDevice); - if(err != cudaSuccess) - std::cerr << "Failed to copy vector from host to device (error code " << err << ")!\n"; + cudaError_t err; + + /* If the host and device pointers are the same, then we don't need + to do a copy (this happens in the managed memory case), but we + still need to synchronize the device to adhere to the unified + memory access rules. */ + if (h_vec_ == d_vec_) { + err = cudaStreamSynchronize(partReduce_->stream()); + if(err != cudaSuccess) + std::cerr << "Failed to synchronize stream in " + << "suncudavec::Vector::copyToDev " + << "(error code " << err << ")\n"; + } else { + err = cudaMemcpyAsync(d_vec_, h_vec_, mem_size_, cudaMemcpyHostToDevice, + partReduce_->stream()); + if(err != cudaSuccess) + std::cerr << "Failed to copy vector from host to device in " + << "suncudavec::Vector::copyToDev " + << "(error code " << err << ")\n"; + } } void copyFromDev() { - cudaError_t err = cudaMemcpy(h_vec_, d_vec_, mem_size_, cudaMemcpyDeviceToHost); - if(err != cudaSuccess) - std::cerr << "Failed to copy vector from device to host (error code " << err << ")!\n"; + cudaError_t err; + + /* If the host and device pointers are the same, then we don't need + to do a copy (this happens in the managed memory case), but we + still need to synchronize the device to adhere to the unified + memory access rules. */ + if (h_vec_ == d_vec_) { + err = cudaStreamSynchronize(partReduce_->stream()); + if(err != cudaSuccess) + std::cerr << "Failed to synchronize stream in " + << "suncudavec::Vector::copyFromDev " + << "(error code " << err << ")\n"; + } else { + err = cudaMemcpyAsync(h_vec_, d_vec_, mem_size_, cudaMemcpyDeviceToHost, + partReduce_->stream()); + if(err != cudaSuccess) + std::cerr << "Failed to copy vector from device to host in " + << "suncudavec::Vector::copyFromDev " + << "(error code " << err << ")\n"; + } + } + + void setPartitioning(ThreadPartitioning* stream, ThreadPartitioning* reduce) + { + if (ownPartitioning_) { + delete partStream_; + delete partReduce_; + } + partStream_ = stream; + partReduce_ = reduce; + ownPartitioning_ = false; } ThreadPartitioning& partStream() const @@ -268,7 +350,6 @@ class Vector : public _N_VectorContent_Cuda private: I size_; I mem_size_; - I global_size_; T* h_vec_; T* d_vec_; ThreadPartitioning* partStream_; @@ -276,8 +357,9 @@ class Vector : public _N_VectorContent_Cuda bool ownPartitioning_; bool ownData_; bool managed_mem_; - SUNMPI_Comm comm_; - + SUNAllocFn allocfn_; + SUNFreeFn freefn_; + }; diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/cuda/VectorArrayKernels.cuh b/deps/AMICI/ThirdParty/sundials/include/nvector/cuda/VectorArrayKernels.cuh index 8311cd863..61e0c56e9 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/cuda/VectorArrayKernels.cuh +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/cuda/VectorArrayKernels.cuh @@ -3,7 +3,7 @@ * Programmer(s): David Gardner @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -526,7 +526,7 @@ inline cudaError_t dotProdMulti(int nvec, Vector* x, Vector** Y, for (int k=0; k** X, for (int k=0; k** X, for (int k=0; k& x, const Vector& y) while (n > nmax) { // Recompute partitioning - p.setPartitioning(n, grid, block, shMemSize); + p.calcPartitioning(n, grid, block, shMemSize); // Rerun reduction kernel math_kernels::sumReduceKernel<<>>(p.devBuffer(), p.devBuffer(), n); @@ -788,7 +788,7 @@ inline T maxNorm(const Vector& x) while (n > nmax) { // Recompute partitioning - p.setPartitioning(n, grid, block, shMemSize); + p.calcPartitioning(n, grid, block, shMemSize); // (Re)run reduction kernel math_kernels::maxNormKernel<<>>(p.devBuffer(), p.devBuffer(), n); @@ -824,7 +824,7 @@ inline T wL2NormSquareMask(const Vector& x, const Vector& w, const Vec while (n > nmax) { // Recompute partitioning - p.setPartitioning(n, grid, block, shMemSize); + p.calcPartitioning(n, grid, block, shMemSize); // (Re)run reduction kernel math_kernels::sumReduceKernel<<>>(p.devBuffer(), p.devBuffer(), n); @@ -861,7 +861,7 @@ inline T findMin(const Vector& x) while (n > nmax) { // Recompute partitioning - p.setPartitioning(n, grid, block, shMemSize); + p.calcPartitioning(n, grid, block, shMemSize); // Rerun reduction kernel math_kernels::findMinKernel<<>>(maxVal, p.devBuffer(), p.devBuffer(), n); @@ -898,7 +898,7 @@ inline T wL2NormSquare(const Vector& x, const Vector& y) while (n > nmax) { // Recompute partitioning - p.setPartitioning(n, grid, block, shMemSize); + p.calcPartitioning(n, grid, block, shMemSize); // Rerun reduction kernel math_kernels::sumReduceKernel<<>>(p.devBuffer(), p.devBuffer(), n); @@ -934,7 +934,7 @@ inline T L1Norm(const Vector& x) while (n > nmax) { // Recompute partitioning - p.setPartitioning(n, grid, block, shMemSize); + p.calcPartitioning(n, grid, block, shMemSize); // Rerun reduction kernel math_kernels::sumReduceKernel<<>>(p.devBuffer(), p.devBuffer(), n); @@ -970,7 +970,7 @@ inline T invTest(const Vector& x, Vector& z) while (n > nmax) { // Recompute partitioning - p.setPartitioning(n, grid, block, shMemSize); + p.calcPartitioning(n, grid, block, shMemSize); // Rerun reduction kernel math_kernels::sumReduceKernel<<>>(p.devBuffer(), p.devBuffer(), n); @@ -1006,7 +1006,7 @@ inline T constrMask(const Vector& c, const Vector& x, Vector& m) while (n > nmax) { // Recompute partitioning - p.setPartitioning(n, grid, block, shMemSize); + p.calcPartitioning(n, grid, block, shMemSize); // Rerun reduction kernel math_kernels::sumReduceKernel<<>>(p.devBuffer(), p.devBuffer(), n); @@ -1046,7 +1046,7 @@ inline T minQuotient(const Vector& num, const Vector& den) while (n > nmax) { // Recompute partitioning - p.setPartitioning(n, grid, block, shMemSize); + p.calcPartitioning(n, grid, block, shMemSize); // Rerun reduction kernel math_kernels::findMinKernel<<>>(maxVal, p.devBuffer(), p.devBuffer(), n); diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_cuda.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_cuda.h index c78989cdf..93cadcb09 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_cuda.h +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_cuda.h @@ -2,7 +2,7 @@ * Programmer(s): Slaven Peles and Cody J. Balos @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -80,6 +80,10 @@ SUNDIALS_EXPORT N_Vector N_VMake_Cuda(sunindextype length, SUNDIALS_EXPORT N_Vector N_VMakeManaged_Cuda(sunindextype length, realtype *vdata); +SUNDIALS_EXPORT N_Vector N_VMakeWithManagedAllocator_Cuda(sunindextype length, + void* (*allocfn)(size_t), + void (*freefn)(void*)); + SUNDIALS_EXPORT sunindextype N_VGetLength_Cuda(N_Vector v); SUNDIALS_EXPORT realtype *N_VGetHostArrayPointer_Cuda(N_Vector v); @@ -153,6 +157,11 @@ SUNDIALS_EXPORT int N_VWrmsNormMaskVectorArray_Cuda(int nvec, N_Vector* X, N_Vector* W, N_Vector id, realtype* nrm); +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VWSqrSumLocal_Cuda(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal_Cuda(N_Vector x, N_Vector w, N_Vector id); + + /* * ----------------------------------------------------------------- * Enable / disable fused vector operations diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_manyvector.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_manyvector.h new file mode 100644 index 000000000..813fd56a6 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_manyvector.h @@ -0,0 +1,163 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------- + * This is the main header file for the "ManyVector" implementation + * of the NVECTOR module. + * + * Notes: + * + * - The definition of the generic N_Vector structure can be found + * in the header file sundials_nvector.h. + * + * - The definitions of the types 'realtype' and 'sunindextype' can + * be found in the header file sundials_types.h, and it may be + * changed (at the configuration stage) according to the user's needs. + * The sundials_types.h file also contains the definition + * for the type 'booleantype'. + * + * - N_Vector arguments to arithmetic vector operations need not + * be distinct. For example, the following call: + * + * N_VLinearSum_ManyVector(a,x,b,y,y); + * + * (which stores the result of the operation a*x+b*y in y) + * is legal. + * -----------------------------------------------------------------*/ + +#ifndef _NVECTOR_MANY_VECTOR_H +#define _NVECTOR_MANY_VECTOR_H + +#include +#include + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------------------------------------------------------- + ManyVector implementation of N_Vector + ----------------------------------------------------------------- */ + +struct _N_VectorContent_ManyVector { + sunindextype num_subvectors; /* number of vectors attached */ + sunindextype global_length; /* overall manyvector length */ + N_Vector* subvec_array; /* pointer to N_Vector array */ + booleantype own_data; /* flag indicating data ownership */ +}; + +typedef struct _N_VectorContent_ManyVector *N_VectorContent_ManyVector; + +/* ----------------------------------------------------------------- + functions exported by ManyVector + ----------------------------------------------------------------- */ + +SUNDIALS_EXPORT N_Vector N_VNew_ManyVector(sunindextype num_subvectors, + N_Vector *vec_array); + +SUNDIALS_EXPORT N_Vector N_VGetSubvector_ManyVector(N_Vector v, + sunindextype vec_num); + +SUNDIALS_EXPORT realtype *N_VGetSubvectorArrayPointer_ManyVector(N_Vector v, + sunindextype vec_num); + +SUNDIALS_EXPORT int N_VSetSubvectorArrayPointer_ManyVector(realtype *v_data, N_Vector v, + sunindextype vec_num); + +SUNDIALS_EXPORT sunindextype N_VGetNumSubvectors_ManyVector(N_Vector v); + +/* standard vector operations */ +SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID_ManyVector(N_Vector v); +SUNDIALS_EXPORT N_Vector N_VCloneEmpty_ManyVector(N_Vector w); +SUNDIALS_EXPORT N_Vector N_VClone_ManyVector(N_Vector w); +SUNDIALS_EXPORT void N_VDestroy_ManyVector(N_Vector v); +SUNDIALS_EXPORT void N_VSpace_ManyVector(N_Vector v, sunindextype *lrw, + sunindextype *liw); +SUNDIALS_EXPORT sunindextype N_VGetLength_ManyVector(N_Vector v); +SUNDIALS_EXPORT void N_VLinearSum_ManyVector(realtype a, N_Vector x, + realtype b, N_Vector y, + N_Vector z); +SUNDIALS_EXPORT void N_VConst_ManyVector(realtype c, N_Vector z); +SUNDIALS_EXPORT void N_VProd_ManyVector(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VDiv_ManyVector(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VScale_ManyVector(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAbs_ManyVector(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VInv_ManyVector(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAddConst_ManyVector(N_Vector x, realtype b, + N_Vector z); +SUNDIALS_EXPORT realtype N_VWrmsNorm_ManyVector(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWrmsNormMask_ManyVector(N_Vector x, N_Vector w, + N_Vector id); +SUNDIALS_EXPORT realtype N_VWL2Norm_ManyVector(N_Vector x, N_Vector w); +SUNDIALS_EXPORT void N_VCompare_ManyVector(realtype c, N_Vector x, N_Vector z); + +/* fused vector operations */ +SUNDIALS_EXPORT int N_VLinearCombination_ManyVector(int nvec, realtype* c, + N_Vector* V, N_Vector z); +SUNDIALS_EXPORT int N_VScaleAddMulti_ManyVector(int nvec, realtype* a, + N_Vector x, N_Vector* Y, + N_Vector* Z); +SUNDIALS_EXPORT int N_VDotProdMulti_ManyVector(int nvec, N_Vector x, + N_Vector *Y, + realtype* dotprods); + +/* vector array operations */ +SUNDIALS_EXPORT int N_VLinearSumVectorArray_ManyVector(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z); +SUNDIALS_EXPORT int N_VScaleVectorArray_ManyVector(int nvec, realtype* c, + N_Vector* X, N_Vector* Z); +SUNDIALS_EXPORT int N_VConstVectorArray_ManyVector(int nvecs, realtype c, + N_Vector* Z); +SUNDIALS_EXPORT int N_VWrmsNormVectorArray_ManyVector(int nvecs, N_Vector* X, + N_Vector* W, realtype* nrm); +SUNDIALS_EXPORT int N_VWrmsNormMaskVectorArray_ManyVector(int nvec, + N_Vector* X, + N_Vector* W, + N_Vector id, + realtype* nrm); + +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VDotProdLocal_ManyVector(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNormLocal_ManyVector(N_Vector x); +SUNDIALS_EXPORT realtype N_VMinLocal_ManyVector(N_Vector x); +SUNDIALS_EXPORT realtype N_VL1NormLocal_ManyVector(N_Vector x); +SUNDIALS_EXPORT realtype N_VWSqrSumLocal_ManyVector(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal_ManyVector(N_Vector x, N_Vector w, + N_Vector id); +SUNDIALS_EXPORT booleantype N_VInvTestLocal_ManyVector(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMaskLocal_ManyVector(N_Vector c, N_Vector x, + N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotientLocal_ManyVector(N_Vector num, + N_Vector denom); + +/* ----------------------------------------------------------------- + Enable / disable fused vector operations + ----------------------------------------------------------------- */ + +SUNDIALS_EXPORT int N_VEnableFusedOps_ManyVector(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearCombination_ManyVector(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMulti_ManyVector(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableDotProdMulti_ManyVector(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearSumVectorArray_ManyVector(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleVectorArray_ManyVector(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableConstVectorArray_ManyVector(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormVectorArray_ManyVector(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormMaskVectorArray_ManyVector(N_Vector v, booleantype tf); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_mpicuda.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_mpicuda.h deleted file mode 100644 index b51b8e634..000000000 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_mpicuda.h +++ /dev/null @@ -1,194 +0,0 @@ -/* ----------------------------------------------------------------- - * Programmer(s): Cody Balos @ LLNL - * ----------------------------------------------------------------- - * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security - * and Southern Methodist University. - * All rights reserved. - * - * See the top-level LICENSE and NOTICE files for details. - * - * SPDX-License-Identifier: BSD-3-Clause - * SUNDIALS Copyright End - * ----------------------------------------------------------------- - * This is the header file for the MPI+CUDA implementation of the - * NVECTOR module. - * - * Notes: - * - * - The definition of the generic N_Vector structure can be found - * in the header file sundials_nvector.h. - * - * - The definitions of the types 'realtype' and 'sunindextype' can - * be found in the header file sundials_types.h, and it may be - * changed (at the configuration stage) according to the user's needs. - * The sundials_types.h file also contains the definition - * for the type 'booleantype'. - * - * - N_Vector arguments to arithmetic vector operations need not - * be distinct. For example, the following call: - * - * N_VLinearSum_Cuda(a,x,b,y,y); - * - * (which stores the result of the operation a*x+b*y in y) - * is legal. - * -----------------------------------------------------------------*/ - -#ifndef _NVECTOR_CUDA_H -#define _NVECTOR_CUDA_H - -#include -#include - -#include -#include - -#ifdef __cplusplus /* wrapper to enable C++ usage */ -extern "C" { -#endif - -/* - * ----------------------------------------------------------------- - * MPI+CUDA implementation of N_Vector - * ----------------------------------------------------------------- - */ - -/* - * CUDA implementation of the N_Vector 'content' is in C++ class - * Vector. The class inherits from structure _N_VectorContent_Cuda - * to create C <--> C++ interface. - */ - -struct _N_VectorContent_Cuda {}; - -typedef struct _N_VectorContent_Cuda *N_VectorContent_Cuda; - -/* - * ----------------------------------------------------------------- - * Functions exported by nvector_mpicuda - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT N_Vector N_VNew_Cuda(MPI_Comm comm, - sunindextype local_length, - sunindextype global_length); - -SUNDIALS_EXPORT N_Vector N_VNewManaged_Cuda(MPI_Comm comm, - sunindextype local_length, - sunindextype global_length); - -SUNDIALS_EXPORT N_Vector N_VNewEmpty_Cuda(); - -SUNDIALS_EXPORT N_Vector N_VMake_Cuda(MPI_Comm comm, - sunindextype local_length, - sunindextype global_length, - realtype *h_vdata, - realtype *d_vdata); - -SUNDIALS_EXPORT N_Vector N_VMakeManaged_Cuda(MPI_Comm comm, - sunindextype local_length, - sunindextype global_length, - realtype *vdata); - -SUNDIALS_EXPORT sunindextype N_VGetLength_Cuda(N_Vector v); - -SUNDIALS_EXPORT sunindextype N_VGetLocalLength_Cuda(N_Vector v); - -SUNDIALS_EXPORT MPI_Comm N_VGetMPIComm_Cuda(N_Vector v); - -SUNDIALS_EXPORT realtype *N_VGetHostArrayPointer_Cuda(N_Vector v); - -SUNDIALS_EXPORT realtype *N_VGetDeviceArrayPointer_Cuda(N_Vector v); - -SUNDIALS_EXPORT booleantype N_VIsManagedMemory_Cuda(N_Vector x); - -SUNDIALS_EXPORT void N_VSetCudaStream_Cuda(N_Vector x, cudaStream_t *stream); - -SUNDIALS_EXPORT void N_VCopyToDevice_Cuda(N_Vector v); - -SUNDIALS_EXPORT void N_VCopyFromDevice_Cuda(N_Vector v); - -SUNDIALS_EXPORT void N_VPrint_Cuda(N_Vector v); - -SUNDIALS_EXPORT void N_VPrintFile_Cuda(N_Vector v, FILE *outfile); - -SUNDIALS_EXPORT N_Vector N_VCloneEmpty_Cuda(N_Vector w); -SUNDIALS_EXPORT N_Vector N_VClone_Cuda(N_Vector w); -SUNDIALS_EXPORT void N_VDestroy_Cuda(N_Vector v); -SUNDIALS_EXPORT void N_VSpace_Cuda(N_Vector v, sunindextype *lrw, sunindextype *liw); - -/* standard vector operations */ -SUNDIALS_EXPORT void N_VLinearSum_Cuda(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); -SUNDIALS_EXPORT void N_VConst_Cuda(realtype c, N_Vector z); -SUNDIALS_EXPORT void N_VProd_Cuda(N_Vector x, N_Vector y, N_Vector z); -SUNDIALS_EXPORT void N_VDiv_Cuda(N_Vector x, N_Vector y, N_Vector z); -SUNDIALS_EXPORT void N_VScale_Cuda(realtype c, N_Vector x, N_Vector z); -SUNDIALS_EXPORT void N_VAbs_Cuda(N_Vector x, N_Vector z); -SUNDIALS_EXPORT void N_VInv_Cuda(N_Vector x, N_Vector z); -SUNDIALS_EXPORT void N_VAddConst_Cuda(N_Vector x, realtype b, N_Vector z); -SUNDIALS_EXPORT realtype N_VDotProd_Cuda(N_Vector x, N_Vector y); -SUNDIALS_EXPORT realtype N_VMaxNorm_Cuda(N_Vector x); -SUNDIALS_EXPORT realtype N_VWrmsNorm_Cuda(N_Vector x, N_Vector w); -SUNDIALS_EXPORT realtype N_VWrmsNormMask_Cuda(N_Vector x, N_Vector w, N_Vector id); -SUNDIALS_EXPORT realtype N_VMin_Cuda(N_Vector x); -SUNDIALS_EXPORT realtype N_VWL2Norm_Cuda(N_Vector x, N_Vector w); -SUNDIALS_EXPORT realtype N_VL1Norm_Cuda(N_Vector x); -SUNDIALS_EXPORT void N_VCompare_Cuda(realtype c, N_Vector x, N_Vector z); -SUNDIALS_EXPORT booleantype N_VInvTest_Cuda(N_Vector x, N_Vector z); -SUNDIALS_EXPORT booleantype N_VConstrMask_Cuda(N_Vector c, N_Vector x, N_Vector m); -SUNDIALS_EXPORT realtype N_VMinQuotient_Cuda(N_Vector num, N_Vector denom); - -/* fused vector operations */ -SUNDIALS_EXPORT int N_VLinearCombination_Cuda(int nvec, realtype* c, N_Vector* X, - N_Vector Z); -SUNDIALS_EXPORT int N_VScaleAddMulti_Cuda(int nvec, realtype* c, N_Vector X, - N_Vector* Y, N_Vector* Z); -SUNDIALS_EXPORT int N_VDotProdMulti_Cuda(int nvec, N_Vector x, N_Vector* Y, - realtype* dotprods); - -/* vector array operations */ -SUNDIALS_EXPORT int N_VLinearSumVectorArray_Cuda(int nvec, - realtype a, N_Vector* X, - realtype b, N_Vector* Y, - N_Vector* Z); -SUNDIALS_EXPORT int N_VScaleVectorArray_Cuda(int nvec, realtype* c, N_Vector* X, - N_Vector* Z); -SUNDIALS_EXPORT int N_VConstVectorArray_Cuda(int nvec, realtype c, N_Vector* Z); -SUNDIALS_EXPORT int N_VScaleAddMultiVectorArray_Cuda(int nvec, int nsum, - realtype* a, N_Vector* X, - N_Vector** Y, N_Vector** Z); -SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_Cuda(int nvec, int nsum, - realtype* c, - N_Vector** X, - N_Vector* Z); -SUNDIALS_EXPORT int N_VWrmsNormVectorArray_Cuda(int nvec, N_Vector* X, - N_Vector* W, realtype* nrm); -SUNDIALS_EXPORT int N_VWrmsNormMaskVectorArray_Cuda(int nvec, N_Vector* X, - N_Vector* W, N_Vector id, - realtype* nrm); - -/* - * ----------------------------------------------------------------- - * Enable / disable fused vector operations - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT int N_VEnableFusedOps_Cuda(N_Vector v, booleantype tf); - -SUNDIALS_EXPORT int N_VEnableLinearCombination_Cuda(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableScaleAddMulti_Cuda(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableDotProdMulti_Cuda(N_Vector v, booleantype tf); - -SUNDIALS_EXPORT int N_VEnableLinearSumVectorArray_Cuda(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableScaleVectorArray_Cuda(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableConstVectorArray_Cuda(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableWrmsNormVectorArray_Cuda(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableWrmsNormMaskVectorArray_Cuda(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableScaleAddMultiVectorArray_Cuda(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableLinearCombinationVectorArray_Cuda(N_Vector v, booleantype tf); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_mpimanyvector.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_mpimanyvector.h new file mode 100644 index 000000000..7e1039da9 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_mpimanyvector.h @@ -0,0 +1,180 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------- + * This is the main header file for the "MPIManyVector" implementation + * of the NVECTOR module. + * + * Notes: + * + * - The definition of the generic N_Vector structure can be found + * in the header file sundials_nvector.h. + * + * - The definitions of the types 'realtype' and 'sunindextype' can + * be found in the header file sundials_types.h, and it may be + * changed (at the configuration stage) according to the user's needs. + * The sundials_types.h file also contains the definition + * for the type 'booleantype'. + * + * - N_Vector arguments to arithmetic vector operations need not + * be distinct. For example, the following call: + * + * N_VLinearSum_MPIManyVector(a,x,b,y,y); + * + * (which stores the result of the operation a*x+b*y in y) + * is legal. + * -----------------------------------------------------------------*/ + +#ifndef _NVECTOR_MANY_VECTOR_H +#define _NVECTOR_MANY_VECTOR_H + +#include +#include +#include +#include + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------------------------------------------------------- + ManyVector implementation of N_Vector + ----------------------------------------------------------------- */ + +struct _N_VectorContent_MPIManyVector { + MPI_Comm comm; /* overall MPI communicator */ + sunindextype num_subvectors; /* number of vectors attached */ + sunindextype global_length; /* overall manyvector length */ + N_Vector* subvec_array; /* pointer to N_Vector array */ + booleantype own_data; /* flag indicating data ownership */ +}; + +typedef struct _N_VectorContent_MPIManyVector *N_VectorContent_MPIManyVector; + +/* ----------------------------------------------------------------- + functions exported by ManyVector + ----------------------------------------------------------------- */ + +SUNDIALS_EXPORT N_Vector N_VMake_MPIManyVector(MPI_Comm comm, + sunindextype num_subvectors, + N_Vector *vec_array); + +SUNDIALS_EXPORT N_Vector N_VNew_MPIManyVector(sunindextype num_subvectors, + N_Vector *vec_array); + +SUNDIALS_EXPORT N_Vector N_VGetSubvector_MPIManyVector(N_Vector v, + sunindextype vec_num); + +SUNDIALS_EXPORT realtype *N_VGetSubvectorArrayPointer_MPIManyVector(N_Vector v, + sunindextype vec_num); + +SUNDIALS_EXPORT int N_VSetSubvectorArrayPointer_MPIManyVector(realtype *v_data, N_Vector v, + sunindextype vec_num); + +SUNDIALS_EXPORT sunindextype N_VGetNumSubvectors_MPIManyVector(N_Vector v); + +/* standard vector operations */ +SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID_MPIManyVector(N_Vector v); +SUNDIALS_EXPORT N_Vector N_VCloneEmpty_MPIManyVector(N_Vector w); +SUNDIALS_EXPORT N_Vector N_VClone_MPIManyVector(N_Vector w); +SUNDIALS_EXPORT void N_VDestroy_MPIManyVector(N_Vector v); +SUNDIALS_EXPORT void N_VSpace_MPIManyVector(N_Vector v, sunindextype *lrw, + sunindextype *liw); +SUNDIALS_EXPORT void *N_VGetCommunicator_MPIManyVector(N_Vector v); +SUNDIALS_EXPORT sunindextype N_VGetLength_MPIManyVector(N_Vector v); +SUNDIALS_EXPORT void N_VLinearSum_MPIManyVector(realtype a, N_Vector x, + realtype b, N_Vector y, + N_Vector z); +SUNDIALS_EXPORT void N_VConst_MPIManyVector(realtype c, N_Vector z); +SUNDIALS_EXPORT void N_VProd_MPIManyVector(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VDiv_MPIManyVector(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VScale_MPIManyVector(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAbs_MPIManyVector(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VInv_MPIManyVector(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAddConst_MPIManyVector(N_Vector x, realtype b, + N_Vector z); +SUNDIALS_EXPORT realtype N_VDotProd_MPIManyVector(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNorm_MPIManyVector(N_Vector x); +SUNDIALS_EXPORT realtype N_VWrmsNorm_MPIManyVector(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWrmsNormMask_MPIManyVector(N_Vector x, N_Vector w, + N_Vector id); +SUNDIALS_EXPORT realtype N_VMin_MPIManyVector(N_Vector x); +SUNDIALS_EXPORT realtype N_VWL2Norm_MPIManyVector(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VL1Norm_MPIManyVector(N_Vector x); +SUNDIALS_EXPORT void N_VCompare_MPIManyVector(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VInvTest_MPIManyVector(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMask_MPIManyVector(N_Vector c, N_Vector x, + N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotient_MPIManyVector(N_Vector num, + N_Vector denom); + +/* fused vector operations */ +SUNDIALS_EXPORT int N_VLinearCombination_MPIManyVector(int nvec, realtype* c, + N_Vector* V, N_Vector z); +SUNDIALS_EXPORT int N_VScaleAddMulti_MPIManyVector(int nvec, realtype* a, + N_Vector x, N_Vector* Y, + N_Vector* Z); +SUNDIALS_EXPORT int N_VDotProdMulti_MPIManyVector(int nvec, N_Vector x, + N_Vector *Y, + realtype* dotprods); + +/* vector array operations */ +SUNDIALS_EXPORT int N_VLinearSumVectorArray_MPIManyVector(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z); +SUNDIALS_EXPORT int N_VScaleVectorArray_MPIManyVector(int nvec, realtype* c, + N_Vector* X, N_Vector* Z); +SUNDIALS_EXPORT int N_VConstVectorArray_MPIManyVector(int nvecs, realtype c, + N_Vector* Z); +SUNDIALS_EXPORT int N_VWrmsNormVectorArray_MPIManyVector(int nvecs, N_Vector* X, + N_Vector* W, realtype* nrm); +SUNDIALS_EXPORT int N_VWrmsNormMaskVectorArray_MPIManyVector(int nvec, + N_Vector* X, + N_Vector* W, + N_Vector id, + realtype* nrm); + +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VDotProdLocal_MPIManyVector(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNormLocal_MPIManyVector(N_Vector x); +SUNDIALS_EXPORT realtype N_VMinLocal_MPIManyVector(N_Vector x); +SUNDIALS_EXPORT realtype N_VL1NormLocal_MPIManyVector(N_Vector x); +SUNDIALS_EXPORT realtype N_VWSqrSumLocal_MPIManyVector(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal_MPIManyVector(N_Vector x, N_Vector w, + N_Vector id); +SUNDIALS_EXPORT booleantype N_VInvTestLocal_MPIManyVector(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMaskLocal_MPIManyVector(N_Vector c, N_Vector x, + N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotientLocal_MPIManyVector(N_Vector num, + N_Vector denom); + +/* ----------------------------------------------------------------- + Enable / disable fused vector operations + ----------------------------------------------------------------- */ + +SUNDIALS_EXPORT int N_VEnableFusedOps_MPIManyVector(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearCombination_MPIManyVector(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMulti_MPIManyVector(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableDotProdMulti_MPIManyVector(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearSumVectorArray_MPIManyVector(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleVectorArray_MPIManyVector(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableConstVectorArray_MPIManyVector(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormVectorArray_MPIManyVector(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormMaskVectorArray_MPIManyVector(N_Vector v, booleantype tf); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_mpiplusx.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_mpiplusx.h new file mode 100644 index 000000000..f304685f2 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_mpiplusx.h @@ -0,0 +1,46 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Cody Balos @ LLNL + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------- + * This is the header file for the MPI+X implementation of the + * NVECTOR module. The MPIPlusX NVECTOR is really just an extension + * of the ManyVector. + * -----------------------------------------------------------------*/ + +#ifndef _NVECTOR_MPIPLUSX_H +#define _NVECTOR_MPIPLUSX_H + +#include +#include +#include + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +SUNDIALS_EXPORT N_Vector N_VMake_MPIPlusX(MPI_Comm comm, N_Vector X); + +SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID_MPIPlusX(N_Vector v); + +SUNDIALS_EXPORT realtype* N_VGetArrayPointer_MPIPlusX(N_Vector v); + +SUNDIALS_EXPORT void N_VSetArrayPointer_MPIPlusX(realtype *vdata, N_Vector v); + +SUNDIALS_EXPORT N_Vector N_VGetLocalVector_MPIPlusX(N_Vector v); + +SUNDIALS_EXPORT sunindextype N_VGetLocalLength_MPIPlusX(N_Vector v); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_mpiraja.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_mpiraja.h deleted file mode 100644 index 4915ea168..000000000 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_mpiraja.h +++ /dev/null @@ -1,180 +0,0 @@ -/* ----------------------------------------------------------------- - * Programmer(s): Cody Balos @ LLNL - * ----------------------------------------------------------------- - * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security - * and Southern Methodist University. - * All rights reserved. - * - * See the top-level LICENSE and NOTICE files for details. - * - * SPDX-License-Identifier: BSD-3-Clause - * SUNDIALS Copyright End - * ----------------------------------------------------------------- - * This is the header file for the MPI+RAJA implementation of the - * NVECTOR module. - * - * Part I contains declarations specific to the RAJA - * implementation of the supplied NVECTOR module. - * - * Part II contains the prototype for the constructor N_VNew_Raja - * as well as implementation-specific prototypes for various useful - * vector operations. - * - * Notes: - * - * - The definition of the generic N_Vector structure can be found - * in the header file sundials_nvector.h. - * - * - The definition of the type 'realtype' can be found in the - * header file sundials_types.h, and it may be changed (at the - * configuration stage) according to the user's needs. - * The sundials_types.h file also contains the definition - * for the type 'booleantype'. - * - * - N_Vector arguments to arithmetic vector operations need not - * be distinct. For example, the following call: - * - * N_VLinearSum_Raja(a,x,b,y,y); - * - * (which stores the result of the operation a*x+b*y in y) - * is legal. - * -----------------------------------------------------------------*/ - -#ifndef _NVECTOR_RAJA_H -#define _NVECTOR_RAJA_H - -#include -#include - -#include -#include - -#ifdef __cplusplus /* wrapper to enable C++ usage */ -extern "C" { -#endif - -/* - * ----------------------------------------------------------------- - * MPI+RAJA implementation of N_Vector - * ----------------------------------------------------------------- - */ - -/* RAJA implementation of the N_Vector 'content' structure - contains the length of the vector, a pointer to an array - of 'realtype' components, and a flag indicating ownership of - the data */ - -struct _N_VectorContent_Raja {}; - -typedef struct _N_VectorContent_Raja *N_VectorContent_Raja; - -/* - * ----------------------------------------------------------------- - * Functions exported by nvector_mpiraja - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT N_Vector N_VNew_Raja(MPI_Comm comm, - sunindextype local_length, - sunindextype global_length); - -SUNDIALS_EXPORT N_Vector N_VNewEmpty_Raja(); - -SUNDIALS_EXPORT N_Vector N_VMake_Raja(N_VectorContent_Raja c); - -SUNDIALS_EXPORT sunindextype N_VGetLength_Raja(N_Vector v); - -SUNDIALS_EXPORT sunindextype N_VGetLocalLength_Raja(N_Vector v); - -SUNDIALS_EXPORT MPI_Comm N_VGetMPIComm_Raja(N_Vector v); - -SUNDIALS_EXPORT realtype *N_VGetHostArrayPointer_Raja(N_Vector v); - -SUNDIALS_EXPORT realtype *N_VGetDeviceArrayPointer_Raja(N_Vector v); - -SUNDIALS_EXPORT void N_VCopyToDevice_Raja(N_Vector v); - -SUNDIALS_EXPORT void N_VCopyFromDevice_Raja(N_Vector v); - -SUNDIALS_EXPORT void N_VPrint_Raja(N_Vector v); - -SUNDIALS_EXPORT void N_VPrintFile_Raja(N_Vector v, FILE *outfile); - -SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID_Raja(N_Vector v); -SUNDIALS_EXPORT N_Vector N_VCloneEmpty_Raja(N_Vector w); -SUNDIALS_EXPORT N_Vector N_VClone_Raja(N_Vector w); -SUNDIALS_EXPORT void N_VDestroy_Raja(N_Vector v); -SUNDIALS_EXPORT void N_VSpace_Raja(N_Vector v, sunindextype *lrw, sunindextype *liw); -SUNDIALS_EXPORT realtype *N_VGetArrayPointer_Raja(N_Vector v); -SUNDIALS_EXPORT void N_VSetArrayPointer_Raja(realtype *v_data, N_Vector v); - -/* standard vector operations */ -SUNDIALS_EXPORT void N_VLinearSum_Raja(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); -SUNDIALS_EXPORT void N_VConst_Raja(realtype c, N_Vector z); -SUNDIALS_EXPORT void N_VProd_Raja(N_Vector x, N_Vector y, N_Vector z); -SUNDIALS_EXPORT void N_VDiv_Raja(N_Vector x, N_Vector y, N_Vector z); -SUNDIALS_EXPORT void N_VScale_Raja(realtype c, N_Vector x, N_Vector z); -SUNDIALS_EXPORT void N_VAbs_Raja(N_Vector x, N_Vector z); -SUNDIALS_EXPORT void N_VInv_Raja(N_Vector x, N_Vector z); -SUNDIALS_EXPORT void N_VAddConst_Raja(N_Vector x, realtype b, N_Vector z); -SUNDIALS_EXPORT realtype N_VDotProd_Raja(N_Vector x, N_Vector y); -SUNDIALS_EXPORT realtype N_VMaxNorm_Raja(N_Vector x); -SUNDIALS_EXPORT realtype N_VWrmsNorm_Raja(N_Vector x, N_Vector w); -SUNDIALS_EXPORT realtype N_VWrmsNormMask_Raja(N_Vector x, N_Vector w, N_Vector id); -SUNDIALS_EXPORT realtype N_VMin_Raja(N_Vector x); -SUNDIALS_EXPORT realtype N_VWL2Norm_Raja(N_Vector x, N_Vector w); -SUNDIALS_EXPORT realtype N_VL1Norm_Raja(N_Vector x); -SUNDIALS_EXPORT void N_VCompare_Raja(realtype c, N_Vector x, N_Vector z); -SUNDIALS_EXPORT booleantype N_VInvTest_Raja(N_Vector x, N_Vector z); -SUNDIALS_EXPORT booleantype N_VConstrMask_Raja(N_Vector c, N_Vector x, N_Vector m); -SUNDIALS_EXPORT realtype N_VMinQuotient_Raja(N_Vector num, N_Vector denom); - -/* fused vector operations */ -SUNDIALS_EXPORT int N_VLinearCombination_Raja(int nvec, realtype* c, N_Vector* X, - N_Vector z); -SUNDIALS_EXPORT int N_VScaleAddMulti_Raja(int nvec, realtype* c, N_Vector x, - N_Vector* Y, N_Vector* Z); - -/* vector array operations */ -SUNDIALS_EXPORT int N_VLinearSumVectorArray_Raja(int nvec, - realtype a, N_Vector* X, - realtype b, N_Vector* Y, - N_Vector* Z); -SUNDIALS_EXPORT int N_VScaleVectorArray_Raja(int nvec, realtype* c, N_Vector* X, - N_Vector* Z); -SUNDIALS_EXPORT int N_VConstVectorArray_Raja(int nvec, realtype c, N_Vector* Z); -SUNDIALS_EXPORT int N_VScaleAddMultiVectorArray_Raja(int nvec, int nsum, - realtype* a, - N_Vector* X, N_Vector** Y, - N_Vector** Z); -SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_Raja(int nvec, int nsum, - realtype* c, - N_Vector** X, - N_Vector* Z); - -/* - * ----------------------------------------------------------------- - * Enable / disable fused vector operations - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT int N_VEnableFusedOps_Raja(N_Vector v, booleantype tf); - -SUNDIALS_EXPORT int N_VEnableLinearCombination_Raja(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableScaleAddMulti_Raja(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableDotProdMulti_Raja(N_Vector v, booleantype tf); - -SUNDIALS_EXPORT int N_VEnableLinearSumVectorArray_Raja(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableScaleVectorArray_Raja(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableConstVectorArray_Raja(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableWrmsNormVectorArray_Raja(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableWrmsNormMaskVectorArray_Raja(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableScaleAddMultiVectorArray_Raja(N_Vector v, booleantype tf); -SUNDIALS_EXPORT int N_VEnableLinearCombinationVectorArray_Raja(N_Vector v, booleantype tf); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_openmp.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_openmp.h index 00d2c8a78..4ad02f190 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_openmp.h +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_openmp.h @@ -1,13 +1,13 @@ -/* ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): David J. Gardner and Carol S. Woodward @ LLNL * ----------------------------------------------------------------- - * Acknowledgements: This NVECTOR module is based on the NVECTOR - * Serial module by Scott D. Cohen, Alan C. - * Hindmarsh, Radu Serban, and Aaron Collier + * Acknowledgements: This NVECTOR module is based on the NVECTOR + * Serial module by Scott D. Cohen, Alan C. + * Hindmarsh, Radu Serban, and Aaron Collier * @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -25,8 +25,8 @@ * in the header file sundials_nvector.h. * * - The definition of the type 'realtype' can be found in the - * header file sundials_types.h, and it may be changed (at the - * configuration stage) according to the user's needs. + * header file sundials_types.h, and it may be changed (at the + * configuration stage) according to the user's needs. * The sundials_types.h file also contains the definition * for the type 'booleantype'. * @@ -96,11 +96,11 @@ SUNDIALS_EXPORT N_Vector N_VNewEmpty_OpenMP(sunindextype vec_length, int num_thr SUNDIALS_EXPORT N_Vector N_VMake_OpenMP(sunindextype vec_length, realtype *v_data, int num_threads); -SUNDIALS_EXPORT N_Vector *N_VCloneVectorArray_OpenMP(int count, N_Vector w); +SUNDIALS_EXPORT N_Vector* N_VCloneVectorArray_OpenMP(int count, N_Vector w); -SUNDIALS_EXPORT N_Vector *N_VCloneVectorArrayEmpty_OpenMP(int count, N_Vector w); +SUNDIALS_EXPORT N_Vector* N_VCloneVectorArrayEmpty_OpenMP(int count, N_Vector w); -SUNDIALS_EXPORT void N_VDestroyVectorArray_OpenMP(N_Vector *vs, int count); +SUNDIALS_EXPORT void N_VDestroyVectorArray_OpenMP(N_Vector* vs, int count); SUNDIALS_EXPORT sunindextype N_VGetLength_OpenMP(N_Vector v); @@ -144,10 +144,10 @@ SUNDIALS_EXPORT int N_VLinearCombination_OpenMP(int nvec, realtype* c, SUNDIALS_EXPORT int N_VScaleAddMulti_OpenMP(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Vector* Z); SUNDIALS_EXPORT int N_VDotProdMulti_OpenMP(int nvec, N_Vector x, - N_Vector *Y, realtype* dotprods); + N_Vector* Y, realtype* dotprods); /* vector array operations */ -SUNDIALS_EXPORT int N_VLinearSumVectorArray_OpenMP(int nvec, +SUNDIALS_EXPORT int N_VLinearSumVectorArray_OpenMP(int nvec, realtype a, N_Vector* X, realtype b, N_Vector* Y, N_Vector* Z); @@ -170,6 +170,12 @@ SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_OpenMP(int nvec, int nsum, N_Vector** X, N_Vector* Z); +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VWSqrSumLocal_OpenMP(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal_OpenMP(N_Vector x, N_Vector w, + N_Vector id); + + /* * ----------------------------------------------------------------- * Enable / disable fused vector operations diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_openmpdev.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_openmpdev.h index 250b57cad..3bfec9771 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_openmpdev.h +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_openmpdev.h @@ -7,7 +7,7 @@ * @ LLNL * ------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -39,8 +39,8 @@ * is legal. * -----------------------------------------------------------------*/ -#ifndef _NVECTOR_OPENMP_H -#define _NVECTOR_OPENMP_H +#ifndef _NVECTOR_OPENMPDEV_H +#define _NVECTOR_OPENMPDEV_H #include #include @@ -174,6 +174,12 @@ SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_OpenMPDEV(int nvec, int nsum N_Vector** X, N_Vector* Z); +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VWSqrSumLocal_OpenMPDEV(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal_OpenMPDEV(N_Vector x, N_Vector w, + N_Vector id); + + /* * ----------------------------------------------------------------- * Enable / disable fused vector operations diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_parallel.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_parallel.h index eaa87a857..65bfdf2f4 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_parallel.h +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_parallel.h @@ -3,7 +3,7 @@ * and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -103,11 +103,11 @@ SUNDIALS_EXPORT N_Vector N_VMake_Parallel(MPI_Comm comm, sunindextype global_length, realtype *v_data); -SUNDIALS_EXPORT N_Vector *N_VCloneVectorArray_Parallel(int count, N_Vector w); +SUNDIALS_EXPORT N_Vector* N_VCloneVectorArray_Parallel(int count, N_Vector w); -SUNDIALS_EXPORT N_Vector *N_VCloneVectorArrayEmpty_Parallel(int count, N_Vector w); +SUNDIALS_EXPORT N_Vector* N_VCloneVectorArrayEmpty_Parallel(int count, N_Vector w); -SUNDIALS_EXPORT void N_VDestroyVectorArray_Parallel(N_Vector *vs, int count); +SUNDIALS_EXPORT void N_VDestroyVectorArray_Parallel(N_Vector* vs, int count); SUNDIALS_EXPORT sunindextype N_VGetLength_Parallel(N_Vector v); @@ -125,6 +125,7 @@ SUNDIALS_EXPORT void N_VSpace_Parallel(N_Vector v, sunindextype *lrw, sunindextype *liw); SUNDIALS_EXPORT realtype *N_VGetArrayPointer_Parallel(N_Vector v); SUNDIALS_EXPORT void N_VSetArrayPointer_Parallel(realtype *v_data, N_Vector v); +SUNDIALS_EXPORT void *N_VGetCommunicator_Parallel(N_Vector v); /* standard vector operations */ SUNDIALS_EXPORT void N_VLinearSum_Parallel(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); @@ -153,7 +154,7 @@ SUNDIALS_EXPORT int N_VLinearCombination_Parallel(int nvec, realtype* c, N_Vecto SUNDIALS_EXPORT int N_VScaleAddMulti_Parallel(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Vector* Z); SUNDIALS_EXPORT int N_VDotProdMulti_Parallel(int nvec, N_Vector x, - N_Vector *Y, realtype* dotprods); + N_Vector* Y, realtype* dotprods); /* vector array operations */ SUNDIALS_EXPORT int N_VLinearSumVectorArray_Parallel(int nvec, @@ -179,6 +180,21 @@ SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_Parallel(int nvec, int nsum, N_Vector** X, N_Vector* Z); +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VDotProdLocal_Parallel(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNormLocal_Parallel(N_Vector x); +SUNDIALS_EXPORT realtype N_VMinLocal_Parallel(N_Vector x); +SUNDIALS_EXPORT realtype N_VL1NormLocal_Parallel(N_Vector x); +SUNDIALS_EXPORT realtype N_VWSqrSumLocal_Parallel(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal_Parallel(N_Vector x, N_Vector w, + N_Vector id); +SUNDIALS_EXPORT booleantype N_VInvTestLocal_Parallel(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMaskLocal_Parallel(N_Vector c, N_Vector x, + N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotientLocal_Parallel(N_Vector num, + N_Vector denom); + + /* * ----------------------------------------------------------------- * Enable / disable fused vector operations diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_parhyp.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_parhyp.h index 992a9913a..a60bed234 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_parhyp.h +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_parhyp.h @@ -1,12 +1,12 @@ /* ----------------------------------------------------------------- * Programmer(s): Jean M. Sexton @ SMU * Slaven Peles @ LLNL - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Based on work by: Scott D. Cohen, Alan C. Hindmarsh, Radu Serban, * and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -24,8 +24,8 @@ * found in the header file sundials_nvector.h. * * - The definition of the type realtype can be found in the - * header file sundials_types.h, and it may be changed (at the - * configuration stage) according to the user's needs. + * header file sundials_types.h, and it may be changed (at the + * configuration stage) according to the user's needs. * The sundials_types.h file also contains the definition * for the type booleantype. * @@ -55,7 +55,7 @@ extern "C" { /* * ----------------------------------------------------------------- - * ParHyp implementation of N_Vector + * ParHyp implementation of N_Vector * ----------------------------------------------------------------- */ @@ -77,7 +77,7 @@ typedef struct _N_VectorContent_ParHyp *N_VectorContent_ParHyp; * ----------------------------------------------------------------- */ -SUNDIALS_EXPORT N_Vector N_VNewEmpty_ParHyp(MPI_Comm comm, +SUNDIALS_EXPORT N_Vector N_VNewEmpty_ParHyp(MPI_Comm comm, sunindextype local_length, sunindextype global_length); @@ -102,6 +102,8 @@ SUNDIALS_EXPORT void N_VDestroy_ParHyp(N_Vector v); SUNDIALS_EXPORT void N_VSpace_ParHyp(N_Vector v, sunindextype *lrw, sunindextype *liw); SUNDIALS_EXPORT realtype *N_VGetArrayPointer_ParHyp(N_Vector v); SUNDIALS_EXPORT void N_VSetArrayPointer_ParHyp(realtype *v_data, N_Vector v); +SUNDIALS_EXPORT void *N_VGetCommunicator_ParHyp(N_Vector v); +SUNDIALS_EXPORT sunindextype N_VGetLength_ParHyp(N_Vector v); /* standard vector operations */ SUNDIALS_EXPORT void N_VLinearSum_ParHyp(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); @@ -133,7 +135,7 @@ SUNDIALS_EXPORT int N_VDotProdMulti_ParHyp(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods); /* vector array operations */ -SUNDIALS_EXPORT int N_VLinearSumVectorArray_ParHyp(int nvec, +SUNDIALS_EXPORT int N_VLinearSumVectorArray_ParHyp(int nvec, realtype a, N_Vector* X, realtype b, N_Vector* Y, N_Vector* Z); @@ -156,6 +158,21 @@ SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_ParHyp(int nvec, int nsum, N_Vector** X, N_Vector* Z); +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VDotProdLocal_ParHyp(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNormLocal_ParHyp(N_Vector x); +SUNDIALS_EXPORT realtype N_VMinLocal_ParHyp(N_Vector x); +SUNDIALS_EXPORT realtype N_VL1NormLocal_ParHyp(N_Vector x); +SUNDIALS_EXPORT realtype N_VWSqrSumLocal_ParHyp(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal_ParHyp(N_Vector x, N_Vector w, + N_Vector id); +SUNDIALS_EXPORT booleantype N_VInvTestLocal_ParHyp(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMaskLocal_ParHyp(N_Vector c, N_Vector x, + N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotientLocal_ParHyp(N_Vector num, + N_Vector denom); + + /* * ----------------------------------------------------------------- * Enable / disable fused vector operations diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_petsc.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_petsc.h index 8f7e11aa9..75f76ebf0 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_petsc.h +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_petsc.h @@ -1,8 +1,8 @@ -/* ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Slaven Peles @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -11,7 +11,7 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the main header file for the PETSc vector wrapper + * This is the main header file for the PETSc vector wrapper * for NVECTOR module. * * Notes: @@ -20,8 +20,8 @@ * found in the header file sundials_nvector.h. * * - The definition of the type realtype can be found in the - * header file sundials_types.h, and it may be changed (at the - * build configuration stage) according to the user's needs. + * header file sundials_types.h, and it may be changed (at the + * build configuration stage) according to the user's needs. * The sundials_types.h file also contains the definition * for the type booleantype. * @@ -48,7 +48,7 @@ extern "C" { /* * ----------------------------------------------------------------- - * PETSc implementation of N_Vector + * PETSc implementation of N_Vector * ----------------------------------------------------------------- */ @@ -68,7 +68,7 @@ typedef struct _N_VectorContent_Petsc *N_VectorContent_Petsc; * ----------------------------------------------------------------- */ -SUNDIALS_EXPORT N_Vector N_VNewEmpty_Petsc(MPI_Comm comm, +SUNDIALS_EXPORT N_Vector N_VNewEmpty_Petsc(MPI_Comm comm, sunindextype local_length, sunindextype global_length); @@ -84,16 +84,21 @@ SUNDIALS_EXPORT void N_VDestroyVectorArray_Petsc(N_Vector *vs, int count); SUNDIALS_EXPORT Vec N_VGetVector_Petsc(N_Vector v); +SUNDIALS_EXPORT void N_VSetVector_Petsc(N_Vector v, Vec p); + SUNDIALS_EXPORT void N_VPrint_Petsc(N_Vector v); SUNDIALS_EXPORT void N_VPrintFile_Petsc(N_Vector v, const char fname[]); +/* nvector API functions */ SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID_Petsc(N_Vector v); SUNDIALS_EXPORT N_Vector N_VCloneEmpty_Petsc(N_Vector w); SUNDIALS_EXPORT N_Vector N_VClone_Petsc(N_Vector w); SUNDIALS_EXPORT void N_VDestroy_Petsc(N_Vector v); SUNDIALS_EXPORT void N_VSpace_Petsc(N_Vector v, sunindextype *lrw, sunindextype *liw); SUNDIALS_EXPORT void N_VSetArrayPointer_Petsc(realtype *v_data, N_Vector v); +SUNDIALS_EXPORT void *N_VGetCommunicator_Petsc(N_Vector v); +SUNDIALS_EXPORT sunindextype N_VGetLength_Petsc(N_Vector v); /* standard vector operations */ SUNDIALS_EXPORT void N_VLinearSum_Petsc(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); @@ -125,7 +130,7 @@ SUNDIALS_EXPORT int N_VDotProdMulti_Petsc(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods); /* vector array operations */ -SUNDIALS_EXPORT int N_VLinearSumVectorArray_Petsc(int nvec, +SUNDIALS_EXPORT int N_VLinearSumVectorArray_Petsc(int nvec, realtype a, N_Vector* X, realtype b, N_Vector* Y, N_Vector* Z); @@ -148,6 +153,21 @@ SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_Petsc(int nvec, int nsum, N_Vector** X, N_Vector* Z); +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VDotProdLocal_Petsc(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNormLocal_Petsc(N_Vector x); +SUNDIALS_EXPORT realtype N_VMinLocal_Petsc(N_Vector x); +SUNDIALS_EXPORT realtype N_VL1NormLocal_Petsc(N_Vector x); +SUNDIALS_EXPORT realtype N_VWSqrSumLocal_Petsc(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal_Petsc(N_Vector x, N_Vector w, + N_Vector id); +SUNDIALS_EXPORT booleantype N_VInvTestLocal_Petsc(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMaskLocal_Petsc(N_Vector c, N_Vector x, + N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotientLocal_Petsc(N_Vector num, + N_Vector denom); + + /* * ----------------------------------------------------------------- * Enable / disable fused vector operations diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_pthreads.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_pthreads.h index 0fc029fa1..43c6b7ff1 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_pthreads.h +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_pthreads.h @@ -1,13 +1,13 @@ -/* ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------- - * Acknowledgements: This NVECTOR module is based on the NVECTOR - * Serial module by Scott D. Cohen, Alan C. - * Hindmarsh, Radu Serban, and Aaron Collier + * Acknowledgements: This NVECTOR module is based on the NVECTOR + * Serial module by Scott D. Cohen, Alan C. + * Hindmarsh, Radu Serban, and Aaron Collier * @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -16,7 +16,7 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the header file for the POSIX Threads (Pthreads) + * This is the header file for the POSIX Threads (Pthreads) * implementation of the NVECTOR module using LOCAL data structs * to share data between threads. * @@ -26,8 +26,8 @@ * in the header file sundials_nvector.h. * * - The definition of the type 'realtype' can be found in the - * header file sundials_types.h, and it may be changed (at the - * configuration stage) according to the user's needs. + * header file sundials_types.h, and it may be changed (at the + * configuration stage) according to the user's needs. * The sundials_types.h file also contains the definition * for the type 'booleantype'. * @@ -131,11 +131,11 @@ SUNDIALS_EXPORT N_Vector N_VNewEmpty_Pthreads(sunindextype vec_length, int n_thr SUNDIALS_EXPORT N_Vector N_VMake_Pthreads(sunindextype vec_length, int n_threads, realtype *v_data); -SUNDIALS_EXPORT N_Vector *N_VCloneVectorArray_Pthreads(int count, N_Vector w); +SUNDIALS_EXPORT N_Vector* N_VCloneVectorArray_Pthreads(int count, N_Vector w); -SUNDIALS_EXPORT N_Vector *N_VCloneVectorArrayEmpty_Pthreads(int count, N_Vector w); +SUNDIALS_EXPORT N_Vector* N_VCloneVectorArrayEmpty_Pthreads(int count, N_Vector w); -SUNDIALS_EXPORT void N_VDestroyVectorArray_Pthreads(N_Vector *vs, int count); +SUNDIALS_EXPORT void N_VDestroyVectorArray_Pthreads(N_Vector* vs, int count); SUNDIALS_EXPORT sunindextype N_VGetLength_Pthreads(N_Vector v); @@ -204,6 +204,11 @@ SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_Pthreads(int nvec, int nsum, N_Vector** X, N_Vector* Z); +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VWSqrSumLocal_Pthreads(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal_Pthreads(N_Vector x, N_Vector w, N_Vector id); + + /* * ----------------------------------------------------------------- * Enable / disable fused vector operations diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_raja.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_raja.h index 22d8e4d73..da8f13ed4 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_raja.h +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_raja.h @@ -2,7 +2,7 @@ * Programmer(s): Slaven Peles @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -138,6 +138,10 @@ SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_Raja(int nvec, int nsum, N_Vector** X, N_Vector* Z); +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VWSqrSumLocal_Raja(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal_Raja(N_Vector x, N_Vector w, N_Vector id); + /* * ----------------------------------------------------------------- * Enable / disable fused vector operations diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_serial.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_serial.h index 10bcffc26..bd78be57d 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_serial.h +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_serial.h @@ -3,7 +3,7 @@ * and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -88,11 +88,11 @@ SUNDIALS_EXPORT N_Vector N_VNewEmpty_Serial(sunindextype vec_length); SUNDIALS_EXPORT N_Vector N_VMake_Serial(sunindextype vec_length, realtype *v_data); -SUNDIALS_EXPORT N_Vector *N_VCloneVectorArray_Serial(int count, N_Vector w); +SUNDIALS_EXPORT N_Vector* N_VCloneVectorArray_Serial(int count, N_Vector w); -SUNDIALS_EXPORT N_Vector *N_VCloneVectorArrayEmpty_Serial(int count, N_Vector w); +SUNDIALS_EXPORT N_Vector* N_VCloneVectorArrayEmpty_Serial(int count, N_Vector w); -SUNDIALS_EXPORT void N_VDestroyVectorArray_Serial(N_Vector *vs, int count); +SUNDIALS_EXPORT void N_VDestroyVectorArray_Serial(N_Vector* vs, int count); SUNDIALS_EXPORT sunindextype N_VGetLength_Serial(N_Vector v); @@ -135,7 +135,7 @@ SUNDIALS_EXPORT int N_VLinearCombination_Serial(int nvec, realtype* c, N_Vector* SUNDIALS_EXPORT int N_VScaleAddMulti_Serial(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Vector* Z); SUNDIALS_EXPORT int N_VDotProdMulti_Serial(int nvec, N_Vector x, - N_Vector *Y, realtype* dotprods); + N_Vector* Y, realtype* dotprods); /* vector array operations */ SUNDIALS_EXPORT int N_VLinearSumVectorArray_Serial(int nvec, @@ -161,6 +161,10 @@ SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_Serial(int nvec, int nsum, N_Vector** X, N_Vector* Z); +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VWSqrSumLocal_Serial(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal_Serial(N_Vector x, N_Vector w, N_Vector id); + /* * ----------------------------------------------------------------- * Enable / disable fused vector operations diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_trilinos.h b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_trilinos.h index 9ffcdc301..4cce9ee1f 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_trilinos.h +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/nvector_trilinos.h @@ -2,7 +2,7 @@ * Programmer(s): Slaven Peles @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -98,6 +98,8 @@ SUNDIALS_EXPORT N_Vector N_VCloneEmpty_Trilinos(N_Vector w); SUNDIALS_EXPORT N_Vector N_VClone_Trilinos(N_Vector w); SUNDIALS_EXPORT void N_VDestroy_Trilinos(N_Vector v); SUNDIALS_EXPORT void N_VSpace_Trilinos(N_Vector v, sunindextype *lrw, sunindextype *liw); +SUNDIALS_EXPORT void *N_VGetCommunicator_Trilinos(N_Vector v); +SUNDIALS_EXPORT sunindextype N_VGetLength_Trilinos(N_Vector v); SUNDIALS_EXPORT void N_VLinearSum_Trilinos(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); SUNDIALS_EXPORT void N_VConst_Trilinos(realtype c, N_Vector z); SUNDIALS_EXPORT void N_VProd_Trilinos(N_Vector x, N_Vector y, N_Vector z); @@ -118,6 +120,20 @@ SUNDIALS_EXPORT booleantype N_VInvTest_Trilinos(N_Vector x, N_Vector z); SUNDIALS_EXPORT booleantype N_VConstrMask_Trilinos(N_Vector c, N_Vector x, N_Vector m); SUNDIALS_EXPORT realtype N_VMinQuotient_Trilinos(N_Vector num, N_Vector denom); +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VDotProdLocal_Trilinos(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNormLocal_Trilinos(N_Vector x); +SUNDIALS_EXPORT realtype N_VMinLocal_Trilinos(N_Vector x); +SUNDIALS_EXPORT realtype N_VL1NormLocal_Trilinos(N_Vector x); +SUNDIALS_EXPORT realtype N_VWSqrSumLocal_Trilinos(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal_Trilinos(N_Vector x, N_Vector w, + N_Vector id); +SUNDIALS_EXPORT booleantype N_VInvTestLocal_Trilinos(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMaskLocal_Trilinos(N_Vector c, N_Vector x, + N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotientLocal_Trilinos(N_Vector num, + N_Vector denom); + #ifdef __cplusplus } #endif diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/raja/Vector.hpp b/deps/AMICI/ThirdParty/sundials/include/nvector/raja/Vector.hpp index b032d93f2..4ae004a60 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/raja/Vector.hpp +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/raja/Vector.hpp @@ -3,7 +3,7 @@ * Programmer(s): Slaven Peles @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -29,13 +29,7 @@ #include #include -#include - -#if SUNDIALS_MPI_ENABLED -#include -#else #include -#endif namespace sunrajavec { @@ -46,18 +40,7 @@ class Vector : public _N_VectorContent_Raja public: Vector(I N) : size_(N), - mem_size_(N*sizeof(T)), - global_size_(N), - comm_(0) - { - allocate(); - } - - Vector(SUNMPI_Comm comm, I N, I Nglobal) - : size_(N), - mem_size_(N*sizeof(T)), - global_size_(Nglobal), - comm_(comm) + mem_size_(N*sizeof(T)) { allocate(); } @@ -65,9 +48,7 @@ class Vector : public _N_VectorContent_Raja // Copy constructor does not copy values explicit Vector(const Vector& v) : size_(v.size()), - mem_size_(size_*sizeof(T)), - global_size_(v.global_size_), - comm_(v.comm_) + mem_size_(size_*sizeof(T)) { allocate(); } @@ -98,16 +79,6 @@ class Vector : public _N_VectorContent_Raja return size_; } - int sizeGlobal() const - { - return global_size_; - } - - SUNMPI_Comm comm() - { - return comm_; - } - T* host() { return h_vec_; @@ -145,10 +116,8 @@ class Vector : public _N_VectorContent_Raja private: I size_; I mem_size_; - I global_size_; T* h_vec_; T* d_vec_; - SUNMPI_Comm comm_; }; diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/trilinos/SundialsTpetraVectorInterface.hpp b/deps/AMICI/ThirdParty/sundials/include/nvector/trilinos/SundialsTpetraVectorInterface.hpp index 2cef0e6cf..ac529f445 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/trilinos/SundialsTpetraVectorInterface.hpp +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/trilinos/SundialsTpetraVectorInterface.hpp @@ -2,7 +2,7 @@ * Programmer(s): Slaven Peles @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/nvector/trilinos/SundialsTpetraVectorKernels.hpp b/deps/AMICI/ThirdParty/sundials/include/nvector/trilinos/SundialsTpetraVectorKernels.hpp index b435e7144..bdc35fb2d 100644 --- a/deps/AMICI/ThirdParty/sundials/include/nvector/trilinos/SundialsTpetraVectorKernels.hpp +++ b/deps/AMICI/ThirdParty/sundials/include/nvector/trilinos/SundialsTpetraVectorKernels.hpp @@ -2,7 +2,7 @@ * Programmer(s): Slaven Peles @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -58,7 +58,8 @@ namespace Sundials const vector_type& y, vector_type& z) { - const local_ordinal_type N = x.getLocalLength(); + const local_ordinal_type N = + static_cast(x.getLocalLength()); if (x.need_sync()) const_cast(x).sync(); @@ -88,7 +89,8 @@ namespace Sundials scalar_type b, vector_type& z) { - const local_ordinal_type N = x.getLocalLength(); + const local_ordinal_type N = + static_cast(x.getLocalLength()); if (x.need_sync()) const_cast(x).sync(); @@ -116,7 +118,8 @@ namespace Sundials const vector_type& x, vector_type& z) { - const local_ordinal_type N = x.getLocalLength(); + const local_ordinal_type N = + static_cast(x.getLocalLength()); if (x.need_sync()) const_cast(x).sync(); @@ -148,8 +151,10 @@ namespace Sundials const vector_type& w) { const Teuchos::RCP >& comm = x.getMap()->getComm(); - const local_ordinal_type N = x.getLocalLength(); - const global_ordinal_type Nglob = x.getGlobalLength(); + const local_ordinal_type N = + static_cast(x.getLocalLength()); + const global_ordinal_type Nglob = + static_cast(x.getGlobalLength()); if (x.need_sync()) const_cast(x).sync(); @@ -180,8 +185,10 @@ namespace Sundials const vector_type& id) { const Teuchos::RCP >& comm = x.getMap()->getComm(); - const local_ordinal_type N = x.getLocalLength(); - const global_ordinal_type Nglob = x.getGlobalLength(); + const local_ordinal_type N = + static_cast(x.getLocalLength()); + const global_ordinal_type Nglob = + static_cast(x.getGlobalLength()); if (x.need_sync()) const_cast(x).sync(); @@ -217,7 +224,8 @@ namespace Sundials using namespace Kokkos; const Teuchos::RCP >& comm = x.getMap()->getComm(); - const local_ordinal_type N = x.getLocalLength(); + const local_ordinal_type N = + static_cast(x.getLocalLength()); if (x.need_sync()) const_cast(x).sync(); @@ -245,7 +253,8 @@ namespace Sundials const vector_type& w) { const Teuchos::RCP >& comm = x.getMap()->getComm(); - const local_ordinal_type N = x.getLocalLength(); + const local_ordinal_type N = + static_cast(x.getLocalLength()); if (x.need_sync()) const_cast(x).sync(); @@ -277,7 +286,8 @@ namespace Sundials using namespace Kokkos; const Teuchos::RCP >& comm = x.getMap()->getComm(); - const local_ordinal_type N = x.getLocalLength(); + const local_ordinal_type N = + static_cast(x.getLocalLength()); if (x.need_sync()) const_cast(x).sync(); @@ -319,7 +329,8 @@ namespace Sundials vector_type& m) { const Teuchos::RCP >& comm = x.getMap()->getComm(); - const local_ordinal_type N = x.getLocalLength(); + const local_ordinal_type N = + static_cast(x.getLocalLength()); if (c.need_sync()) const_cast(c).sync(); @@ -335,18 +346,18 @@ namespace Sundials m.modify(); - scalar_type sum = zero; + mag_type sum = zero; Kokkos::parallel_reduce ("constraintMask", Kokkos::RangePolicy(0, N), - KOKKOS_LAMBDA (const local_ordinal_type &i, scalar_type &local_sum) + KOKKOS_LAMBDA (const local_ordinal_type &i, mag_type &local_sum) { - const bool test = (abs(c_1d(i)) > onept5 && c_1d(i)*x_1d(i) <= zero) || - (abs(c_1d(i)) > half && c_1d(i)*x_1d(i) < zero); + const bool test = (std::abs(c_1d(i)) > onept5 && c_1d(i)*x_1d(i) <= zero) || + (std::abs(c_1d(i)) > half && c_1d(i)*x_1d(i) < zero); m_1d(i) = test ? one : zero; local_sum += m_1d(i); }, sum); - scalar_type globalSum = zero; - reduceAll(*comm, REDUCE_SUM, sum, outArg(globalSum)); + mag_type globalSum = zero; + reduceAll(*comm, REDUCE_SUM, sum, outArg(globalSum)); return (globalSum < half); } @@ -358,7 +369,8 @@ namespace Sundials using namespace Kokkos; const Teuchos::RCP >& comm = num.getMap()->getComm(); - const local_ordinal_type N = num.getLocalLength(); + const local_ordinal_type N = + static_cast(num.getLocalLength()); if (num.need_sync()) const_cast(num).sync(); @@ -386,6 +398,276 @@ namespace Sundials } + /// MPI task-local dot-product + inline scalar_type dotProdLocal(const vector_type& x, + const vector_type& y) + { + const local_ordinal_type N = + static_cast(x.getLocalLength()); + if (x.need_sync()) + const_cast(x).sync(); + if (y.need_sync()) + const_cast(y).sync(); + + auto x_2d = x.getLocalView(); + auto x_1d = Kokkos::subview (x_2d, Kokkos::ALL(), 0); + auto y_2d = y.getLocalView(); + auto y_1d = Kokkos::subview (y_2d, Kokkos::ALL(), 0); + + scalar_type sum = zero; + Kokkos::parallel_reduce ("dotProdLocal", Kokkos::RangePolicy(0, N), + KOKKOS_LAMBDA (const local_ordinal_type &i, scalar_type &local_sum) + { + local_sum += x_1d(i)*y_1d(i); + }, sum); + + return sum; + } + + + /// MPI task-local maximum norm of a vector + inline mag_type maxNormLocal(const vector_type& x) + { + using namespace Kokkos; + + const local_ordinal_type N = + static_cast(x.getLocalLength()); + if (x.need_sync()) + const_cast(x).sync(); + + auto x_2d = x.getLocalView(); + auto x_1d = Kokkos::subview (x_2d, Kokkos::ALL(), 0); + + mag_type maximum; + Max max_reducer(maximum); + + Kokkos::parallel_reduce ("maxNormLocal", Kokkos::RangePolicy(0, N), + KOKKOS_LAMBDA (const local_ordinal_type &i, mag_type &local_max) + { + max_reducer.join(local_max, std::abs(x_1d(i))); + }, max_reducer); + + return maximum; + } + + + /// MPI task-local minimum element in the vector + inline scalar_type minLocal(const vector_type& x) + { + using namespace Kokkos; + + const local_ordinal_type N = + static_cast(x.getLocalLength()); + if (x.need_sync()) + const_cast(x).sync(); + + auto x_2d = x.getLocalView(); + auto x_1d = Kokkos::subview (x_2d, Kokkos::ALL(), 0); + + scalar_type minimum; + Min min_reducer(minimum); + + Kokkos::parallel_reduce ("minElement", Kokkos::RangePolicy(0, N), + KOKKOS_LAMBDA (const local_ordinal_type &i, scalar_type &local_min) + { + min_reducer.join(local_min, x_1d(i)); + }, min_reducer); + + return minimum; + } + + + /// MPI task-local L1 norm of a vector + inline mag_type L1NormLocal(const vector_type& x) + { + using namespace Kokkos; + + const local_ordinal_type N = + static_cast(x.getLocalLength()); + if (x.need_sync()) + const_cast(x).sync(); + + auto x_2d = x.getLocalView(); + auto x_1d = Kokkos::subview (x_2d, Kokkos::ALL(), 0); + + mag_type sum = zero; + Kokkos::parallel_reduce ("L1NormLocal", Kokkos::RangePolicy(0, N), + KOKKOS_LAMBDA (const local_ordinal_type &i, mag_type &local_sum) + { + local_sum += std::abs(x_1d(i)); + }, sum); + + return sum; + } + + + /// MPI task-local weighted squared sum + inline mag_type WSqrSumLocal(const vector_type& x, + const vector_type& w) + { + const local_ordinal_type N = + static_cast(x.getLocalLength()); + if (x.need_sync()) + const_cast(x).sync(); + if (w.need_sync()) + const_cast(w).sync(); + + auto x_2d = x.getLocalView(); + auto x_1d = Kokkos::subview (x_2d, Kokkos::ALL(), 0); + auto w_2d = w.getLocalView(); + auto w_1d = Kokkos::subview (w_2d, Kokkos::ALL(), 0); + + mag_type sum = zero; + Kokkos::parallel_reduce ("WSqrSumLocal", Kokkos::RangePolicy(0, N), + KOKKOS_LAMBDA (const local_ordinal_type &i, mag_type &local_sum) + { + local_sum += x_1d(i)*w_1d(i)*(x_1d(i)*w_1d(i)); + }, sum); + + return sum; + } + + + /// MPI task-local weighted squared masked sum + inline mag_type WSqrSumMaskLocal(const vector_type& x, + const vector_type& w, + const vector_type& id) + { + const local_ordinal_type N = + static_cast(x.getLocalLength()); + if (x.need_sync()) + const_cast(x).sync(); + if (w.need_sync()) + const_cast(w).sync(); + if (id.need_sync()) + const_cast(id).sync(); + + auto x_2d = x.getLocalView(); + auto x_1d = Kokkos::subview (x_2d, Kokkos::ALL(), 0); + auto w_2d = w.getLocalView(); + auto w_1d = Kokkos::subview (w_2d, Kokkos::ALL(), 0); + auto id_2d = id.getLocalView(); + auto id_1d = Kokkos::subview (id_2d, Kokkos::ALL(), 0); + + mag_type sum = zero; + Kokkos::parallel_reduce ("WSqrSumMaskLocal", Kokkos::RangePolicy(0, N), + KOKKOS_LAMBDA (const local_ordinal_type &i, mag_type &local_sum) + { + if (id_1d(i) > zero) + local_sum += x_1d(i)*w_1d(i)*(x_1d(i)*w_1d(i)); + }, sum); + + return sum; + } + + + /// MPI task-local elementwise inverse, return false if any denominator is zero. + inline bool invTestLocal(const vector_type& x, + vector_type& z) + { + using namespace Kokkos; + + const local_ordinal_type N = + static_cast(x.getLocalLength()); + if (x.need_sync()) + const_cast(x).sync(); + + auto x_2d = x.getLocalView(); + auto x_1d = Kokkos::subview (x_2d, Kokkos::ALL(), 0); + auto z_2d = z.getLocalView(); + auto z_1d = Kokkos::subview (z_2d, Kokkos::ALL(), 0); + + scalar_type minimum; + Min min_reducer(minimum); + + z.modify(); + + Kokkos::parallel_reduce ("invTestLocal", Kokkos::RangePolicy(0, N), + KOKKOS_LAMBDA (const local_ordinal_type &i, scalar_type &local_min) + { + static constexpr scalar_type zero = 0; + static constexpr scalar_type one = 1.0; + if (x_1d(i) == zero) + { + min_reducer.join(local_min, zero); + } + else + { + z_1d(i) = one/x_1d(i); + } + }, min_reducer); + + return (minimum > half); + } + + + /// MPI task-local constraint violation check + inline bool constraintMaskLocal(const vector_type& c, + const vector_type& x, + vector_type& m) + { + const local_ordinal_type N = + static_cast(x.getLocalLength()); + if (c.need_sync()) + const_cast(c).sync(); + if (x.need_sync()) + const_cast(x).sync(); + + auto c_2d = c.getLocalView(); + auto c_1d = Kokkos::subview (c_2d, Kokkos::ALL(), 0); + auto x_2d = x.getLocalView(); + auto x_1d = Kokkos::subview (x_2d, Kokkos::ALL(), 0); + auto m_2d = m.getLocalView(); + auto m_1d = Kokkos::subview (m_2d, Kokkos::ALL(), 0); + + m.modify(); + + mag_type sum = zero; + Kokkos::parallel_reduce ("constraintMaskLocal", Kokkos::RangePolicy(0, N), + KOKKOS_LAMBDA (const local_ordinal_type &i, mag_type &local_sum) + { + const bool test = (std::abs(c_1d(i)) > onept5 && c_1d(i)*x_1d(i) <= zero) || + (std::abs(c_1d(i)) > half && c_1d(i)*x_1d(i) < zero); + m_1d(i) = test ? one : zero; + local_sum += m_1d(i); + }, sum); + + return (sum < half); + } + + + /// MPI task-local minimum quotient: min_i(num(i)/den(i)) + inline scalar_type minQuotientLocal(const vector_type& num, + const vector_type& den) + { + using namespace Kokkos; + + const local_ordinal_type N = + static_cast(num.getLocalLength()); + if (num.need_sync()) + const_cast(num).sync(); + if (den.need_sync()) + const_cast(den).sync(); + + auto num_2d = num.getLocalView(); + auto num_1d = Kokkos::subview (num_2d, Kokkos::ALL(), 0); + auto den_2d = den.getLocalView(); + auto den_1d = Kokkos::subview (den_2d, Kokkos::ALL(), 0); + + scalar_type minimum; + Min min_reducer(minimum); + + Kokkos::parallel_reduce ("minQuotient", Kokkos::RangePolicy(0, N), + KOKKOS_LAMBDA (const local_ordinal_type &i, scalar_type &local_min) + { + if (den_1d(i) != zero) + min_reducer.join(local_min, num_1d(i)/den_1d(i)); + }, min_reducer); + + return minimum; + } + + } // namespace TpetraVector } // namespace Sundials diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_band.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_band.h index c549d2916..1f22f0112 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_band.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_band.h @@ -2,7 +2,7 @@ * Programmer(s): Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_config.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_config.h index 21a35407f..f41ac5221 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_config.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_config.h @@ -73,7 +73,7 @@ /* Use POSIX timers if available. * #define SUNDIALS_HAVE_POSIX_TIMERS */ -#define SUNDIALS_HAVE_POSIX_TIMERS +/* #undef SUNDIALS_HAVE_POSIX_TIMERS */ /* Blas/Lapack available * If working libraries for Blas/lapack support were found, then @@ -88,12 +88,29 @@ /* #undef SUNDIALS_SUPERLUMT */ /* #undef SUNDIALS_SUPERLUMT_THREAD_TYPE */ +/* SUPERLUDIST available + * If working libraries for SUPERLUDIST support were found, then + * #define SUNDIALS_SUPERLUDIST + */ +/* #undef SUNDIALS_SUPERLUDIST */ + /* KLU available * If working libraries for KLU support were found, then * #define SUNDIALS_KLU */ #define SUNDIALS_KLU +/* Trilinos available + * If working libraries for Trilinos support were found, then + * #define SUNDIALS_TRILINOS + */ +/* #undef SUNDIALS_TRILINOS */ + + /* Trilinos with MPI is available, then + * #define SUNDIALS_TRILINOS_HAVE_MPI + */ +/* #undef SUNDIALS_TRILINOS_HAVE_MPI */ + /* Set if SUNDIALS is built with MPI support. * */ diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_config.in b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_config.in index 8c7c7a2cf..604518eba 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_config.in +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_config.in @@ -88,12 +88,29 @@ #cmakedefine SUNDIALS_SUPERLUMT #cmakedefine SUNDIALS_SUPERLUMT_THREAD_TYPE "@SUPERLUMT_THREAD_TYPE@" +/* SUPERLUDIST available + * If working libraries for SUPERLUDIST support were found, then + * #define SUNDIALS_SUPERLUDIST + */ +#cmakedefine SUNDIALS_SUPERLUDIST + /* KLU available * If working libraries for KLU support were found, then * #define SUNDIALS_KLU */ #cmakedefine SUNDIALS_KLU +/* Trilinos available + * If working libraries for Trilinos support were found, then + * #define SUNDIALS_TRILINOS + */ +#cmakedefine SUNDIALS_TRILINOS + + /* Trilinos with MPI is available, then + * #define SUNDIALS_TRILINOS_HAVE_MPI + */ +#cmakedefine SUNDIALS_TRILINOS_HAVE_MPI + /* Set if SUNDIALS is built with MPI support. * */ diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_dense.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_dense.h index 7dee165cf..e1a95a073 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_dense.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_dense.h @@ -2,7 +2,7 @@ * Programmer: Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_direct.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_direct.h index da4be7791..daa34de3f 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_direct.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_direct.h @@ -2,7 +2,7 @@ * Programmer: Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_fnvector.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_fnvector.h index a1946f0be..23b809766 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_fnvector.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_fnvector.h @@ -2,7 +2,7 @@ * Programmer(s): Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_futils.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_futils.h new file mode 100644 index 000000000..fe9af33c1 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_futils.h @@ -0,0 +1,38 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Cody J. Balos + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------- + * SUNDIALS Fortran 2003 interface utility definitions. + * -----------------------------------------------------------------*/ + +#ifndef _SUNDIALS_FUTILS_H +#define _SUNDIALS_FUTILS_H + +#include +#include + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Create a file pointer with the given file name and mode. */ +SUNDIALS_EXPORT FILE* SUNDIALSFileOpen(const char* filename, const char* modes); + +/* Close a file pointer with the given file name. */ +SUNDIALS_EXPORT void SUNDIALSFileClose(FILE* fp); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_iterative.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_iterative.h index 8d5ab4dc3..ae3d2e0b4 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_iterative.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_iterative.h @@ -2,7 +2,7 @@ * Programmer(s): Scott D. Cohen and Alan C. Hindmarsh @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -161,7 +161,7 @@ typedef int (*PSolveFn)(void *P_data, N_Vector r, N_Vector z, * ----------------------------------------------------------------- */ -SUNDIALS_EXPORT int ModifiedGS(N_Vector *v, realtype **h, int k, int p, +SUNDIALS_EXPORT int ModifiedGS(N_Vector* v, realtype **h, int k, int p, realtype *new_vk_norm); /* @@ -184,9 +184,9 @@ SUNDIALS_EXPORT int ModifiedGS(N_Vector *v, realtype **h, int k, int p, * ----------------------------------------------------------------- */ -SUNDIALS_EXPORT int ClassicalGS(N_Vector *v, realtype **h, int k, int p, +SUNDIALS_EXPORT int ClassicalGS(N_Vector* v, realtype **h, int k, int p, realtype *new_vk_norm, realtype *stemp, - N_Vector *vtemp); + N_Vector* vtemp); /* * ----------------------------------------------------------------- diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_klu_impl.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_klu_impl.h deleted file mode 100644 index fecca9a56..000000000 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_klu_impl.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- - * Programmer(s): Carol S. Woodward @ LLNL - * ----------------------------------------------------------------- - * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security - * and Southern Methodist University. - * All rights reserved. - * - * See the top-level LICENSE and NOTICE files for details. - * - * SPDX-License-Identifier: BSD-3-Clause - * SUNDIALS Copyright End - * ----------------------------------------------------------------- - * Implementation header file for the Sundials interface to - * the KLU linear solver. - * ----------------------------------------------------------------- - */ - -#ifndef _SUNKLU_IMPL_H -#define _SUNKLU_IMPL_H - -#ifndef _S_KLU_H -#define _S_KLU_H -#include "klu.h" -#endif - -#ifdef __cplusplus /* wrapper to enable C++ usage */ -extern "C" { -#endif - -/* - * ----------------------------------------------------------------- - * Definition of KLUData - * ----------------------------------------------------------------- - */ - -typedef struct KLUDataRec { - - /* Structure for KLU-specific data */ - - klu_symbolic *s_Symbolic; - klu_numeric *s_Numeric; - klu_common s_Common; - int s_ordering; - int (*sun_klu_solve)(klu_symbolic*, klu_numeric*, int, int, double*, klu_common*); - -} *KLUData; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_lapack.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_lapack.h index 886fecb9c..02e714b66 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_lapack.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_lapack.h @@ -1,13 +1,9 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer: Radu Serban @ LLNL * Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -18,12 +14,13 @@ * ----------------------------------------------------------------- * This is the header file for a generic package of direct matrix * operations for use with BLAS/LAPACK. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #ifndef _SUNDIALS_LAPACK_H #define _SUNDIALS_LAPACK_H +#include + #ifdef __cplusplus /* wrapper to enable C++ usage */ extern "C" { #endif @@ -106,100 +103,150 @@ extern "C" { /* Level-1 BLAS */ -extern void dcopy_f77(int *n, const double *x, const int *inc_x, double *y, const int *inc_y); -extern void dscal_f77(int *n, const double *alpha, double *x, const int *inc_x); +extern void dcopy_f77(sunindextype *n, const double *x, + const sunindextype *inc_x, double *y, + const sunindextype *inc_y); + +extern void dscal_f77(sunindextype *n, const double *alpha, double *x, + const sunindextype *inc_x); + +extern void scopy_f77(sunindextype *n, const float *x, + const sunindextype *inc_x, float *y, + const sunindextype *inc_y); -extern void scopy_f77(int *n, const float *x, const int *inc_x, float *y, const int *inc_y); -extern void sscal_f77(int *n, const float *alpha, float *x, const int *inc_x); +extern void sscal_f77(sunindextype *n, const float *alpha, float *x, + const sunindextype *inc_x); /* Level-2 BLAS */ -extern void dgemv_f77(const char *trans, int *m, int *n, const double *alpha, const double *a, - int *lda, const double *x, int *inc_x, const double *beta, double *y, int *inc_y, - int len_trans); +extern void dgemv_f77(const char *trans, sunindextype *m, sunindextype *n, + const double *alpha, const double *a, sunindextype *lda, + const double *x, sunindextype *inc_x, const double *beta, + double *y, sunindextype *inc_y); -extern void dtrsv_f77(const char *uplo, const char *trans, const char *diag, const int *n, - const double *a, const int *lda, double *x, const int *inc_x, - int len_uplo, int len_trans, int len_diag); +extern void dtrsv_f77(const char *uplo, const char *trans, const char *diag, + const sunindextype *n, const double *a, + const sunindextype *lda, double *x, + const sunindextype *inc_x); -extern void sgemv_f77(const char *trans, int *m, int *n, const float *alpha, const float *a, - int *lda, const float *x, int *inc_x, const float *beta, float *y, int *inc_y, - int len_trans); +extern void sgemv_f77(const char *trans, sunindextype *m, sunindextype *n, + const float *alpha, const float *a, sunindextype *lda, + const float *x, sunindextype *inc_x, const float *beta, + float *y, sunindextype *inc_y); -extern void strsv_f77(const char *uplo, const char *trans, const char *diag, const int *n, - const float *a, const int *lda, float *x, const int *inc_x, - int len_uplo, int len_trans, int len_diag); +extern void strsv_f77(const char *uplo, const char *trans, const char *diag, + const sunindextype *n, const float *a, + const sunindextype *lda, float *x, + const sunindextype *inc_x); /* Level-3 BLAS */ -extern void dsyrk_f77(const char *uplo, const char *trans, const int *n, const int *k, - const double *alpha, const double *a, const int *lda, const double *beta, - const double *c, const int *ldc, int len_uplo, int len_trans); +extern void dsyrk_f77(const char *uplo, const char *trans, + const sunindextype *n, const sunindextype *k, + const double *alpha, const double *a, + const sunindextype *lda, const double *beta, + const double *c, const sunindextype *ldc); -extern void ssyrk_f77(const char *uplo, const char *trans, const int *n, const int *k, - const float *alpha, const float *a, const int *lda, const float *beta, - const float *c, const int *ldc, int len_uplo, int len_trans); +extern void ssyrk_f77(const char *uplo, const char *trans, + const sunindextype *n, const sunindextype *k, + const float *alpha, const float *a, + const sunindextype *lda, const float *beta, + const float *c, const sunindextype *ldc); /* LAPACK */ -extern void dgbtrf_f77(const int *m, const int *n, const int *kl, const int *ku, - double *ab, int *ldab, int *ipiv, int *info); +extern void dgbtrf_f77(const sunindextype *m, const sunindextype *n, + const sunindextype *kl, const sunindextype *ku, + double *ab, sunindextype *ldab, sunindextype *ipiv, + sunindextype *info); -extern void dgbtrs_f77(const char *trans, const int *n, const int *kl, const int *ku, const int *nrhs, - double *ab, const int *ldab, int *ipiv, double *b, const int *ldb, - int *info, int len_trans); +extern void dgbtrs_f77(const char *trans, const sunindextype *n, + const sunindextype *kl, const sunindextype *ku, + const sunindextype *nrhs, double *ab, + const sunindextype *ldab, sunindextype *ipiv, + double *b, const sunindextype *ldb, sunindextype *info); -extern void dgeqp3_f77(const int *m, const int *n, double *a, const int *lda, int *jpvt, double *tau, - double *work, const int *lwork, int *info); +extern void dgeqp3_f77(const sunindextype *m, const sunindextype *n, double *a, + const sunindextype *lda, sunindextype *jpvt, double *tau, + double *work, const sunindextype *lwork, + sunindextype *info); -extern void dgeqrf_f77(const int *m, const int *n, double *a, const int *lda, double *tau, double *work, - const int *lwork, int *info); +extern void dgeqrf_f77(const sunindextype *m, const sunindextype *n, double *a, + const sunindextype *lda, double *tau, double *work, + const sunindextype *lwork, sunindextype *info); -extern void dgetrf_f77(const int *m, const int *n, double *a, int *lda, int *ipiv, int *info); +extern void dgetrf_f77(const sunindextype *m, const sunindextype *n, double *a, + sunindextype *lda, sunindextype *ipiv, + sunindextype *info); -extern void dgetrs_f77(const char *trans, const int *n, const int *nrhs, double *a, const int *lda, - int *ipiv, double *b, const int *ldb, int *info, int len_trans); +extern void dgetrs_f77(const char *trans, const sunindextype *n, + const sunindextype *nrhs, double *a, + const sunindextype *lda, sunindextype *ipiv, double *b, + const sunindextype *ldb, sunindextype *info); -extern void dormqr_f77(const char *side, const char *trans, const int *m, const int *n, const int *k, - double *a, const int *lda, double *tau, double *c, const int *ldc, - double *work, const int *lwork, int *info, int len_side, int len_trans); +extern void dormqr_f77(const char *side, const char *trans, + const sunindextype *m, const sunindextype *n, + const sunindextype *k, double *a, + const sunindextype *lda, double *tau, double *c, + const sunindextype *ldc, double *work, + const sunindextype *lwork, sunindextype *info); -extern void dpotrf_f77(const char *uplo, const int *n, double *a, int *lda, int *info, int len_uplo); +extern void dpotrf_f77(const char *uplo, const sunindextype *n, double *a, + sunindextype *lda, sunindextype *info); -extern void dpotrs_f77(const char *uplo, const int *n, const int *nrhs, double *a, const int *lda, - double *b, const int *ldb, int * info, int len_uplo); +extern void dpotrs_f77(const char *uplo, const sunindextype *n, + const sunindextype *nrhs, double *a, + const sunindextype *lda, double *b, + const sunindextype *ldb, sunindextype *info); -extern void sgbtrf_f77(const int *m, const int *n, const int *kl, const int *ku, - float *ab, int *ldab, int *ipiv, int *info); +extern void sgbtrf_f77(const sunindextype *m, const sunindextype *n, + const sunindextype *kl, const sunindextype *ku, + float *ab, sunindextype *ldab, sunindextype *ipiv, + sunindextype *info); -extern void sgbtrs_f77(const char *trans, const int *n, const int *kl, const int *ku, const int *nrhs, - float *ab, const int *ldab, int *ipiv, float *b, const int *ldb, - int *info, int len_trans); +extern void sgbtrs_f77(const char *trans, const sunindextype *n, + const sunindextype *kl, const sunindextype *ku, + const sunindextype *nrhs, float *ab, + const sunindextype *ldab, sunindextype *ipiv, + float *b, const sunindextype *ldb, sunindextype *info); -extern void sgeqp3_f77(const int *m, const int *n, float *a, const int *lda, int *jpvt, float *tau, - float *work, const int *lwork, int *info); +extern void sgeqp3_f77(const sunindextype *m, const sunindextype *n, float *a, + const sunindextype *lda, sunindextype *jpvt, float *tau, + float *work, const sunindextype *lwork, + sunindextype *info); -extern void sgeqrf_f77(const int *m, const int *n, float *a, const int *lda, float *tau, float *work, - const int *lwork, int *info); +extern void sgeqrf_f77(const sunindextype *m, const sunindextype *n, float *a, + const sunindextype *lda, float *tau, float *work, + const sunindextype *lwork, sunindextype *info); -extern void sgetrf_f77(const int *m, const int *n, float *a, int *lda, int *ipiv, int *info); +extern void sgetrf_f77(const sunindextype *m, const sunindextype *n, float *a, + sunindextype *lda, sunindextype *ipiv, + sunindextype *info); -extern void sgetrs_f77(const char *trans, const int *n, const int *nrhs, float *a, const int *lda, - int *ipiv, float *b, const int *ldb, int *info, int len_trans); +extern void sgetrs_f77(const char *trans, const sunindextype *n, + const sunindextype *nrhs, float *a, + const sunindextype *lda, sunindextype *ipiv, + float *b, const sunindextype *ldb, sunindextype *info); -extern void sormqr_f77(const char *side, const char *trans, const int *m, const int *n, const int *k, - float *a, const int *lda, float *tau, float *c, const int *ldc, - float *work, const int *lwork, int *info, int len_side, int len_trans); +extern void sormqr_f77(const char *side, const char *trans, + const sunindextype *m, const sunindextype *n, + const sunindextype *k, float *a, const sunindextype *lda, + float *tau, float *c, const sunindextype *ldc, + float *work, const sunindextype *lwork, + sunindextype *info); -extern void spotrf_f77(const char *uplo, const int *n, float *a, int *lda, int *info, int len_uplo); +extern void spotrf_f77(const char *uplo, const sunindextype *n, float *a, + sunindextype *lda, sunindextype *info); -extern void spotrs_f77(const char *uplo, const int *n, const int *nrhs, float *a, const int *lda, - float *b, const int *ldb, int * info, int len_uplo); +extern void spotrs_f77(const char *uplo, const sunindextype *n, + const sunindextype *nrhs, float *a, + const sunindextype *lda, float *b, + const sunindextype *ldb, sunindextype *info); #ifdef __cplusplus diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_linearsolver.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_linearsolver.h index 3d290972e..d0e3badd1 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_linearsolver.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_linearsolver.h @@ -3,7 +3,7 @@ * David Gardner, Carol Woodward, Slaven Peles @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -63,7 +63,7 @@ extern "C" { /* ----------------------------------------------------------------- - * Implemented SUNLinearSolver types: + * Implemented SUNLinearSolver types and IDs: * ----------------------------------------------------------------- */ typedef enum { @@ -72,20 +72,38 @@ typedef enum { SUNLINEARSOLVER_MATRIX_ITERATIVE } SUNLinearSolver_Type; +typedef enum { + SUNLINEARSOLVER_BAND, + SUNLINEARSOLVER_DENSE, + SUNLINEARSOLVER_KLU, + SUNLINEARSOLVER_LAPACKBAND, + SUNLINEARSOLVER_LAPACKDENSE, + SUNLINEARSOLVER_PCG, + SUNLINEARSOLVER_SPBCGS, + SUNLINEARSOLVER_SPFGMR, + SUNLINEARSOLVER_SPGMR, + SUNLINEARSOLVER_SPTFQMR, + SUNLINEARSOLVER_SUPERLUDIST, + SUNLINEARSOLVER_SUPERLUMT, + SUNLINEARSOLVER_CUSOLVERSP_BATCHQR, + SUNLINEARSOLVER_CUSTOM +} SUNLinearSolver_ID; + /* ----------------------------------------------------------------- * Generic definition of SUNLinearSolver * ----------------------------------------------------------------- */ /* Forward reference for pointer to SUNLinearSolver_Ops object */ -typedef struct _generic_SUNLinearSolver_Ops *SUNLinearSolver_Ops; +typedef _SUNDIALS_STRUCT_ _generic_SUNLinearSolver_Ops *SUNLinearSolver_Ops; /* Forward reference for pointer to SUNLinearSolver object */ -typedef struct _generic_SUNLinearSolver *SUNLinearSolver; +typedef _SUNDIALS_STRUCT_ _generic_SUNLinearSolver *SUNLinearSolver; /* Structure containing function pointers to linear solver operations */ struct _generic_SUNLinearSolver_Ops { SUNLinearSolver_Type (*gettype)(SUNLinearSolver); + SUNLinearSolver_ID (*getid)(SUNLinearSolver); int (*setatimes)(SUNLinearSolver, void*, ATimesFn); int (*setpreconditioner)(SUNLinearSolver, void*, PSetupFn, PSolveFn); @@ -97,7 +115,7 @@ struct _generic_SUNLinearSolver_Ops { N_Vector, realtype); int (*numiters)(SUNLinearSolver); realtype (*resnorm)(SUNLinearSolver); - long int (*lastflag)(SUNLinearSolver); + sunindextype (*lastflag)(SUNLinearSolver); int (*space)(SUNLinearSolver, long int*, long int*); N_Vector (*resid)(SUNLinearSolver); int (*free)(SUNLinearSolver); @@ -108,7 +126,7 @@ struct _generic_SUNLinearSolver_Ops { operations corresponding to that implementation. */ struct _generic_SUNLinearSolver { void *content; - struct _generic_SUNLinearSolver_Ops *ops; + SUNLinearSolver_Ops ops; }; @@ -116,8 +134,14 @@ struct _generic_SUNLinearSolver { * Functions exported by SUNLinearSolver module * ----------------------------------------------------------------- */ +SUNDIALS_EXPORT SUNLinearSolver SUNLinSolNewEmpty(); + +SUNDIALS_EXPORT void SUNLinSolFreeEmpty(SUNLinearSolver S); + SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID(SUNLinearSolver S); + SUNDIALS_EXPORT int SUNLinSolSetATimes(SUNLinearSolver S, void* A_data, ATimesFn ATimes); @@ -140,7 +164,7 @@ SUNDIALS_EXPORT realtype SUNLinSolResNorm(SUNLinearSolver S); SUNDIALS_EXPORT N_Vector SUNLinSolResid(SUNLinearSolver S); -SUNDIALS_EXPORT long int SUNLinSolLastFlag(SUNLinearSolver S); +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSpace(SUNLinearSolver S, long int *lenrwLS, long int *leniwLS); @@ -152,27 +176,27 @@ SUNDIALS_EXPORT int SUNLinSolFree(SUNLinearSolver S); * SUNLinearSolver return values * ----------------------------------------------------------------- */ -#define SUNLS_SUCCESS 0 /* successful/converged */ - -#define SUNLS_MEM_NULL -1 /* mem argument is NULL */ -#define SUNLS_ILL_INPUT -2 /* illegal function input */ -#define SUNLS_MEM_FAIL -3 /* failed memory access */ -#define SUNLS_ATIMES_FAIL_UNREC -4 /* atimes unrecoverable failure */ -#define SUNLS_PSET_FAIL_UNREC -5 /* pset unrecoverable failure */ -#define SUNLS_PSOLVE_FAIL_UNREC -6 /* psolve unrecoverable failure */ -#define SUNLS_PACKAGE_FAIL_UNREC -7 /* external package unrec. fail */ -#define SUNLS_GS_FAIL -8 /* Gram-Schmidt failure */ -#define SUNLS_QRSOL_FAIL -9 /* QRsol found singular R */ -#define SUNLS_VECTOROP_ERR -10 /* vector operation error */ - -#define SUNLS_RES_REDUCED 1 /* nonconv. solve, resid reduced */ -#define SUNLS_CONV_FAIL 2 /* nonconvergent solve */ -#define SUNLS_ATIMES_FAIL_REC 3 /* atimes failed recoverably */ -#define SUNLS_PSET_FAIL_REC 4 /* pset failed recoverably */ -#define SUNLS_PSOLVE_FAIL_REC 5 /* psolve failed recoverably */ -#define SUNLS_PACKAGE_FAIL_REC 6 /* external package recov. fail */ -#define SUNLS_QRFACT_FAIL 7 /* QRfact found singular matrix */ -#define SUNLS_LUFACT_FAIL 8 /* LUfact found singular matrix */ +#define SUNLS_SUCCESS 0 /* successful/converged */ + +#define SUNLS_MEM_NULL -801 /* mem argument is NULL */ +#define SUNLS_ILL_INPUT -802 /* illegal function input */ +#define SUNLS_MEM_FAIL -803 /* failed memory access */ +#define SUNLS_ATIMES_FAIL_UNREC -804 /* atimes unrecoverable failure */ +#define SUNLS_PSET_FAIL_UNREC -805 /* pset unrecoverable failure */ +#define SUNLS_PSOLVE_FAIL_UNREC -806 /* psolve unrecoverable failure */ +#define SUNLS_PACKAGE_FAIL_UNREC -807 /* external package unrec. fail */ +#define SUNLS_GS_FAIL -808 /* Gram-Schmidt failure */ +#define SUNLS_QRSOL_FAIL -809 /* QRsol found singular R */ +#define SUNLS_VECTOROP_ERR -810 /* vector operation error */ + +#define SUNLS_RES_REDUCED 801 /* nonconv. solve, resid reduced */ +#define SUNLS_CONV_FAIL 802 /* nonconvergent solve */ +#define SUNLS_ATIMES_FAIL_REC 803 /* atimes failed recoverably */ +#define SUNLS_PSET_FAIL_REC 804 /* pset failed recoverably */ +#define SUNLS_PSOLVE_FAIL_REC 805 /* psolve failed recoverably */ +#define SUNLS_PACKAGE_FAIL_REC 806 /* external package recov. fail */ +#define SUNLS_QRFACT_FAIL 807 /* QRfact found singular matrix */ +#define SUNLS_LUFACT_FAIL 808 /* LUfact found singular matrix */ #ifdef __cplusplus } diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_math.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_math.h index ab25391e7..96ec82f0d 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_math.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_math.h @@ -4,7 +4,7 @@ * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -34,17 +34,19 @@ extern "C" { * ----------------------------------------------------------------- * Macros * ----------------------------------------------------------------- - * MIN(A,B) returns the minimum of A and B + * SUNMIN(A,B) returns the minimum of A and B * - * MAX(A,B) returns the maximum of A and B + * SUNMAX(A,B) returns the maximum of A and B * - * SQR(A) returns A^2 + * SUNSQR(A) returns A^2 * * SUNRsqrt calls the appropriate version of sqrt * * SUNRabs calls the appropriate version of abs * * SUNRexp calls the appropriate version of exp + * + * SUNRceil calls the appropriate version of ceil * ----------------------------------------------------------------- */ @@ -130,6 +132,29 @@ extern "C" { #endif #endif +/* + * ----------------------------------------------------------------- + * Function : SUNRceil + * ----------------------------------------------------------------- + * Usage : realtype ceil_x; + * ceil_x = SUNRceil(x); + * ----------------------------------------------------------------- + * SUNRceil(x) returns the smallest integer value not less than x. + * ----------------------------------------------------------------- + */ + +#ifndef SUNRceil +#if defined(SUNDIALS_USE_GENERIC_MATH) +#define SUNRceil(x) ((realtype) ceil((double) (x))) +#elif defined(SUNDIALS_DOUBLE_PRECISION) +#define SUNRceil(x) (ceil((x))) +#elif defined(SUNDIALS_SINGLE_PRECISION) +#define SUNRceil(x) (ceilf((x))) +#elif defined(SUNDIALS_EXTENDED_PRECISION) +#define SUNRceil(x) (ceill((x))) +#endif +#endif + /* * ----------------------------------------------------------------- * Function : SUNRpowerI diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_matrix.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_matrix.h index 2ac25c7ae..366520241 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_matrix.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_matrix.h @@ -1,9 +1,10 @@ /* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU - * David Gardner, Carol Woodward, Slaven Peles @ LLNL + * David Gardner, Carol Woodward, Slaven Peles, + * Cody Balos @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -56,9 +57,11 @@ extern "C" { * ----------------------------------------------------------------- */ typedef enum { - SUNMATRIX_DENSE, - SUNMATRIX_BAND, + SUNMATRIX_DENSE, + SUNMATRIX_BAND, SUNMATRIX_SPARSE, + SUNMATRIX_SLUNRLOC, + SUNMATRIX_CUSPARSE, SUNMATRIX_CUSTOM } SUNMatrix_ID; @@ -68,10 +71,10 @@ typedef enum { * ----------------------------------------------------------------- */ /* Forward reference for pointer to SUNMatrix_Ops object */ -typedef struct _generic_SUNMatrix_Ops *SUNMatrix_Ops; +typedef _SUNDIALS_STRUCT_ _generic_SUNMatrix_Ops *SUNMatrix_Ops; /* Forward reference for pointer to SUNMatrix object */ -typedef struct _generic_SUNMatrix *SUNMatrix; +typedef _SUNDIALS_STRUCT_ _generic_SUNMatrix *SUNMatrix; /* Structure containing function pointers to matrix operations */ struct _generic_SUNMatrix_Ops { @@ -82,6 +85,7 @@ struct _generic_SUNMatrix_Ops { int (*copy)(SUNMatrix, SUNMatrix); int (*scaleadd)(realtype, SUNMatrix, SUNMatrix); int (*scaleaddi)(realtype, SUNMatrix); + int (*matvecsetup)(SUNMatrix); int (*matvec)(SUNMatrix, N_Vector, N_Vector); int (*space)(SUNMatrix, long int*, long int*); }; @@ -91,7 +95,7 @@ struct _generic_SUNMatrix_Ops { operations corresponding to that implementation. */ struct _generic_SUNMatrix { void *content; - struct _generic_SUNMatrix_Ops *ops; + SUNMatrix_Ops ops; }; @@ -99,6 +103,9 @@ struct _generic_SUNMatrix { * Functions exported by SUNMatrix module * ----------------------------------------------------------------- */ +SUNDIALS_EXPORT SUNMatrix SUNMatNewEmpty(); +SUNDIALS_EXPORT void SUNMatFreeEmpty(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatCopyOps(SUNMatrix A, SUNMatrix B); SUNDIALS_EXPORT SUNMatrix_ID SUNMatGetID(SUNMatrix A); SUNDIALS_EXPORT SUNMatrix SUNMatClone(SUNMatrix A); SUNDIALS_EXPORT void SUNMatDestroy(SUNMatrix A); @@ -106,9 +113,21 @@ SUNDIALS_EXPORT int SUNMatZero(SUNMatrix A); SUNDIALS_EXPORT int SUNMatCopy(SUNMatrix A, SUNMatrix B); SUNDIALS_EXPORT int SUNMatScaleAdd(realtype c, SUNMatrix A, SUNMatrix B); SUNDIALS_EXPORT int SUNMatScaleAddI(realtype c, SUNMatrix A); +SUNDIALS_EXPORT int SUNMatMatvecSetup(SUNMatrix A); SUNDIALS_EXPORT int SUNMatMatvec(SUNMatrix A, N_Vector x, N_Vector y); -SUNDIALS_EXPORT int SUNMatSpace(SUNMatrix A, long int *lenrw, - long int *leniw); +SUNDIALS_EXPORT int SUNMatSpace(SUNMatrix A, long int *lenrw, long int *leniw); + +/* + * ----------------------------------------------------------------- + * IV. SUNMatrix error codes + * --------------------------------------------------------------- + */ + +#define SUNMAT_SUCCESS 0 /* function successfull */ +#define SUNMAT_ILL_INPUT -701 /* illegal function input */ +#define SUNMAT_MEM_FAIL -702 /* failed memory access/alloc */ +#define SUNMAT_OPERATION_FAIL -703 /* a SUNMatrix operation returned nonzero */ +#define SUNMAT_MATVEC_SETUP_REQUIRED -704 /* the SUNMatMatvecSetup routine needs to be called */ #ifdef __cplusplus } diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_mpi.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_mpi.h deleted file mode 100644 index bf80bcd6a..000000000 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_mpi.h +++ /dev/null @@ -1,54 +0,0 @@ -/* ----------------------------------------------------------------- - * Programmer(s): Slaven Peles @ LLNL - * ----------------------------------------------------------------- - * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security - * and Southern Methodist University. - * All rights reserved. - * - * See the top-level LICENSE and NOTICE files for details. - * - * SPDX-License-Identifier: BSD-3-Clause - * SUNDIALS Copyright End - * ----------------------------------------------------------------- - * This header file contains definitions of MPI data types, which - * are used by MPI parallel vector implementations. - * -----------------------------------------------------------------*/ - -#ifndef _SUNDIALS_MPI_H -#define _SUNDIALS_MPI_H - -#include -#include - - -#if SUNDIALS_MPI_ENABLED - -#include -#define SUNMPI_COMM_WORLD MPI_COMM_WORLD - -typedef MPI_Comm SUNMPI_Comm; - -#else - -#define SUNMPI_COMM_WORLD 0 - -typedef int SUNMPI_Comm; - -#endif - -#ifdef __cplusplus /* wrapper to enable C++ usage */ -extern "C" { -#endif - -SUNDIALS_EXPORT int SUNMPI_Comm_size(SUNMPI_Comm comm, int *size); -SUNDIALS_EXPORT realtype SUNMPI_Allreduce_scalar(realtype d, int op, SUNMPI_Comm comm); -SUNDIALS_EXPORT void SUNMPI_Allreduce(realtype *d, int nvec, int op, SUNMPI_Comm comm); - -#ifdef __cplusplus -} -#endif - - - -#endif /* _SUNDIALS_MPI_H */ diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_mpi_types.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_mpi_types.h index ea034d65e..248bc9cfa 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_mpi_types.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_mpi_types.h @@ -3,7 +3,7 @@ * Aaron Collier, and Slaven Peles @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -21,15 +21,19 @@ /* define MPI data types */ #if defined(SUNDIALS_SINGLE_PRECISION) - #define PVEC_REAL_MPI_TYPE MPI_FLOAT + #define MPI_SUNREALTYPE MPI_FLOAT #elif defined(SUNDIALS_DOUBLE_PRECISION) - #define PVEC_REAL_MPI_TYPE MPI_DOUBLE + #define MPI_SUNREALTYPE MPI_DOUBLE #elif defined(SUNDIALS_EXTENDED_PRECISION) - #define PVEC_REAL_MPI_TYPE MPI_LONG_DOUBLE + #define MPI_SUNREALTYPE MPI_LONG_DOUBLE #endif #if defined(SUNDIALS_INT64_T) - #define PVEC_INTEGER_MPI_TYPE MPI_INT64_T + #define MPI_SUNINDEXTYPE MPI_INT64_T #elif defined(SUNDIALS_INT32_T) - #define PVEC_INTEGER_MPI_TYPE MPI_INT32_T + #define MPI_SUNINDEXTYPE MPI_INT32_T #endif + +/* define legacy SUNDIALS MPI data types */ +#define PVEC_REAL_MPI_TYPE MPI_SUNREALTYPE +#define PVEC_INTEGER_MPI_TYPE MPI_SUNINDEXTYPE diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_nonlinearsolver.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_nonlinearsolver.h index 0930136c1..6fb18d765 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_nonlinearsolver.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_nonlinearsolver.h @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -60,10 +60,10 @@ extern "C" { * ---------------------------------------------------------------------------*/ /* Forward reference for pointer to SUNNonlinearSolver_Ops object */ -typedef struct _generic_SUNNonlinearSolver_Ops *SUNNonlinearSolver_Ops; +typedef _SUNDIALS_STRUCT_ _generic_SUNNonlinearSolver_Ops *SUNNonlinearSolver_Ops; /* Forward reference for pointer to SUNNonlinearSolver object */ -typedef struct _generic_SUNNonlinearSolver *SUNNonlinearSolver; +typedef _SUNDIALS_STRUCT_ _generic_SUNNonlinearSolver *SUNNonlinearSolver; /* ----------------------------------------------------------------------------- @@ -72,10 +72,10 @@ typedef struct _generic_SUNNonlinearSolver *SUNNonlinearSolver; typedef int (*SUNNonlinSolSysFn)(N_Vector y, N_Vector F, void* mem); -typedef int (*SUNNonlinSolLSetupFn)(N_Vector y, N_Vector F, booleantype jbad, - booleantype* jcur, void* mem); +typedef int (*SUNNonlinSolLSetupFn)(booleantype jbad, booleantype* jcur, + void* mem); -typedef int (*SUNNonlinSolLSolveFn)(N_Vector y, N_Vector b, void* mem); +typedef int (*SUNNonlinSolLSolveFn)(N_Vector b, void* mem); typedef int (*SUNNonlinSolConvTestFn)(SUNNonlinearSolver NLS, N_Vector y, N_Vector del, realtype tol, N_Vector ewt, @@ -107,7 +107,7 @@ struct _generic_SUNNonlinearSolver_Ops { int (*setsysfn)(SUNNonlinearSolver, SUNNonlinSolSysFn); int (*setlsetupfn)(SUNNonlinearSolver, SUNNonlinSolLSetupFn); int (*setlsolvefn)(SUNNonlinearSolver, SUNNonlinSolLSolveFn); - int (*setctestfn)(SUNNonlinearSolver, SUNNonlinSolConvTestFn); + int (*setctestfn)(SUNNonlinearSolver, SUNNonlinSolConvTestFn, void*); int (*setmaxiters)(SUNNonlinearSolver, int); int (*getnumiters)(SUNNonlinearSolver, long int*); int (*getcuriter)(SUNNonlinearSolver, int*); @@ -119,7 +119,7 @@ struct _generic_SUNNonlinearSolver_Ops { corresponding to that implementation. */ struct _generic_SUNNonlinearSolver { void *content; - struct _generic_SUNNonlinearSolver_Ops *ops; + SUNNonlinearSolver_Ops ops; }; @@ -127,6 +127,10 @@ struct _generic_SUNNonlinearSolver { * Functions exported by SUNNonlinearSolver module * ---------------------------------------------------------------------------*/ +/* empty constructor/destructor */ +SUNDIALS_EXPORT SUNNonlinearSolver SUNNonlinSolNewEmpty(); +SUNDIALS_EXPORT void SUNNonlinSolFreeEmpty(SUNNonlinearSolver NLS); + /* core functions */ SUNDIALS_EXPORT SUNNonlinearSolver_Type SUNNonlinSolGetType(SUNNonlinearSolver NLS); @@ -153,7 +157,8 @@ SUNDIALS_EXPORT int SUNNonlinSolSetLSolveFn(SUNNonlinearSolver NLS, SUNNonlinSolLSolveFn SolveFn); SUNDIALS_EXPORT int SUNNonlinSolSetConvTestFn(SUNNonlinearSolver NLS, - SUNNonlinSolConvTestFn CTestFn); + SUNNonlinSolConvTestFn CTestFn, + void* ctest_data); SUNDIALS_EXPORT int SUNNonlinSolSetMaxIters(SUNNonlinearSolver NLS, int maxiters); @@ -172,17 +177,18 @@ SUNDIALS_EXPORT int SUNNonlinSolGetNumConvFails(SUNNonlinearSolver NLS, * SUNNonlinearSolver return values * ---------------------------------------------------------------------------*/ -#define SUN_NLS_SUCCESS 0 /* successful / converged */ +#define SUN_NLS_SUCCESS 0 /* successful / converged */ /* Recoverable */ -#define SUN_NLS_CONTINUE +1 /* not converged, keep iterating */ -#define SUN_NLS_CONV_RECVR +2 /* convergece failure, try to recover */ +#define SUN_NLS_CONTINUE +901 /* not converged, keep iterating */ +#define SUN_NLS_CONV_RECVR +902 /* convergece failure, try to recover */ /* Unrecoverable */ -#define SUN_NLS_MEM_NULL -1 /* memory argument is NULL */ -#define SUN_NLS_MEM_FAIL -2 /* failed memory access / allocation */ -#define SUN_NLS_ILL_INPUT -3 /* illegal function input */ -#define SUN_NLS_VECTOROP_ERR -4 /* failed NVector operation */ +#define SUN_NLS_MEM_NULL -901 /* memory argument is NULL */ +#define SUN_NLS_MEM_FAIL -902 /* failed memory access / allocation */ +#define SUN_NLS_ILL_INPUT -903 /* illegal function input */ +#define SUN_NLS_VECTOROP_ERR -904 /* failed NVector operation */ +#define SUN_NLS_EXT_FAIL -905 /* failed in external library call */ #ifdef __cplusplus } diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_nvector.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_nvector.h index 810dad67e..e343fb56a 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_nvector.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_nvector.h @@ -2,7 +2,7 @@ * Programmer(s): Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -67,6 +67,9 @@ typedef enum { SUNDIALS_NVEC_RAJA, SUNDIALS_NVEC_OPENMPDEV, SUNDIALS_NVEC_TRILINOS, + SUNDIALS_NVEC_MANYVECTOR, + SUNDIALS_NVEC_MPIMANYVECTOR, + SUNDIALS_NVEC_MPIPLUSX, SUNDIALS_NVEC_CUSTOM } N_Vector_ID; @@ -76,23 +79,25 @@ typedef enum { * ----------------------------------------------------------------- */ /* Forward reference for pointer to N_Vector_Ops object */ -typedef struct _generic_N_Vector_Ops *N_Vector_Ops; +typedef _SUNDIALS_STRUCT_ _generic_N_Vector_Ops *N_Vector_Ops; /* Forward reference for pointer to N_Vector object */ -typedef struct _generic_N_Vector *N_Vector; +typedef _SUNDIALS_STRUCT_ _generic_N_Vector *N_Vector; /* Define array of N_Vectors */ typedef N_Vector *N_Vector_S; /* Structure containing function pointers to vector operations */ struct _generic_N_Vector_Ops { - N_Vector_ID (*nvgetvectorid)(N_Vector); - N_Vector (*nvclone)(N_Vector); - N_Vector (*nvcloneempty)(N_Vector); - void (*nvdestroy)(N_Vector); - void (*nvspace)(N_Vector, sunindextype *, sunindextype *); - realtype* (*nvgetarraypointer)(N_Vector); - void (*nvsetarraypointer)(realtype *, N_Vector); + N_Vector_ID (*nvgetvectorid)(N_Vector); + N_Vector (*nvclone)(N_Vector); + N_Vector (*nvcloneempty)(N_Vector); + void (*nvdestroy)(N_Vector); + void (*nvspace)(N_Vector, sunindextype *, sunindextype *); + realtype* (*nvgetarraypointer)(N_Vector); + void (*nvsetarraypointer)(realtype *, N_Vector); + void* (*nvgetcommunicator)(N_Vector); + sunindextype (*nvgetlength)(N_Vector); /* standard vector operations */ void (*nvlinearsum)(realtype, N_Vector, realtype, N_Vector, N_Vector); @@ -126,12 +131,20 @@ struct _generic_N_Vector_Ops { int (*nvscalevectorarray)(int, realtype*, N_Vector*, N_Vector*); int (*nvconstvectorarray)(int, realtype, N_Vector*); int (*nvwrmsnormvectorarray)(int, N_Vector*, N_Vector*, realtype*); - int (*nvwrmsnormmaskvectorarray)(int, N_Vector*, N_Vector*, N_Vector, - realtype*); - int (*nvscaleaddmultivectorarray)(int, int, realtype*, N_Vector*, N_Vector**, - N_Vector**); - int (*nvlinearcombinationvectorarray)(int, int, realtype*, N_Vector**, - N_Vector*); + int (*nvwrmsnormmaskvectorarray)(int, N_Vector*, N_Vector*, N_Vector, realtype*); + int (*nvscaleaddmultivectorarray)(int, int, realtype*, N_Vector*, N_Vector**, N_Vector**); + int (*nvlinearcombinationvectorarray)(int, int, realtype*, N_Vector**, N_Vector*); + + /* OPTIONAL local reduction kernels (no parallel communication) */ + realtype (*nvdotprodlocal)(N_Vector, N_Vector); + realtype (*nvmaxnormlocal)(N_Vector); + realtype (*nvminlocal)(N_Vector); + realtype (*nvl1normlocal)(N_Vector); + booleantype (*nvinvtestlocal)(N_Vector, N_Vector); + booleantype (*nvconstrmasklocal)(N_Vector, N_Vector, N_Vector); + realtype (*nvminquotientlocal)(N_Vector, N_Vector); + realtype (*nvwsqrsumlocal)(N_Vector, N_Vector); + realtype (*nvwsqrsummasklocal)(N_Vector, N_Vector, N_Vector); }; /* A vector is a structure with an implementation-dependent @@ -139,7 +152,7 @@ struct _generic_N_Vector_Ops { operations corresponding to that implementation. */ struct _generic_N_Vector { void *content; - struct _generic_N_Vector_Ops *ops; + N_Vector_Ops ops; }; @@ -147,6 +160,10 @@ struct _generic_N_Vector { * Functions exported by NVECTOR module * ----------------------------------------------------------------- */ +SUNDIALS_EXPORT N_Vector N_VNewEmpty(); +SUNDIALS_EXPORT void N_VFreeEmpty(N_Vector v); +SUNDIALS_EXPORT int N_VCopyOps(N_Vector w, N_Vector v); + SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID(N_Vector w); SUNDIALS_EXPORT N_Vector N_VClone(N_Vector w); SUNDIALS_EXPORT N_Vector N_VCloneEmpty(N_Vector w); @@ -154,6 +171,8 @@ SUNDIALS_EXPORT void N_VDestroy(N_Vector v); SUNDIALS_EXPORT void N_VSpace(N_Vector v, sunindextype *lrw, sunindextype *liw); SUNDIALS_EXPORT realtype *N_VGetArrayPointer(N_Vector v); SUNDIALS_EXPORT void N_VSetArrayPointer(realtype *v_data, N_Vector v); +SUNDIALS_EXPORT void *N_VGetCommunicator(N_Vector v); +SUNDIALS_EXPORT sunindextype N_VGetLength(N_Vector v); /* standard vector operations */ SUNDIALS_EXPORT void N_VLinearSum(realtype a, N_Vector x, realtype b, @@ -177,7 +196,7 @@ SUNDIALS_EXPORT booleantype N_VInvTest(N_Vector x, N_Vector z); SUNDIALS_EXPORT booleantype N_VConstrMask(N_Vector c, N_Vector x, N_Vector m); SUNDIALS_EXPORT realtype N_VMinQuotient(N_Vector num, N_Vector denom); -/* fused vector operations */ +/* OPTIONAL fused vector operations */ SUNDIALS_EXPORT int N_VLinearCombination(int nvec, realtype* c, N_Vector* X, N_Vector z); @@ -187,7 +206,7 @@ SUNDIALS_EXPORT int N_VScaleAddMulti(int nvec, realtype* a, N_Vector x, SUNDIALS_EXPORT int N_VDotProdMulti(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods); -/* vector array operations */ +/* OPTIONAL vector array operations */ SUNDIALS_EXPORT int N_VLinearSumVectorArray(int nvec, realtype a, N_Vector* X, realtype b, N_Vector* Y, @@ -213,14 +232,30 @@ SUNDIALS_EXPORT int N_VLinearCombinationVectorArray(int nvec, int nsum, realtype* c, N_Vector** X, N_Vector* Z); +/* OPTIONAL local reduction kernels (no parallel communication) */ +SUNDIALS_EXPORT realtype N_VDotProdLocal(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNormLocal(N_Vector x); +SUNDIALS_EXPORT realtype N_VMinLocal(N_Vector x); +SUNDIALS_EXPORT realtype N_VL1NormLocal(N_Vector x); +SUNDIALS_EXPORT realtype N_VWSqrSumLocal(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWSqrSumMaskLocal(N_Vector x, N_Vector w, N_Vector id); +SUNDIALS_EXPORT booleantype N_VInvTestLocal(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMaskLocal(N_Vector c, N_Vector x, N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotientLocal(N_Vector num, N_Vector denom); + /* ----------------------------------------------------------------- * Additional functions exported by NVECTOR module * ----------------------------------------------------------------- */ -SUNDIALS_EXPORT N_Vector *N_VCloneEmptyVectorArray(int count, N_Vector w); -SUNDIALS_EXPORT N_Vector *N_VCloneVectorArray(int count, N_Vector w); -SUNDIALS_EXPORT void N_VDestroyVectorArray(N_Vector *vs, int count); +SUNDIALS_EXPORT N_Vector* N_VNewVectorArray(int count); +SUNDIALS_EXPORT N_Vector* N_VCloneEmptyVectorArray(int count, N_Vector w); +SUNDIALS_EXPORT N_Vector* N_VCloneVectorArray(int count, N_Vector w); +SUNDIALS_EXPORT void N_VDestroyVectorArray(N_Vector* vs, int count); + +/* These function are really only for users of the Fortran interface */ +SUNDIALS_EXPORT N_Vector N_VGetVecAtIndexVectorArray(N_Vector* vs, int index); +SUNDIALS_EXPORT void N_VSetVecAtIndexVectorArray(N_Vector* vs, int index, N_Vector w); #ifdef __cplusplus } diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_nvector_senswrapper.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_nvector_senswrapper.h index 728ded66c..49172ec8a 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_nvector_senswrapper.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_nvector_senswrapper.h @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_pcg.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_pcg.h deleted file mode 100644 index 2918c6906..000000000 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_pcg.h +++ /dev/null @@ -1,164 +0,0 @@ -/*--------------------------------------------------------------- - Programmer(s): Daniel R. Reynolds @ SMU - ---------------------------------------------------------------- - LLNS/SMU Copyright Start - Copyright (c) 2002-2018, Southern Methodist University and - Lawrence Livermore National Security - - This work was performed under the auspices of the U.S. Department - of Energy by Southern Methodist University and Lawrence Livermore - National Laboratory under Contract DE-AC52-07NA27344. - Produced at Southern Methodist University and the Lawrence - Livermore National Laboratory. - - All rights reserved. - For details, see the LICENSE file. - LLNS/SMU Copyright End - ---------------------------------------------------------------- - This is the header for the preconditioned conjugate gradient - solver in SUNDIALS. - ---------------------------------------------------------------*/ - -#ifndef _PCG_H -#define _PCG_H - -#include - -#ifdef __cplusplus /* wrapper to enable C++ usage */ -extern "C" { -#endif - -/*--------------------------------------------------------------- - Types: struct PcgMemRec and struct *PcgMem - ---------------------------------------------------------------- - A variable declaration of type struct *PcgMem denotes a pointer - to a data structure of type struct PcgMemRec. The PcgMemRec - structure contains numerous fields that must be accessed by the - PCG linear solver module. - * l_max maximum Krylov subspace dimension that PcgSolve will - be permitted to use - * r vector (type N_Vector) which holds the preconditioned - linear system residual - * p, z and Ap vectors (type N_Vector) used for workspace by - the PCG algorithm - --------------------------------------------------------------*/ -typedef struct { - int l_max; - N_Vector r; - N_Vector p; - N_Vector z; - N_Vector Ap; -} PcgMemRec, *PcgMem; - -/*--------------------------------------------------------------- - Function : PcgMalloc - ---------------------------------------------------------------- - PcgMalloc allocates additional memory needed by the PCG linear - solver module. - - l_max maximum Krylov subspace dimension that PcgSolve will - be permitted to use - - vec_tmpl implementation-specific template vector (of type - N_Vector) - - If successful, PcgMalloc returns a non-NULL memory pointer. If - an error occurs, then a NULL pointer is returned. - --------------------------------------------------------------*/ - -SUNDIALS_EXPORT PcgMem PcgMalloc(int l_max, N_Vector vec_tmpl); - -/*--------------------------------------------------------------- - Function : PcgSolve - ---------------------------------------------------------------- - PcgSolve solves the linear system Ax = b by means of a - preconditioned Conjugate-Gradient (PCG) iterative method. - - mem pointer to an internal memory block allocated during a - prior call to PcgMalloc - - A_data pointer to a data structure containing information - about the coefficient matrix A (passed to user-supplied - function referenced by atimes (function pointer)) - - x vector (type N_Vector) containing initial guess x_0 upon - entry, but which upon return contains an approximate - solution of the linear system Ax = b (solution only - valid if return value is either PCG_SUCCESS or - PCG_RES_REDUCED) - - b vector (type N_Vector) set to the right-hand side vector b - of the linear system (unchanged by function) - - pretype variable (type int) indicating the type of - preconditioning to be used (see sundials_iterative.h); - Note: since CG is for symmetric problems, preconditioning - is applied symmetrically by default, so any nonzero flag - will indicate to use the preconditioner. - - delta tolerance on the L2 norm of the residual (if the - return value == PCG_SUCCESS, then ||b-Ax||_L2 <= delta) - - P_data pointer to a data structure containing preconditioner - information (passed to user-supplied function referenced - by psolve (function pointer)) - - w vector (type N_Vector) used in computing the residual norm - for stopping solver (unchanged by function). This is - needed since PCG cannot utilize the same scaling vectors - as used in the other SUNDIALS solvers, due to - symmetry-breaking nature of scaling operators. - - atimes user-supplied routine responsible for computing the - matrix-vector product Ax (see sundials_iterative.h) - - psolve user-supplied routine responsible for solving the - preconditioned linear system Pz = r (ignored if - pretype == PREC_NONE) (see sundials_iterative.h) - - res_norm pointer (type realtype*) to the L2 norm of the - residual (if return value is either PCG_SUCCESS or - PCG_RES_REDUCED, then - *res_norm = ||b-Ax||_L2, where x is - the computed approximate solution) - - nli pointer (type int*) to the total number of linear - iterations performed - - nps pointer (type int*) to the total number of calls made - to the psolve routine - --------------------------------------------------------------*/ - -SUNDIALS_EXPORT int PcgSolve(PcgMem mem, void *A_data, N_Vector x, N_Vector b, - int pretype, realtype delta, void *P_data, - N_Vector w, ATimesFn atimes, PSolveFn psolve, - realtype *res_norm, int *nli, int *nps); - -/* Return values for PcgSolve */ -#define PCG_SUCCESS 0 /* PCG algorithm converged */ -#define PCG_RES_REDUCED 1 /* PCG did NOT converge, but the - residual was reduced */ -#define PCG_CONV_FAIL 2 /* PCG algorithm failed to converge */ -#define PCG_PSOLVE_FAIL_REC 3 /* psolve failed recoverably */ -#define PCG_ATIMES_FAIL_REC 4 /* atimes failed recoverably */ -#define PCG_PSET_FAIL_REC 5 /* pset failed recoverably */ - -#define PCG_MEM_NULL -1 /* mem argument is NULL */ -#define PCG_ATIMES_FAIL_UNREC -2 /* atimes returned failure flag */ -#define PCG_PSOLVE_FAIL_UNREC -3 /* psolve failed unrecoverably */ -#define PCG_PSET_FAIL_UNREC -4 /* pset failed unrecoverably */ - -/*--------------------------------------------------------------- - Function : PcgFree - ---------------------------------------------------------------- - PcgFree frees the memory allocated by a call to PcgMalloc. - It is illegal to use the pointer mem after a call to PcgFree. - ---------------------------------------------------------------*/ - -SUNDIALS_EXPORT void PcgFree(PcgMem mem); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_sparse.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_sparse.h deleted file mode 100644 index bcffb58f7..000000000 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_sparse.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- - * Programmer: Carol Woodward, Slaven Peles @ LLNL, - * Daniel R. Reynolds @ SMU. - * ----------------------------------------------------------------- - * For details, see the LICENSE file. - * ----------------------------------------------------------------- - * This header file contains definitions and declarations for use by - * sparse linear solvers for Ax = b. - * ----------------------------------------------------------------- - */ - -#ifndef _SUNDIALS_SPARSE_H -#define _SUNDIALS_SPARSE_H - -#include - -#include -#include - -#ifdef __cplusplus /* wrapper to enable C++ usage */ -extern "C" { -#endif - -/* - * ================================================================== - * Type definitions - * ================================================================== - */ - -#define CSC_MAT 0 -#define CSR_MAT 1 - -/* - * Type : SlsMat - */ - -typedef struct _SlsMat { - int M; - int N; - int NNZ; - int NP; - realtype *data; - int sparsetype; - int *indexvals; - int *indexptrs; - /* CSC indices */ - int **rowvals; - int **colptrs; - /* CSR indices */ - int **colvals; - int **rowptrs; -} *SlsMat; - -/* - * ================================================================== - * Exported function prototypes (functions working on SlsMat) - * ================================================================== - */ - -SUNDIALS_EXPORT SlsMat SparseNewMat(int M, int N, int NNZ, int sparsetype); - -SUNDIALS_EXPORT SlsMat SparseFromDenseMat(const DlsMat A, int sparsetype); - -SUNDIALS_EXPORT int SparseDestroyMat(SlsMat A); - -SUNDIALS_EXPORT int SparseSetMatToZero(SlsMat A); - -SUNDIALS_EXPORT int SparseCopyMat(const SlsMat A, SlsMat B); - -SUNDIALS_EXPORT int SparseScaleMat(realtype b, SlsMat A); - -SUNDIALS_EXPORT int SparseAddIdentityMat(SlsMat A); - -SUNDIALS_EXPORT int SparseAddMat(SlsMat A, const SlsMat B); - -SUNDIALS_EXPORT int SparseReallocMat(SlsMat A); - -SUNDIALS_EXPORT int SparseMatvec(const SlsMat A, const realtype *x, realtype *y); - -SUNDIALS_EXPORT void SparsePrintMat(const SlsMat A, FILE* outfile); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_spbcgs.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_spbcgs.h deleted file mode 100644 index c6a57a4c5..000000000 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_spbcgs.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- - * Programmer(s): Peter Brown and Aaron Collier @ LLNL - * ----------------------------------------------------------------- - * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security - * and Southern Methodist University. - * All rights reserved. - * - * See the top-level LICENSE and NOTICE files for details. - * - * SPDX-License-Identifier: BSD-3-Clause - * SUNDIALS Copyright End - * ----------------------------------------------------------------- - * This is the header file for the implementation of the scaled, - * preconditioned Bi-CGSTAB (SPBCG) iterative linear solver. - * ----------------------------------------------------------------- - */ - -#ifndef _SPBCG_H -#define _SPBCG_H - -#include - -#ifdef __cplusplus /* wrapper to enable C++ usage */ -extern "C" { -#endif - -/* - * ----------------------------------------------------------------- - * Types: struct SpbcgMemRec and struct *SpbcgMem - * ----------------------------------------------------------------- - * A variable declaration of type struct *SpbcgMem denotes a pointer - * to a data structure of type struct SpbcgMemRec. The SpbcgMemRec - * structure contains numerous fields that must be accessed by the - * SPBCG linear solver module. - * - * l_max maximum Krylov subspace dimension that SpbcgSolve will - * be permitted to use - * - * r_star vector (type N_Vector) which holds the initial scaled, - * preconditioned linear system residual - * - * r vector (type N_Vector) which holds the scaled, preconditioned - * linear system residual - * - * p, q, u and Ap vectors (type N_Vector) used for workspace by - * the SPBCG algorithm - * - * vtemp scratch vector (type N_Vector) used as temporary vector - * storage - * ----------------------------------------------------------------- - */ - -typedef struct { - - int l_max; - - N_Vector r_star; - N_Vector r; - N_Vector p; - N_Vector q; - N_Vector u; - N_Vector Ap; - N_Vector vtemp; - -} SpbcgMemRec, *SpbcgMem; - -/* - * ----------------------------------------------------------------- - * Function : SpbcgMalloc - * ----------------------------------------------------------------- - * SpbcgMalloc allocates additional memory needed by the SPBCG - * linear solver module. - * - * l_max maximum Krylov subspace dimension that SpbcgSolve will - * be permitted to use - * - * vec_tmpl implementation-specific template vector (type N_Vector) - * (created using either N_VNew_Serial or N_VNew_Parallel) - * - * If successful, SpbcgMalloc returns a non-NULL memory pointer. If - * an error occurs, then a NULL pointer is returned. - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT SpbcgMem SpbcgMalloc(int l_max, N_Vector vec_tmpl); - -/* - * ----------------------------------------------------------------- - * Function : SpbcgSolve - * ----------------------------------------------------------------- - * SpbcgSolve solves the linear system Ax = b by means of a scaled - * preconditioned Bi-CGSTAB (SPBCG) iterative method. - * - * mem pointer to an internal memory block allocated during a - * prior call to SpbcgMalloc - * - * A_data pointer to a data structure containing information - * about the coefficient matrix A (passed to user-supplied - * function referenced by atimes (function pointer)) - * - * x vector (type N_Vector) containing initial guess x_0 upon - * entry, but which upon return contains an approximate solution - * of the linear system Ax = b (solution only valid if return - * value is either SPBCG_SUCCESS or SPBCG_RES_REDUCED) - * - * b vector (type N_Vector) set to the right-hand side vector b - * of the linear system (undisturbed by function) - * - * pretype variable (type int) indicating the type of - * preconditioning to be used (see sundials_iterative.h) - * - * delta tolerance on the L2 norm of the scaled, preconditioned - * residual (if return value == SPBCG_SUCCESS, then - * ||sb*P1_inv*(b-Ax)||_L2 <= delta) - * - * P_data pointer to a data structure containing preconditioner - * information (passed to user-supplied function referenced - * by psolve (function pointer)) - * - * sx vector (type N_Vector) containing positive scaling factors - * for x (pass sx == NULL if scaling NOT required) - * - * sb vector (type N_Vector) containing positive scaling factors - * for b (pass sb == NULL if scaling NOT required) - * - * atimes user-supplied routine responsible for computing the - * matrix-vector product Ax (see sundials_iterative.h) - * - * psolve user-supplied routine responsible for solving the - * preconditioned linear system Pz = r (ignored if - * pretype == PREC_NONE) (see sundials_iterative.h) - * - * res_norm pointer (type realtype*) to the L2 norm of the - * scaled, preconditioned residual (if return value - * is either SPBCG_SUCCESS or SPBCG_RES_REDUCED, then - * *res_norm = ||sb*P1_inv*(b-Ax)||_L2, where x is - * the computed approximate solution, sb is the diagonal - * scaling matrix for the right-hand side b, and P1_inv - * is the inverse of the left-preconditioner matrix) - * - * nli pointer (type int*) to the total number of linear - * iterations performed - * - * nps pointer (type int*) to the total number of calls made - * to the psolve routine - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT int SpbcgSolve(SpbcgMem mem, void *A_data, N_Vector x, N_Vector b, - int pretype, realtype delta, void *P_data, N_Vector sx, - N_Vector sb, ATimesFn atimes, PSolveFn psolve, - realtype *res_norm, int *nli, int *nps); - -/* Return values for SpbcgSolve */ - -#define SPBCG_SUCCESS 0 /* SPBCG algorithm converged */ -#define SPBCG_RES_REDUCED 1 /* SPBCG did NOT converge, but the - residual was reduced */ -#define SPBCG_CONV_FAIL 2 /* SPBCG algorithm failed to converge */ -#define SPBCG_PSOLVE_FAIL_REC 3 /* psolve failed recoverably */ -#define SPBCG_ATIMES_FAIL_REC 4 /* atimes failed recoverably */ -#define SPBCG_PSET_FAIL_REC 5 /* pset failed recoverably */ - -#define SPBCG_MEM_NULL -1 /* mem argument is NULL */ -#define SPBCG_ATIMES_FAIL_UNREC -2 /* atimes returned failure flag */ -#define SPBCG_PSOLVE_FAIL_UNREC -3 /* psolve failed unrecoverably */ -#define SPBCG_PSET_FAIL_UNREC -4 /* pset failed unrecoverably */ - -/* - * ----------------------------------------------------------------- - * Function : SpbcgFree - * ----------------------------------------------------------------- - * SpbcgFree frees the memory allocated by a call to SpbcgMalloc. - * It is illegal to use the pointer mem after a call to SpbcgFree. - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT void SpbcgFree(SpbcgMem mem); - -/* - * ----------------------------------------------------------------- - * Macro : SPBCG_VTEMP - * ----------------------------------------------------------------- - * This macro provides access to the vector r in the - * memory block of the SPBCG module. The argument mem is the - * memory pointer returned by SpbcgMalloc, of type SpbcgMem, - * and the macro value is of type N_Vector. - * - * Note: Only used by IDA (r contains P_inverse F if nli_inc == 0). - * ----------------------------------------------------------------- - */ - -#define SPBCG_VTEMP(mem) (mem->r) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_spfgmr.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_spfgmr.h deleted file mode 100644 index e4a79a387..000000000 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_spfgmr.h +++ /dev/null @@ -1,294 +0,0 @@ -/* ----------------------------------------------------------------- - Programmer(s): Daniel R. Reynolds and Hilari C. Tiedeman @ SMU - ------------------------------------------------------------------- - LLNS/SMU Copyright Start - Copyright (c) 2002-2018, Southern Methodist University and - Lawrence Livermore National Security - - This work was performed under the auspices of the U.S. Department - of Energy by Southern Methodist University and Lawrence Livermore - National Laboratory under Contract DE-AC52-07NA27344. - Produced at Southern Methodist University and the Lawrence - Livermore National Laboratory. - - All rights reserved. - For details, see the LICENSE file. - LLNS/SMU Copyright End - ------------------------------------------------------------------- - This is the header file for the implementation of SPFGMR Krylov - iterative linear solver. The SPFGMR algorithm is based on the - Scaled Preconditioned Flexible GMRES (Generalized Minimal Residual) - method [Y. Saad, SIAM J. Sci. Comput., 1993]. - - The SPFGMR algorithm solves a linear system A x = b. - Preconditioning is only allowed on the right. - Scaling is allowed on the right, and restarts are also allowed. - We denote the preconditioner and scaling matrices as follows: - P = right preconditioner - S1 = diagonal matrix of scale factors for P-inverse b - S2 = diagonal matrix of scale factors for x - The matrices A and P are not required explicitly; only - routines that provide A and P-inverse as operators are required. - - In this notation, SPFGMR applies the underlying FGMRES method to - the equivalent transformed system - Abar xbar = bbar , where - Abar = S1 A (P-inverse) (S2-inverse), - bbar = S1 b , and xbar = S2 P x . - - The scaling matrix must be chosen so that the vectors S1 b and - S2 P x have dimensionless components. If preconditioning is not - performed (P = I), then S2 must be a scaling for x, while S1 is a - scaling for b. Similarly, if preconditioning is performed, then S1 - must be a scaling for b, while S2 is a scaling for P x, and may - also be taken as a scaling for b. - - The stopping test for the SPFGMR iterations is on the L2 norm of - the scaled preconditioned residual: - || bbar - Abar xbar ||_2 < delta - with an input test constant delta. - - The usage of this SPFGMR solver involves supplying two routines - and making three calls. The user-supplied routines are - atimes (A_data, x, y) to compute y = A x, given x, - and - psolve (P_data, y, x, lr) - to solve P x = y for x, given y. - The three user calls are: - mem = SpfgmrMalloc(lmax, vec_tmpl); - to initialize memory, - flag = SpfgmrSolve(mem,A_data,x,b,..., - P_data,s1,s2,atimes,psolve,...); - to solve the system, and - SpfgmrFree(mem); - to free the memory created by SpfgmrMalloc. - Complete details for specifying atimes and psolve and for the - usage calls are given in the paragraphs below and in iterative.h. - -----------------------------------------------------------------*/ - -#ifndef _SPFGMR_H -#define _SPFGMR_H - -#include - -#ifdef __cplusplus /* wrapper to enable C++ usage */ -extern "C" { -#endif - -/* ----------------------------------------------------------------- - Types: SpfgmrMemRec, SpfgmrMem - ------------------------------------------------------------------- - SpfgmrMem is a pointer to an SpfgmrMemRec which contains - the memory needed by SpfgmrSolve. The SpfgmrMalloc routine - returns a pointer of type SpfgmrMem which should then be passed - in subsequent calls to SpfgmrSolve. The SpfgmrFree routine frees - the memory allocated by SpfgmrMalloc. - - l_max is the maximum Krylov dimension that SpfgmrSolve will be - permitted to use. - - V is the array of Krylov basis vectors v_1, ..., v_(l_max+1), - stored in V[0], ..., V[l_max], where l_max is the second - parameter to SpfgmrMalloc. Each v_i is a vector of type - N_Vector. - - Z is the array of preconditioned basis vectors z_1, ..., - z_(l_max+1), stored in Z[0], ..., Z[l_max], where l_max is the - second parameter to SpfgmrMalloc. Each z_i is a vector of type - N_Vector. - - Hes is the (l_max+1) x l_max Hessenberg matrix. It is stored - row-wise so that the (i,j)th element is given by Hes[i][j]. - - givens is a length 2*l_max array which represents the - Givens rotation matrices that arise in the algorithm. The - Givens rotation matrices F_0, F_1, ..., F_j, where F_i is - - 1 - 1 - c_i -s_i <--- row i - s_i c_i - 1 - 1 - - are represented in the givens vector as - givens[0]=c_0, givens[1]=s_0, givens[2]=c_1, givens[3]=s_1, - ..., givens[2j]=c_j, givens[2j+1]=s_j. - - xcor is a vector (type N_Vector) which holds the scaled, - preconditioned correction to the initial guess. - - yg is a length (l_max+1) array of realtype used to hold "short" - vectors (e.g. y and g). - - vtemp is a vector (type N_Vector) used as temporary vector - storage during calculations. - -----------------------------------------------------------------*/ -typedef struct _SpfgmrMemRec { - int l_max; - N_Vector *V; - N_Vector *Z; - realtype **Hes; - realtype *givens; - N_Vector xcor; - realtype *yg; - N_Vector vtemp; -} SpfgmrMemRec, *SpfgmrMem; - -/*---------------------------------------------------------------- - Function : SpfgmrMalloc - ----------------------------------------------------------------- - SpfgmrMalloc allocates the memory used by SpfgmrSolve. It - returns a pointer of type SpfgmrMem which the user of the - SPGMR package should pass to SpfgmrSolve. The parameter l_max - is the maximum Krylov dimension that SpfgmrSolve will be - permitted to use. The parameter vec_tmpl is a pointer to an - N_Vector used as a template to create new vectors by duplication. - This routine returns NULL if there is a memory request failure. - ---------------------------------------------------------------*/ - -SUNDIALS_EXPORT SpfgmrMem SpfgmrMalloc(int l_max, N_Vector vec_tmpl); - -/*---------------------------------------------------------------- - Function : SpfgmrSolve - ----------------------------------------------------------------- - SpfgmrSolve solves the linear system Ax = b using the SPFGMR - method. The return values are given by the symbolic constants - below. The first SpfgmrSolve parameter is a pointer to memory - allocated by a prior call to SpfgmrMalloc. - - mem is the pointer returned by SpfgmrMalloc to the structure - containing the memory needed by SpfgmrSolve. - - A_data is a pointer to information about the coefficient - matrix A. This pointer is passed to the user-supplied function - atimes. - - x is the initial guess x_0 upon entry and the solution - N_Vector upon exit with return value SPFGMR_SUCCESS or - SPFGMR_RES_REDUCED. For all other return values, the output x - is undefined. - - b is the right hand side N_Vector. It is undisturbed by this - function. - - pretype is the type of preconditioning to be used. Its - legal possible values are enumerated in iterative.h. These - values are PREC_NONE, PREC_LEFT, PREC_RIGHT and PREC_BOTH; - however since this solver can only precondition on the right, - then right-preconditioning will be done if any of the values - PREC_LEFT, PREC_RIGHT or PREC_BOTH are provided.. - - gstype is the type of Gram-Schmidt orthogonalization to be - used. Its legal values are enumerated in iterativ.h. These - values are MODIFIED_GS=0 and CLASSICAL_GS=1. - - delta is the tolerance on the L2 norm of the scaled, - preconditioned residual. On return with value SPFGMR_SUCCESS, - this residual satisfies || s1 P1_inv (b - Ax) ||_2 <= delta. - - max_restarts is the maximum number of times the algorithm is - allowed to restart. - - maxit is the maximum number of iterations allowed within the - solve. This value must be less than or equal to the "l_max" - value previously supplied to SpfgmrMalloc. If maxit is too - large, l_max will be used instead. - - P_data is a pointer to preconditioner information. This - pointer is passed to the user-supplied function psolve. - - s1 is an N_Vector of positive scale factors for b. (Not - tested for positivity.) Pass NULL if no scaling on b is - required. - - s2 is an N_Vector of positive scale factors for P x, where - P is the right preconditioner. (Not tested for positivity.) - Pass NULL if no scaling on P x is required. - - atimes is the user-supplied function which performs the - operation of multiplying A by a given vector. Its description - is given in iterative.h. - - psolve is the user-supplied function which solves a - preconditioner system Pz = r, where P is P1 or P2. Its full - description is given in iterative.h. The psolve function will - not be called if pretype is NONE; in that case, the user - should pass NULL for psolve. - - res_norm is a pointer to the L2 norm of the scaled, - preconditioned residual. On return with value SPFGMR_SUCCESS or - SPFGMR_RES_REDUCED, (*res_norm) contains the value - || s1 (b - Ax) ||_2 for the computed solution x. - For all other return values, (*res_norm) is undefined. The - caller is responsible for allocating the memory (*res_norm) - to be filled in by SpfgmrSolve. - - nli is a pointer to the number of linear iterations done in - the execution of SpfgmrSolve. The caller is responsible for - allocating the memory (*nli) to be filled in by SpfgmrSolve. - - nps is a pointer to the number of calls made to psolve during - the execution of SpfgmrSolve. The caller is responsible for - allocating the memory (*nps) to be filled in by SpfgmrSolve. - - Note: Repeated calls can be made to SpfgmrSolve with varying - input arguments. If, however, the problem size N or the - maximum Krylov dimension l_max changes, then a call to - SpfgmrMalloc must be made to obtain new memory for SpfgmrSolve - to use. - ---------------------------------------------------------------*/ - -SUNDIALS_EXPORT int SpfgmrSolve(SpfgmrMem mem, void *A_data, N_Vector x, - N_Vector b, int pretype, int gstype, - realtype delta, int max_restarts, - int maxit, void *P_data, N_Vector s1, - N_Vector s2, ATimesFn atimes, PSolveFn psolve, - realtype *res_norm, int *nli, int *nps); - - -/* Return values for SpfgmrSolve */ -#define SPFGMR_SUCCESS 0 /* Converged */ -#define SPFGMR_RES_REDUCED 1 /* Did not converge, but reduced - norm of residual */ -#define SPFGMR_CONV_FAIL 2 /* Failed to converge */ -#define SPFGMR_QRFACT_FAIL 3 /* QRfact found singular matrix */ -#define SPFGMR_PSOLVE_FAIL_REC 4 /* psolve failed recoverably */ -#define SPFGMR_ATIMES_FAIL_REC 5 /* atimes failed recoverably */ -#define SPFGMR_PSET_FAIL_REC 6 /* pset failed recoverably */ - -#define SPFGMR_MEM_NULL -1 /* mem argument is NULL */ -#define SPFGMR_ATIMES_FAIL_UNREC -2 /* atimes returned failure flag */ -#define SPFGMR_PSOLVE_FAIL_UNREC -3 /* psolve failed unrecoverably */ -#define SPFGMR_GS_FAIL -4 /* Gram-Schmidt routine faiuled */ -#define SPFGMR_QRSOL_FAIL -5 /* QRsol found singular R */ -#define SPFGMR_PSET_FAIL_UNREC -6 /* pset failed unrecoverably */ - -/*---------------------------------------------------------------- - Function : SpfgmrFree - ----------------------------------------------------------------- - SpfgmrMalloc frees the memory allocated by SpfgmrMalloc. It is - illegal to use the pointer mem after a call to SpfgmrFree. - ---------------------------------------------------------------*/ - -SUNDIALS_EXPORT void SpfgmrFree(SpfgmrMem mem); - -/*---------------------------------------------------------------- - Macro: SPFGMR_VTEMP - ----------------------------------------------------------------- - This macro provides access to the work vector vtemp in the - memory block of the SPFGMR module. The argument mem is the - memory pointer returned by SpfgmrMalloc, of type SpfgmrMem, - and the macro value is of type N_Vector. - On a return from SpfgmrSolve with *nli = 0, this vector - contains the scaled preconditioned initial residual, - s1 * P1_inverse * (b - A x_0). - ---------------------------------------------------------------*/ - -#define SPFGMR_VTEMP(mem) (mem->vtemp) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_spgmr.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_spgmr.h deleted file mode 100644 index 53e0fc2b6..000000000 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_spgmr.h +++ /dev/null @@ -1,301 +0,0 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- - * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh and - * Radu Serban @ LLNL - * ----------------------------------------------------------------- - * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security - * and Southern Methodist University. - * All rights reserved. - * - * See the top-level LICENSE and NOTICE files for details. - * - * SPDX-License-Identifier: BSD-3-Clause - * SUNDIALS Copyright End - * ----------------------------------------------------------------- - * This is the header file for the implementation of SPGMR Krylov - * iterative linear solver. The SPGMR algorithm is based on the - * Scaled Preconditioned GMRES (Generalized Minimal Residual) - * method. - * - * The SPGMR algorithm solves a linear system A x = b. - * Preconditioning is allowed on the left, right, or both. - * Scaling is allowed on both sides, and restarts are also allowed. - * We denote the preconditioner and scaling matrices as follows: - * P1 = left preconditioner - * P2 = right preconditioner - * S1 = diagonal matrix of scale factors for P1-inverse b - * S2 = diagonal matrix of scale factors for P2 x - * The matrices A, P1, and P2 are not required explicitly; only - * routines that provide A, P1-inverse, and P2-inverse as - * operators are required. - * - * In this notation, SPGMR applies the underlying GMRES method to - * the equivalent transformed system - * Abar xbar = bbar , where - * Abar = S1 (P1-inverse) A (P2-inverse) (S2-inverse) , - * bbar = S1 (P1-inverse) b , and xbar = S2 P2 x . - * - * The scaling matrices must be chosen so that vectors S1 - * P1-inverse b and S2 P2 x have dimensionless components. - * If preconditioning is done on the left only (P2 = I), by a - * matrix P, then S2 must be a scaling for x, while S1 is a - * scaling for P-inverse b, and so may also be taken as a scaling - * for x. Similarly, if preconditioning is done on the right only - * (P1 = I, P2 = P), then S1 must be a scaling for b, while S2 is - * a scaling for P x, and may also be taken as a scaling for b. - * - * The stopping test for the SPGMR iterations is on the L2 norm of - * the scaled preconditioned residual: - * || bbar - Abar xbar ||_2 < delta - * with an input test constant delta. - * - * The usage of this SPGMR solver involves supplying two routines - * and making three calls. The user-supplied routines are - * atimes (A_data, x, y) to compute y = A x, given x, - * and - * psolve (P_data, y, x, lr) - * to solve P1 x = y or P2 x = y for x, given y. - * The three user calls are: - * mem = SpgmrMalloc(lmax, vec_tmpl); - * to initialize memory, - * flag = SpgmrSolve(mem,A_data,x,b,..., - * P_data,s1,s2,atimes,psolve,...); - * to solve the system, and - * SpgmrFree(mem); - * to free the memory created by SpgmrMalloc. - * Complete details for specifying atimes and psolve and for the - * usage calls are given below and in sundials_iterative.h. - * ----------------------------------------------------------------- - */ - -#ifndef _SPGMR_H -#define _SPGMR_H - -#include - -#ifdef __cplusplus /* wrapper to enable C++ usage */ -extern "C" { -#endif - -/* - * ----------------------------------------------------------------- - * Types: SpgmrMemRec, SpgmrMem - * ----------------------------------------------------------------- - * SpgmrMem is a pointer to an SpgmrMemRec which contains - * the memory needed by SpgmrSolve. The SpgmrMalloc routine - * returns a pointer of type SpgmrMem which should then be passed - * in subsequent calls to SpgmrSolve. The SpgmrFree routine frees - * the memory allocated by SpgmrMalloc. - * - * l_max is the maximum Krylov dimension that SpgmrSolve will be - * permitted to use. - * - * V is the array of Krylov basis vectors v_1, ..., v_(l_max+1), - * stored in V[0], ..., V[l_max], where l_max is the second - * parameter to SpgmrMalloc. Each v_i is a vector of type - * N_Vector. - * - * Hes is the (l_max+1) x l_max Hessenberg matrix. It is stored - * row-wise so that the (i,j)th element is given by Hes[i][j]. - * - * givens is a length 2*l_max array which represents the - * Givens rotation matrices that arise in the algorithm. The - * Givens rotation matrices F_0, F_1, ..., F_j, where F_i is - * - * 1 - * 1 - * c_i -s_i <--- row i - * s_i c_i - * 1 - * 1 - * - * are represented in the givens vector as - * givens[0]=c_0, givens[1]=s_0, givens[2]=c_1, givens[3]=s_1, - * ..., givens[2j]=c_j, givens[2j+1]=s_j. - * - * xcor is a vector (type N_Vector) which holds the scaled, - * preconditioned correction to the initial guess. - * - * yg is a length (l_max+1) array of realtype used to hold "short" - * vectors (e.g. y and g). - * - * vtemp is a vector (type N_Vector) used as temporary vector - * storage during calculations. - * ----------------------------------------------------------------- - */ - -typedef struct _SpgmrMemRec { - - int l_max; - - N_Vector *V; - realtype **Hes; - realtype *givens; - N_Vector xcor; - realtype *yg; - N_Vector vtemp; - -} SpgmrMemRec, *SpgmrMem; - -/* - * ----------------------------------------------------------------- - * Function : SpgmrMalloc - * ----------------------------------------------------------------- - * SpgmrMalloc allocates the memory used by SpgmrSolve. It - * returns a pointer of type SpgmrMem which the user of the - * SPGMR package should pass to SpgmrSolve. The parameter l_max - * is the maximum Krylov dimension that SpgmrSolve will be - * permitted to use. The parameter vec_tmpl is a pointer to an - * N_Vector used as a template to create new vectors by duplication. - * This routine returns NULL if there is a memory request failure. - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT SpgmrMem SpgmrMalloc(int l_max, N_Vector vec_tmpl); - -/* - * ----------------------------------------------------------------- - * Function : SpgmrSolve - * ----------------------------------------------------------------- - * SpgmrSolve solves the linear system Ax = b using the SPGMR - * method. The return values are given by the symbolic constants - * below. The first SpgmrSolve parameter is a pointer to memory - * allocated by a prior call to SpgmrMalloc. - * - * mem is the pointer returned by SpgmrMalloc to the structure - * containing the memory needed by SpgmrSolve. - * - * A_data is a pointer to information about the coefficient - * matrix A. This pointer is passed to the user-supplied function - * atimes. - * - * x is the initial guess x_0 upon entry and the solution - * N_Vector upon exit with return value SPGMR_SUCCESS or - * SPGMR_RES_REDUCED. For all other return values, the output x - * is undefined. - * - * b is the right hand side N_Vector. It is undisturbed by this - * function. - * - * pretype is the type of preconditioning to be used. Its - * legal values are enumerated in sundials_iterative.h. These - * values are PREC_NONE=0, PREC_LEFT=1, PREC_RIGHT=2, and - * PREC_BOTH=3. - * - * gstype is the type of Gram-Schmidt orthogonalization to be - * used. Its legal values are enumerated in sundials_iterative.h. - * These values are MODIFIED_GS=0 and CLASSICAL_GS=1. - * - * delta is the tolerance on the L2 norm of the scaled, - * preconditioned residual. On return with value SPGMR_SUCCESS, - * this residual satisfies || s1 P1_inv (b - Ax) ||_2 <= delta. - * - * max_restarts is the maximum number of times the algorithm is - * allowed to restart. - * - * P_data is a pointer to preconditioner information. This - * pointer is passed to the user-supplied function psolve. - * - * s1 is an N_Vector of positive scale factors for P1-inv b, where - * P1 is the left preconditioner. (Not tested for positivity.) - * Pass NULL if no scaling on P1-inv b is required. - * - * s2 is an N_Vector of positive scale factors for P2 x, where - * P2 is the right preconditioner. (Not tested for positivity.) - * Pass NULL if no scaling on P2 x is required. - * - * atimes is the user-supplied function which performs the - * operation of multiplying A by a given vector. Its description - * is given in sundials_iterative.h. - * - * psolve is the user-supplied function which solves a - * preconditioner system Pz = r, where P is P1 or P2. Its full - * description is given in sundials_iterative.h. The psolve function - * will not be called if pretype is NONE; in that case, the user - * should pass NULL for psolve. - * - * res_norm is a pointer to the L2 norm of the scaled, - * preconditioned residual. On return with value SPGMR_SUCCESS or - * SPGMR_RES_REDUCED, (*res_norm) contains the value - * || s1 P1_inv (b - Ax) ||_2 for the computed solution x. - * For all other return values, (*res_norm) is undefined. The - * caller is responsible for allocating the memory (*res_norm) - * to be filled in by SpgmrSolve. - * - * nli is a pointer to the number of linear iterations done in - * the execution of SpgmrSolve. The caller is responsible for - * allocating the memory (*nli) to be filled in by SpgmrSolve. - * - * nps is a pointer to the number of calls made to psolve during - * the execution of SpgmrSolve. The caller is responsible for - * allocating the memory (*nps) to be filled in by SpgmrSolve. - * - * Note: Repeated calls can be made to SpgmrSolve with varying - * input arguments. If, however, the problem size N or the - * maximum Krylov dimension l_max changes, then a call to - * SpgmrMalloc must be made to obtain new memory for SpgmrSolve - * to use. - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT int SpgmrSolve(SpgmrMem mem, void *A_data, N_Vector x, N_Vector b, - int pretype, int gstype, realtype delta, - int max_restarts, void *P_data, N_Vector s1, - N_Vector s2, ATimesFn atimes, PSolveFn psolve, - realtype *res_norm, int *nli, int *nps); - - -/* Return values for SpgmrSolve */ - -#define SPGMR_SUCCESS 0 /* Converged */ -#define SPGMR_RES_REDUCED 1 /* Did not converge, but reduced - norm of residual */ -#define SPGMR_CONV_FAIL 2 /* Failed to converge */ -#define SPGMR_QRFACT_FAIL 3 /* QRfact found singular matrix */ -#define SPGMR_PSOLVE_FAIL_REC 4 /* psolve failed recoverably */ -#define SPGMR_ATIMES_FAIL_REC 5 /* atimes failed recoverably */ -#define SPGMR_PSET_FAIL_REC 6 /* pset failed recoverably */ - -#define SPGMR_MEM_NULL -1 /* mem argument is NULL */ -#define SPGMR_ATIMES_FAIL_UNREC -2 /* atimes returned failure flag */ -#define SPGMR_PSOLVE_FAIL_UNREC -3 /* psolve failed unrecoverably */ -#define SPGMR_GS_FAIL -4 /* Gram-Schmidt routine faiuled */ -#define SPGMR_QRSOL_FAIL -5 /* QRsol found singular R */ -#define SPGMR_PSET_FAIL_UNREC -6 /* pset failed unrecoverably */ - -/* - * ----------------------------------------------------------------- - * Function : SpgmrFree - * ----------------------------------------------------------------- - * SpgmrMalloc frees the memory allocated by SpgmrMalloc. It is - * illegal to use the pointer mem after a call to SpgmrFree. - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT void SpgmrFree(SpgmrMem mem); - -/* - * ----------------------------------------------------------------- - * Macro: SPGMR_VTEMP - * ----------------------------------------------------------------- - * This macro provides access to the work vector vtemp in the - * memory block of the SPGMR module. The argument mem is the - * memory pointer returned by SpgmrMalloc, of type SpgmrMem, - * and the macro value is of type N_Vector. - * On a return from SpgmrSolve with *nli = 0, this vector - * contains the scaled preconditioned initial residual, - * s1 * P1_inverse * (b - A x_0). - * ----------------------------------------------------------------- - */ - -#define SPGMR_VTEMP(mem) (mem->vtemp) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_sptfqmr.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_sptfqmr.h deleted file mode 100644 index f2bcea873..000000000 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_sptfqmr.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- - * Programmer(s): Aaron Collier @ LLNL - * ----------------------------------------------------------------- - * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security - * and Southern Methodist University. - * All rights reserved. - * - * See the top-level LICENSE and NOTICE files for details. - * - * SPDX-License-Identifier: BSD-3-Clause - * SUNDIALS Copyright End - * ----------------------------------------------------------------- - * This is the header file for the implementation of the scaled - * preconditioned Transpose-Free Quasi-Minimal Residual (SPTFQMR) - * linear solver. - * - * The SPTFQMR algorithm solves a linear system of the form Ax = b. - * Preconditioning is allowed on the left (PREC_LEFT), right - * (PREC_RIGHT), or both (PREC_BOTH). Scaling is allowed on both - * sides. We denote the preconditioner and scaling matrices as - * follows: - * P1 = left preconditioner - * P2 = right preconditioner - * S1 = diagonal matrix of scale factors for P1-inverse b - * S2 = diagonal matrix of scale factors for P2 x - * The matrices A, P1, and P2 are not required explicitly; only - * routines that provide A, P1-inverse, and P2-inverse as operators - * are required. - * - * In this notation, SPTFQMR applies the underlying TFQMR method to - * the equivalent transformed system: - * Abar xbar = bbar, where - * Abar = S1 (P1-inverse) A (P2-inverse) (S2-inverse), - * bbar = S1 (P1-inverse) b, and - * xbar = S2 P2 x. - * - * The scaling matrices must be chosen so that vectors - * S1 P1-inverse b and S2 P2 x have dimensionless components. If - * preconditioning is done on the left only (P2 = I), by a matrix P, - * then S2 must be a scaling for x, while S1 is a scaling for - * P-inverse b, and so may also be taken as a scaling for x. - * Similarly, if preconditioning is done on the right only (P1 = I, - * P2 = P), then S1 must be a scaling for b, while S2 is a scaling - * for P x, and may also be taken as a scaling for b. - * - * The stopping test for the SPTFQMR iterations is on the L2-norm of - * the scaled preconditioned residual: - * || bbar - Abar xbar ||_2 < delta - * with an input test constant delta. - * - * The usage of this SPTFQMR solver involves supplying two routines - * and making three calls. The user-supplied routines are: - * atimes(A_data, x, y) to compute y = A x, given x, - * and - * psolve(P_data, y, x, lr) to solve P1 x = y or P2 x = y for x, - * given y. - * The three user calls are: - * mem = SptfqmrMalloc(lmax, vec_tmpl); - * to initialize memory - * flag = SptfqmrSolve(mem, A_data, x, b, pretype, delta, P_data, - * sx, sb, atimes, psolve, res_norm, nli, nps); - * to solve the system, and - * SptfqmrFree(mem); - * to free the memory allocated by SptfqmrMalloc(). - * Complete details for specifying atimes() and psolve() and for the - * usage calls are given in the paragraphs below and in the header - * file sundials_iterative.h. - * ----------------------------------------------------------------- - */ - -#ifndef _SPTFQMR_H -#define _SPTFQMR_H - -#include - -#ifdef __cplusplus /* wrapper to enable C++ usage */ -extern "C" { -#endif - -/* - * ----------------------------------------------------------------- - * Types: struct SptfqmrMemRec and struct *SptfqmrMem - * ----------------------------------------------------------------- - * A variable declaration of type struct *SptfqmrMem denotes a pointer - * to a data structure of type struct SptfqmrMemRec. The SptfqmrMemRec - * structure contains numerous fields that must be accessed by the - * SPTFQMR linear solver module. - * - * l_max maximum Krylov subspace dimension that SptfqmrSolve will - * be permitted to use - * - * r_star vector (type N_Vector) which holds the initial scaled, - * preconditioned linear system residual - * - * q/d/v/p/u/r vectors (type N_Vector) used for workspace by - * the SPTFQMR algorithm - * - * vtemp1/vtemp2/vtemp3 scratch vectors (type N_Vector) used as - * temporary storage - * ----------------------------------------------------------------- - */ - -typedef struct { - - int l_max; - - N_Vector r_star; - N_Vector q; - N_Vector d; - N_Vector v; - N_Vector p; - N_Vector *r; - N_Vector u; - N_Vector vtemp1; - N_Vector vtemp2; - N_Vector vtemp3; - -} SptfqmrMemRec, *SptfqmrMem; - -/* - * ----------------------------------------------------------------- - * Function : SptfqmrMalloc - * ----------------------------------------------------------------- - * SptfqmrMalloc allocates additional memory needed by the SPTFQMR - * linear solver module. - * - * l_max maximum Krylov subspace dimension that SptfqmrSolve will - * be permitted to use - * - * vec_tmpl implementation-specific template vector (type N_Vector) - * (created using either N_VNew_Serial or N_VNew_Parallel) - * - * If successful, SptfqmrMalloc returns a non-NULL memory pointer. If - * an error occurs, then a NULL pointer is returned. - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT SptfqmrMem SptfqmrMalloc(int l_max, N_Vector vec_tmpl); - -/* - * ----------------------------------------------------------------- - * Function : SptfqmrSolve - * ----------------------------------------------------------------- - * SptfqmrSolve solves the linear system Ax = b by means of a scaled - * preconditioned Transpose-Free Quasi-Minimal Residual (SPTFQMR) - * method. - * - * mem pointer to an internal memory block allocated during a - * prior call to SptfqmrMalloc - * - * A_data pointer to a data structure containing information - * about the coefficient matrix A (passed to user-supplied - * function referenced by atimes (function pointer)) - * - * x vector (type N_Vector) containing initial guess x_0 upon - * entry, but which upon return contains an approximate solution - * of the linear system Ax = b (solution only valid if return - * value is either SPTFQMR_SUCCESS or SPTFQMR_RES_REDUCED) - * - * b vector (type N_Vector) set to the right-hand side vector b - * of the linear system (undisturbed by function) - * - * pretype variable (type int) indicating the type of - * preconditioning to be used (see sundials_iterative.h) - * - * delta tolerance on the L2 norm of the scaled, preconditioned - * residual (if return value == SPTFQMR_SUCCESS, then - * ||sb*P1_inv*(b-Ax)||_L2 <= delta) - * - * P_data pointer to a data structure containing preconditioner - * information (passed to user-supplied function referenced - * by psolve (function pointer)) - * - * sx vector (type N_Vector) containing positive scaling factors - * for x (pass sx == NULL if scaling NOT required) - * - * sb vector (type N_Vector) containing positive scaling factors - * for b (pass sb == NULL if scaling NOT required) - * - * atimes user-supplied routine responsible for computing the - * matrix-vector product Ax (see sundials_iterative.h) - * - * psolve user-supplied routine responsible for solving the - * preconditioned linear system Pz = r (ignored if - * pretype == PREC_NONE) (see sundials_iterative.h) - * - * res_norm pointer (type realtype*) to the L2 norm of the - * scaled, preconditioned residual (if return value - * is either SPTFQMR_SUCCESS or SPTFQMR_RES_REDUCED, then - * *res_norm = ||sb*P1_inv*(b-Ax)||_L2, where x is - * the computed approximate solution, sb is the diagonal - * scaling matrix for the right-hand side b, and P1_inv - * is the inverse of the left-preconditioner matrix) - * - * nli pointer (type int*) to the total number of linear - * iterations performed - * - * nps pointer (type int*) to the total number of calls made - * to the psolve routine - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT int SptfqmrSolve(SptfqmrMem mem, void *A_data, N_Vector x, N_Vector b, - int pretype, realtype delta, void *P_data, N_Vector sx, - N_Vector sb, ATimesFn atimes, PSolveFn psolve, - realtype *res_norm, int *nli, int *nps); - -/* Return values for SptfqmrSolve */ - -#define SPTFQMR_SUCCESS 0 /* SPTFQMR algorithm converged */ -#define SPTFQMR_RES_REDUCED 1 /* SPTFQMR did NOT converge, but the - residual was reduced */ -#define SPTFQMR_CONV_FAIL 2 /* SPTFQMR algorithm failed to converge */ -#define SPTFQMR_PSOLVE_FAIL_REC 3 /* psolve failed recoverably */ -#define SPTFQMR_ATIMES_FAIL_REC 4 /* atimes failed recoverably */ -#define SPTFQMR_PSET_FAIL_REC 5 /* pset failed recoverably */ - -#define SPTFQMR_MEM_NULL -1 /* mem argument is NULL */ -#define SPTFQMR_ATIMES_FAIL_UNREC -2 /* atimes returned failure flag */ -#define SPTFQMR_PSOLVE_FAIL_UNREC -3 /* psolve failed unrecoverably */ -#define SPTFQMR_PSET_FAIL_UNREC -4 /* pset failed unrecoverably */ - -/* - * ----------------------------------------------------------------- - * Function : SptfqmrFree - * ----------------------------------------------------------------- - * SptfqmrFree frees the memory allocated by a call to SptfqmrMalloc. - * It is illegal to use the pointer mem after a call to SptfqmrFree. - * ----------------------------------------------------------------- - */ - -SUNDIALS_EXPORT void SptfqmrFree(SptfqmrMem mem); - -/* - * ----------------------------------------------------------------- - * Macro : SPTFQMR_VTEMP - * ----------------------------------------------------------------- - * This macro provides access to the work vector vtemp1 in the - * memory block of the SPTFQMR module. The argument mem is the - * memory pointer returned by SptfqmrMalloc, of type SptfqmrMem, - * and the macro value is of type N_Vector. - * - * Note: Only used by IDA (vtemp1 contains P_inverse F if - * nli_inc == 0). - * ----------------------------------------------------------------- - */ - -#define SPTFQMR_VTEMP(mem) (mem->vtemp1) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_superlumt_impl.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_superlumt_impl.h deleted file mode 100644 index 271777641..000000000 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_superlumt_impl.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- - * Programmer(s): Carol S. Woodward @ LLNL - * ----------------------------------------------------------------- - * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security - * and Southern Methodist University. - * All rights reserved. - * - * See the top-level LICENSE and NOTICE files for details. - * - * SPDX-License-Identifier: BSD-3-Clause - * SUNDIALS Copyright End - * ----------------------------------------------------------------- - * Implementation header file for the SUNDIALS interface to the - * SuperLUMT linear solver. - * ----------------------------------------------------------------- - */ - -#ifndef _SUNSLUMT_IMPL_H -#define _SUNSLUMT_IMPL_H - -#ifndef _SLUMT_H -#define _SLUMT_H -/* #include "pdsp_defs.h" */ -#include "slu_mt_ddefs.h" -#endif - -#ifdef __cplusplus /* wrapper to enable C++ usage */ -extern "C" { -#endif - -/* - * ----------------------------------------------------------------- - * Definition of SLUMTData - * ----------------------------------------------------------------- - */ - -typedef struct SLUMTDataRec { - - /* Structure for SuperLUMT-specific data */ - - SuperMatrix *s_A, *s_AC, *s_L, *s_U, *s_B; - Gstat_t *Gstat; - int *perm_r, *perm_c; - int num_threads; - double diag_pivot_thresh; - superlumt_options_t *superlumt_options; - - int s_ordering; - -} *SLUMTData; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_types.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_types.h index bba7c074c..4f8158cfd 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_types.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_types.h @@ -3,7 +3,7 @@ * Aaron Collier, and Slaven Peles @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -54,12 +54,28 @@ #endif #include +#include #include #ifdef __cplusplus /* wrapper to enable C++ usage */ extern "C" { #endif +/* + *------------------------------------------------------------------ + * Macro _SUNDIALS_STRUCT_ + * The _SUNDIALS_STRUCT_ macro is defined as a `struct` unless + * generating the SWIG interfaces - in that case it is defined as + * nothing. This is needed to work around a bug in SWIG which prevents + * it from properly parsing our generic module structures. + *------------------------------------------------------------------ + */ +#ifdef SWIG +#define _SUNDIALS_STRUCT_ +#else +#define _SUNDIALS_STRUCT_ struct +#endif + /* *------------------------------------------------------------------ * Type realtype @@ -137,7 +153,6 @@ typedef SUNDIALS_INDEX_TYPE sunindextype; #define SUNTRUE 1 #endif - #ifdef __cplusplus } #endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_version.h b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_version.h index e5574053a..7d5a6057a 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_version.h +++ b/deps/AMICI/ThirdParty/sundials/include/sundials/sundials_version.h @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_band.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_band.h index a4acb16fb..39005ff8d 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_band.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_band.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds, Ashley Crawford @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -12,11 +12,11 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the header file for the band implementation of the + * This is the header file for the band implementation of the * SUNLINSOL module, SUNLINSOL_BAND. * * Note: - * - The definition of the generic SUNLinearSolver structure can + * - The definition of the generic SUNLinearSolver structure can * be found in the header file sundials_linearsolver.h. * ----------------------------------------------------------------- */ @@ -37,16 +37,16 @@ extern "C" { /* --------------------------------------- * Band Implementation of SUNLinearSolver * --------------------------------------- */ - + struct _SUNLinearSolverContent_Band { sunindextype N; sunindextype *pivots; - long int last_flag; + sunindextype last_flag; }; typedef struct _SUNLinearSolverContent_Band *SUNLinearSolverContent_Band; - + /* -------------------------------------- * Exported Functions for SUNLINSOL_BAND * -------------------------------------- */ @@ -58,11 +58,12 @@ SUNDIALS_EXPORT SUNLinearSolver SUNBandLinearSolver(N_Vector y, SUNMatrix A); SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_Band(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_Band(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolInitialize_Band(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSetup_Band(SUNLinearSolver S, SUNMatrix A); SUNDIALS_EXPORT int SUNLinSolSolve_Band(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype tol); -SUNDIALS_EXPORT long int SUNLinSolLastFlag_Band(SUNLinearSolver S); +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_Band(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSpace_Band(SUNLinearSolver S, long int *lenrwLS, long int *leniwLS); diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_cusolversp_batchqr.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_cusolversp_batchqr.h new file mode 100644 index 000000000..a7ee27857 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_cusolversp_batchqr.h @@ -0,0 +1,111 @@ +/* ---------------------------------------------------------------------------- + * Programmer(s): Cody J. Balos @ LLNL + * ---------------------------------------------------------------------------- + * Based on work by Donald Wilcox @ LBNL + * ---------------------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ---------------------------------------------------------------------------- + * Header file for cuSolverSp batched QR SUNLinearSolver interface. + * ----------------------------------------------------------------------------*/ + +#ifndef _SUNLINSOL_CUSOLVERSP_H +#define _SUNLINSOL_CUSOLVERSP_H + +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * ---------------------------------------------------------------------------- + * PART I: cuSolverSp implementation of SUNLinearSolver + * ---------------------------------------------------------------------------- + */ + +struct _SUNLinearSolverContent_cuSolverSp_batchQR { + int last_flag; /* last return flag */ + booleantype first_factorize; /* is this the first factorization? */ + size_t internal_size; /* size of cusolver internal buffer for Q and R */ + size_t workspace_size; /* size of cusolver memory block for num. factorization */ + cusolverSpHandle_t cusolver_handle; /* cuSolverSp context */ + csrqrInfo_t info; /* opaque cusolver data structure */ + void* workspace; /* memory block used by cusolver */ + const char* desc; /* description of this linear solver */ +}; + +typedef struct _SUNLinearSolverContent_cuSolverSp_batchQR *SUNLinearSolverContent_cuSolverSp_batchQR; + + +/* + * ---------------------------------------------------------------------------- + * PART II: Functions exported by sunlinsol_sludist + * ---------------------------------------------------------------------------- + */ + +SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_cuSolverSp_batchQR(N_Vector y, SUNMatrix A, + cusolverSpHandle_t cusol_handle); + + +/* + * ---------------------------------------------------------------------------- + * cuSolverSp implementations of SUNLinearSolver operations + * ---------------------------------------------------------------------------- + */ + +SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_cuSolverSp_batchQR(SUNLinearSolver S); + +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_cuSolverSp_batchQR(SUNLinearSolver S); + +SUNDIALS_EXPORT int SUNLinSolInitialize_cuSolverSp_batchQR(SUNLinearSolver S); + +SUNDIALS_EXPORT int SUNLinSolSetup_cuSolverSp_batchQR(SUNLinearSolver S, + SUNMatrix A); + +SUNDIALS_EXPORT int SUNLinSolSolve_cuSolverSp_batchQR(SUNLinearSolver S, + SUNMatrix A, + N_Vector x, + N_Vector b, + realtype tol); + +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_cuSolverSp_batchQR(SUNLinearSolver S); + +SUNDIALS_EXPORT int SUNLinSolFree_cuSolverSp_batchQR(SUNLinearSolver S); + + +/* + * ---------------------------------------------------------------------------- + * Additional get and set functions. + * ---------------------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void SUNLinSol_cuSolverSp_batchQR_GetDescription(SUNLinearSolver S, + char** desc); + +SUNDIALS_EXPORT void SUNLinSol_cuSolverSp_batchQR_SetDescription(SUNLinearSolver S, + const char* desc); + +SUNDIALS_EXPORT void SUNLinSol_cuSolverSp_batchQR_GetDeviceSpace(SUNLinearSolver S, + size_t* cuSolverInternal, + size_t* cuSolverWorkspace); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_dense.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_dense.h index a2161cd10..ed8563de7 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_dense.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_dense.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds, Ashley Crawford @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -46,7 +46,7 @@ extern "C" { struct _SUNLinearSolverContent_Dense { sunindextype N; sunindextype *pivots; - long int last_flag; + sunindextype last_flag; }; typedef struct _SUNLinearSolverContent_Dense *SUNLinearSolverContent_Dense; @@ -62,11 +62,12 @@ SUNDIALS_EXPORT SUNLinearSolver SUNDenseLinearSolver(N_Vector y, SUNMatrix A); SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_Dense(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_Dense(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolInitialize_Dense(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSetup_Dense(SUNLinearSolver S, SUNMatrix A); SUNDIALS_EXPORT int SUNLinSolSolve_Dense(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype tol); -SUNDIALS_EXPORT long int SUNLinSolLastFlag_Dense(SUNLinearSolver S); +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_Dense(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSpace_Dense(SUNLinearSolver S, long int *lenrwLS, long int *leniwLS); diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_klu.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_klu.h index dca22db6f..b23e7e73f 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_klu.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_klu.h @@ -1,11 +1,11 @@ /* * ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU - * Based on sundials_klu_impl.h and arkode_klu.h/cvode_klu.h/... + * Based on sundials_klu_impl.h and arkode_klu.h/cvode_klu.h/... * code, written by Carol S. Woodward @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -14,11 +14,11 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the header file for the KLU implementation of the + * This is the header file for the KLU implementation of the * SUNLINSOL module, SUNLINSOL_KLU. - * + * * Note: - * - The definition of the generic SUNLinearSolver structure can + * - The definition of the generic SUNLinearSolver structure can * be found in the header file sundials_linearsolver.h. * ----------------------------------------------------------------- */ @@ -87,9 +87,9 @@ extern "C" { typedef sunindextype (*KLUSolveFn)(sun_klu_symbolic*, sun_klu_numeric*, sunindextype, sunindextype, double*, sun_klu_common*); - + struct _SUNLinearSolverContent_KLU { - long int last_flag; + int last_flag; int first_factorize; sun_klu_symbolic *symbolic; sun_klu_numeric *numeric; @@ -99,7 +99,7 @@ struct _SUNLinearSolverContent_KLU { typedef struct _SUNLinearSolverContent_KLU *SUNLinearSolverContent_KLU; - + /* ------------------------------------- * Exported Functions for SUNLINSOL_KLU * ------------------------------------- */ @@ -119,17 +119,31 @@ SUNDIALS_EXPORT int SUNKLUReInit(SUNLinearSolver S, SUNMatrix A, SUNDIALS_EXPORT int SUNKLUSetOrdering(SUNLinearSolver S, int ordering_choice); +/* -------------------- + * Accessor functions + * -------------------- */ + +SUNDIALS_EXPORT sun_klu_symbolic* SUNLinSol_KLUGetSymbolic(SUNLinearSolver S); +SUNDIALS_EXPORT sun_klu_numeric* SUNLinSol_KLUGetNumeric(SUNLinearSolver S); +SUNDIALS_EXPORT sun_klu_common* SUNLinSol_KLUGetCommon(SUNLinearSolver S); + + +/* ----------------------------------------------- + * Implementations of SUNLinearSolver operations + * ----------------------------------------------- */ + SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_KLU(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_KLU(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolInitialize_KLU(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSetup_KLU(SUNLinearSolver S, SUNMatrix A); SUNDIALS_EXPORT int SUNLinSolSolve_KLU(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype tol); -SUNDIALS_EXPORT long int SUNLinSolLastFlag_KLU(SUNLinearSolver S); +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_KLU(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSpace_KLU(SUNLinearSolver S, long int *lenrwLS, long int *leniwLS); SUNDIALS_EXPORT int SUNLinSolFree_KLU(SUNLinearSolver S); - + #ifdef __cplusplus } diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackband.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackband.h index 71aed4c14..ed353e262 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackband.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackband.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -12,11 +12,11 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the header file for the LAPACK band implementation of the + * This is the header file for the LAPACK band implementation of the * SUNLINSOL module, SUNLINSOL_LAPACKBAND. - * + * * Note: - * - The definition of the generic SUNLinearSolver structure can + * - The definition of the generic SUNLinearSolver structure can * be found in the header file sundials_linearsolver.h. * ----------------------------------------------------------------- */ @@ -45,41 +45,36 @@ extern "C" { #error Incompatible realtype for LAPACK; disable LAPACK and rebuild #endif -/* Catch to disable LAPACK linear solvers with incompatible sunindextype */ -#if defined(SUNDIALS_INT32_T) -#else /* incompatible sunindextype for LAPACK */ -#error Incompatible sunindextype for LAPACK; disable LAPACK and rebuild -#endif - /* ---------------------------------------------- * LAPACK band implementation of SUNLinearSolver * ---------------------------------------------- */ - + struct _SUNLinearSolverContent_LapackBand { sunindextype N; sunindextype *pivots; - long int last_flag; + sunindextype last_flag; }; typedef struct _SUNLinearSolverContent_LapackBand *SUNLinearSolverContent_LapackBand; - + /* -------------------------------------------- * Exported Functions for SUNLINSOL_LAPACKBAND * -------------------------------------------- */ SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_LapackBand(N_Vector y, SUNMatrix A); - + /* deprecated */ SUNDIALS_EXPORT SUNLinearSolver SUNLapackBand(N_Vector y, SUNMatrix A); SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_LapackBand(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_LapackBand(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolInitialize_LapackBand(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSetup_LapackBand(SUNLinearSolver S, SUNMatrix A); SUNDIALS_EXPORT int SUNLinSolSolve_LapackBand(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype tol); -SUNDIALS_EXPORT long int SUNLinSolLastFlag_LapackBand(SUNLinearSolver S); +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_LapackBand(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSpace_LapackBand(SUNLinearSolver S, long int *lenrwLS, long int *leniwLS); diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackdense.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackdense.h index cdc35d4ab..a2dbe6f52 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackdense.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackdense.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -12,11 +12,11 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the header file for the LAPACK dense implementation of the + * This is the header file for the LAPACK dense implementation of the * SUNLINSOL module, SUNLINSOL_LINPACKDENSE. * * Note: - * - The definition of the generic SUNLinearSolver structure can + * - The definition of the generic SUNLinearSolver structure can * be found in the header file sundials_linearsolver.h. * ----------------------------------------------------------------- */ @@ -45,46 +45,41 @@ extern "C" { #error Incompatible realtype for LAPACK; disable LAPACK and rebuild #endif -/* Catch to disable LAPACK linear solvers with incompatible sunindextype */ -#if defined(SUNDIALS_INT32_T) -#else /* incompatible sunindextype for LAPACK */ -#error Incompatible sunindextype for LAPACK; disable LAPACK and rebuild -#endif - /* ----------------------------------------------- * LAPACK dense implementation of SUNLinearSolver * ----------------------------------------------- */ - + struct _SUNLinearSolverContent_LapackDense { sunindextype N; sunindextype *pivots; - long int last_flag; + sunindextype last_flag; }; typedef struct _SUNLinearSolverContent_LapackDense *SUNLinearSolverContent_LapackDense; - + /* --------------------------------------------- * Exported Functions for SUNLINSOL_LAPACKDENSE * --------------------------------------------- */ SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_LapackDense(N_Vector y, SUNMatrix A); - + /* deprecated */ SUNDIALS_EXPORT SUNLinearSolver SUNLapackDense(N_Vector y, SUNMatrix A); SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_LapackDense(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_LapackDense(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolInitialize_LapackDense(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSetup_LapackDense(SUNLinearSolver S, SUNMatrix A); SUNDIALS_EXPORT int SUNLinSolSolve_LapackDense(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype tol); -SUNDIALS_EXPORT long int SUNLinSolLastFlag_LapackDense(SUNLinearSolver S); +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_LapackDense(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSpace_LapackDense(SUNLinearSolver S, long int *lenrwLS, long int *leniwLS); SUNDIALS_EXPORT int SUNLinSolFree_LapackDense(SUNLinearSolver S); - + #ifdef __cplusplus } #endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_pcg.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_pcg.h index 17343fba6..9476d555f 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_pcg.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_pcg.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds, Ashley Crawford @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -12,12 +12,12 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the header file for the PCG implementation of the + * This is the header file for the PCG implementation of the * SUNLINSOL module, SUNLINSOL_PCG. The PCG algorithm is based * on the Preconditioned Conjugate Gradient. * * Note: - * - The definition of the generic SUNLinearSolver structure can + * - The definition of the generic SUNLinearSolver structure can * be found in the header file sundials_linearsolver.h. * ----------------------------------------------------------------- */ @@ -28,7 +28,6 @@ #include #include #include -#include #ifdef __cplusplus /* wrapper to enable C++ usage */ extern "C" { @@ -40,13 +39,13 @@ extern "C" { /* -------------------------------------- * PCG Implementation of SUNLinearSolver * -------------------------------------- */ - + struct _SUNLinearSolverContent_PCG { int maxl; int pretype; int numiters; realtype resnorm; - long int last_flag; + int last_flag; ATimesFn ATimes; void* ATData; @@ -63,7 +62,7 @@ struct _SUNLinearSolverContent_PCG { typedef struct _SUNLinearSolverContent_PCG *SUNLinearSolverContent_PCG; - + /* ------------------------------------- * Exported Functions for SUNLINSOL_PCG * ------------------------------------- */ @@ -84,6 +83,7 @@ SUNDIALS_EXPORT int SUNPCGSetPrecType(SUNLinearSolver S, int pretype); SUNDIALS_EXPORT int SUNPCGSetMaxl(SUNLinearSolver S, int maxl); SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_PCG(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_PCG(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolInitialize_PCG(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSetATimes_PCG(SUNLinearSolver S, void* A_data, ATimesFn ATimes); @@ -100,9 +100,9 @@ SUNDIALS_EXPORT int SUNLinSolSolve_PCG(SUNLinearSolver S, SUNMatrix nul, SUNDIALS_EXPORT int SUNLinSolNumIters_PCG(SUNLinearSolver S); SUNDIALS_EXPORT realtype SUNLinSolResNorm_PCG(SUNLinearSolver S); SUNDIALS_EXPORT N_Vector SUNLinSolResid_PCG(SUNLinearSolver S); -SUNDIALS_EXPORT long int SUNLinSolLastFlag_PCG(SUNLinearSolver S); -SUNDIALS_EXPORT int SUNLinSolSpace_PCG(SUNLinearSolver S, - long int *lenrwLS, +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_PCG(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSpace_PCG(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS); SUNDIALS_EXPORT int SUNLinSolFree_PCG(SUNLinearSolver S); diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_spbcgs.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_spbcgs.h index 282b5af9d..738f6b3a8 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_spbcgs.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_spbcgs.h @@ -1,11 +1,11 @@ /* * ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU - * Based on code sundials_spbcgs.h by: Peter Brown and + * Based on code sundials_spbcgs.h by: Peter Brown and * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -14,12 +14,12 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the header file for the SPBCGS implementation of the + * This is the header file for the SPBCGS implementation of the * SUNLINSOL module, SUNLINSOL_SPBCGS. The SPBCGS algorithm is based * on the Scaled Preconditioned Bi-CG-Stabilized method. * * Note: - * - The definition of the generic SUNLinearSolver structure can + * - The definition of the generic SUNLinearSolver structure can * be found in the header file sundials_linearsolver.h. * ----------------------------------------------------------------- */ @@ -30,7 +30,6 @@ #include #include #include -#include #ifdef __cplusplus /* wrapper to enable C++ usage */ extern "C" { @@ -42,13 +41,13 @@ extern "C" { /* ----------------------------------------- * SPBCGS Implementation of SUNLinearSolver * ---------------------------------------- */ - + struct _SUNLinearSolverContent_SPBCGS { int maxl; int pretype; int numiters; realtype resnorm; - long int last_flag; + int last_flag; ATimesFn ATimes; void* ATData; @@ -69,7 +68,7 @@ struct _SUNLinearSolverContent_SPBCGS { typedef struct _SUNLinearSolverContent_SPBCGS *SUNLinearSolverContent_SPBCGS; - + /* --------------------------------------- *Exported Functions for SUNLINSOL_SPBCGS * --------------------------------------- */ @@ -90,6 +89,7 @@ SUNDIALS_EXPORT int SUNSPBCGSSetPrecType(SUNLinearSolver S, int pretype); SUNDIALS_EXPORT int SUNSPBCGSSetMaxl(SUNLinearSolver S, int maxl); SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_SPBCGS(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_SPBCGS(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolInitialize_SPBCGS(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSetATimes_SPBCGS(SUNLinearSolver S, void* A_data, ATimesFn ATimes); @@ -106,9 +106,9 @@ SUNDIALS_EXPORT int SUNLinSolSolve_SPBCGS(SUNLinearSolver S, SUNMatrix A, SUNDIALS_EXPORT int SUNLinSolNumIters_SPBCGS(SUNLinearSolver S); SUNDIALS_EXPORT realtype SUNLinSolResNorm_SPBCGS(SUNLinearSolver S); SUNDIALS_EXPORT N_Vector SUNLinSolResid_SPBCGS(SUNLinearSolver S); -SUNDIALS_EXPORT long int SUNLinSolLastFlag_SPBCGS(SUNLinearSolver S); -SUNDIALS_EXPORT int SUNLinSolSpace_SPBCGS(SUNLinearSolver S, - long int *lenrwLS, +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_SPBCGS(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSpace_SPBCGS(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS); SUNDIALS_EXPORT int SUNLinSolFree_SPBCGS(SUNLinearSolver S); diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_spfgmr.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_spfgmr.h index 98cc92b5f..1fcc8caab 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_spfgmr.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_spfgmr.h @@ -1,11 +1,11 @@ /* * ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU - * Based on code sundials_spfgmr.h by: Daniel R. Reynolds and + * Based on code sundials_spfgmr.h by: Daniel R. Reynolds and * Hilari C. Tiedeman @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -14,13 +14,13 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the header file for the SPFGMR implementation of the + * This is the header file for the SPFGMR implementation of the * SUNLINSOL module, SUNLINSOL_SPFGMR. The SPFGMR algorithm is based - * on the Scaled Preconditioned FGMRES (Flexible Generalized Minimal + * on the Scaled Preconditioned FGMRES (Flexible Generalized Minimal * Residual) method [Y. Saad, SIAM J. Sci. Comput., 1993]. * * Note: - * - The definition of the generic SUNLinearSolver structure can + * - The definition of the generic SUNLinearSolver structure can * be found in the header file sundials_linearsolver.h. * ----------------------------------------------------------------- */ @@ -31,7 +31,6 @@ #include #include #include -#include #ifdef __cplusplus /* wrapper to enable C++ usage */ extern "C" { @@ -45,7 +44,7 @@ extern "C" { /* ----------------------------------------- * SPFGMR Implementation of SUNLinearSolver * ----------------------------------------- */ - + struct _SUNLinearSolverContent_SPFGMR { int maxl; int pretype; @@ -53,7 +52,7 @@ struct _SUNLinearSolverContent_SPFGMR { int max_restarts; int numiters; realtype resnorm; - long int last_flag; + int last_flag; ATimesFn ATimes; void* ATData; @@ -102,6 +101,7 @@ SUNDIALS_EXPORT int SUNSPFGMRSetMaxRestarts(SUNLinearSolver S, int maxrs); SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_SPFGMR(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_SPFGMR(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolInitialize_SPFGMR(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSetATimes_SPFGMR(SUNLinearSolver S, void* A_data, ATimesFn ATimes); @@ -118,9 +118,9 @@ SUNDIALS_EXPORT int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, SUNDIALS_EXPORT int SUNLinSolNumIters_SPFGMR(SUNLinearSolver S); SUNDIALS_EXPORT realtype SUNLinSolResNorm_SPFGMR(SUNLinearSolver S); SUNDIALS_EXPORT N_Vector SUNLinSolResid_SPFGMR(SUNLinearSolver S); -SUNDIALS_EXPORT long int SUNLinSolLastFlag_SPFGMR(SUNLinearSolver S); -SUNDIALS_EXPORT int SUNLinSolSpace_SPFGMR(SUNLinearSolver S, - long int *lenrwLS, +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_SPFGMR(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSpace_SPFGMR(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS); SUNDIALS_EXPORT int SUNLinSolFree_SPFGMR(SUNLinearSolver S); diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_spgmr.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_spgmr.h index 9c7925293..6227c3ee6 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_spgmr.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_spgmr.h @@ -1,11 +1,11 @@ /* * ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU - * Based on code sundials_spgmr.h by: Scott D. Cohen, + * Based on code sundials_spgmr.h by: Scott D. Cohen, * Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -14,13 +14,13 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the header file for the SPGMR implementation of the + * This is the header file for the SPGMR implementation of the * SUNLINSOL module, SUNLINSOL_SPGMR. The SPGMR algorithm is based * on the Scaled Preconditioned GMRES (Generalized Minimal Residual) * method. * * Note: - * - The definition of the generic SUNLinearSolver structure can + * - The definition of the generic SUNLinearSolver structure can * be found in the header file sundials_linearsolver.h. * ----------------------------------------------------------------- */ @@ -31,7 +31,6 @@ #include #include #include -#include #ifdef __cplusplus /* wrapper to enable C++ usage */ extern "C" { @@ -45,7 +44,7 @@ extern "C" { /* ---------------------------------------- * SPGMR Implementation of SUNLinearSolver * ---------------------------------------- */ - + struct _SUNLinearSolverContent_SPGMR { int maxl; int pretype; @@ -53,7 +52,7 @@ struct _SUNLinearSolverContent_SPGMR { int max_restarts; int numiters; realtype resnorm; - long int last_flag; + int last_flag; ATimesFn ATimes; void* ATData; @@ -101,6 +100,7 @@ SUNDIALS_EXPORT int SUNSPGMRSetGSType(SUNLinearSolver S, int gstype); SUNDIALS_EXPORT int SUNSPGMRSetMaxRestarts(SUNLinearSolver S, int maxrs); SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_SPGMR(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_SPGMR(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolInitialize_SPGMR(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSetATimes_SPGMR(SUNLinearSolver S, void* A_data, ATimesFn ATimes); @@ -117,9 +117,9 @@ SUNDIALS_EXPORT int SUNLinSolSolve_SPGMR(SUNLinearSolver S, SUNMatrix A, SUNDIALS_EXPORT int SUNLinSolNumIters_SPGMR(SUNLinearSolver S); SUNDIALS_EXPORT realtype SUNLinSolResNorm_SPGMR(SUNLinearSolver S); SUNDIALS_EXPORT N_Vector SUNLinSolResid_SPGMR(SUNLinearSolver S); -SUNDIALS_EXPORT long int SUNLinSolLastFlag_SPGMR(SUNLinearSolver S); -SUNDIALS_EXPORT int SUNLinSolSpace_SPGMR(SUNLinearSolver S, - long int *lenrwLS, +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_SPGMR(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSpace_SPGMR(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS); SUNDIALS_EXPORT int SUNLinSolFree_SPGMR(SUNLinearSolver S); diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_sptfqmr.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_sptfqmr.h index 57c1b4605..8cd72380f 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_sptfqmr.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_sptfqmr.h @@ -4,7 +4,7 @@ * Based on code sundials_sptfqmr.h by: Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -13,13 +13,13 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the header file for the SPTFQMR implementation of the + * This is the header file for the SPTFQMR implementation of the * SUNLINSOL module, SUNLINSOL_SPTFQMR. The SPTFQMR algorithm is * based on the Scaled Preconditioned Transpose-free Quasi-Minimum * Residual method. * * Note: - * - The definition of the generic SUNLinearSolver structure can + * - The definition of the generic SUNLinearSolver structure can * be found in the header file sundials_linearsolver.h. * ----------------------------------------------------------------- */ @@ -30,7 +30,6 @@ #include #include #include -#include #ifdef __cplusplus /* wrapper to enable C++ usage */ extern "C" { @@ -42,13 +41,13 @@ extern "C" { /* ------------------------------------------ * SPTFQMR Implementation of SUNLinearSolver * ------------------------------------------ */ - + struct _SUNLinearSolverContent_SPTFQMR { int maxl; int pretype; int numiters; realtype resnorm; - long int last_flag; + int last_flag; ATimesFn ATimes; void* ATData; @@ -92,6 +91,7 @@ SUNDIALS_EXPORT int SUNSPTFQMRSetPrecType(SUNLinearSolver S, int pretype); SUNDIALS_EXPORT int SUNSPTFQMRSetMaxl(SUNLinearSolver S, int maxl); SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_SPTFQMR(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_SPTFQMR(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolInitialize_SPTFQMR(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSetATimes_SPTFQMR(SUNLinearSolver S, void* A_data, ATimesFn ATimes); @@ -108,9 +108,9 @@ SUNDIALS_EXPORT int SUNLinSolSolve_SPTFQMR(SUNLinearSolver S, SUNMatrix A, SUNDIALS_EXPORT int SUNLinSolNumIters_SPTFQMR(SUNLinearSolver S); SUNDIALS_EXPORT realtype SUNLinSolResNorm_SPTFQMR(SUNLinearSolver S); SUNDIALS_EXPORT N_Vector SUNLinSolResid_SPTFQMR(SUNLinearSolver S); -SUNDIALS_EXPORT long int SUNLinSolLastFlag_SPTFQMR(SUNLinearSolver S); -SUNDIALS_EXPORT int SUNLinSolSpace_SPTFQMR(SUNLinearSolver S, - long int *lenrwLS, +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_SPTFQMR(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSpace_SPTFQMR(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS); SUNDIALS_EXPORT int SUNLinSolFree_SPTFQMR(SUNLinearSolver S); diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_superludist.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_superludist.h new file mode 100644 index 000000000..3d4a768df --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_superludist.h @@ -0,0 +1,119 @@ +/* + * ---------------------------------------------------------------------------- + * Programmer(s): Cody J. Balos @ LLNL + * ---------------------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ---------------------------------------------------------------------------- + * This is the header file for the SuperLU-DIST implementation of the SUNLINSOL + * module. + * + * Part I contains declarations specific to the SuperLU-Dist implementation of + * the supplied SUNLINSOL module. + * + * Part II contains the prototype for the constructor SUNSuperLUDIST as well as + * implementation-specific prototypes for various useful solver operations. + * + * Notes: + * + * - The definition of the generic SUNLinearSolver structure can be found in + * the header file sundials_linearsolver.h. + * ---------------------------------------------------------------------------- + */ + +#ifndef _SUNLINSOL_SLUDIST_H +#define _SUNLINSOL_SLUDIST_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * ---------------------------------------------------------------------------- + * PART I: SuperLU-DIST implementation of SUNLinearSolver + * ---------------------------------------------------------------------------- + */ + +struct _SUNLinearSolverContent_SuperLUDIST { + booleantype first_factorize; + int last_flag; + realtype berr; + gridinfo_t *grid; + LUstruct_t *lu; + superlu_dist_options_t *options; + ScalePermstruct_t *scaleperm; + SOLVEstruct_t *solve; + SuperLUStat_t *stat; + sunindextype N; +}; + +typedef struct _SUNLinearSolverContent_SuperLUDIST *SUNLinearSolverContent_SuperLUDIST; + + +/* + * ---------------------------------------------------------------------------- + * PART II: Functions exported by sunlinsol_sludist + * ---------------------------------------------------------------------------- + */ + +SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_SuperLUDIST(N_Vector y, SUNMatrix A, + gridinfo_t *grid, + LUstruct_t *lu, + ScalePermstruct_t *scaleperm, + SOLVEstruct_t *solve, + SuperLUStat_t *stat, + superlu_dist_options_t *options); + +/* + * ---------------------------------------------------------------------------- + * Accessor functions. + * ---------------------------------------------------------------------------- + */ + +SUNDIALS_EXPORT realtype SUNLinSol_SuperLUDIST_GetBerr(SUNLinearSolver LS); +SUNDIALS_EXPORT gridinfo_t* SUNLinSol_SuperLUDIST_GetGridinfo(SUNLinearSolver LS); +SUNDIALS_EXPORT LUstruct_t* SUNLinSol_SuperLUDIST_GetLUstruct(SUNLinearSolver LS); +SUNDIALS_EXPORT superlu_dist_options_t* SUNLinSol_SuperLUDIST_GetSuperLUOptions(SUNLinearSolver LS); +SUNDIALS_EXPORT ScalePermstruct_t* SUNLinSol_SuperLUDIST_GetScalePermstruct(SUNLinearSolver LS); +SUNDIALS_EXPORT SOLVEstruct_t* SUNLinSol_SuperLUDIST_GetSOLVEstruct(SUNLinearSolver LS); +SUNDIALS_EXPORT SuperLUStat_t* SUNLinSol_SuperLUDIST_GetSuperLUStat(SUNLinearSolver LS); + +/* + * ---------------------------------------------------------------------------- + * SuperLU-DIST implementations of SUNLinearSolver operations + * ---------------------------------------------------------------------------- + */ + +SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_SuperLUDIST(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_SuperLUDIST(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolInitialize_SuperLUDIST(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSetup_SuperLUDIST(SUNLinearSolver S, SUNMatrix A); +SUNDIALS_EXPORT int SUNLinSolSolve_SuperLUDIST(SUNLinearSolver S, SUNMatrix A, + N_Vector x, N_Vector b, realtype tol); +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_SuperLUDIST(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSpace_SuperLUDIST(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int SUNLinSolFree_SuperLUDIST(SUNLinearSolver S); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_superlumt.h b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_superlumt.h index 962976b9e..60dd5a862 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_superlumt.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunlinsol/sunlinsol_superlumt.h @@ -5,7 +5,7 @@ * written by Carol S. Woodward @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -14,11 +14,11 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the header file for the SuperLUMT implementation of the + * This is the header file for the SuperLUMT implementation of the * SUNLINSOL module, SUNLINSOL_SUPERLUMT. - * + * * Note: - * - The definition of the generic SUNLinearSolver structure can + * - The definition of the generic SUNLinearSolver structure can * be found in the header file sundials_linearsolver.h. * ----------------------------------------------------------------- */ @@ -31,7 +31,7 @@ #include #include -/* Assume SuperLU_MT library was built with compatible index type */ +/* Assume SuperLU_MT library was built with compatible index type */ #if defined(SUNDIALS_INT64_T) #define _LONGINT #endif @@ -68,27 +68,27 @@ extern "C" { #error Incompatible realtype for SuperLUMT #endif - + /* -------------------------------------------- * SuperLUMT Implementation of SUNLinearSolver * -------------------------------------------- */ - + struct _SUNLinearSolverContent_SuperLUMT { - long int last_flag; + int last_flag; int first_factorize; SuperMatrix *A, *AC, *L, *U, *B; Gstat_t *Gstat; sunindextype *perm_r, *perm_c; sunindextype N; int num_threads; - realtype diag_pivot_thresh; + realtype diag_pivot_thresh; int ordering; superlumt_options_t *options; }; typedef struct _SUNLinearSolverContent_SuperLUMT *SUNLinearSolverContent_SuperLUMT; - + /* ------------------------------------------- * Exported Functions for SUNLINSOL_SUPERLUMT * ------------------------------------------- */ @@ -107,16 +107,17 @@ SUNDIALS_EXPORT int SUNSuperLUMTSetOrdering(SUNLinearSolver S, int ordering_choice); SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_SuperLUMT(SUNLinearSolver S); +SUNDIALS_EXPORT SUNLinearSolver_ID SUNLinSolGetID_SuperLUMT(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolInitialize_SuperLUMT(SUNLinearSolver S); SUNDIALS_EXPORT int SUNLinSolSetup_SuperLUMT(SUNLinearSolver S, SUNMatrix A); SUNDIALS_EXPORT int SUNLinSolSolve_SuperLUMT(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype tol); -SUNDIALS_EXPORT long int SUNLinSolLastFlag_SuperLUMT(SUNLinearSolver S); -SUNDIALS_EXPORT int SUNLinSolSpace_SuperLUMT(SUNLinearSolver S, - long int *lenrwLS, +SUNDIALS_EXPORT sunindextype SUNLinSolLastFlag_SuperLUMT(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSpace_SuperLUMT(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS); SUNDIALS_EXPORT int SUNLinSolFree_SuperLUMT(SUNLinearSolver S); - + #ifdef __cplusplus } diff --git a/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_band.h b/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_band.h index ea0727dce..ffc4660ff 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_band.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_band.h @@ -5,7 +5,7 @@ * Based on code sundials_direct.h by: Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_cusparse.h b/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_cusparse.h new file mode 100644 index 000000000..20cf5081d --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_cusparse.h @@ -0,0 +1,121 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Cody J. Balos @ LLNL + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------- + * This is the header file is for the cuSPARSE implementation of the + * SUNMATRIX module. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNMATRIX_CUSPARSE_H +#define _SUNMATRIX_CUSPARSE_H + +#include + +#include +#include + +#include + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ------------------------------------------ + * Implementation of SUNMATRIX_CUSPARSE + * ------------------------------------------ */ + +/* storage formats */ +#define SUNMAT_CUSPARSE_CSR 0 +#define SUNMAT_CUSPARSE_BCSR 1 + +struct _SUNMatrix_Content_cuSparse { + int M; + int N; + int NNZ; + int nblocks; + int blockrows; + int blockcols; + int blocknnz; + int sparse_type; + booleantype own_data; + booleantype fixed_pattern; + int* colind; + int* rowptrs; + realtype* data; + cusparseMatDescr_t mat_descr; + cusparseHandle_t cusp_handle; +}; + +typedef struct _SUNMatrix_Content_cuSparse *SUNMatrix_Content_cuSparse; + + +/* ------------------------------------------------------------------ + * Constructors. + * ------------------------------------------------------------------ */ + +SUNDIALS_EXPORT SUNMatrix SUNMatrix_cuSparse_NewCSR(int M, int N, int NNZ, cusparseHandle_t cusp); +SUNDIALS_EXPORT SUNMatrix SUNMatrix_cuSparse_MakeCSR(cusparseMatDescr_t mat_descr, int M, int N, int NNZ, + int *rowptrs , int *colind , realtype *data, + cusparseHandle_t cusp); + +/* Creates a CSR block-diagonal matrix where each block shares the same sparsity structure. + Reduces memory usage by only storing the row pointers and column indices for one block. */ +SUNDIALS_EXPORT SUNMatrix SUNMatrix_cuSparse_NewBlockCSR(int nblocks, int blockrows, int blockcols, + int blocknnz, cusparseHandle_t cusp); + + +/* ------------------------------------------------------------------ + * Implementation specific routines. + * ------------------------------------------------------------------ */ + +SUNDIALS_EXPORT int SUNMatrix_cuSparse_SparseType(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatrix_cuSparse_Rows(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatrix_cuSparse_Columns(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatrix_cuSparse_NNZ(SUNMatrix A); +SUNDIALS_EXPORT int* SUNMatrix_cuSparse_IndexPointers(SUNMatrix A); +SUNDIALS_EXPORT int* SUNMatrix_cuSparse_IndexValues(SUNMatrix A); +SUNDIALS_EXPORT realtype* SUNMatrix_cuSparse_Data(SUNMatrix A); + +SUNDIALS_EXPORT int SUNMatrix_cuSparse_SetFixedPattern(SUNMatrix A, booleantype yesno); +SUNDIALS_EXPORT int SUNMatrix_cuSparse_NumBlocks(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatrix_cuSparse_BlockRows(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatrix_cuSparse_BlockColumns(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatrix_cuSparse_BlockNNZ(SUNMatrix A); +SUNDIALS_EXPORT realtype* SUNMatrix_cuSparse_BlockData(SUNMatrix A, int blockidx); +SUNDIALS_EXPORT cusparseMatDescr_t SUNMatrix_cuSparse_MatDescr(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatrix_cuSparse_CopyToDevice(SUNMatrix device, realtype* h_data, + int* h_idxptrs, int* h_idxvals); +SUNDIALS_EXPORT int SUNMatrix_cuSparse_CopyFromDevice(SUNMatrix device, realtype* h_data, + int* h_idxptrs, int* h_idxvals); + + +/* ------------------------------------------------------------------ + * SUNMatrix API routines. + * ------------------------------------------------------------------ */ + +SUNDIALS_EXPORT SUNMatrix_ID SUNMatGetID_cuSparse(SUNMatrix A); +SUNDIALS_EXPORT SUNMatrix SUNMatClone_cuSparse(SUNMatrix A); +SUNDIALS_EXPORT void SUNMatDestroy_cuSparse(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatZero_cuSparse(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatCopy_cuSparse(SUNMatrix A, SUNMatrix B); +SUNDIALS_EXPORT int SUNMatScaleAdd_cuSparse(realtype c, SUNMatrix A, SUNMatrix B); +SUNDIALS_EXPORT int SUNMatScaleAddI_cuSparse(realtype c, SUNMatrix A); +SUNDIALS_EXPORT int SUNMatMatvec_cuSparse(SUNMatrix A, N_Vector x, N_Vector y); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_dense.h b/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_dense.h index de40e560c..79c4e4e91 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_dense.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_dense.h @@ -5,7 +5,7 @@ * Based on code sundials_direct.h by: Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_slunrloc.h b/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_slunrloc.h new file mode 100644 index 000000000..2574a686c --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_slunrloc.h @@ -0,0 +1,86 @@ +/* + * ---------------------------------------------------------------------------- + * Programmer(s): Cody Balos @ LLNL + * ---------------------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ---------------------------------------------------------------------------- + * This is the header file for the SuperLU SLU_NR_loc SUNMatrix. + * ---------------------------------------------------------------------------- + */ + + +#ifndef _SUNMATRIX_SUPERLUNRLOC_H +#define _SUNMATRIX_SUPERLUNRLOC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* ---------------------------------------------------------------------------- + * PART 1: SUNMatrix wrapper for the SuperLU SuperMatrix structure with + * Stype = SLU_NR_loc, i.e. a SuperMatrix stored in a distributed + * CSR format. + * ---------------------------------------------------------------------------*/ + + +struct _SUNMatrixContent_SLUNRloc { + booleantype own_data; + gridinfo_t *grid; + sunindextype *row_to_proc; + pdgsmv_comm_t *gsmv_comm; + SuperMatrix *A_super; + SuperMatrix *ACS_super; +}; + +typedef struct _SUNMatrixContent_SLUNRloc *SUNMatrixContent_SLUNRloc; + + +/* ---------------------------------------------------------------------------- + * PART 2: Functions exported by SUNMatrix_SLUNRloc: + * --------------------------------------------------------------------------*/ + + +SUNDIALS_EXPORT SUNMatrix SUNMatrix_SLUNRloc(SuperMatrix *A_super, gridinfo_t *grid); +SUNDIALS_EXPORT void SUNMatrix_SLUNRloc_Print(SUNMatrix A, FILE *fp); + +/* ---------------------------------------------------------------------------- + * Accessor Functions: + * --------------------------------------------------------------------------*/ + +SUNDIALS_EXPORT SuperMatrix* SUNMatrix_SLUNRloc_SuperMatrix(SUNMatrix A); +SUNDIALS_EXPORT gridinfo_t* SUNMatrix_SLUNRloc_ProcessGrid(SUNMatrix A); +SUNDIALS_EXPORT booleantype SUNMatrix_SLUNRloc_OwnData(SUNMatrix A); + +/* ----------------------------------------------------------------------------- + * SuperLU implementations of various SUNMatrix operations: + * ----------------------------------------------------------------------------*/ + +SUNDIALS_EXPORT SUNMatrix_ID SUNMatGetID_SLUNRloc(SUNMatrix A); +SUNDIALS_EXPORT SUNMatrix SUNMatClone_SLUNRloc(SUNMatrix A); +SUNDIALS_EXPORT void SUNMatDestroy_SLUNRloc(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatZero_SLUNRloc(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatCopy_SLUNRloc(SUNMatrix A, SUNMatrix B); +SUNDIALS_EXPORT int SUNMatScaleAdd_SLUNRloc(realtype c, SUNMatrix A, SUNMatrix B); +SUNDIALS_EXPORT int SUNMatScaleAddI_SLUNRloc(realtype c, SUNMatrix A); +SUNDIALS_EXPORT int SUNMatMatvecSetup_SLUNRloc(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatMatvec_SLUNRloc(SUNMatrix A, N_Vector x, N_Vector y); +SUNDIALS_EXPORT int SUNMatSpace_SLUNRloc(SUNMatrix A, long int *lenrw, long int *leniw); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_sparse.h b/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_sparse.h index aea60aafa..b42af27f5 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_sparse.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunmatrix/sunmatrix_sparse.h @@ -6,7 +6,7 @@ * Slaven Peles @ LLNL, and Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -110,6 +110,9 @@ SUNDIALS_EXPORT SUNMatrix SUNSparseFromBandMatrix(SUNMatrix A, realtype droptol, int sparsetype); +SUNDIALS_EXPORT int SUNSparseMatrix_ToCSR(const SUNMatrix A, SUNMatrix* Bout); +SUNDIALS_EXPORT int SUNSparseMatrix_ToCSC(const SUNMatrix A, SUNMatrix* Bout); + SUNDIALS_EXPORT int SUNSparseMatrix_Realloc(SUNMatrix A); SUNDIALS_EXPORT int SUNSparseMatrix_Reallocate(SUNMatrix A, sunindextype NNZ); diff --git a/deps/AMICI/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_fixedpoint.h b/deps/AMICI/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_fixedpoint.h index e75c42b02..046f2939a 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_fixedpoint.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_fixedpoint.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -41,24 +41,27 @@ struct _SUNNonlinearSolverContent_FixedPoint { SUNNonlinSolConvTestFn CTest; /* convergence test function */ /* nonlinear solver variables */ - int m; /* number of acceleration vectors to use */ - int *imap; /* array of length m */ - realtype *R; /* array of length m*m */ - realtype *gamma; /* array of length m */ - realtype *cvals; /* array of length m+1 for fused vector op */ - N_Vector *df; /* vector array of length m */ - N_Vector *dg; /* vector array of length m */ - N_Vector *q; /* vector array of length m */ - N_Vector *Xvecs; /* array of length m+1 for fused vector op */ - N_Vector yprev; /* temporary vectors for performing solve */ - N_Vector gy; - N_Vector fold; - N_Vector gold; - N_Vector delta; /* correction vector (change between 2 iterates) */ - int curiter; /* current iteration number in a solve attempt */ - int maxiters; /* maximum number of iterations per solve attempt */ - long int niters; /* total number of iterations across all solves */ - long int nconvfails; /* total number of convergence failures */ + int m; /* number of acceleration vectors to use */ + int *imap; /* array of length m */ + booleantype damping; /* flag to apply dampling in acceleration */ + realtype beta; /* damping paramter */ + realtype *R; /* array of length m*m */ + realtype *gamma; /* array of length m */ + realtype *cvals; /* array of length m+1 for fused vector op */ + N_Vector *df; /* vector array of length m */ + N_Vector *dg; /* vector array of length m */ + N_Vector *q; /* vector array of length m */ + N_Vector *Xvecs; /* array of length m+1 for fused vector op */ + N_Vector yprev; /* temporary vectors for performing solve */ + N_Vector gy; + N_Vector fold; + N_Vector gold; + N_Vector delta; /* correction vector (change between 2 iterates) */ + int curiter; /* current iteration number in a solve attempt */ + int maxiters; /* maximum number of iterations per solve attempt */ + long int niters; /* total number of iterations across all solves */ + long int nconvfails; /* total number of convergence failures */ + void *ctest_data; /* data to pass to convergence test function */ }; typedef struct _SUNNonlinearSolverContent_FixedPoint *SUNNonlinearSolverContent_FixedPoint; @@ -88,11 +91,15 @@ SUNDIALS_EXPORT int SUNNonlinSolSetSysFn_FixedPoint(SUNNonlinearSolver NLS, SUNNonlinSolSysFn SysFn); SUNDIALS_EXPORT int SUNNonlinSolSetConvTestFn_FixedPoint(SUNNonlinearSolver NLS, - SUNNonlinSolConvTestFn CTestFn); + SUNNonlinSolConvTestFn CTestFn, + void* ctest_data); SUNDIALS_EXPORT int SUNNonlinSolSetMaxIters_FixedPoint(SUNNonlinearSolver NLS, int maxiters); +SUNDIALS_EXPORT int SUNNonlinSolSetDamping_FixedPoint(SUNNonlinearSolver NLS, + realtype beta); + /* get functions */ SUNDIALS_EXPORT int SUNNonlinSolGetNumIters_FixedPoint(SUNNonlinearSolver NLS, long int *niters); diff --git a/deps/AMICI/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_newton.h b/deps/AMICI/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_newton.h index 3db653c1c..f1e54bb67 100644 --- a/deps/AMICI/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_newton.h +++ b/deps/AMICI/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_newton.h @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -49,6 +49,7 @@ struct _SUNNonlinearSolverContent_Newton { int maxiters; /* maximum number of iterations in a solve attempt */ long int niters; /* total number of nonlinear iterations across all solves */ long int nconvfails; /* total number of convergence failures across all solves */ + void* ctest_data; /* data to pass to convergence test function */ }; typedef struct _SUNNonlinearSolverContent_Newton *SUNNonlinearSolverContent_Newton; @@ -84,7 +85,8 @@ SUNDIALS_EXPORT int SUNNonlinSolSetLSolveFn_Newton(SUNNonlinearSolver NLS, SUNNonlinSolLSolveFn LSolveFn); SUNDIALS_EXPORT int SUNNonlinSolSetConvTestFn_Newton(SUNNonlinearSolver NLS, - SUNNonlinSolConvTestFn CTestFn); + SUNNonlinSolConvTestFn CTestFn, + void* ctest_data); SUNDIALS_EXPORT int SUNNonlinSolSetMaxIters_Newton(SUNNonlinearSolver NLS, int maxiters); diff --git a/deps/AMICI/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_petscsnes.h b/deps/AMICI/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_petscsnes.h new file mode 100644 index 000000000..be9d5c520 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_petscsnes.h @@ -0,0 +1,97 @@ +/* ----------------------------------------------------------------------------- + * Programmer(s): Cody J. Balos @ LLNL + * ----------------------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------------------- + * This is the header file for the SUNNonlinearSolver module implementation of + * a wrapper to the PETSc SNES nonlinear solvers. + * + * Part I defines the solver-specific content structure. + * + * Part II contains prototypes for the solver constructor and operations. + * ---------------------------------------------------------------------------*/ + +#ifndef _SUNNONLINSOL_PETSCSNES_H +#define _SUNNONLINSOL_PETSCSNES_H + +#include "sundials/sundials_types.h" +#include "sundials/sundials_nvector.h" +#include "sundials/sundials_nonlinearsolver.h" +#include + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------------------------------------------------------------------- + * I. Content structure + * ---------------------------------------------------------------------------*/ + +struct _SUNNonlinearSolverContent_PetscSNES { + int sysfn_last_err; /* last error returned by the system function Sys */ + PetscErrorCode petsc_last_err; /* last error return by PETSc */ + long int nconvfails; /* number of nonlinear converge failures (recoverable or not) */ + long int nni; /* number of nonlinear iterations */ + void *imem; /* SUNDIALS integrator memory */ + SNES snes; /* PETSc SNES context */ + Vec r; /* nonlinear residual */ + N_Vector y, f; /* wrappers for PETSc vectors in system function */ + /* functions provided by the integrator */ + SUNNonlinSolSysFn Sys; /* nonlinear system function */ +}; + +typedef struct _SUNNonlinearSolverContent_PetscSNES *SUNNonlinearSolverContent_PetscSNES; + +/* ----------------------------------------------------------------------------- + * II: Exported functions + * ---------------------------------------------------------------------------*/ + +/* Constructor to create solver and allocates memory */ + +SUNDIALS_EXPORT SUNNonlinearSolver SUNNonlinSol_PetscSNES(N_Vector y, SNES snes); + +/* SUNNonlinearSolver API functions */ + +SUNDIALS_EXPORT SUNNonlinearSolver_Type SUNNonlinSolGetType_PetscSNES(SUNNonlinearSolver NLS); + +SUNDIALS_EXPORT int SUNNonlinSolInitialize_PetscSNES(SUNNonlinearSolver NLS); + +SUNDIALS_EXPORT int SUNNonlinSolSolve_PetscSNES(SUNNonlinearSolver NLS, + N_Vector y0, N_Vector y, + N_Vector w, realtype tol, + booleantype callLSetup, void* mem); + +SUNDIALS_EXPORT int SUNNonlinSolSetSysFn_PetscSNES(SUNNonlinearSolver NLS, + SUNNonlinSolSysFn SysFn); + +SUNDIALS_EXPORT int SUNNonlinSolGetNumIters_PetscSNES(SUNNonlinearSolver NLS, long int* nni); + +SUNDIALS_EXPORT int SUNNonlinSolGetNumConvFails_PetscSNES(SUNNonlinearSolver NLS, + long int* nconvfails); + +SUNDIALS_EXPORT int SUNNonlinSolFree_PetscSNES(SUNNonlinearSolver NLS); + +/* Implementation specific functions */ + +SUNDIALS_EXPORT int SUNNonlinSolGetSNES_PetscSNES(SUNNonlinearSolver NLS, SNES* snes); + +SUNDIALS_EXPORT int SUNNonlinSolGetPetscError_PetscSNES(SUNNonlinearSolver NLS, + PetscErrorCode* err); + +SUNDIALS_EXPORT int SUNNonlinSolGetSysFn_PetscSNES(SUNNonlinearSolver NLS, + SUNNonlinSolSysFn* SysFn); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/AMICI/ThirdParty/sundials/src/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/CMakeLists.txt index 934c7a9d5..cccea3340 100644 --- a/deps/AMICI/ThirdParty/sundials/src/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/CMakeLists.txt @@ -1,8 +1,9 @@ # --------------------------------------------------------------- -# Programmer: David Gardner, Slaven Peles, and Cody Balos @ LLNL +# Programmer(s): David J. Gardner, Slaven Peles, and +# Cody Balos @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -11,60 +12,59 @@ # SPDX-License-Identifier: BSD-3-Clause # SUNDIALS Copyright End # --------------------------------------------------------------- -# src level CMakeLists.txt for SUNDIALS (for cmake build system) +# src level CMakeLists.txt for SUNDIALS # --------------------------------------------------------------- # Add all of the shared SUNDIALS components -ADD_SUBDIRECTORY(sundials) -ADD_SUBDIRECTORY(nvector) -ADD_SUBDIRECTORY(sunmatrix) -ADD_SUBDIRECTORY(sunlinsol) -ADD_SUBDIRECTORY(sunnonlinsol) +add_subdirectory(sundials) +add_subdirectory(nvector) +add_subdirectory(sunmatrix) +add_subdirectory(sunlinsol) +add_subdirectory(sunnonlinsol) # ARKODE library -IF(BUILD_ARKODE) - ADD_SUBDIRECTORY(arkode) - IF(F77_INTERFACE_ENABLE AND F77_FOUND) - ADD_SUBDIRECTORY(arkode/fcmix) - ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) -ENDIF(BUILD_ARKODE) +if(BUILD_ARKODE) + add_subdirectory(arkode) + if(F77_INTERFACE_ENABLE AND F77_FOUND) + add_subdirectory(arkode/fcmix) + endif(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(BUILD_ARKODE) # CVODE library -IF(BUILD_CVODE) - ADD_SUBDIRECTORY(cvode) - IF(F77_INTERFACE_ENABLE AND F77_FOUND) - ADD_SUBDIRECTORY(cvode/fcmix) - ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) -ENDIF(BUILD_CVODE) +if(BUILD_CVODE) + add_subdirectory(cvode) + if(F77_INTERFACE_ENABLE AND F77_FOUND) + add_subdirectory(cvode/fcmix) + endif(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(BUILD_CVODE) # CVODES library -IF(BUILD_CVODES) - ADD_SUBDIRECTORY(cvodes) -ENDIF(BUILD_CVODES) +if(BUILD_CVODES) + add_subdirectory(cvodes) +endif(BUILD_CVODES) # IDA library -IF(BUILD_IDA) - ADD_SUBDIRECTORY(ida) - IF(F77_INTERFACE_ENABLE AND F77_FOUND) - ADD_SUBDIRECTORY(ida/fcmix) - ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) -ENDIF(BUILD_IDA) +if(BUILD_IDA) + add_subdirectory(ida) + if(F77_INTERFACE_ENABLE AND F77_FOUND) + add_subdirectory(ida/fcmix) + endif(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(BUILD_IDA) # IDAS library -IF(BUILD_IDAS) - ADD_SUBDIRECTORY(idas) -ENDIF(BUILD_IDAS) +if(BUILD_IDAS) + add_subdirectory(idas) +endif(BUILD_IDAS) # KINSOL library -IF(BUILD_KINSOL) - ADD_SUBDIRECTORY(kinsol) - IF(F77_INTERFACE_ENABLE AND F77_FOUND) - ADD_SUBDIRECTORY(kinsol/fcmix) - ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) -ENDIF(BUILD_KINSOL) +if(BUILD_KINSOL) + add_subdirectory(kinsol) + if(F77_INTERFACE_ENABLE AND F77_FOUND) + add_subdirectory(kinsol/fcmix) + endif(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(BUILD_KINSOL) # CPODES library -IF(BUILD_CPODES) - ADD_SUBDIRECTORY(cpodes) -ENDIF(BUILD_CPODES) - +if(BUILD_CPODES) + add_subdirectory(cpodes) +endif(BUILD_CPODES) diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/arkode/CMakeLists.txt index 50a8d0c3e..4e80c8d79 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,11 +12,17 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the ARKODE library +# --------------------------------------------------------------- + +install(CODE "MESSAGE(\"\nInstall ARKODE\n\")") -INSTALL(CODE "MESSAGE(\"\nInstall ARKODE\n\")") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) # Add variable arkode_SOURCES with the sources for the ARKODE library -SET(arkode_SOURCES +set(arkode_SOURCES arkode.c arkode_adapt.c arkode_arkstep.c @@ -39,7 +45,7 @@ SET(arkode_SOURCES # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the ARKODE library -SET(shared_SOURCES +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_matrix.c ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c @@ -51,12 +57,13 @@ SET(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c ${sundials_SOURCE_DIR}/src/sundials/sundials_version.c ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector_senswrapper.c + ${sundials_SOURCE_DIR}/src/sundials/sundials_futils.c ${sundials_SOURCE_DIR}/src/nvector/serial/nvector_serial.c ) # Add variable sunmatrix_SOURCES with the common SUNMatrix sources which will # also be included in the ARKODE library -SET(sunmatrix_SOURCES +set(sunmatrix_SOURCES ${sundials_SOURCE_DIR}/src/sunmatrix/band/sunmatrix_band.c ${sundials_SOURCE_DIR}/src/sunmatrix/dense/sunmatrix_dense.c ${sundials_SOURCE_DIR}/src/sunmatrix/sparse/sunmatrix_sparse.c @@ -64,7 +71,7 @@ SET(sunmatrix_SOURCES # Add variable sunlinsol_SOURCES with the common SUNLinearSolver sources which will # also be included in the ARKODE library -SET(sunlinsol_SOURCES +set(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/band/sunlinsol_band.c ${sundials_SOURCE_DIR}/src/sunlinsol/dense/sunlinsol_dense.c ${sundials_SOURCE_DIR}/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c @@ -76,13 +83,13 @@ SET(sunlinsol_SOURCES # Add variable sunnonlinsol_SOURCES with the common SUNNonlinearSolver sources which will # also be included in the ARKODE library -SET(sunnonlinsol_SOURCES +set(sunnonlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunnonlinsol/newton/sunnonlinsol_newton.c ${sundials_SOURCE_DIR}/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c ) # Add variable arkode_HEADERS with the exported ARKODE header files -SET(arkode_HEADERS +set(arkode_HEADERS arkode.h arkode_arkstep.h arkode_bandpre.h @@ -96,58 +103,58 @@ SET(arkode_HEADERS ) # Add prefix with complete path to the ARKODE header files -ADD_PREFIX(${sundials_SOURCE_DIR}/include/arkode/ arkode_HEADERS) +add_prefix(${sundials_SOURCE_DIR}/include/arkode/ arkode_HEADERS) # Add source directories to include directories for access to # implementation only header files. -INCLUDE_DIRECTORIES(.) -INCLUDE_DIRECTORIES(../sundials) +include_directories(.) +include_directories(../sundials) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) # Build the static library -IF(BUILD_STATIC_LIBS) +if(BUILD_STATIC_LIBS) # Add the build target for the static ARKODE library - ADD_LIBRARY(sundials_arkode_static STATIC + add_library(sundials_arkode_static STATIC ${arkode_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ${sunnonlinsol_SOURCES}) # Set the library name and make sure it is not deleted - SET_TARGET_PROPERTIES(sundials_arkode_static + set_target_properties(sundials_arkode_static PROPERTIES OUTPUT_NAME sundials_arkode CLEAN_DIRECT_OUTPUT 1) # Install the ARKODE library - INSTALL(TARGETS sundials_arkode_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS sundials_arkode_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +endif(BUILD_STATIC_LIBS) # Build the shared library -IF(BUILD_SHARED_LIBS) +if(BUILD_SHARED_LIBS) # Add the build target for the ARKODE library - ADD_LIBRARY(sundials_arkode_shared SHARED + add_library(sundials_arkode_shared SHARED ${arkode_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ${sunnonlinsol_SOURCES}) - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_arkode_shared m) - ENDIF() + if(UNIX) + target_link_libraries(sundials_arkode_shared m) + endif() # Set the library name and make sure it is not deleted - SET_TARGET_PROPERTIES(sundials_arkode_shared + set_target_properties(sundials_arkode_shared PROPERTIES OUTPUT_NAME sundials_arkode CLEAN_DIRECT_OUTPUT 1) # Set VERSION and SOVERSION for shared libraries - SET_TARGET_PROPERTIES(sundials_arkode_shared + set_target_properties(sundials_arkode_shared PROPERTIES VERSION ${arkodelib_VERSION} SOVERSION ${arkodelib_SOVERSION}) # Install the ARKODE library - INSTALL(TARGETS sundials_arkode_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS sundials_arkode_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) +endif(BUILD_SHARED_LIBS) # Install the ARKODE header files -INSTALL(FILES ${arkode_HEADERS} DESTINATION include/arkode) +install(FILES ${arkode_HEADERS} DESTINATION include/arkode) # -MESSAGE(STATUS "Added ARKODE module") +message(STATUS "Added ARKODE module") diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/README b/deps/AMICI/ThirdParty/sundials/src/arkode/README deleted file mode 100644 index 6f476557a..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/README +++ /dev/null @@ -1,73 +0,0 @@ - ARKODE - Release 3.1.0, Feb 2019 - Daniel R. Reynolds - Department of Mathematics, SMU - -ARKODE is a solver for multi-rate ODE systems (initial value problems) -given in explicit form M*dy/dt = f(t,y). It is written in ANSI standard C. - -ARKODE can be used both on serial and parallel (MPI) computers. The main -difference is in the NVECTOR module of vector kernels. The desired -version is obtained when compiling the example files by linking the -appropriate library of NVECTOR kernels. In the parallel version, -communication between processors is done with the MPI (Message Passage -Interface) system, with OpenMP, or with Pthreads. - -When used with the serial NVECTOR module, ARKODE provides both direct (dense -and band) and preconditioned Krylov (iterative) linear solvers. Many different -iterative solvers are available: scaled preconditioned GMRES (SPGMR), -scaled preconditioned Flexible GMRES (SPFGMR), scaled preconditioned -conjugate gradient, scaled preconditioned BiCGStab (SPBCG), -and scaled preconditioned TFQMR (SPTFQMR). When ARKODE is used with -the parallel NVECTOR module, only the Krylov linear solvers are available. -For the serial version, there is a banded preconditioner module called -ARKBANDPRE available for use with the Krylov solvers, while for the -parallel version there is a preconditioner module called ARKBBDPRE -which provides a band-block-diagonal preconditioner. - -ARKODE is part of a software family called SUNDIALS: SUite of Nonlinear -and DIfferential/ALgebraic equation Solvers. This suite consists of -ARKODE, CVODE, CVODES, KINSOL, IDAS, and IDA. The directory structure -of the package supplied reflects this family relationship. - -For use with Fortran applications, a set of Fortran/C interface routines, -called FARKODE, is also supplied. These are written in C, but assume that -the user calling program and all user-supplied routines are in Fortran. - -The notes below provide the location of documentation, directions for the -installation of the ARKode package, and relevant references. Following that -is a brief history of revisions to the package. - - -A. Documentation ----------------- - -/sundials/doc/arkode/ contains PDF files for the ARKODE User Guide [1] -(ark_guide.pdf) and the ARKODE Examples [2] (ark_examples.pdf) documents. - - -B. Installation ---------------- - -For basic installation instructions see the file /sundials/INSTALL_GUIDE.pdf. -For complete installation instructions see the "Installation Procedure" -chapter in the ARKODE User Guide. - - -C. Releases ------------ - -v. 3.1.0 - Feb. 2019 -v. 3.0.2 - Jan. 2019 -v. 3.0.1 - Dec. 2018 -v. 3.0.0 - Dec. 2018 -v. 2.2.1 - Oct. 2018 -v. 2.2.0 - Sep. 2018 -v. 2.1.2 - Jul. 2018 -v. 2.1.1 - May 2018 -v. 2.1.0 - Nov. 2017 -v. 2.0.0 - Sep. 2017 -v. 1.1.0 - Sep. 2016 -v. 1.0.2 - Aug. 2015 -v. 1.0.1 - Mar. 2015 -v. 1.0.0 - Mar. 2015 diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/README.md b/deps/AMICI/ThirdParty/sundials/src/arkode/README.md new file mode 100644 index 000000000..741d1d371 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/README.md @@ -0,0 +1,56 @@ +# ARKode +### Version 4.2.0 (Mar 2020) + +**Daniel R. Reynolds and Jean M. Sexton + Department of Mathematics, SMU** + +**David J. Gardner, Alan C. Hindmarsh, and Carol S. Woodward + Center for Applied Scientific Computing, LLNL** + +ARKode is a package for the solution of stiff, nonstiff, and multirate ordinary +differential equation (ODE) systems (initial value problems) given in linearly +implicit the form +``` +M y' = f1(t,y) + f2(t,y), y(t0) = y0. +``` +The integration methods implemented in ARKode include explicit and implicit +Runge-Kutta methods, implicit-explicit (IMEX) additive Runge-Kutta methods, and +multirate infatesemial step (MIS) methods. + +ARKode is part of a the SUNDIALS Suite of Nonlinear and Differential/Algebraic +equation Solvers which consists of ARKode, CVODE, CVODES, IDA, IDAS, and KINSOL. +It is written in ANSI standard C and can be used in a variety of computing +environments including serial, shared memory, distributed memory, and +accelerator-based (e.g., GPU) systems. This flexibility is obtained from a +modular design that leverages the shared vector, matrix, linear solver, and +nonlinear solver APIs used across SUNDIALS packages. + +For use with Fortran applications, a set of Fortran/C interface routines, called +FARKODE, is also supplied. These are written in C, but assume that the user +calling program and all user-supplied routines are in Fortran. + +## Documentation + +See the [ARKode User Guide](/doc/arkode/ark_guide.pdf) and +[ARKode Examples](/doc/arkode/ark_examples.pdf) document for more information +about ARKode usage and the provided example programs respectively. + +## Installation + +For installation instructions see the [INSTALL_GUIDE](/INSTALL_GUIDE.pdf) +or "Installation Procedure" chapter in the ARKode User Guide. + +## Release History + +Information on recent changes to ARKode can be found in the "Introduction" +chapter of the ARKode User Guide and a complete release history is available in +the "SUNDIALS Release History" appendix of the ARKode User Guide. + +## References + +* D. R. Reynolds, D. J. Gardner, A. C. Hindmarsh, C. S. Woodward, and + J. M. Sexton, "User Documentation for ARKode v4.2.0," LLNL technical report + LLNL-SM-668082, Mar 2020. + +* D. R. Reynolds, "Example Programs for ARKode v4.2.0," Technical Report, + Southern Methodist University Center for Scientific Computation, Mar 2020. diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode.c index 65916ba25..53c80e744 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -26,6 +26,7 @@ #include #include "arkode_impl.h" +#include "arkode_interp_impl.h" #include #include @@ -74,32 +75,28 @@ ARKodeMem arkCreate() /* Set uround */ ark_mem->uround = UNIT_ROUNDOFF; - /* Set default values for integrator optional inputs */ - iret = arkSetDefaults(ark_mem); - if (iret != ARK_SUCCESS) { - arkProcessError(NULL, 0, "ARKode", "arkCreate", - "Error setting default solver options"); - return(NULL); - } - /* Initialize time step module to NULL */ - ark_mem->step_attachlinsol = NULL; - ark_mem->step_attachmasssol = NULL; - ark_mem->step_disablelsetup = NULL; - ark_mem->step_disablemsetup = NULL; - ark_mem->step_getlinmem = NULL; - ark_mem->step_getmassmem = NULL; + ark_mem->step_attachlinsol = NULL; + ark_mem->step_attachmasssol = NULL; + ark_mem->step_disablelsetup = NULL; + ark_mem->step_disablemsetup = NULL; + ark_mem->step_getlinmem = NULL; + ark_mem->step_getmassmem = NULL; ark_mem->step_getimplicitrhs = NULL; - ark_mem->step_mmult = NULL; - ark_mem->step_getgammas = NULL; - ark_mem->step_init = NULL; - ark_mem->step_fullrhs = NULL; - ark_mem->step = NULL; - ark_mem->step_mem = NULL; + ark_mem->step_mmult = NULL; + ark_mem->step_getgammas = NULL; + ark_mem->step_init = NULL; + ark_mem->step_fullrhs = NULL; + ark_mem->step = NULL; + ark_mem->step_mem = NULL; /* Initialize root finding variables */ ark_mem->root_mem = NULL; + /* Initialize inequality constraints variables */ + ark_mem->constraintsSet = SUNFALSE; + ark_mem->constraints = NULL; + /* Initialize diagnostics reporting variables */ ark_mem->report = SUNFALSE; ark_mem->diagfp = NULL; @@ -109,12 +106,38 @@ ARKodeMem arkCreate() ark_mem->liw = 39; /* fcn/data ptr, int, long int, sunindextype, booleantype */ /* No mallocs have been done yet */ - ark_mem->VabstolMallocDone = SUNFALSE; - ark_mem->VRabstolMallocDone = SUNFALSE; - ark_mem->MallocDone = SUNFALSE; + ark_mem->VabstolMallocDone = SUNFALSE; + ark_mem->VRabstolMallocDone = SUNFALSE; + ark_mem->MallocDone = SUNFALSE; + ark_mem->ConstraintsMallocDone = SUNFALSE; /* No user-supplied step postprocessing function yet */ - ark_mem->ProcessStep = NULL; + ark_mem->ProcessStep = NULL; + ark_mem->ps_data = NULL; + + /* No user-supplied stage postprocessing function yet */ + ark_mem->ProcessStage = NULL; + + /* No user_data pointer yet */ + ark_mem->user_data = NULL; + + /* Allocate step adaptivity structure and note storage */ + ark_mem->hadapt_mem = arkAdaptInit(); + if (ark_mem->hadapt_mem == NULL) { + arkProcessError(NULL, ARK_MEM_FAIL, "ARKode", "arkCreate", + "Allocation of step adaptivity structure failed"); + return(NULL); + } + ark_mem->lrw += ARK_ADAPT_LRW; + ark_mem->liw += ARK_ADAPT_LIW; + + /* Set default values for integrator optional inputs */ + iret = arkSetDefaults(ark_mem); + if (iret != ARK_SUCCESS) { + arkProcessError(NULL, 0, "ARKode", "arkCreate", + "Error setting default solver options"); + return(NULL); + } /* Return pointer to ARKode memory block */ return(ark_mem); @@ -162,7 +185,7 @@ int arkResize(ARKodeMem ark_mem, N_Vector y0, realtype hscale, realtype t0, ARKVecResizeFn resize, void *resize_data) { sunindextype lrw1, liw1, lrw_diff, liw_diff; - int ier; + int retval; /* Check ark_mem */ if (ark_mem==NULL) { @@ -191,8 +214,8 @@ int arkResize(ARKodeMem ark_mem, N_Vector y0, realtype hscale, /* Update time-stepping parameters */ /* adjust upcoming step size depending on hscale */ - if (hscale < 0.0) hscale = 1.0; - if (hscale != 1.0) { + if (hscale < ZERO) hscale = ONE; + if (hscale != ONE) { /* Encode hscale into ark_mem structure */ ark_mem->eta = hscale; @@ -219,52 +242,59 @@ int arkResize(ARKodeMem ark_mem, N_Vector y0, realtype hscale, /* Resize the ARKode vectors */ /* Vabstol */ - ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, liw_diff, y0, &ark_mem->Vabstol); - if (ier != ARK_SUCCESS) return(ier); + if (retval != ARK_SUCCESS) return(retval); /* VRabstol */ - ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, liw_diff, y0, &ark_mem->VRabstol); - if (ier != ARK_SUCCESS) return(ier); + if (retval != ARK_SUCCESS) return(retval); /* ewt */ - ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, liw_diff, y0, &ark_mem->ewt); - if (ier != ARK_SUCCESS) return(ier); + if (retval != ARK_SUCCESS) return(retval); /* rwt */ if (ark_mem->rwt_is_ewt) { /* update pointer to ewt */ ark_mem->rwt = ark_mem->ewt; - } else { /* resize if distinct from ewt */ - ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + } else { /* resize if distinct from ewt */ + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, liw_diff, y0, &ark_mem->rwt); - if (ier != ARK_SUCCESS) return(ier); + if (retval != ARK_SUCCESS) return(retval); } /* yn */ - ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, liw_diff, y0, &ark_mem->yn); - if (ier != ARK_SUCCESS) return(ier); + if (retval != ARK_SUCCESS) return(retval); + /* fn */ + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &ark_mem->fn); + if (retval != ARK_SUCCESS) return(retval); /* tempv* */ - ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, liw_diff, y0, &ark_mem->tempv1); - if (ier != ARK_SUCCESS) return(ier); - ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + if (retval != ARK_SUCCESS) return(retval); + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, liw_diff, y0, &ark_mem->tempv2); - if (ier != ARK_SUCCESS) return(ier); - ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + if (retval != ARK_SUCCESS) return(retval); + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, liw_diff, y0, &ark_mem->tempv3); - if (ier != ARK_SUCCESS) return(ier); - ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + if (retval != ARK_SUCCESS) return(retval); + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, liw_diff, y0, &ark_mem->tempv4); - if (ier != ARK_SUCCESS) return(ier); + if (retval != ARK_SUCCESS) return(retval); + /* Indicate that the fullrhs is not required after each step, this is updated + by the interpolation module constructor and stepper init function */ + ark_mem->call_fullrhs = SUNFALSE; - /* Resize interpolation structure memory */ - if (ark_mem->interp) { - ier = arkInterpResize(ark_mem, ark_mem->interp, resize, - resize_data, lrw_diff, liw_diff, y0); - if (ier != ARK_SUCCESS) { - arkProcessError(ark_mem, ier, "ARKode", "arkResize", + /* Resize the interpolation structure memory */ + if (ark_mem->interp != NULL) { + retval = arkInterpResize(ark_mem, ark_mem->interp, resize, + resize_data, lrw_diff, liw_diff, y0); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode", "arkResize", "Interpolation module resize failure"); - return(ier); + return(retval); } } @@ -272,7 +302,7 @@ int arkResize(ARKodeMem ark_mem, N_Vector y0, realtype hscale, N_VScale(ONE, y0, ark_mem->yn); /* Indicate that problem size is new */ - ark_mem->resized = SUNTRUE; + ark_mem->resized = SUNTRUE; ark_mem->firststage = SUNTRUE; /* Problem has been successfully re-sized */ @@ -322,14 +352,17 @@ int arkSStolerances(ARKodeMem ark_mem, realtype reltol, realtype abstol) return(ARK_ILL_INPUT); } + /* Set flag indicating whether abstol == 0 */ + ark_mem->atolmin0 = (abstol == ZERO); + /* Copy tolerances into memory */ ark_mem->reltol = reltol; ark_mem->Sabstol = abstol; ark_mem->itol = ARK_SS; - /* enforce use of arkEwtSet */ + /* enforce use of arkEwtSetSS */ ark_mem->user_efun = SUNFALSE; - ark_mem->efun = arkEwtSet; + ark_mem->efun = arkEwtSetSS; ark_mem->e_data = ark_mem; return(ARK_SUCCESS); @@ -338,6 +371,9 @@ int arkSStolerances(ARKodeMem ark_mem, realtype reltol, realtype abstol) int arkSVtolerances(ARKodeMem ark_mem, realtype reltol, N_Vector abstol) { + /* local variables */ + realtype abstolmin; + /* Check inputs */ if (ark_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", @@ -354,12 +390,26 @@ int arkSVtolerances(ARKodeMem ark_mem, realtype reltol, N_Vector abstol) "arkSVtolerances", MSG_ARK_BAD_RELTOL); return(ARK_ILL_INPUT); } - if (N_VMin(abstol) < ZERO) { + if (abstol == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSVtolerances", MSG_ARK_NULL_ABSTOL); + return(ARK_ILL_INPUT); + } + if (abstol->ops->nvmin == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkSVtolerances", + "Missing N_VMin routine from N_Vector"); + return(ARK_ILL_INPUT); + } + abstolmin = N_VMin(abstol); + if (abstolmin < ZERO) { arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkSVtolerances", MSG_ARK_BAD_ABSTOL); return(ARK_ILL_INPUT); } + /* Set flag indicating whether min(abstol) == 0 */ + ark_mem->atolmin0 = (abstolmin == ZERO); + /* Copy tolerances into memory */ if ( !(ark_mem->VabstolMallocDone) ) { ark_mem->Vabstol = N_VClone(ark_mem->ewt); @@ -371,9 +421,9 @@ int arkSVtolerances(ARKodeMem ark_mem, realtype reltol, N_Vector abstol) ark_mem->reltol = reltol; ark_mem->itol = ARK_SV; - /* enforce use of arkEwtSet */ + /* enforce use of arkEwtSetSV */ ark_mem->user_efun = SUNFALSE; - ark_mem->efun = arkEwtSet; + ark_mem->efun = arkEwtSetSV; ark_mem->e_data = ark_mem; return(ARK_SUCCESS); @@ -397,7 +447,7 @@ int arkWFtolerances(ARKodeMem ark_mem, ARKEwtFn efun) ark_mem->itol = ARK_WF; ark_mem->user_efun = SUNTRUE; ark_mem->efun = efun; - ark_mem->e_data = NULL; /* set to user_data in InitialSetup */ + ark_mem->e_data = ark_mem->user_data; return(ARK_SUCCESS); } @@ -444,6 +494,9 @@ int arkResStolerance(ARKodeMem ark_mem, realtype rabstol) return(ARK_ILL_INPUT); } + /* Set flag indicating whether rabstol == 0 */ + ark_mem->Ratolmin0 = (rabstol == ZERO); + /* Allocate space for rwt if necessary */ if (ark_mem->rwt_is_ewt) { ark_mem->rwt_is_ewt = SUNFALSE; @@ -467,23 +520,40 @@ int arkResStolerance(ARKodeMem ark_mem, realtype rabstol) int arkResVtolerance(ARKodeMem ark_mem, N_Vector rabstol) { + /* local variables */ + realtype rabstolmin; + /* Check inputs */ if (ark_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", - "arkResVtolerances", MSG_ARK_NO_MEM); + "arkResVtolerance", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } if (ark_mem->MallocDone == SUNFALSE) { arkProcessError(ark_mem, ARK_NO_MALLOC, "ARKode", - "arkResVtolerances", MSG_ARK_NO_MALLOC); + "arkResVtolerance", MSG_ARK_NO_MALLOC); return(ARK_NO_MALLOC); } - if (N_VMin(rabstol) < ZERO) { + if (rabstol == NULL) { + arkProcessError(ark_mem, ARK_NO_MALLOC, "ARKode", + "arkResVtolerance", MSG_ARK_NULL_RABSTOL); + return(ARK_NO_MALLOC); + } + if (rabstol->ops->nvmin == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkResVtolerance", + "Missing N_VMin routine from N_Vector"); + return(ARK_ILL_INPUT); + } + rabstolmin = N_VMin(rabstol); + if (rabstolmin < ZERO) { arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", - "arkResVtolerances", MSG_ARK_BAD_RABSTOL); + "arkResVtolerance", MSG_ARK_BAD_RABSTOL); return(ARK_ILL_INPUT); } + /* Set flag indicating whether min(abstol) == 0 */ + ark_mem->Ratolmin0 = (rabstolmin == ZERO); + /* Allocate space for rwt if necessary */ if (ark_mem->rwt_is_ewt) { ark_mem->rwt_is_ewt = SUNFALSE; @@ -537,7 +607,7 @@ int arkResFtolerance(ARKodeMem ark_mem, ARKRwtFn rfun) ark_mem->ritol = ARK_WF; ark_mem->user_rfun = SUNTRUE; ark_mem->rfun = rfun; - ark_mem->r_data = NULL; /* set to user_data in InitialSetup */ + ark_mem->r_data = ark_mem->user_data; return(ARK_SUCCESS); } @@ -569,11 +639,12 @@ int arkEvolve(ARKodeMem ark_mem, realtype tout, N_Vector yout, realtype *tret, int itask) { long int nstloc; - int retval, kflag, istate, ir, ier; + int retval, kflag, istate, ir; int ewtsetOK; realtype troundoff, nrm; booleantype inactive_roots; - + realtype dsm; + int nflag, ncf, nef, constrfails; /* Check and process inputs */ @@ -624,36 +695,43 @@ int arkEvolve(ARKodeMem ark_mem, realtype tout, N_Vector yout, - perform initial integrator setup */ if (ark_mem->nst == 0) { ark_mem->tretlast = *tret = ark_mem->tcur; - ier = arkInitialSetup(ark_mem, tout); - if (ier!= ARK_SUCCESS) return(ier); + retval = arkInitialSetup(ark_mem, tout); + if (retval!= ARK_SUCCESS) return(retval); } /* perform first-step-after-resize initializations */ if (ark_mem->nst > 0 && ark_mem->resized) { - ier = arkPostResizeSetup(ark_mem); - if (ier!= ARK_SUCCESS) return(ier); + retval = arkPostResizeSetup(ark_mem); + if (retval!= ARK_SUCCESS) return(retval); } /* perform stopping tests */ if (ark_mem->nst > 0 && !ark_mem->resized) - if (arkStopTests(ark_mem, tout, yout, tret, itask, &ier)) - return(ier); + if (arkStopTests(ark_mem, tout, yout, tret, itask, &retval)) + return(retval); /*-------------------------------------------------- - Looping point for internal steps + Looping point for successful internal steps - - update the ewt vector for the next step + - update the ewt/rwt vectors for upcoming step - check for errors (too many steps, too much accuracy requested, step size too small) - - take a new step (via time stepper); stop on error + - loop over attempts at a new step: + * try to take step (via time stepper module), + handle solver convergence or other failures + * perform constraint-handling (if selected) + * check temporal error + * if all of the above pass, complete step by + updating current time, solution, error & + stepsize history arrays. - perform stop tests: - - check for root in last step taken - - check if tout was passed - - check if close to tstop - - check if in ONE_STEP mode (must return) + * check for root in last step taken + * check if tout was passed + * check if close to tstop + * check if in ONE_STEP mode (must return) --------------------------------------------------*/ nstloc = 0; for(;;) { @@ -748,14 +826,70 @@ int arkEvolve(ARKodeMem ark_mem, realtype tout, N_Vector yout, ark_mem->next_h = ark_mem->h; } - /* Call time stepper module to take a step */ - kflag = ark_mem->step((void*) ark_mem); + /* Looping point for step attempts */ + dsm = ZERO; + ncf = nef = constrfails = 0; + nflag = FIRST_CALL; + for(;;) { + + /* increment attempt counter */ + ark_mem->nst_attempts++; + + /* Call time stepper module to attempt a step: + 0 => step completed successfully + >0 => step encountered recoverable failure; reduce step if possible + <0 => step encountered unrecoverable failure */ + kflag = ark_mem->step((void*) ark_mem, &dsm, &nflag); + if (kflag < 0) break; + + /* handle solver convergence failures */ + kflag = arkCheckConvergence(ark_mem, &nflag, &ncf); + if (kflag < 0) break; + + /* perform constraint-handling (if selected, and if solver check passed) */ + if (ark_mem->constraintsSet && (kflag == ARK_SUCCESS)) { + kflag = arkCheckConstraints(ark_mem, &constrfails, &nflag); + if (kflag < 0) break; + } + + /* when fixed time-stepping is enabled, 'success' == successful stage solves + (checked in previous block), so just enforce no step size change */ + if (ark_mem->fixedstep) { + ark_mem->eta = ONE; + break; + } + + /* check temporal error (if checks above passed) */ + if (kflag == ARK_SUCCESS) { + kflag = arkCheckTemporalError(ark_mem, &nflag, &nef, dsm); + if (kflag < 0) break; + } + + /* if we've made it here then no nonrecoverable failures occurred; someone above + has recommended an 'eta' value for the next step -- enforce bounds on that value + and set upcoming step size */ + ark_mem->eta = SUNMIN(ark_mem->eta, ark_mem->hadapt_mem->etamax); + ark_mem->eta = SUNMAX(ark_mem->eta, ark_mem->hmin / SUNRabs(ark_mem->h)); + ark_mem->eta /= SUNMAX(ONE, SUNRabs(ark_mem->h) * ark_mem->hmax_inv*ark_mem->eta); + + /* break attempt loop on successful step */ + if (kflag == ARK_SUCCESS) break; + + /* unsuccessful step, if |h| = hmin, return ARK_ERR_FAILURE */ + if (SUNRabs(ark_mem->h) <= ark_mem->hmin*ONEPSM) return(ARK_ERR_FAILURE); - /* Process successful step, catch additional errors to send to arkHandleFailure */ - if (kflag == ARK_SUCCESS) - kflag = arkCompleteStep(ark_mem); + /* update h, hprime and next_h for next iteration */ + ark_mem->h *= ark_mem->eta; + ark_mem->next_h = ark_mem->hprime = ark_mem->h; - /* Process failed step cases, and exit loop */ + } + + /* If step attempt loop succeeded, complete step (update current time, solution, + error stepsize history arrays; call user-supplied step postprocessing function) + (added stuff from arkStep_PrepareNextStep -- revisit) */ + if (kflag == ARK_SUCCESS) kflag = arkCompleteStep(ark_mem, dsm); + + /* If step attempt loop failed, process flag and return to user */ if (kflag != ARK_SUCCESS) { istate = arkHandleFailure(ark_mem, kflag); ark_mem->tretlast = *tret = ark_mem->tcur; @@ -849,18 +983,20 @@ int arkEvolve(ARKodeMem ark_mem, realtype tout, N_Vector yout, This routine computes the k-th derivative of the interpolating polynomial at the time t and stores the result in the vector - dky. This routine internally calls arkInterpEvaluate to perform the - interpolation. We have the restriction that 0 <= k <= 3. This - routine uses an interpolating polynomial of degree - max(ark_dense_q, k), i.e. it will form a polynomial of the - degree requested by the user through ark_dense_q, unless - higher-order derivatives are requested. - - This function is called by arkEvolve with k=0 and t=tout to perform - interpolation of outputs, but may also be called indirectly by the - user via time step module *StepGetDky calls. Note: in all cases - it will be called after ark_tcur has been updated to correspond - with the end time of the last successful step. + dky. This routine internally calls arkInterpEvaluate to perform + the interpolation. We have the restriction that 0 <= k <= 3. + This routine uses an interpolating polynomial of degree + max(deg, k), i.e. it will form a polynomial of the degree + available by the interpolation module and/or requested by + the user through deg, unless higher-order derivatives are + requested. + + This function is called by arkEvolve with k=0 and t=tout to + perform interpolation of outputs, but may also be called + indirectly by the user via time step module *StepGetDky calls. + Note: in all cases it will be called after ark_tcur has been + updated to correspond with the end time of the last successful + step. ---------------------------------------------------------------*/ int arkGetDky(ARKodeMem ark_mem, realtype t, int k, N_Vector dky) { @@ -901,7 +1037,7 @@ int arkGetDky(ARKodeMem ark_mem, realtype t, int k, N_Vector dky) /* call arkInterpEvaluate to evaluate result */ s = (t - ark_mem->tcur) / ark_mem->h; retval = arkInterpEvaluate(ark_mem, ark_mem->interp, s, - k, ark_mem->dense_q, dky); + k, ARK_INTERP_MAX_DEGREE, dky); if (retval != ARK_SUCCESS) { arkProcessError(ark_mem, retval, "ARKode", "arkGetDky", "Error calling arkInterpEvaluate"); @@ -924,12 +1060,26 @@ void arkFree(void **arkode_mem) ark_mem = (ARKodeMem) (*arkode_mem); + /* free vector storage */ arkFreeVectors(ark_mem); - if (ark_mem->interp != NULL) - arkInterpFree(&(ark_mem->interp)); - if (ark_mem->root_mem != NULL) + /* free the time step adaptivity module */ + if (ark_mem->hadapt_mem != NULL) { + free(ark_mem->hadapt_mem); + ark_mem->hadapt_mem = NULL; + } + + /* free the interpolation module */ + if (ark_mem->interp != NULL) { + arkInterpFree(ark_mem, ark_mem->interp); + ark_mem->interp = NULL; + } + + /* free the root-finding module */ + if (ark_mem->root_mem != NULL) { (void) arkRootFree(*arkode_mem); + ark_mem->root_mem = NULL; + } free(*arkode_mem); *arkode_mem = NULL; @@ -941,44 +1091,6 @@ void arkFree(void **arkode_mem) Internal functions that may be replaced by the user ===============================================================*/ -/*--------------------------------------------------------------- - arkEwtSet - - This routine is responsible for setting the error weight vector ewt, - according to tol_type, as follows: - - (1) ewt[i] = 1 / (reltol * SUNRabs(ycur[i]) + abstol), i=0,...,neq-1 - if tol_type = ARK_SS - (2) ewt[i] = 1 / (reltol * SUNRabs(ycur[i]) + abstol[i]), i=0,...,neq-1 - if tol_type = ARK_SV - - arkEwtSet returns 0 if ewt is successfully set as above to a - positive vector and -1 otherwise. In the latter case, ewt is - considered undefined. - - All the real work is done in the routines arkEwtSetSS, arkEwtSetSV. - ---------------------------------------------------------------*/ -int arkEwtSet(N_Vector ycur, N_Vector weight, void *data) -{ - ARKodeMem ark_mem; - int flag = 0; - - /* data points to ark_mem here */ - ark_mem = (ARKodeMem) data; - - switch(ark_mem->itol) { - case ARK_SS: - flag = arkEwtSetSS(ark_mem, ycur, weight); - break; - case ARK_SV: - flag = arkEwtSetSV(ark_mem, ycur, weight); - break; - } - - return(flag); -} - - /*--------------------------------------------------------------- arkRwtSet @@ -1124,8 +1236,13 @@ int arkInit(ARKodeMem ark_mem, realtype t0, N_Vector y0) return(ARK_MEM_FAIL); } - /* Initialize the interpolation structure to NULL */ - ark_mem->interp = NULL; + /* Create default Hermite interpolation module */ + ark_mem->interp = arkInterpCreate_Hermite(ark_mem, ARK_INTERP_MAX_DEGREE); + if (ark_mem->interp == NULL) { + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode", "arkInit", + "Unable to allocate interpolation module"); + return(ARK_MEM_FAIL); + } /* All error checking is complete at this point */ @@ -1134,17 +1251,18 @@ int arkInit(ARKodeMem ark_mem, realtype t0, N_Vector y0) ark_mem->tn = t0; /* Set step parameters */ - ark_mem->hold = ZERO; - ark_mem->tolsf = ONE; - ark_mem->hmin = ZERO; /* no minimum step size */ - ark_mem->hmax_inv = ZERO; /* no maximum step size */ + ark_mem->hold = ZERO; + ark_mem->tolsf = ONE; /* Initialize yn */ N_VScale(ONE, y0, ark_mem->yn); /* Initialize all the counters */ - ark_mem->nst = 0; - ark_mem->nhnil = 0; + ark_mem->nst_attempts = 0; + ark_mem->nst = 0; + ark_mem->nhnil = 0; + ark_mem->ncfn = 0; + ark_mem->netf = 0; /* Initialize other integrator optional outputs */ ark_mem->h0u = ZERO; @@ -1154,8 +1272,9 @@ int arkInit(ARKodeMem ark_mem, realtype t0, N_Vector y0) ark_mem->rwt_is_ewt = SUNTRUE; /* Indicate that problem size is new */ - ark_mem->resized = SUNTRUE; - ark_mem->firststage = SUNTRUE; + ark_mem->resized = SUNTRUE; + ark_mem->firststage = SUNTRUE; + ark_mem->initialized = SUNFALSE; /* Problem has been successfully initialized */ ark_mem->MallocDone = SUNTRUE; @@ -1200,10 +1319,8 @@ int arkReInit(ARKodeMem ark_mem, realtype t0, N_Vector y0) ark_mem->tn = t0; /* Set step parameters */ - ark_mem->hold = ZERO; - ark_mem->tolsf = ONE; - ark_mem->hmin = ZERO; /* no minimum step size */ - ark_mem->hmax_inv = ZERO; /* no maximum step size */ + ark_mem->hold = ZERO; + ark_mem->tolsf = ONE; /* Do not reset the linear solver addresses to NULL. This means that if the user does not re-set these manually, we'll re-use @@ -1212,13 +1329,25 @@ int arkReInit(ARKodeMem ark_mem, realtype t0, N_Vector y0) /* Initialize yn */ N_VScale(ONE, y0, ark_mem->yn); + /* Reset time step adaptivity structure */ + ark_mem->hadapt_mem->ehist[0] = ONE; + ark_mem->hadapt_mem->ehist[1] = ONE; + ark_mem->hadapt_mem->hhist[0] = ZERO; + ark_mem->hadapt_mem->hhist[1] = ZERO; + ark_mem->hadapt_mem->nst_acc = 0; + ark_mem->hadapt_mem->nst_exp = 0; + /* Initialize all the counters */ - ark_mem->nst = 0; - ark_mem->nhnil = 0; + ark_mem->nst_attempts = 0; + ark_mem->nst = 0; + ark_mem->nhnil = 0; + ark_mem->ncfn = 0; + ark_mem->netf = 0; /* Indicate that problem size is new */ - ark_mem->resized = SUNTRUE; - ark_mem->firststage = SUNTRUE; + ark_mem->resized = SUNTRUE; + ark_mem->firststage = SUNTRUE; + ark_mem->initialized = SUNFALSE; /* Initialize other integrator optional outputs */ ark_mem->h0u = ZERO; @@ -1238,93 +1367,114 @@ int arkReInit(ARKodeMem ark_mem, realtype t0, N_Vector y0) void arkPrintMem(ARKodeMem ark_mem, FILE *outfile) { /* output general values */ - fprintf(outfile, "ark_itol = %i\n", ark_mem->itol); - fprintf(outfile, "ark_ritol = %i\n", ark_mem->ritol); - fprintf(outfile, "ark_dense_q = %i\n", ark_mem->dense_q); - fprintf(outfile, "ark_mxhnil = %i\n", ark_mem->mxhnil); - fprintf(outfile, "ark_mxstep = %li\n", ark_mem->mxstep); - fprintf(outfile, "ark_lrw1 = %li\n", (long int) ark_mem->lrw1); - fprintf(outfile, "ark_liw1 = %li\n", (long int) ark_mem->liw1); - fprintf(outfile, "ark_lrw = %li\n", (long int) ark_mem->lrw); - fprintf(outfile, "ark_liw = %li\n", (long int) ark_mem->liw); - fprintf(outfile, "ark_user_efun = %i\n", ark_mem->user_efun); - fprintf(outfile, "ark_tstopset = %i\n", ark_mem->tstopset); - fprintf(outfile, "ark_tstop = %" RSYM"\n", ark_mem->tstop); - fprintf(outfile, "ark_report = %i\n", ark_mem->report); - fprintf(outfile, "ark_VabstolMallocDone = %i\n", ark_mem->VabstolMallocDone); - fprintf(outfile, "ark_MallocDone = %i\n", ark_mem->MallocDone); - fprintf(outfile, "ark_resized = %i\n", ark_mem->resized); - fprintf(outfile, "ark_firststage = %i\n", ark_mem->firststage); - fprintf(outfile, "ark_uround = %" RSYM"\n", ark_mem->uround); - fprintf(outfile, "ark_reltol = %" RSYM"\n", ark_mem->reltol); - fprintf(outfile, "ark_Sabstol = %" RSYM"\n", ark_mem->Sabstol); - fprintf(outfile, "ark_fixedstep = %i\n", ark_mem->fixedstep); - fprintf(outfile, "ark_tolsf = %" RSYM"\n", ark_mem->tolsf); + fprintf(outfile, "itol = %i\n", ark_mem->itol); + fprintf(outfile, "ritol = %i\n", ark_mem->ritol); + fprintf(outfile, "mxhnil = %i\n", ark_mem->mxhnil); + fprintf(outfile, "mxstep = %li\n", ark_mem->mxstep); + fprintf(outfile, "lrw1 = %li\n", (long int) ark_mem->lrw1); + fprintf(outfile, "liw1 = %li\n", (long int) ark_mem->liw1); + fprintf(outfile, "lrw = %li\n", (long int) ark_mem->lrw); + fprintf(outfile, "liw = %li\n", (long int) ark_mem->liw); + fprintf(outfile, "user_efun = %i\n", ark_mem->user_efun); + fprintf(outfile, "tstopset = %i\n", ark_mem->tstopset); + fprintf(outfile, "tstop = %" RSYM"\n", ark_mem->tstop); + fprintf(outfile, "report = %i\n", ark_mem->report); + fprintf(outfile, "VabstolMallocDone = %i\n", ark_mem->VabstolMallocDone); + fprintf(outfile, "MallocDone = %i\n", ark_mem->MallocDone); + fprintf(outfile, "resized = %i\n", ark_mem->resized); + fprintf(outfile, "firststage = %i\n", ark_mem->firststage); + fprintf(outfile, "uround = %" RSYM"\n", ark_mem->uround); + fprintf(outfile, "reltol = %" RSYM"\n", ark_mem->reltol); + fprintf(outfile, "Sabstol = %" RSYM"\n", ark_mem->Sabstol); + fprintf(outfile, "fixedstep = %i\n", ark_mem->fixedstep); + fprintf(outfile, "tolsf = %" RSYM"\n", ark_mem->tolsf); + fprintf(outfile, "call_fullrhs = %i\n", ark_mem->call_fullrhs); /* output counters */ - fprintf(outfile, "ark_nhnil = %i\n", ark_mem->nhnil); - fprintf(outfile, "ark_nst = %li\n", ark_mem->nst); + fprintf(outfile, "nhnil = %i\n", ark_mem->nhnil); + fprintf(outfile, "nst_attempts = %li\n", ark_mem->nst_attempts); + fprintf(outfile, "nst = %li\n", ark_mem->nst); + fprintf(outfile, "ncfn = %li\n", ark_mem->ncfn); + fprintf(outfile, "netf = %li\n", ark_mem->netf); /* output time-stepping values */ - fprintf(outfile, "ark_hin = %" RSYM"\n", ark_mem->hin); - fprintf(outfile, "ark_h = %" RSYM"\n", ark_mem->h); - fprintf(outfile, "ark_hprime = %" RSYM"\n", ark_mem->hprime); - fprintf(outfile, "ark_next_h = %" RSYM"\n", ark_mem->next_h); - fprintf(outfile, "ark_eta = %" RSYM"\n", ark_mem->eta); - fprintf(outfile, "ark_tcur = %" RSYM"\n", ark_mem->tcur); - fprintf(outfile, "ark_tretlast = %" RSYM"\n", ark_mem->tretlast); - fprintf(outfile, "ark_hmin = %" RSYM"\n", ark_mem->hmin); - fprintf(outfile, "ark_hmax_inv = %" RSYM"\n", ark_mem->hmax_inv); - fprintf(outfile, "ark_h0u = %" RSYM"\n", ark_mem->h0u); - fprintf(outfile, "ark_tn = %" RSYM"\n", ark_mem->tn); - fprintf(outfile, "ark_hold = %" RSYM"\n", ark_mem->hold); + fprintf(outfile, "hin = %" RSYM"\n", ark_mem->hin); + fprintf(outfile, "h = %" RSYM"\n", ark_mem->h); + fprintf(outfile, "hprime = %" RSYM"\n", ark_mem->hprime); + fprintf(outfile, "next_h = %" RSYM"\n", ark_mem->next_h); + fprintf(outfile, "eta = %" RSYM"\n", ark_mem->eta); + fprintf(outfile, "tcur = %" RSYM"\n", ark_mem->tcur); + fprintf(outfile, "tretlast = %" RSYM"\n", ark_mem->tretlast); + fprintf(outfile, "hmin = %" RSYM"\n", ark_mem->hmin); + fprintf(outfile, "hmax_inv = %" RSYM"\n", ark_mem->hmax_inv); + fprintf(outfile, "h0u = %" RSYM"\n", ark_mem->h0u); + fprintf(outfile, "tn = %" RSYM"\n", ark_mem->tn); + fprintf(outfile, "hold = %" RSYM"\n", ark_mem->hold); + fprintf(outfile, "maxnef = %i\n", ark_mem->maxnef); + fprintf(outfile, "maxncf = %i\n", ark_mem->maxncf); + + /* output time-stepping adaptivity structure */ + fprintf(outfile, "timestep adaptivity structure:\n"); + arkPrintAdaptMem(ark_mem->hadapt_mem, outfile); + + /* output inequality constraints quantities */ + fprintf(outfile, "constraintsSet = %i\n", ark_mem->constraintsSet); + fprintf(outfile, "ConstraintsDone = %i\n", ark_mem->ConstraintsMallocDone); + fprintf(outfile, "maxconstrfails = %i\n", ark_mem->maxconstrfails); /* output root-finding quantities */ if (ark_mem->root_mem != NULL) (void) arkPrintRootMem((void*) ark_mem, outfile); /* output interpolation quantities */ - if (ark_mem->interp != NULL) - arkPrintInterpMem(ark_mem->interp, outfile); + arkInterpPrintMem(ark_mem->interp, outfile); #ifdef DEBUG_OUTPUT /* output vector quantities */ if (ark_mem->Vabstol != NULL) { - fprintf(outfile, "ark_Vapbsol:\n"); + fprintf(outfile, "Vapbsol:\n"); N_VPrint_Serial(ark_mem->Vabstol); } if (ark_mem->ewt != NULL) { - fprintf(outfile, "ark_ewt:\n"); + fprintf(outfile, "ewt:\n"); N_VPrint_Serial(ark_mem->ewt); } if (!ark_mem->rwt_is_ewt && ark_mem->rwt != NULL) { - fprintf(outfile, "ark_rwt:\n"); + fprintf(outfile, "rwt:\n"); N_VPrint_Serial(ark_mem->rwt); } if (ark_mem->ycur != NULL) { - fprintf(outfile, "ark_ycur:\n"); + fprintf(outfile, "ycur:\n"); N_VPrint_Serial(ark_mem->ycur); } if (ark_mem->yn != NULL) { - fprintf(outfile, "ark_yn:\n"); + fprintf(outfile, "yn:\n"); N_VPrint_Serial(ark_mem->yn); } + if (ark_mem->fn != NULL) { + fprintf(outfile, "fn:\n"); + N_VPrint_Serial(ark_mem->fn); + } if (ark_mem->tempv1 != NULL) { - fprintf(outfile, "ark_tempv1:\n"); + fprintf(outfile, "tempv1:\n"); N_VPrint_Serial(ark_mem->tempv1); } if (ark_mem->tempv2 != NULL) { - fprintf(outfile, "ark_tempv2:\n"); + fprintf(outfile, "tempv2:\n"); N_VPrint_Serial(ark_mem->tempv2); } if (ark_mem->tempv3 != NULL) { - fprintf(outfile, "ark_tempv3:\n"); + fprintf(outfile, "tempv3:\n"); N_VPrint_Serial(ark_mem->tempv3); } if (ark_mem->tempv4 != NULL) { - fprintf(outfile, "ark_tempv4:\n"); + fprintf(outfile, "tempv4:\n"); N_VPrint_Serial(ark_mem->tempv4); } + if (ark_mem->constraints != NULL) { + fprintf(outfile, "constraints:\n"); + N_VPrint_Serial(ark_mem->constraints); + } #endif } @@ -1339,11 +1489,9 @@ void arkPrintMem(ARKodeMem ark_mem, FILE *outfile) ---------------------------------------------------------------*/ booleantype arkCheckTimestepper(ARKodeMem ark_mem) { - if ( (ark_mem->step_init == NULL) || - (ark_mem->step == NULL) || - (ark_mem->step_mem == NULL) ) - return(SUNFALSE); - if ( (ark_mem->interp != NULL) && + if ( (ark_mem->step_init == NULL) || + (ark_mem->step == NULL) || + (ark_mem->step_mem == NULL) || (ark_mem->step_fullrhs == NULL) ) return(SUNFALSE); return(SUNTRUE); @@ -1368,8 +1516,7 @@ booleantype arkCheckNvector(N_Vector tmpl) /* to be updated?? */ (tmpl->ops->nvinv == NULL) || (tmpl->ops->nvaddconst == NULL) || (tmpl->ops->nvmaxnorm == NULL) || - (tmpl->ops->nvwrmsnorm == NULL) || - (tmpl->ops->nvmin == NULL)) + (tmpl->ops->nvwrmsnorm == NULL)) return(SUNFALSE); else return(SUNTRUE); @@ -1482,6 +1629,10 @@ booleantype arkAllocVectors(ARKodeMem ark_mem, N_Vector tmpl) if (!arkAllocVec(ark_mem, tmpl, &ark_mem->yn)) return(SUNFALSE); + /* Allocate fn if needed */ + if (!arkAllocVec(ark_mem, tmpl, &ark_mem->fn)) + return(SUNFALSE); + /* Allocate tempv1 if needed */ if (!arkAllocVec(ark_mem, tmpl, &ark_mem->tempv1)) return(SUNFALSE); @@ -1518,7 +1669,10 @@ void arkFreeVectors(ARKodeMem ark_mem) arkFreeVec(ark_mem, &ark_mem->tempv3); arkFreeVec(ark_mem, &ark_mem->tempv4); arkFreeVec(ark_mem, &ark_mem->yn); + arkFreeVec(ark_mem, &ark_mem->fn); arkFreeVec(ark_mem, &ark_mem->Vabstol); + if (ark_mem->ConstraintsMallocDone) + arkFreeVec(ark_mem, &ark_mem->constraints); } @@ -1534,8 +1688,9 @@ void arkFreeVectors(ARKodeMem ark_mem) ---------------------------------------------------------------*/ int arkInitialSetup(ARKodeMem ark_mem, realtype tout) { - int retval, hflag, istate, ier; + int retval, hflag, istate; realtype tout_hin, rh; + booleantype conOK; /* Temporarily set ark_h */ ark_mem->h = SUNRabs(tout - ark_mem->tcur); @@ -1556,23 +1711,37 @@ int arkInitialSetup(ARKodeMem ark_mem, realtype tout) /* Check that user has supplied an initial step size if fixedstep mode is on */ if ( (ark_mem->fixedstep) && (ark_mem->hin == ZERO) ) { - arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", - "arkInitialSetup", + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkInitialSetup", "Fixed step mode enabled, but no step size set"); return(ARK_ILL_INPUT); } - /* Set data for efun (if left unspecified) */ - if (ark_mem->user_efun) - ark_mem->e_data = ark_mem->user_data; - else - ark_mem->e_data = ark_mem; + /* If using a built-in routine for error/residual weights with abstol==0, + ensure that N_VMin is available */ + if ((!ark_mem->user_efun) && (ark_mem->atolmin0) && (!ark_mem->yn->ops->nvmin)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkInitialSetup", + "N_VMin unimplemented (required by error-weight function)"); + return(ARK_ILL_INPUT); + } + if ( (!ark_mem->user_rfun) && (!ark_mem->rwt_is_ewt) && + (ark_mem->Ratolmin0) && (!ark_mem->yn->ops->nvmin) ) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkInitialSetup", + "N_VMin unimplemented (required by residual-weight function)"); + return(ARK_ILL_INPUT); + } + + /* Check to see if y0 satisfies constraints */ + if (ark_mem->constraintsSet) { + conOK = N_VConstrMask(ark_mem->constraints, ark_mem->yn, ark_mem->tempv1); + if (!conOK) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkInitialSetup", MSG_ARK_Y0_FAIL_CONSTR); + return(ARK_ILL_INPUT); + } + } /* Load initial error weights */ - ier = ark_mem->efun(ark_mem->yn, - ark_mem->ewt, - ark_mem->e_data); - if (ier != 0) { + retval = ark_mem->efun(ark_mem->yn, ark_mem->ewt, ark_mem->e_data); + if (retval != 0) { if (ark_mem->itol == ARK_WF) arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkInitialSetup", MSG_ARK_EWT_FAIL); @@ -1582,20 +1751,12 @@ int arkInitialSetup(ARKodeMem ark_mem, realtype tout) return(ARK_ILL_INPUT); } - /* Set data for rfun (if left unspecified) */ - if (ark_mem->user_rfun) - ark_mem->r_data = ark_mem->user_data; - else - ark_mem->r_data = ark_mem; - /* Load initial residual weights */ if (ark_mem->rwt_is_ewt) { /* update pointer to ewt */ ark_mem->rwt = ark_mem->ewt; } else { - ier = ark_mem->rfun(ark_mem->yn, - ark_mem->rwt, - ark_mem->r_data); - if (ier != 0) { + retval = ark_mem->rfun(ark_mem->yn, ark_mem->rwt, ark_mem->r_data); + if (retval != 0) { if (ark_mem->itol == ARK_WF) arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkInitialSetup", MSG_ARK_RWT_FAIL); @@ -1606,19 +1767,21 @@ int arkInitialSetup(ARKodeMem ark_mem, realtype tout) } } - /* Allocate interpolation memory (if unallocated, and if needed) */ - if (ark_mem->interp == NULL) { - ark_mem->interp = arkInterpCreate(ark_mem); - if (ark_mem->interp == NULL) - return(ARK_MEM_FAIL); - } + /* Call fullrhs (used in estimating initial step, explicit steppers, Hermite + interpolation module, and possibly (but not always) arkRootCheck1) */ + retval = ark_mem->step_fullrhs(ark_mem, ark_mem->tcur, + ark_mem->yn, ark_mem->fn, 0); + if (retval != 0) return(ARK_RHSFUNC_FAIL); /* Fill initial interpolation data (if needed) */ if (ark_mem->interp != NULL) { - ier = arkInterpInit(ark_mem, ark_mem->interp, ark_mem->tcur); - if (ier != 0) return(ier); + retval = arkInterpInit(ark_mem, ark_mem->interp, ark_mem->tcur); + if (retval != 0) return(retval); } + /* initialization complete */ + ark_mem->initialized = SUNTRUE; + /* Test input tstop for legality. */ if ( ark_mem->tstopset ) { if ( (ark_mem->tstop - ark_mem->tcur)*(tout - ark_mem->tcur) <= ZERO ) { @@ -1675,6 +1838,9 @@ int arkInitialSetup(ARKodeMem ark_mem, realtype tout) ark_mem->h0u = ark_mem->h; ark_mem->hprime = ark_mem->h; + /* Set first step growth factor */ + ark_mem->hadapt_mem->etamax = ark_mem->hadapt_mem->etamx1; + /* Check for zeros of root function g at and near t0. */ if (ark_mem->root_mem != NULL) if (ark_mem->root_mem->nrtfn > 0) { @@ -1703,13 +1869,25 @@ int arkInitialSetup(ARKodeMem ark_mem, realtype tout) ---------------------------------------------------------------*/ int arkPostResizeSetup(ARKodeMem ark_mem) { - int retval, ier; + int retval; + booleantype call_fullrhs; + + /* re-initialize the time stepper module */ + if (ark_mem->step_init == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkPostResizeSetup", "Time stepper module is missing"); + return(ARK_ILL_INPUT); + } + retval = ark_mem->step_init(ark_mem, 1); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode", "arkPostResizeSetup", + "Error in re-initialization of time stepper module"); + return(retval); + } /* Load updated error weights */ - ier = ark_mem->efun(ark_mem->yn, - ark_mem->ewt, - ark_mem->e_data); - if (ier != 0) { + retval = ark_mem->efun(ark_mem->yn, ark_mem->ewt, ark_mem->e_data); + if (retval != 0) { if (ark_mem->itol == ARK_WF) arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkPostResizeSetup", MSG_ARK_EWT_FAIL); @@ -1721,10 +1899,8 @@ int arkPostResizeSetup(ARKodeMem ark_mem) /* Load updated residual weights */ if (!ark_mem->rwt_is_ewt) { - ier = ark_mem->rfun(ark_mem->yn, - ark_mem->rwt, - ark_mem->r_data); - if (ier != 0) { + retval = ark_mem->rfun(ark_mem->yn, ark_mem->rwt, ark_mem->r_data); + if (retval != 0) { if (ark_mem->itol == ARK_WF) arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkPostResizeSetup", MSG_ARK_RWT_FAIL); @@ -1735,10 +1911,23 @@ int arkPostResizeSetup(ARKodeMem ark_mem) } } + /* Call fullrhs if needed (used in explicit steppers, Hermite interpolant + module, and possibly (but not always) arkRootCheck1) */ + call_fullrhs = ark_mem->call_fullrhs; + if (ark_mem->root_mem != NULL) + if (ark_mem->root_mem->nrtfn > 0) + call_fullrhs = SUNTRUE; + + if (call_fullrhs) { + retval = ark_mem->step_fullrhs(ark_mem, ark_mem->tcur, + ark_mem->yn, ark_mem->fn, 0); + if (retval != 0) return(ARK_RHSFUNC_FAIL); + } + /* Fill initial interpolation data (if needed) */ if (ark_mem->interp != NULL) { - ier = arkInterpInit(ark_mem, ark_mem->interp, ark_mem->tcur); - if (ier != 0) return(ier); + retval = arkInterpInit(ark_mem, ark_mem->interp, ark_mem->tcur); + if (retval != 0) return(retval); } /* Check for legal tstop (correct direction of integration) */ @@ -1750,19 +1939,6 @@ int arkPostResizeSetup(ARKodeMem ark_mem) } } - /* re-initialize the time stepper module */ - if (ark_mem->step_init == NULL) { - arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", - "arkPostResizeSetup", "Time stepper module is missing"); - return(ARK_ILL_INPUT); - } - retval = ark_mem->step_init(ark_mem, 1); - if (retval != ARK_SUCCESS) { - arkProcessError(ark_mem, retval, "ARKode", "arkPostResizeSetup", - "Error in re-initialization of time stepper module"); - return(retval); - } - /* Check for zeros of root function g at and near t0. */ if (ark_mem->root_mem != NULL) if (ark_mem->root_mem->nrtfn > 0) { @@ -1808,8 +1984,23 @@ int arkStopTests(ARKodeMem ark_mem, realtype tout, N_Vector yout, if (ark_mem->root_mem != NULL) if (ark_mem->root_mem->nrtfn > 0) { + /* Shortcut to roots found in previous step */ irfndp = ark_mem->root_mem->irfnd; + /* If the full rhs was not computed in the last call to arkCompleteStep + and roots were found in the previous step, then compute the full rhs + for possible use in arkRootCheck2 (not always necessary) */ + if (!(ark_mem->call_fullrhs) && irfndp != 0) { + retval = ark_mem->step_fullrhs(ark_mem, ark_mem->tcur, + ark_mem->yn, ark_mem->fn, 1); + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode", "arkStopTests", + MSG_ARK_RHSFUNC_FAILED); + *ier = ARK_RHSFUNC_FAIL; + return(1); + } + } + retval = arkRootCheck2((void*) ark_mem); if (retval == CLOSERT) { @@ -1995,7 +2186,7 @@ int arkHin(ARKodeMem ark_mem, realtype tout) /* If successful, we can use ydd */ if (retval == ARK_SUCCESS) {hgOK = SUNTRUE; break;} /* f() failed recoverably; cut step size and test it again */ - hg *= POINT2; + hg *= RCONST(0.2); } /* If f() failed recoverably H0_ITERS times */ @@ -2013,10 +2204,10 @@ int arkHin(ARKodeMem ark_mem, realtype tout) /* Propose new step size */ hnew = (yddnrm*hub*hub > TWO) ? SUNRsqrt(TWO/yddnrm) : SUNRsqrt(hg*hub); - + /* If last pass, stop now with hnew */ if (count1 == H0_ITERS) break; - + hrat = hnew/hg; /* Accept hnew if it does not differ from hg by more than a factor of 2 */ @@ -2065,7 +2256,7 @@ realtype arkUpperBoundH0(ARKodeMem ark_mem, realtype tdist) N_VInv(temp1, temp1); N_VLinearSum(H0_UBFACTOR, temp2, ONE, temp1, temp1); - N_VAbs(ark_mem->interp->fnew, temp2); + N_VAbs(ark_mem->fn, temp2); N_VDiv(temp2, temp1, temp1); hub_inv = N_VMaxNorm(temp1); @@ -2098,8 +2289,7 @@ int arkYddNorm(ARKodeMem ark_mem, realtype hg, realtype *yddnrm) } /* increment y with a multiple of f */ - N_VLinearSum(hg, ark_mem->interp->fnew, ONE, - ark_mem->yn, ark_mem->ycur); + N_VLinearSum(hg, ark_mem->fn, ONE, ark_mem->yn, ark_mem->ycur); /* compute y', via the ODE RHS routine */ retval = ark_mem->step_fullrhs(ark_mem, ark_mem->tcur+hg, @@ -2108,12 +2298,11 @@ int arkYddNorm(ARKodeMem ark_mem, realtype hg, realtype *yddnrm) if (retval != 0) return(ARK_RHSFUNC_FAIL); /* difference new f and original f to estimate y'' */ - N_VLinearSum(ONE/hg, ark_mem->tempv1, -ONE/hg, - ark_mem->interp->fnew, ark_mem->tempv1); + N_VLinearSum(ONE/hg, ark_mem->tempv1, -ONE/hg, ark_mem->fn, ark_mem->tempv1); /* reset ycur to equal yn (unnecessary?) */ N_VScale(ONE, ark_mem->yn, ark_mem->ycur); - + /* compute norm of y'' */ *yddnrm = N_VWrmsNorm(ark_mem->tempv1, ark_mem->ewt); @@ -2133,9 +2322,9 @@ int arkYddNorm(ARKodeMem ark_mem, realtype hg, realtype *yddnrm) and tnew, reset the resized flag, allow for user-provided postprocessing, and update the interpolation structure. ---------------------------------------------------------------*/ -int arkCompleteStep(ARKodeMem ark_mem) +int arkCompleteStep(ARKodeMem ark_mem, realtype dsm) { - int retval; + int retval, mode; /* Set current time to the end of the step (in case the last stage time does not coincide with the step solution time). @@ -2152,25 +2341,42 @@ int arkCompleteStep(ARKodeMem ark_mem) if (ark_mem->ProcessStep != NULL) { retval = ark_mem->ProcessStep(ark_mem->tcur, ark_mem->ycur, - ark_mem->user_data); - if (retval != 0) return(ARK_POSTPROCESS_FAIL); + ark_mem->ps_data); + if (retval != 0) return(ARK_POSTPROCESS_STEP_FAIL); } /* update interpolation structure */ if (ark_mem->interp != NULL) { - retval = arkInterpUpdate(ark_mem, ark_mem->interp, - ark_mem->tcur, - (ark_mem->ProcessStep != NULL)); + retval = arkInterpUpdate(ark_mem, ark_mem->interp, ark_mem->tcur); if (retval != ARK_SUCCESS) return(retval); } + /* call fullrhs if needed */ + if (ark_mem->call_fullrhs) { + mode = (ark_mem->ProcessStep != NULL) ? 0 : 1; + retval = ark_mem->step_fullrhs(ark_mem, ark_mem->tcur, + ark_mem->ycur, + ark_mem->fn, mode); + if (retval != 0) return(ARK_RHSFUNC_FAIL); + } + /* update yn to current solution */ N_VScale(ONE, ark_mem->ycur, ark_mem->yn); + /* Update step size and error history arrays */ + ark_mem->hadapt_mem->ehist[1] = ark_mem->hadapt_mem->ehist[0]; + ark_mem->hadapt_mem->ehist[0] = dsm*ark_mem->hadapt_mem->bias; + ark_mem->hadapt_mem->hhist[1] = ark_mem->hadapt_mem->hhist[0]; + ark_mem->hadapt_mem->hhist[0] = ark_mem->h; + /* update scalar quantities */ ark_mem->nst++; - ark_mem->hold = ark_mem->h; - ark_mem->tn = ark_mem->tcur; + ark_mem->hold = ark_mem->h; + ark_mem->tn = ark_mem->tcur; + ark_mem->hprime = ark_mem->h * ark_mem->eta; + + /* Reset growth factor for subsequent time step */ + ark_mem->hadapt_mem->etamax = ark_mem->hadapt_mem->growth; /* turn off flag regarding resized problem */ ark_mem->resized = SUNFALSE; @@ -2227,6 +2433,9 @@ int arkHandleFailure(ARKodeMem ark_mem, int flag) arkProcessError(ark_mem, ARK_TOO_CLOSE, "ARKode", "ARKode", MSG_ARK_TOO_CLOSE); break; + case ARK_CONSTR_FAIL: + arkProcessError(ark_mem, ARK_CONSTR_FAIL, "ARKode", "ARKode", + MSG_ARK_FAILED_CONSTR, ark_mem->tcur); case ARK_MASSSOLVE_FAIL: arkProcessError(ark_mem, ARK_MASSSOLVE_FAIL, "ARKode", "ARKode", MSG_ARK_MASSSOLVE_FAIL); @@ -2244,6 +2453,26 @@ int arkHandleFailure(ARKodeMem ark_mem, int flag) arkProcessError(ark_mem, ARK_INNERSTEP_FAIL, "ARKode", "ARKode", MSG_ARK_INNERSTEP_FAILED, ark_mem->tcur); break; + case ARK_NLS_OP_ERR: + arkProcessError(ark_mem, ARK_NLS_OP_ERR, "ARKode", "ARKode", + MSG_ARK_NLS_FAIL, ark_mem->tcur); + break; + case ARK_USER_PREDICT_FAIL: + arkProcessError(ark_mem, ARK_USER_PREDICT_FAIL, "ARKode", "ARKode", + MSG_ARK_USER_PREDICT_FAIL, ark_mem->tcur); + break; + case ARK_POSTPROCESS_STEP_FAIL: + arkProcessError(ark_mem, ARK_POSTPROCESS_STEP_FAIL, "ARKode", "ARKode", + MSG_ARK_POSTPROCESS_STEP_FAIL, ark_mem->tcur); + break; + case ARK_POSTPROCESS_STAGE_FAIL: + arkProcessError(ark_mem, ARK_POSTPROCESS_STAGE_FAIL, "ARKode", "ARKode", + MSG_ARK_POSTPROCESS_STAGE_FAIL, ark_mem->tcur); + case ARK_INTERP_FAIL: + arkProcessError(ark_mem, ARK_INTERP_FAIL, "ARKode", "ARKode", + "At t = %Lg the interpolation module failed unrecoverably", + (long double) ark_mem->tcur); + break; default: /* This return should never happen */ arkProcessError(ark_mem, ARK_UNRECOGNIZED_ERROR, "ARKode", "ARKode", @@ -2258,17 +2487,25 @@ int arkHandleFailure(ARKodeMem ark_mem, int flag) /*--------------------------------------------------------------- arkEwtSetSS - This routine sets ewt as decribed above in the case tol_type = ARK_SS. - It tests for non-positive components before inverting. arkEwtSetSS - returns 0 if ewt is successfully set to a positive vector - and -1 otherwise. In the latter case, ewt is considered undefined. + This routine is responsible for setting the error weight vector + ewt as follows: + + ewt[i] = 1 / (reltol * SUNRabs(ycur[i]) + abstol), i=0,...,neq-1 + + When the absolute tolerance is zero, it tests for non-positive + components before inverting. arkEwtSetSS returns 0 if ewt is + successfully set to a positive vector and -1 otherwise. In the + latter case, ewt is considered undefined. ---------------------------------------------------------------*/ -int arkEwtSetSS(ARKodeMem ark_mem, N_Vector ycur, N_Vector weight) +int arkEwtSetSS(N_Vector ycur, N_Vector weight, void* arkode_mem) { + ARKodeMem ark_mem = (ARKodeMem) arkode_mem; N_VAbs(ycur, ark_mem->tempv1); N_VScale(ark_mem->reltol, ark_mem->tempv1, ark_mem->tempv1); N_VAddConst(ark_mem->tempv1, ark_mem->Sabstol, ark_mem->tempv1); - if (N_VMin(ark_mem->tempv1) <= ZERO) return(-1); + if (ark_mem->atolmin0) { + if (N_VMin(ark_mem->tempv1) <= ZERO) return(-1); + } N_VInv(ark_mem->tempv1, weight); return(0); } @@ -2277,36 +2514,66 @@ int arkEwtSetSS(ARKodeMem ark_mem, N_Vector ycur, N_Vector weight) /*--------------------------------------------------------------- arkEwtSetSV - This routine sets ewt as decribed above in the case tol_type = ARK_SV. - It tests for non-positive components before inverting. arkEwtSetSV - returns 0 if ewt is successfully set to a positive vector - and -1 otherwise. In the latter case, ewt is considered undefined. + This routine is responsible for setting the error weight vector + ewt as follows: + + ewt[i] = 1 / (reltol * SUNRabs(ycur[i]) + abstol[i]), i=0,...,neq-1 + + When any absolute tolerance is zero, it tests for non-positive + components before inverting. arkEwtSetSV returns 0 if ewt is + successfully set to a positive vector and -1 otherwise. In the + latter case, ewt is considered undefined. ---------------------------------------------------------------*/ -int arkEwtSetSV(ARKodeMem ark_mem, N_Vector ycur, N_Vector weight) +int arkEwtSetSV(N_Vector ycur, N_Vector weight, void* arkode_mem) { + ARKodeMem ark_mem = (ARKodeMem) arkode_mem; N_VAbs(ycur, ark_mem->tempv1); N_VLinearSum(ark_mem->reltol, ark_mem->tempv1, ONE, ark_mem->Vabstol, ark_mem->tempv1); - if (N_VMin(ark_mem->tempv1) <= ZERO) return(-1); + if (ark_mem->atolmin0) { + if (N_VMin(ark_mem->tempv1) <= ZERO) return(-1); + } N_VInv(ark_mem->tempv1, weight); return(0); } +/*--------------------------------------------------------------- + arkEwtSetSmallReal + + This routine is responsible for setting the error weight vector + ewt as follows: + + ewt[i] = SMALL_REAL + + This is routine is only used with explicit time stepping with + a fixed step size to avoid a potential too much error return + to the user. + ---------------------------------------------------------------*/ +int arkEwtSetSmallReal(N_Vector ycur, N_Vector weight, void* arkode_mem) +{ + N_VConst(SMALL_REAL, weight); + return(ARK_SUCCESS); +} + + /*--------------------------------------------------------------- arkRwtSetSS This routine sets rwt as decribed above in the case tol_type = ARK_SS. - It tests for non-positive components before inverting. arkRwtSetSS - returns 0 if rwt is successfully set to a positive vector - and -1 otherwise. In the latter case, rwt is considered undefined. + When the absolute tolerance is zero, it tests for non-positive + components before inverting. arkRwtSetSS returns 0 if rwt is + successfully set to a positive vector and -1 otherwise. In the + latter case, rwt is considered undefined. ---------------------------------------------------------------*/ int arkRwtSetSS(ARKodeMem ark_mem, N_Vector My, N_Vector weight) { N_VAbs(My, ark_mem->tempv1); N_VScale(ark_mem->reltol, ark_mem->tempv1, ark_mem->tempv1); N_VAddConst(ark_mem->tempv1, ark_mem->SRabstol, ark_mem->tempv1); - if (N_VMin(ark_mem->tempv1) <= ZERO) return(-1); + if (ark_mem->Ratolmin0) { + if (N_VMin(ark_mem->tempv1) <= ZERO) return(-1); + } N_VInv(ark_mem->tempv1, weight); return(0); } @@ -2316,16 +2583,19 @@ int arkRwtSetSS(ARKodeMem ark_mem, N_Vector My, N_Vector weight) arkRwtSetSV This routine sets rwt as decribed above in the case tol_type = ARK_SV. - It tests for non-positive components before inverting. arkRwtSetSV - returns 0 if rwt is successfully set to a positive vector - and -1 otherwise. In the latter case, rwt is considered undefined. + When any absolute tolerance is zero, it tests for non-positive + components before inverting. arkRwtSetSV returns 0 if rwt is + successfully set to a positive vector and -1 otherwise. In the + latter case, rwt is considered undefined. ---------------------------------------------------------------*/ int arkRwtSetSV(ARKodeMem ark_mem, N_Vector My, N_Vector weight) { N_VAbs(My, ark_mem->tempv1); N_VLinearSum(ark_mem->reltol, ark_mem->tempv1, ONE, ark_mem->VRabstol, ark_mem->tempv1); - if (N_VMin(ark_mem->tempv1) <= ZERO) return(-1); + if (ark_mem->Ratolmin0) { + if (N_VMin(ark_mem->tempv1) <= ZERO) return(-1); + } N_VInv(ark_mem->tempv1, weight); return(0); } @@ -2350,7 +2620,7 @@ int arkExpStab(N_Vector y, realtype t, realtype *hstab, void *data) This routine predicts the nonlinear implicit stage solution using the ARKode interpolation module. This uses the highest-degree interpolant supported by the module (stored - as dense_q in the ark_mem structure). + in the interpolation module). ---------------------------------------------------------------*/ int arkPredict_MaximumOrder(ARKodeMem ark_mem, realtype tau, N_Vector yguess) { @@ -2371,7 +2641,7 @@ int arkPredict_MaximumOrder(ARKodeMem ark_mem, realtype tau, N_Vector yguess) /* call the interpolation module to do the work */ return(arkInterpEvaluate(ark_mem, ark_mem->interp, tau, - 0, ark_mem->dense_q, yguess)); + 0, ARK_INTERP_MAX_DEGREE, yguess)); } @@ -2424,8 +2694,8 @@ int arkPredict_VariableOrder(ARKodeMem ark_mem, realtype tau, N_Vector yguess) This routine predicts the nonlinear implicit stage solution using the ARKode interpolation module. If the level of extrapolation is small enough, it uses the maximum degree - polynomial available (stored in ark_mem->dense_q); otherwise - it uses a linear polynomial. + polynomial available (stored in the interpolation module + structure); otherwise it uses a linear polynomial. ---------------------------------------------------------------*/ int arkPredict_CutoffOrder(ARKodeMem ark_mem, realtype tau, N_Vector yguess) { @@ -2448,7 +2718,7 @@ int arkPredict_CutoffOrder(ARKodeMem ark_mem, realtype tau, N_Vector yguess) /* set the polynomial order based on tau input */ if (tau <= tau_tol) { - ord = ark_mem->dense_q; + ord = ARK_INTERP_MAX_DEGREE; } else { ord = 1; } @@ -2466,9 +2736,9 @@ int arkPredict_CutoffOrder(ARKodeMem ark_mem, realtype tau, N_Vector yguess) using a quadratic Hermite interpolating polynomial, based on the data {y_n, f(t_n,y_n), f(t_n+hj,z_j)}. - Note: we assume that ftemp = f(t_n+hj,z_j) can be computed via + Note: we assume that ftemp = f(t_n+hj,z_j) can be computed via N_VLinearCombination(nvec, cvals, Xvecs, ftemp), - i.e. the inputs cvals[0:nvec-1] and Xvecs[0:nvec-1] may be + i.e. the inputs cvals[0:nvec-1] and Xvecs[0:nvec-1] may be combined to form f(t_n+hj,z_j). ---------------------------------------------------------------*/ int arkPredict_Bootstrap(ARKodeMem ark_mem, realtype hj, @@ -2476,7 +2746,7 @@ int arkPredict_Bootstrap(ARKodeMem ark_mem, realtype hj, N_Vector *Xvecs, N_Vector yguess) { realtype a0, a1, a2; - int i; + int i, retval; /* verify that ark_mem and interpolation structure are provided */ if (ark_mem == NULL) { @@ -2497,7 +2767,7 @@ int arkPredict_Bootstrap(ARKodeMem ark_mem, realtype hj, a2 = tau*tau/TWO/hj; a1 = tau - a2; - /* set arrays for fused vector operation; shift inputs for + /* set arrays for fused vector operation; shift inputs for f(t_n+hj,z_j) to end of queue */ for (i=0; iyn; cvals[1] = a1; - Xvecs[1] = ark_mem->interp->fnew; + Xvecs[1] = ark_mem->fn; /* call fused vector operation to compute prediction */ - return(N_VLinearCombination(nvec+2, cvals, Xvecs, yguess)); + retval = N_VLinearCombination(nvec+2, cvals, Xvecs, yguess); + if (retval != 0) return(ARK_VECTOROP_ERR); + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkCheckConvergence + + This routine checks the return flag from the time-stepper's + "step" routine for algebraic solver convergence issues. + + Returns ARK_SUCCESS (0) if successful, PREDICT_AGAIN (>0) + on a recoverable convergence failure, or a relevant + nonrecoverable failure flag (<0). + --------------------------------------------------------------*/ +int arkCheckConvergence(ARKodeMem ark_mem, int *nflagPtr, int *ncfPtr) +{ + ARKodeHAdaptMem hadapt_mem; + + if (*nflagPtr == ARK_SUCCESS) return(ARK_SUCCESS); + + /* The nonlinear soln. failed; increment ncfn */ + ark_mem->ncfn++; + + /* If fixed time stepping, then return with convergence failure */ + if (ark_mem->fixedstep) return(ARK_CONV_FAILURE); + + /* Otherwise, access adaptivity structure */ + if (ark_mem->hadapt_mem == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", "arkCheckConvergence", + MSG_ARKADAPT_NO_MEM); + return(ARK_MEM_NULL); + } + hadapt_mem = ark_mem->hadapt_mem; + + /* Return if lsetup, lsolve, or rhs failed unrecoverably */ + if (*nflagPtr < 0) { + if (*nflagPtr == ARK_LSETUP_FAIL) return(ARK_LSETUP_FAIL); + else if (*nflagPtr == ARK_LSOLVE_FAIL) return(ARK_LSOLVE_FAIL); + else if (*nflagPtr == ARK_RHSFUNC_FAIL) return(ARK_RHSFUNC_FAIL); + else return(ARK_NLS_OP_ERR); + } + + /* At this point, nflag = CONV_FAIL or RHSFUNC_RECVR; increment ncf */ + (*ncfPtr)++; + hadapt_mem->etamax = ONE; + + /* If we had maxncf failures, or if |h| = hmin, + return ARK_CONV_FAILURE or ARK_REPTD_RHSFUNC_ERR. */ + if ((*ncfPtr == ark_mem->maxncf) || + (SUNRabs(ark_mem->h) <= ark_mem->hmin*ONEPSM)) { + if (*nflagPtr == CONV_FAIL) return(ARK_CONV_FAILURE); + if (*nflagPtr == RHSFUNC_RECVR) return(ARK_REPTD_RHSFUNC_ERR); + } + + /* Reduce step size due to convergence failure */ + ark_mem->eta = hadapt_mem->etacf; + + /* Signal for Jacobian/preconditioner setup */ + *nflagPtr = PREV_CONV_FAIL; + + /* Return to reattempt the step */ + return(PREDICT_AGAIN); +} + + +/*--------------------------------------------------------------- + arkCheckConstraints + + This routine determines if the constraints of the problem + are satisfied by the proposed step + + Returns ARK_SUCCESS if successful, otherwise CONSTR_RECVR + --------------------------------------------------------------*/ +int arkCheckConstraints(ARKodeMem ark_mem, int *constrfails, int *nflag) +{ + booleantype constraintsPassed; + N_Vector mm = ark_mem->tempv4; + N_Vector tmp = ark_mem->tempv1; + + /* Check constraints and get mask vector mm for where constraints failed */ + constraintsPassed = N_VConstrMask(ark_mem->constraints, ark_mem->ycur, mm); + if (constraintsPassed) return(ARK_SUCCESS); + + /* Constraints not met */ + + /* Update total fails and fails in current step */ + ark_mem->nconstrfails++; + (*constrfails)++; + + /* Return with error if reached max fails in a step */ + if (*constrfails == ark_mem->maxconstrfails) return(ARK_CONSTR_FAIL); + + /* Return with error if using fixed step sizes */ + if (ark_mem->fixedstep) return(ARK_CONSTR_FAIL); + + /* Return with error if |h| == hmin */ + if (SUNRabs(ark_mem->h) <= ark_mem->hmin*ONEPSM) return(ARK_CONSTR_FAIL); + + /* Reduce h by computing eta = h'/h */ + N_VLinearSum(ONE, ark_mem->yn, -ONE, ark_mem->ycur, tmp); + N_VProd(mm, tmp, tmp); + ark_mem->eta = RCONST(0.9)*N_VMinQuotient(ark_mem->yn, tmp); + ark_mem->eta = SUNMAX(ark_mem->eta, TENTH); + + /* Signal for Jacobian/preconditioner setup */ + *nflag = PREV_CONV_FAIL; + + /* Return to reattempt the step */ + return(CONSTR_RECVR); +} + + +/*--------------------------------------------------------------- + arkCheckTemporalError + + This routine performs the local error test for the method. + The weighted local error norm dsm is passed in. This value is + used to predict the next step to attempt based on dsm. + The test dsm <= 1 is made, and if this fails then additional + checks are performed based on the number of successive error + test failures. + + Returns ARK_SUCCESS if the test passes. + + If the test fails: + - if maxnef error test failures have occurred or if + SUNRabs(h) = hmin, we return ARK_ERR_FAILURE. + - otherwise: set *nflagPtr to PREV_ERR_FAIL, and + return TRY_AGAIN. + --------------------------------------------------------------*/ +int arkCheckTemporalError(ARKodeMem ark_mem, int *nflagPtr, int *nefPtr, realtype dsm) +{ + int retval; + realtype ttmp; + long int nsttmp; + ARKodeHAdaptMem hadapt_mem; + + /* Access hadapt_mem structure */ + if (ark_mem->hadapt_mem == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", "arkCheckTemporalError", + MSG_ARKADAPT_NO_MEM); + return(ARK_MEM_NULL); + } + hadapt_mem = ark_mem->hadapt_mem; + + /* consider change of step size for next step attempt (may be + larger/smaller than current step, depending on dsm) */ + ttmp = (dsm < ONE) ? ark_mem->tn + ark_mem->h : ark_mem->tn; + nsttmp = (dsm < ONE) ? ark_mem->nst+1 : ark_mem->nst; + retval = arkAdapt((void*) ark_mem, hadapt_mem, ark_mem->ycur, ttmp, + ark_mem->h, dsm*ark_mem->hadapt_mem->bias, nsttmp); + if (retval != ARK_SUCCESS) return(ARK_ERR_FAILURE); + + /* If est. local error norm dsm passes test, return ARK_SUCCESS */ + if (dsm <= ONE) return(ARK_SUCCESS); + + /* Test failed; increment counters, set nflag */ + (*nefPtr)++; + ark_mem->netf++; + *nflagPtr = PREV_ERR_FAIL; + + /* At maxnef failures, return ARK_ERR_FAILURE */ + if (*nefPtr == ark_mem->maxnef) return(ARK_ERR_FAILURE); + + /* Set etamax=1 to prevent step size increase at end of this step */ + hadapt_mem->etamax = ONE; + + /* Enforce failure bounds on eta, update h, and return for retry of step */ + if (*nefPtr >= hadapt_mem->small_nef) + ark_mem->eta = SUNMIN(ark_mem->eta, hadapt_mem->etamxf); + return(TRY_AGAIN); +} + + +/*--------------------------------------------------------------- + arkAccessHAdaptMem: + + Shortcut routine to unpack ark_mem and hadapt_mem structures from + void* pointer. If either is missing it returns ARK_MEM_NULL. + ---------------------------------------------------------------*/ +int arkAccessHAdaptMem(void* arkode_mem, const char *fname, + ARKodeMem *ark_mem, ARKodeHAdaptMem *hadapt_mem) +{ + + /* access ARKodeMem structure */ + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + fname, MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + *ark_mem = (ARKodeMem) arkode_mem; + if ((*ark_mem)->hadapt_mem==NULL) { + arkProcessError(*ark_mem, ARK_MEM_NULL, "ARKode", + fname, MSG_ARKADAPT_NO_MEM); + return(ARK_MEM_NULL); + } + *hadapt_mem = (ARKodeHAdaptMem) (*ark_mem)->hadapt_mem; + return(ARK_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_adapt.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_adapt.c index 84619ffb5..f7f7345ca 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_adapt.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_adapt.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -47,35 +47,14 @@ ARKodeHAdaptMem arkAdaptInit() hadapt_mem = (ARKodeHAdaptMem) malloc(sizeof(struct ARKodeHAdaptMemRec)); if (hadapt_mem == NULL) return(NULL); - /* initialize default values */ + /* initialize values (default parameters are set in arkSetDefaults) */ memset(hadapt_mem, 0, sizeof(struct ARKodeHAdaptMemRec)); - hadapt_mem->etamx1 = ETAMX1; /* max change on first step */ - hadapt_mem->etamxf = ETAMXF; /* max change on error-failed step */ - hadapt_mem->small_nef = SMALL_NEF; /* num error fails before ETAMXF enforced */ - hadapt_mem->etacf = ETACF; /* max change on convergence failure */ - hadapt_mem->HAdapt = NULL; /* step adaptivity fn */ - hadapt_mem->HAdapt_data = NULL; /* step adaptivity data */ - hadapt_mem->imethod = 0; /* PID controller */ - hadapt_mem->cfl = CFLFAC; /* explicit stability factor */ - hadapt_mem->safety = SAFETY; /* step adaptivity safety factor */ - hadapt_mem->bias = BIAS; /* step adaptivity error bias */ - hadapt_mem->growth = GROWTH; /* step adaptivity growth factor */ - hadapt_mem->lbound = HFIXED_LB; /* step adaptivity no-change lower bound */ - hadapt_mem->ubound = HFIXED_UB; /* step adaptivity no-change upper bound */ - hadapt_mem->k1 = AD0_K1; /* step adaptivity parameter */ - hadapt_mem->k2 = AD0_K2; /* step adaptivity parameter */ - hadapt_mem->k3 = AD0_K3; /* step adaptivity parameter */ - hadapt_mem->ehist[0] = ONE; - hadapt_mem->ehist[1] = ONE; - hadapt_mem->ehist[2] = ONE; - hadapt_mem->hhist[0] = ZERO; - hadapt_mem->hhist[1] = ZERO; - hadapt_mem->hhist[2] = ZERO; - hadapt_mem->nst_acc = 0; - hadapt_mem->nst_exp = 0; - - hadapt_mem->expstab = arkExpStab; - hadapt_mem->estab_data = NULL; + hadapt_mem->ehist[0] = ONE; + hadapt_mem->ehist[1] = ONE; + hadapt_mem->hhist[0] = ZERO; + hadapt_mem->hhist[1] = ZERO; + hadapt_mem->nst_acc = 0; + hadapt_mem->nst_exp = 0; return(hadapt_mem); } @@ -92,17 +71,16 @@ void arkPrintAdaptMem(ARKodeHAdaptMem hadapt_mem, FILE *outfile) fprintf(outfile, "ark_hadapt: etamax = %"RSYM"\n", hadapt_mem->etamax); fprintf(outfile, "ark_hadapt: etamx1 = %"RSYM"\n", hadapt_mem->etamx1); fprintf(outfile, "ark_hadapt: etamxf = %"RSYM"\n", hadapt_mem->etamxf); + fprintf(outfile, "ark_hadapt: etamin = %"RSYM"\n", hadapt_mem->etamin); fprintf(outfile, "ark_hadapt: small_nef = %i\n", hadapt_mem->small_nef); fprintf(outfile, "ark_hadapt: etacf = %"RSYM"\n", hadapt_mem->etacf); fprintf(outfile, "ark_hadapt: imethod = %i\n", hadapt_mem->imethod); - fprintf(outfile, "ark_hadapt: ehist = %"RSYM" %"RSYM" %"RSYM"\n", + fprintf(outfile, "ark_hadapt: ehist = %"RSYM" %"RSYM"\n", hadapt_mem->ehist[0], - hadapt_mem->ehist[1], - hadapt_mem->ehist[2]); - fprintf(outfile, "ark_hadapt: hhist = %"RSYM" %"RSYM" %"RSYM"\n", + hadapt_mem->ehist[1]); + fprintf(outfile, "ark_hadapt: hhist = %"RSYM" %"RSYM"\n", hadapt_mem->hhist[0], - hadapt_mem->hhist[1], - hadapt_mem->hhist[2]); + hadapt_mem->hhist[1]); fprintf(outfile, "ark_hadapt: cfl = %"RSYM"\n", hadapt_mem->cfl); fprintf(outfile, "ark_hadapt: safety = %"RSYM"\n", hadapt_mem->safety); fprintf(outfile, "ark_hadapt: bias = %"RSYM"\n", hadapt_mem->bias); @@ -112,6 +90,9 @@ void arkPrintAdaptMem(ARKodeHAdaptMem hadapt_mem, FILE *outfile) fprintf(outfile, "ark_hadapt: k1 = %"RSYM"\n", hadapt_mem->k1); fprintf(outfile, "ark_hadapt: k2 = %"RSYM"\n", hadapt_mem->k2); fprintf(outfile, "ark_hadapt: k3 = %"RSYM"\n", hadapt_mem->k3); + fprintf(outfile, "ark_hadapt: q = %i\n", hadapt_mem->q); + fprintf(outfile, "ark_hadapt: p = %i\n", hadapt_mem->p); + fprintf(outfile, "ark_hadapt: pq = %i\n", hadapt_mem->pq); fprintf(outfile, "ark_hadapt: nst_acc = %li\n", hadapt_mem->nst_acc); fprintf(outfile, "ark_hadapt: nst_exp = %li\n", hadapt_mem->nst_exp); if (hadapt_mem->expstab == arkExpStab) { @@ -134,7 +115,7 @@ void arkPrintAdaptMem(ARKodeHAdaptMem hadapt_mem, FILE *outfile) ---------------------------------------------------------------*/ int arkAdapt(void* arkode_mem, ARKodeHAdaptMem hadapt_mem, N_Vector ycur, realtype tcur, realtype hcur, - int q, int p, booleantype pq, long int nst) + realtype ecur, long int nst) { int ier, k; realtype h_acc, h_cfl, int_dir; @@ -147,37 +128,35 @@ int arkAdapt(void* arkode_mem, ARKodeHAdaptMem hadapt_mem, ark_mem = (ARKodeMem) arkode_mem; /* Set k as either p or q, based on pq flag */ - k = (pq) ? q : p; - + k = (hadapt_mem->pq) ? hadapt_mem->q : hadapt_mem->p; + /* Call algorithm-specific error adaptivity method */ switch (hadapt_mem->imethod) { case(0): /* PID controller */ - ier = arkAdaptPID(hadapt_mem, k, hcur, &h_acc); + ier = arkAdaptPID(hadapt_mem, k, hcur, ecur, &h_acc); break; case(1): /* PI controller */ - ier = arkAdaptPI(hadapt_mem, k, hcur, &h_acc); + ier = arkAdaptPI(hadapt_mem, k, hcur, ecur, &h_acc); break; case(2): /* I controller */ - ier = arkAdaptI(hadapt_mem, k, hcur, &h_acc); + ier = arkAdaptI(hadapt_mem, k, hcur, ecur, &h_acc); break; case(3): /* explicit Gustafsson controller */ - ier = arkAdaptExpGus(hadapt_mem, k, nst, hcur, &h_acc); + ier = arkAdaptExpGus(hadapt_mem, k, nst, hcur, ecur, &h_acc); break; case(4): /* implicit Gustafsson controller */ - ier = arkAdaptImpGus(hadapt_mem, k, nst, hcur, &h_acc); + ier = arkAdaptImpGus(hadapt_mem, k, nst, hcur, ecur, &h_acc); break; case(5): /* imex Gustafsson controller */ - ier = arkAdaptImExGus(hadapt_mem, k, nst, hcur, &h_acc); + ier = arkAdaptImExGus(hadapt_mem, k, nst, hcur, ecur, &h_acc); break; case(-1): /* user-supplied controller */ - ier = hadapt_mem->HAdapt(ycur, tcur, - hadapt_mem->hhist[0], - hadapt_mem->hhist[1], - hadapt_mem->hhist[2], + ier = hadapt_mem->HAdapt(ycur, tcur, hcur, hadapt_mem->hhist[0], + hadapt_mem->hhist[1], ecur, hadapt_mem->ehist[0], hadapt_mem->ehist[1], - hadapt_mem->ehist[2], - q, p, &h_acc, hadapt_mem->HAdapt_data); + hadapt_mem->q, hadapt_mem->p, + &h_acc, hadapt_mem->HAdapt_data); break; default: arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkAdapt", @@ -200,14 +179,13 @@ int arkAdapt(void* arkode_mem, ARKodeHAdaptMem hadapt_mem, "Error in explicit stability function."); return (ARK_ILL_INPUT); } - if (h_cfl <= 0.0) h_cfl = RCONST(1.0e30) * SUNRabs(hcur); + if (h_cfl <= ZERO) h_cfl = RCONST(1.0e30) * SUNRabs(hcur); /* Solver diagnostics reporting */ if (ark_mem->report) fprintf(ark_mem->diagfp, "ARKadapt adapt %"RSYM" %"RSYM" %"RSYM" %"RSYM" %"RSYM" %"RSYM" %"RSYM" %"RSYM" ", - hadapt_mem->ehist[0], hadapt_mem->ehist[1], - hadapt_mem->ehist[2], hadapt_mem->hhist[0], - hadapt_mem->hhist[1], hadapt_mem->hhist[2], h_acc, h_cfl); + ecur, hadapt_mem->ehist[0], hadapt_mem->ehist[1], + hcur, hadapt_mem->hhist[0], hadapt_mem->hhist[1], h_acc, h_cfl); /* enforce safety factors */ h_acc *= hadapt_mem->safety; @@ -217,7 +195,7 @@ int arkAdapt(void* arkode_mem, ARKodeHAdaptMem hadapt_mem, h_acc = int_dir * SUNMIN(SUNRabs(h_acc), SUNRabs(hadapt_mem->etamax*hcur)); /* enforce minimum bound time step reduction */ - h_acc = int_dir * SUNMAX(SUNRabs(h_acc), SUNRabs(ETAMIN*hcur)); + h_acc = int_dir * SUNMAX(SUNRabs(h_acc), SUNRabs(hadapt_mem->etamin*hcur)); /* Solver diagnostics reporting */ if (ark_mem->report) @@ -258,7 +236,7 @@ int arkAdapt(void* arkode_mem, ARKodeHAdaptMem hadapt_mem, arkAdaptPID implements a PID time step control algorithm. ---------------------------------------------------------------*/ int arkAdaptPID(ARKodeHAdaptMem hadapt_mem, int k, realtype hcur, - realtype *hnew) + realtype ecur, realtype *hnew) { realtype k1, k2, k3, e1, e2, e3, h_acc; @@ -266,9 +244,9 @@ int arkAdaptPID(ARKodeHAdaptMem hadapt_mem, int k, realtype hcur, k1 = -hadapt_mem->k1 / k; k2 = hadapt_mem->k2 / k; k3 = -hadapt_mem->k3 / k; - e1 = SUNMAX(hadapt_mem->ehist[0], TINY); - e2 = SUNMAX(hadapt_mem->ehist[1], TINY); - e3 = SUNMAX(hadapt_mem->ehist[2], TINY); + e1 = SUNMAX(ecur, TINY); + e2 = SUNMAX(hadapt_mem->ehist[0], TINY); + e3 = SUNMAX(hadapt_mem->ehist[1], TINY); /* compute estimated optimal time step size, set into output */ h_acc = hcur * SUNRpowerR(e1,k1) * SUNRpowerR(e2,k2) * SUNRpowerR(e3,k3); @@ -282,15 +260,15 @@ int arkAdaptPID(ARKodeHAdaptMem hadapt_mem, int k, realtype hcur, arkAdaptPI implements a PI time step control algorithm. ---------------------------------------------------------------*/ int arkAdaptPI(ARKodeHAdaptMem hadapt_mem, int k, realtype hcur, - realtype *hnew) + realtype ecur, realtype *hnew) { realtype k1, k2, e1, e2, h_acc; /* set usable time-step adaptivity parameters */ k1 = -hadapt_mem->k1 / k; k2 = hadapt_mem->k2 / k; - e1 = SUNMAX(hadapt_mem->ehist[0], TINY); - e2 = SUNMAX(hadapt_mem->ehist[1], TINY); + e1 = SUNMAX(ecur, TINY); + e2 = SUNMAX(hadapt_mem->ehist[0], TINY); /* compute estimated optimal time step size, set into output */ h_acc = hcur * SUNRpowerR(e1,k1) * SUNRpowerR(e2,k2); @@ -304,13 +282,13 @@ int arkAdaptPI(ARKodeHAdaptMem hadapt_mem, int k, realtype hcur, arkAdaptI implements an I time step control algorithm. ---------------------------------------------------------------*/ int arkAdaptI(ARKodeHAdaptMem hadapt_mem, int k, realtype hcur, - realtype *hnew) + realtype ecur, realtype *hnew) { realtype k1, e1, h_acc; /* set usable time-step adaptivity parameters */ k1 = -hadapt_mem->k1 / k; - e1 = SUNMAX(hadapt_mem->ehist[0], TINY); + e1 = SUNMAX(ecur, TINY); /* compute estimated optimal time step size, set into output */ h_acc = hcur * SUNRpowerR(e1,k1); @@ -325,7 +303,7 @@ int arkAdaptI(ARKodeHAdaptMem hadapt_mem, int k, realtype hcur, control algorithm. ---------------------------------------------------------------*/ int arkAdaptExpGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, - realtype hcur, realtype *hnew) + realtype hcur, realtype ecur, realtype *hnew) { realtype k1, k2, e1, e2, h_acc; @@ -333,7 +311,7 @@ int arkAdaptExpGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, if (nst < 2) { k1 = -ONE / k; - e1 = SUNMAX(hadapt_mem->ehist[0], TINY); + e1 = SUNMAX(ecur, TINY); h_acc = hcur * SUNRpowerR(e1,k1); /* general estimate */ @@ -341,8 +319,8 @@ int arkAdaptExpGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, k1 = -hadapt_mem->k1 / k; k2 = -hadapt_mem->k2 / k; - e1 = SUNMAX(hadapt_mem->ehist[0], TINY); - e2 = e1 / SUNMAX(hadapt_mem->ehist[1], TINY); + e1 = SUNMAX(ecur, TINY); + e2 = e1 / SUNMAX(hadapt_mem->ehist[0], TINY); h_acc = hcur * SUNRpowerR(e1,k1) * SUNRpowerR(e2,k2); } @@ -357,7 +335,7 @@ int arkAdaptExpGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, control algorithm. ---------------------------------------------------------------*/ int arkAdaptImpGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, - realtype hcur, realtype *hnew) + realtype hcur, realtype ecur, realtype *hnew) { realtype k1, k2, e1, e2, hrat, h_acc; @@ -365,7 +343,7 @@ int arkAdaptImpGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, if (nst < 2) { k1 = -ONE / k; - e1 = SUNMAX(hadapt_mem->ehist[0], TINY); + e1 = SUNMAX(ecur, TINY); h_acc = hcur * SUNRpowerR(e1,k1); /* general estimate */ @@ -373,9 +351,9 @@ int arkAdaptImpGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, k1 = -hadapt_mem->k1 / k; k2 = -hadapt_mem->k2 / k; - e1 = SUNMAX(hadapt_mem->ehist[0], TINY); - e2 = e1 / SUNMAX(hadapt_mem->ehist[1], TINY); - hrat = hcur / hadapt_mem->hhist[1]; + e1 = SUNMAX(ecur, TINY); + e2 = e1 / SUNMAX(hadapt_mem->ehist[0], TINY); + hrat = hcur / hadapt_mem->hhist[0]; h_acc = hcur * hrat * SUNRpowerR(e1,k1) * SUNRpowerR(e2,k2); } @@ -390,7 +368,7 @@ int arkAdaptImpGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, Gustafsson time step control algorithm. ---------------------------------------------------------------*/ int arkAdaptImExGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, - realtype hcur, realtype *hnew) + realtype hcur, realtype ecur, realtype *hnew) { realtype k1, k2, k3, e1, e2, hrat, h_acc; @@ -398,7 +376,7 @@ int arkAdaptImExGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, if (nst < 2) { k1 = -ONE / k; - e1 = SUNMAX(hadapt_mem->ehist[0], TINY); + e1 = SUNMAX(ecur, TINY); h_acc = hcur * SUNRpowerR(e1,k1); /* general estimate */ @@ -407,9 +385,9 @@ int arkAdaptImExGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, k1 = -hadapt_mem->k1 / k; k2 = -hadapt_mem->k2 / k; k3 = -hadapt_mem->k3 / k; - e1 = SUNMAX(hadapt_mem->ehist[0], TINY); - e2 = e1 / SUNMAX(hadapt_mem->ehist[1], TINY); - hrat = hcur / hadapt_mem->hhist[1]; + e1 = SUNMAX(ecur, TINY); + e2 = e1 / SUNMAX(hadapt_mem->ehist[0], TINY); + hrat = hcur / hadapt_mem->hhist[0]; /* implicit estimate */ h_acc = hcur * hrat * SUNRpowerR(e1,k3) * SUNRpowerR(e2,k3); /* explicit estimate */ diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_adapt_impl.h b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_adapt_impl.h index 4e48bced4..06c80189d 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_adapt_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_adapt_impl.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -11,7 +11,7 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End *--------------------------------------------------------------- - * Implementation header file for ARKode's time step adaptivity + * Implementation header file for ARKode's time step adaptivity * utilities. *--------------------------------------------------------------*/ @@ -27,18 +27,54 @@ extern "C" { /*=============================================================== - ARKode Time Step Adaptivity Data Structure -===============================================================*/ + ARKode Time Step Adaptivity Private Constants + ===============================================================*/ /* size constants for the adaptivity memory structure */ #define ARK_ADAPT_LRW 19 -#define ARK_ADAPT_LIW 8 /* includes functin/data pointers */ - +#define ARK_ADAPT_LIW 8 /* includes function/data pointers */ + +/* Time step controller default values */ +#define CFLFAC RCONST(0.5) +#define SAFETY RCONST(0.96) /* CVODE uses 1.0 */ +#define BIAS RCONST(1.5) /* CVODE uses 6.0 */ +#define GROWTH RCONST(20.0) /* CVODE uses 10.0 */ +#define HFIXED_LB RCONST(1.0) /* CVODE uses 1.0 */ +#define HFIXED_UB RCONST(1.5) /* CVODE uses 1.5 */ +#define AD0_K1 RCONST(0.58) /* PID controller constants */ +#define AD0_K2 RCONST(0.21) +#define AD0_K3 RCONST(0.1) +#define AD1_K1 RCONST(0.8) /* PI controller constants */ +#define AD1_K2 RCONST(0.31) +#define AD2_K1 RCONST(1.0) /* I controller constants */ +#define AD3_K1 RCONST(0.367) /* explicit Gustafsson controller */ +#define AD3_K2 RCONST(0.268) +#define AD4_K1 RCONST(0.98) /* implicit Gustafsson controller */ +#define AD4_K2 RCONST(0.95) +#define AD5_K1 RCONST(0.367) /* imex Gustafsson controller */ +#define AD5_K2 RCONST(0.268) +#define AD5_K3 RCONST(0.95) + +#define ETAMX1 RCONST(10000.0) /* maximum step size change on first step */ +#define ETAMXF RCONST(0.3) /* step size reduction factor on multiple error + test failures (multiple implies >= SMALL_NEF) */ +#define ETAMIN RCONST(0.1) /* smallest allowable step size reduction factor + on an error test failure */ +#define ETACF RCONST(0.25) /* step size reduction factor on nonlinear + convergence failure */ +#define SMALL_NEF 2 /* if an error failure occurs and SMALL_NEF <= nef, + then reset eta = MIN(eta, ETAMXF) */ + + +/*=============================================================== + ARKode Time Step Adaptivity Data Structure + ===============================================================*/ + /*--------------------------------------------------------------- Types : struct ARKodeHAdaptMemRec, ARKodeHAdaptMem ----------------------------------------------------------------- - The type ARKodeHAdaptMem is type pointer to struct - ARKodeHAdaptMemRec. This structure contains fields to + The type ARKodeHAdaptMem is type pointer to struct + ARKodeHAdaptMemRec. This structure contains fields to keep track of temporal adaptivity. ---------------------------------------------------------------*/ typedef struct ARKodeHAdaptMemRec { @@ -46,12 +82,13 @@ typedef struct ARKodeHAdaptMemRec { realtype etamax; /* eta <= etamax */ realtype etamx1; /* max step size change on first step */ realtype etamxf; /* h reduction factor on multiple error fails */ + realtype etamin; /* eta >= etamin on error test fail */ int small_nef; /* bound to determine 'multiple' above */ realtype etacf; /* h reduction factor on nonlinear conv fail */ ARKAdaptFn HAdapt; /* function to set the new time step size */ void *HAdapt_data; /* user pointer passed to hadapt */ - realtype ehist[3]; /* error history for time adaptivity */ - realtype hhist[3]; /* step history for time adaptivity */ + realtype ehist[2]; /* error history for time adaptivity */ + realtype hhist[2]; /* step history for time adaptivity */ int imethod; /* step adaptivity method to use: -1 -> User-specified function above 0 -> PID controller @@ -69,13 +106,16 @@ typedef struct ARKodeHAdaptMemRec { realtype k1; /* method-specific adaptivity parameters */ realtype k2; realtype k3; + int q; /* method order */ + int p; /* embedding order */ + booleantype pq; /* choice of using p (0) vs q (1) */ ARKExpStabFn expstab; /* step stability function */ void *estab_data; /* user pointer passed to expstab */ long int nst_acc; /* num accuracy-limited internal steps */ long int nst_exp; /* num stability-limited internal steps */ - + } *ARKodeHAdaptMem; @@ -87,21 +127,21 @@ ARKodeHAdaptMem arkAdaptInit(); void arkPrintAdaptMem(ARKodeHAdaptMem hadapt_mem, FILE *outfile); int arkAdapt(void* arkode_mem, ARKodeHAdaptMem hadapt_mem, N_Vector ycur, realtype tcur, realtype hcur, - int q, int p, booleantype pq, long int nst); -int arkAdaptPID(ARKodeHAdaptMem hadapt_mem, int k, - realtype hcur, realtype *hnew); -int arkAdaptPI(ARKodeHAdaptMem hadapt_mem, int k, - realtype hcur, realtype *hnew); -int arkAdaptI(ARKodeHAdaptMem hadapt_mem, int k, - realtype hcur, realtype *hnew); -int arkAdaptExpGus(ARKodeHAdaptMem hadapt_mem, int k, - long int nst, realtype hcur, realtype *hnew); -int arkAdaptImpGus(ARKodeHAdaptMem hadapt_mem, int k, - long int nst, realtype hcur, realtype *hnew); -int arkAdaptImExGus(ARKodeHAdaptMem hadapt_mem, int k, - long int nst, realtype hcur, realtype *hnew); - - + realtype ecur, long int nst); +int arkAdaptPID(ARKodeHAdaptMem hadapt_mem, int k, + realtype hcur, realtype ecur, realtype *hnew); +int arkAdaptPI(ARKodeHAdaptMem hadapt_mem, int k, + realtype hcur, realtype ecur, realtype *hnew); +int arkAdaptI(ARKodeHAdaptMem hadapt_mem, int k, + realtype hcur, realtype ecur, realtype *hnew); +int arkAdaptExpGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, + realtype hcur, realtype ecur, realtype *hnew); +int arkAdaptImpGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, + realtype hcur, realtype ecur, realtype *hnew); +int arkAdaptImExGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, + realtype hcur, realtype ecur, realtype *hnew); + + #ifdef __cplusplus } #endif diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep.c index 583ab80fe..2b4091438 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -21,6 +21,7 @@ #include "arkode_impl.h" #include "arkode_arkstep_impl.h" +#include "arkode_interp_impl.h" #include #include @@ -143,16 +144,6 @@ void* ARKStepCreate(ARKRhsFn fe, ARKRhsFn fi, realtype t0, N_Vector y0) ark_mem->liw += 41; /* fcn/data ptr, int, long int, sunindextype, booleantype */ ark_mem->lrw += 10; - /* Allocate step adaptivity structure, set default values, note storage */ - step_mem->hadapt_mem = arkAdaptInit(); - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ARKStep", "ARKStepCreate", - "Allocation of step adaptivity structure failed"); - return(NULL); - } - ark_mem->lrw += ARK_ADAPT_LRW; - ark_mem->liw += ARK_ADAPT_LIW; - /* If an implicit component is to be solved, create default Newton NLS object */ step_mem->ownNLS = SUNFALSE; if (step_mem->implicit) { @@ -173,34 +164,42 @@ void* ARKStepCreate(ARKRhsFn fe, ARKRhsFn fi, realtype t0, N_Vector y0) } /* Set the linear solver addresses to NULL (we check != NULL later) */ - step_mem->linit = NULL; - step_mem->lsetup = NULL; - step_mem->lsolve = NULL; - step_mem->lfree = NULL; - step_mem->lmem = NULL; + step_mem->linit = NULL; + step_mem->lsetup = NULL; + step_mem->lsolve = NULL; + step_mem->lfree = NULL; + step_mem->lmem = NULL; step_mem->lsolve_type = -1; /* Set the mass matrix solver addresses to NULL */ - step_mem->minit = NULL; - step_mem->msetup = NULL; - step_mem->mmult = NULL; - step_mem->msolve = NULL; - step_mem->mfree = NULL; - step_mem->mass_mem = NULL; - step_mem->msetuptime = -RCONST(99999999999.0); + step_mem->minit = NULL; + step_mem->msetup = NULL; + step_mem->mmult = NULL; + step_mem->msolve = NULL; + step_mem->mfree = NULL; + step_mem->mass_mem = NULL; + step_mem->msetuptime = -RCONST(99999999999.0); step_mem->msolve_type = -1; /* Initialize initial error norm */ - step_mem->eRNrm = 1.0; + step_mem->eRNrm = ONE; /* Initialize all the counters */ - step_mem->nst_attempts = 0; - step_mem->nfe = 0; - step_mem->nfi = 0; - step_mem->ncfn = 0; - step_mem->netf = 0; - step_mem->nsetups = 0; - step_mem->nstlp = 0; + step_mem->nfe = 0; + step_mem->nfi = 0; + step_mem->nsetups = 0; + step_mem->nstlp = 0; + + /* Initialize fused op work space */ + step_mem->cvals = NULL; + step_mem->Xvecs = NULL; + step_mem->nfusedopvecs = 0; + + /* Initialize external polynomial forcing data */ + step_mem->expforcing = SUNFALSE; + step_mem->impforcing = SUNFALSE; + step_mem->forcing = NULL; + step_mem->nforcing = 0; /* Initialize main ARKode infrastructure */ retval = arkInit(ark_mem, t0, y0); @@ -255,17 +254,17 @@ int ARKStepResize(void *arkode_mem, N_Vector y0, realtype hscale, /* Resize the sdata, zpred and zcor vectors */ if (step_mem->sdata != NULL) { retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, - liw_diff, y0, &step_mem->sdata); + liw_diff, y0, &step_mem->sdata); if (retval != ARK_SUCCESS) return(retval); } if (step_mem->zpred != NULL) { retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, - liw_diff, y0, &step_mem->zpred); + liw_diff, y0, &step_mem->zpred); if (retval != ARK_SUCCESS) return(retval); } if (step_mem->zcor != NULL) { retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, - liw_diff, y0, &step_mem->zcor); + liw_diff, y0, &step_mem->zcor); if (retval != ARK_SUCCESS) return(retval); } @@ -274,7 +273,7 @@ int ARKStepResize(void *arkode_mem, N_Vector y0, realtype hscale, if (step_mem->Fe != NULL) { for (i=0; istages; i++) { retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, - liw_diff, y0, &step_mem->Fe[i]); + liw_diff, y0, &step_mem->Fe[i]); if (retval != ARK_SUCCESS) return(retval); } } @@ -282,7 +281,7 @@ int ARKStepResize(void *arkode_mem, N_Vector y0, realtype hscale, if (step_mem->Fi != NULL) { for (i=0; istages; i++) { retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, - liw_diff, y0, &step_mem->Fi[i]); + liw_diff, y0, &step_mem->Fi[i]); if (retval != ARK_SUCCESS) return(retval); } } @@ -319,7 +318,6 @@ int ARKStepResize(void *arkode_mem, N_Vector y0, realtype hscale, /* reset nonlinear solver counters */ if (step_mem->NLS != NULL) { - step_mem->ncfn = 0; step_mem->nsetups = 0; } @@ -359,14 +357,6 @@ int ARKStepReInit(void* arkode_mem, ARKRhsFn fe, return(ARK_ILL_INPUT); } - /* ReInitialize main ARKode infrastructure */ - retval = arkReInit(ark_mem, t0, y0); - if (retval != ARK_SUCCESS) { - arkProcessError(ark_mem, retval, "ARKode::ARKStep", "ARKStepReInit", - "Unable to initialize main ARKode infrastructure"); - return(retval); - } - /* Set implicit/explicit problem based on function pointers */ step_mem->explicit = (fe == NULL) ? SUNFALSE : SUNTRUE; step_mem->implicit = (fi == NULL) ? SUNFALSE : SUNTRUE; @@ -375,27 +365,22 @@ int ARKStepReInit(void* arkode_mem, ARKRhsFn fe, step_mem->fe = fe; step_mem->fi = fi; - /* Destroy/Reinitialize time step adaptivity structure (if present) */ - if (step_mem->hadapt_mem != NULL) { - free(step_mem->hadapt_mem); - step_mem->hadapt_mem = arkAdaptInit(); - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ARKStep", "ARKStepReInit", - "Allocation of Step Adaptivity Structure Failed"); - return(ARK_MEM_FAIL); - } - } /* Initialize initial error norm */ - step_mem->eRNrm = 1.0; + step_mem->eRNrm = ONE; + + /* ReInitialize main ARKode infrastructure */ + retval = arkReInit(ark_mem, t0, y0); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode::ARKStep", "ARKStepReInit", + "Unable to initialize main ARKode infrastructure"); + return(retval); + } /* Initialize all the counters */ - step_mem->nst_attempts = 0; - step_mem->nfe = 0; - step_mem->nfi = 0; - step_mem->ncfn = 0; - step_mem->netf = 0; - step_mem->nsetups = 0; - step_mem->nstlp = 0; + step_mem->nfe = 0; + step_mem->nfi = 0; + step_mem->nsetups = 0; + step_mem->nstlp = 0; return(ARK_SUCCESS); } @@ -569,14 +554,6 @@ void ARKStepFree(void **arkode_mem) step_mem = (ARKodeARKStepMem) ark_mem->step_mem; - /* free the time step adaptivity module */ - if (step_mem->hadapt_mem != NULL) { - free(step_mem->hadapt_mem); - step_mem->hadapt_mem = NULL; - ark_mem->lrw -= ARK_ADAPT_LRW; - ark_mem->liw -= ARK_ADAPT_LIW; - } - /* free the Butcher tables */ if (step_mem->Be != NULL) { ARKodeButcherTable_Space(step_mem->Be, &Bliw, &Blrw); @@ -646,13 +623,14 @@ void ARKStepFree(void **arkode_mem) if (step_mem->cvals != NULL) { free(step_mem->cvals); step_mem->cvals = NULL; - ark_mem->lrw -= (2*step_mem->stages + 1); + ark_mem->lrw -= step_mem->nfusedopvecs; } if (step_mem->Xvecs != NULL) { free(step_mem->Xvecs); step_mem->Xvecs = NULL; - ark_mem->liw -= (2*step_mem->stages + 1); + ark_mem->liw -= step_mem->nfusedopvecs; } + step_mem->nfusedopvecs = 0; /* free the time stepper module itself */ free(ark_mem->step_mem); @@ -696,8 +674,6 @@ void ARKStepPrintMem(void* arkode_mem, FILE* outfile) fprintf(outfile,"ARKStep: stages = %i\n", step_mem->stages); fprintf(outfile,"ARKStep: mnewt = %i\n", step_mem->mnewt); fprintf(outfile,"ARKStep: maxcor = %i\n", step_mem->maxcor); - fprintf(outfile,"ARKStep: maxnef = %i\n", step_mem->maxnef); - fprintf(outfile,"ARKStep: maxncf = %i\n", step_mem->maxncf); fprintf(outfile,"ARKStep: msbp = %i\n", step_mem->msbp); fprintf(outfile,"ARKStep: predictor = %i\n", step_mem->predictor); fprintf(outfile,"ARKStep: lsolve_type = %i\n", step_mem->lsolve_type); @@ -705,11 +681,8 @@ void ARKStepPrintMem(void* arkode_mem, FILE* outfile) fprintf(outfile,"ARKStep: convfail = %i\n", step_mem->convfail); /* output long integer quantities */ - fprintf(outfile,"ARKStep: nst_attempts = %li\n", step_mem->nst_attempts); fprintf(outfile,"ARKStep: nfe = %li\n", step_mem->nfe); fprintf(outfile,"ARKStep: nfi = %li\n", step_mem->nfi); - fprintf(outfile,"ARKStep: ncfn = %li\n", step_mem->ncfn); - fprintf(outfile,"ARKStep: netf = %li\n", step_mem->netf); fprintf(outfile,"ARKStep: nsetups = %li\n", step_mem->nsetups); fprintf(outfile,"ARKStep: nstlp = %li\n", step_mem->nstlp); @@ -718,7 +691,6 @@ void ARKStepPrintMem(void* arkode_mem, FILE* outfile) fprintf(outfile,"ARKStep: user_linear_timedep = %i\n", step_mem->linear_timedep); fprintf(outfile,"ARKStep: user_explicit = %i\n", step_mem->explicit); fprintf(outfile,"ARKStep: user_implicit = %i\n", step_mem->implicit); - fprintf(outfile,"ARKStep: hadapt_pq = %i\n", step_mem->hadapt_pq); fprintf(outfile,"ARKStep: jcur = %i\n", step_mem->jcur); /* output realtype quantities */ @@ -736,10 +708,6 @@ void ARKStepPrintMem(void* arkode_mem, FILE* outfile) fprintf(outfile,"ARKStep: crate = %"RSYM"\n", step_mem->crate); fprintf(outfile,"ARKStep: eRNrm = %"RSYM"\n", step_mem->eRNrm); fprintf(outfile,"ARKStep: nlscoef = %"RSYM"\n", step_mem->nlscoef); - if (step_mem->hadapt_mem != NULL) { - fprintf(outfile,"ARKStep: timestep adaptivity structure:\n"); - arkPrintAdaptMem(step_mem->hadapt_mem, outfile); - } fprintf(outfile,"ARKStep: crdown = %"RSYM"\n", step_mem->crdown); fprintf(outfile,"ARKStep: rdiv = %"RSYM"\n", step_mem->rdiv); fprintf(outfile,"ARKStep: dgmax = %"RSYM"\n", step_mem->dgmax); @@ -1029,6 +997,7 @@ int arkStep_Init(void* arkode_mem, int init_type) ARKodeARKStepMem step_mem; sunindextype Blrw, Bliw; int j, retval; + booleantype reset_efun; /* access ARKodeARKStepMem structure */ retval = arkStep_AccessStepMem(arkode_mem, "arkStep_Init", @@ -1038,16 +1007,22 @@ int arkStep_Init(void* arkode_mem, int init_type) /* perform initializations specific to init_type 0 */ if (init_type == 0) { - /* destroy adaptivity structure if fixed-stepping is requested */ - if (ark_mem->fixedstep) - if (step_mem->hadapt_mem != NULL) { - free(step_mem->hadapt_mem); - step_mem->hadapt_mem = NULL; - } - - /* Set first step growth factor */ - if (step_mem->hadapt_mem != NULL) - step_mem->hadapt_mem->etamax = step_mem->hadapt_mem->etamx1; + /* enforce use of arkEwtSmallReal if using a fixed step size for + an explicit method, an internal error weight function, and not + using an iterative mass matrix solver with rwt=ewt */ + reset_efun = SUNTRUE; + if ( step_mem->implicit ) reset_efun = SUNFALSE; + if ( !ark_mem->fixedstep ) reset_efun = SUNFALSE; + if ( ark_mem->user_efun ) reset_efun = SUNFALSE; + if ( ark_mem->rwt_is_ewt && (step_mem->msolve_type == SUNLINEARSOLVER_ITERATIVE) ) + reset_efun = SUNFALSE; + if ( ark_mem->rwt_is_ewt && (step_mem->msolve_type == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) + reset_efun = SUNFALSE; + if (reset_efun) { + ark_mem->user_efun = SUNFALSE; + ark_mem->efun = arkEwtSetSmallReal; + ark_mem->e_data = ark_mem; + } /* Create Butcher tables (if not already set) */ retval = arkStep_SetButcherTables(ark_mem); @@ -1073,6 +1048,22 @@ int arkStep_Init(void* arkode_mem, int init_type) ark_mem->liw += Bliw; ark_mem->lrw += Blrw; + /* Retrieve/store method and embedding orders now that tables are finalized */ + if (step_mem->Bi != NULL) { + step_mem->q = ark_mem->hadapt_mem->q = step_mem->Bi->q; + step_mem->p = ark_mem->hadapt_mem->p = step_mem->Bi->p; + } else { + step_mem->q = ark_mem->hadapt_mem->q = step_mem->Be->q; + step_mem->p = ark_mem->hadapt_mem->p = step_mem->Be->p; + } + + /* Ensure that if adaptivity is enabled, then method includes embedding coefficients */ + if (!ark_mem->fixedstep && (step_mem->p == 0)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", "arkStep_Init", + "Adaptive timestepping cannot be performed without embedding coefficients"); + return(ARK_ILL_INPUT); + } + /* Allocate ARK RHS vector memory, update storage requirements */ /* Allocate Fe[0] ... Fe[stages-1] if needed */ if (step_mem->explicit) { @@ -1096,31 +1087,38 @@ int arkStep_Init(void* arkode_mem, int init_type) ark_mem->liw += step_mem->stages; /* pointers */ } - /* Allocate reusable arrays for fused vector interface */ - j = (2*step_mem->stages+1 > 4) ? 2*step_mem->stages+1 : 4; + /* Allocate reusable arrays for fused vector operations */ + step_mem->nfusedopvecs = 2 * step_mem->stages + 2 + step_mem->nforcing; if (step_mem->cvals == NULL) { - step_mem->cvals = (realtype *) calloc(j, sizeof(realtype)); + step_mem->cvals = (realtype *) calloc(step_mem->nfusedopvecs, + sizeof(realtype)); if (step_mem->cvals == NULL) return(ARK_MEM_FAIL); - ark_mem->lrw += j; + ark_mem->lrw += step_mem->nfusedopvecs; } if (step_mem->Xvecs == NULL) { - step_mem->Xvecs = (N_Vector *) calloc(j, sizeof(N_Vector)); + step_mem->Xvecs = (N_Vector *) calloc(step_mem->nfusedopvecs, + sizeof(N_Vector)); if (step_mem->Xvecs == NULL) return(ARK_MEM_FAIL); - ark_mem->liw += j; /* pointers */ + ark_mem->liw += step_mem->nfusedopvecs; /* pointers */ } - /* Allocate interpolation memory (if unallocated, and needed) */ - if ((ark_mem->interp == NULL) && (step_mem->predictor > 0)) { - ark_mem->interp = arkInterpCreate(ark_mem); - if (ark_mem->interp == NULL) { - arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ARKStep", "arkStep_Init", - "Unable to allocate interpolation structure"); - return(ARK_MEM_FAIL); + /* Limit interpolant degree based on method order (use negative + argument to specify update instead of overwrite) */ + if (ark_mem->interp != NULL) { + retval = arkInterpSetDegree(ark_mem, ark_mem->interp, -(step_mem->q-1)); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", "arkStep_Init", + "Unable to update interpolation polynomial degree"); + return(ARK_ILL_INPUT); } } - } + } /* end (init_type == 0) */ + /* If the bootstrap predictor is enabled, signal to shared arkode module that + fullrhs is required after each step */ + if (step_mem->predictor == 4) ark_mem->call_fullrhs = SUNTRUE; + /* Check for consistency between linear system modules (e.g., if lsolve is direct, msolve needs to match) */ if (step_mem->mass_mem != NULL) { /* M != I */ @@ -1204,8 +1202,8 @@ int arkStep_Init(void* arkode_mem, int init_type) support it, we may just copy vectors Fe[stages] and Fi[stages] to fill f instead of calling fe() and fi(). - Mode 2 is only called for dense output in-between steps, or - when estimating the initial time step size, so we strive to + Mode 2 is only called for dense output in-between steps, or + when estimating the initial time step size, so we strive to store the intermediate parts so that they do not interfere with the other two modes. ---------------------------------------------------------------*/ @@ -1214,14 +1212,21 @@ int arkStep_FullRHS(void* arkode_mem, realtype t, { ARKodeMem ark_mem; ARKodeARKStepMem step_mem; - int retval; + int i, nvec, retval; + realtype tau, taui; booleantype recomputeRHS; + realtype* cvals; + N_Vector* Xvecs; /* access ARKodeARKStepMem structure */ retval = arkStep_AccessStepMem(arkode_mem, "arkStep_FullRHS", &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); + /* local shortcuts for use with fused vector operations */ + cvals = step_mem->cvals; + Xvecs = step_mem->Xvecs; + /* if the problem involves a non-identity mass matrix and setup is required, do so here (use output f as a temporary) */ if ( (step_mem->mass_mem != NULL) && (step_mem->msetup != NULL) ) @@ -1249,6 +1254,25 @@ int arkStep_FullRHS(void* arkode_mem, realtype t, "arkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); return(ARK_RHSFUNC_FAIL); } + /* apply external polynomial forcing */ + if (step_mem->expforcing) { + cvals[0] = ONE; + Xvecs[0] = step_mem->Fe[0]; + nvec = 1; + cvals[1] = ONE; + Xvecs[1] = step_mem->forcing[0]; + nvec = 2; + /* compute normalized time tau and initialize tau^i */ + tau = (t - step_mem->tshift) / (step_mem->tscale); + taui = tau; + for (i = 1; i < step_mem->nforcing; i++) { + cvals[nvec] = taui; + Xvecs[nvec] = step_mem->forcing[i]; + taui *= tau; + nvec += 1; + } + N_VLinearCombination(nvec, cvals, Xvecs, step_mem->Fe[0]); + } } /* call fi if the problem has an implicit component */ @@ -1260,6 +1284,25 @@ int arkStep_FullRHS(void* arkode_mem, realtype t, "arkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); return(ARK_RHSFUNC_FAIL); } + /* apply external polynomial forcing */ + if (step_mem->impforcing) { + cvals[0] = ONE; + Xvecs[0] = step_mem->Fi[0]; + nvec = 1; + cvals[1] = ONE; + Xvecs[1] = step_mem->forcing[0]; + nvec = 2; + /* compute normalized time tau and initialize tau^i */ + tau = (t - step_mem->tshift) / (step_mem->tscale); + taui = tau; + for (i = 1; i < step_mem->nforcing; i++) { + cvals[nvec] = taui; + Xvecs[nvec] = step_mem->forcing[i]; + taui *= tau; + nvec += 1; + } + N_VLinearCombination(nvec, cvals, Xvecs, step_mem->Fi[0]); + } } /* combine RHS vector(s) into output */ @@ -1299,6 +1342,25 @@ int arkStep_FullRHS(void* arkode_mem, realtype t, "arkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); return(ARK_RHSFUNC_FAIL); } + /* apply external polynomial forcing */ + if (step_mem->expforcing) { + cvals[0] = ONE; + Xvecs[0] = step_mem->Fe[0]; + nvec = 1; + cvals[1] = ONE; + Xvecs[1] = step_mem->forcing[0]; + nvec = 2; + /* compute normalized time tau and initialize tau^i */ + tau = (t - step_mem->tshift) / (step_mem->tscale); + taui = tau; + for (i = 1; i < step_mem->nforcing; i++) { + cvals[nvec] = taui; + Xvecs[nvec] = step_mem->forcing[i]; + taui *= tau; + nvec += 1; + } + N_VLinearCombination(nvec, cvals, Xvecs, step_mem->Fe[0]); + } } /* call fi if the problem has an implicit component */ @@ -1310,6 +1372,25 @@ int arkStep_FullRHS(void* arkode_mem, realtype t, "arkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); return(ARK_RHSFUNC_FAIL); } + /* apply external polynomial forcing */ + if (step_mem->impforcing) { + cvals[0] = ONE; + Xvecs[0] = step_mem->Fi[0]; + nvec = 1; + cvals[1] = ONE; + Xvecs[1] = step_mem->forcing[0]; + nvec = 2; + /* compute normalized time tau and initialize tau^i */ + tau = (t - step_mem->tshift) / (step_mem->tscale); + taui = tau; + for (i = 1; i < step_mem->nforcing; i++) { + cvals[nvec] = taui; + Xvecs[nvec] = step_mem->forcing[i]; + taui *= tau; + nvec += 1; + } + N_VLinearCombination(nvec, cvals, Xvecs, step_mem->Fi[0]); + } } } else { if (step_mem->explicit) @@ -1330,7 +1411,7 @@ int arkStep_FullRHS(void* arkode_mem, realtype t, break; /* Mode 2: called for dense output in-between steps or for estimation - of the initial time step size, store the intermediate calculations + of the initial time step size, store the intermediate calculations in such a way as to not interfere with the other two modes */ default: @@ -1343,6 +1424,25 @@ int arkStep_FullRHS(void* arkode_mem, realtype t, "arkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); return(ARK_RHSFUNC_FAIL); } + /* apply external polynomial forcing */ + if (step_mem->expforcing) { + cvals[0] = ONE; + Xvecs[0] = ark_mem->tempv2; + nvec = 1; + cvals[1] = ONE; + Xvecs[1] = step_mem->forcing[0]; + nvec = 2; + /* compute normalized time tau and initialize tau^i */ + tau = (t - step_mem->tshift) / (step_mem->tscale); + taui = tau; + for (i = 1; i < step_mem->nforcing; i++) { + cvals[nvec] = taui; + Xvecs[nvec] = step_mem->forcing[i]; + taui *= tau; + nvec += 1; + } + N_VLinearCombination(nvec, cvals, Xvecs, ark_mem->tempv2); + } } /* call fi if the problem has an implicit component (store in sdata) */ @@ -1354,6 +1454,25 @@ int arkStep_FullRHS(void* arkode_mem, realtype t, "arkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); return(ARK_RHSFUNC_FAIL); } + /* apply external polynomial forcing */ + if (step_mem->impforcing) { + cvals[0] = ONE; + Xvecs[0] = step_mem->sdata; + nvec = 1; + cvals[1] = ONE; + Xvecs[1] = step_mem->forcing[0]; + nvec = 2; + /* compute normalized time tau and initialize tau^i */ + tau = (t - step_mem->tshift) / (step_mem->tscale); + taui = tau; + for (i = 1; i < step_mem->nforcing; i++) { + cvals[nvec] = taui; + Xvecs[nvec] = step_mem->forcing[i]; + taui *= tau; + nvec += 1; + } + N_VLinearCombination(nvec, cvals, Xvecs, step_mem->sdata); + } } /* combine RHS vector(s) into output */ @@ -1387,224 +1506,244 @@ int arkStep_FullRHS(void* arkode_mem, realtype t, arkStep_TakeStep: This routine serves the primary purpose of the ARKStep module: - it performs a single successful ARK step (with embedding, if - possible). Multiple attempts may be taken in this process -- - once a step completes with successful (non)linear solves at - each stage and passes the error estimate, the routine returns - successfully. If it cannot do so, it returns with an - appropriate error flag. + it performs a single ARK step (with embedding, if possible). + + The output variable dsmPtr should contain estimate of the + weighted local error if an embedding is present; otherwise it + should be 0. + + The input/output variable nflagPtr is used to gauge convergence + of any algebraic solvers within the step. At the start of a new + time step, this will initially have the value FIRST_CALL. On + return from this function, nflagPtr should have a value: + 0 => algebraic solve completed successfully + >0 => solve did not converge at this step size + (but may with a smaller stepsize) + <0 => solve encountered an unrecoverable failure + + The return value from this routine is: + 0 => step completed successfully + >0 => step encountered recoverable failure; + reduce step and retry (if possible) + <0 => step encountered unrecoverable failure ---------------------------------------------------------------*/ -int arkStep_TakeStep(void* arkode_mem) +int arkStep_TakeStep(void* arkode_mem, realtype *dsmPtr, int *nflagPtr) { - realtype dsm; - int retval, ncf, nef, is, nflag, kflag, eflag; + int retval, is, i, nvec; + realtype tau, taui; booleantype implicit_stage; ARKodeMem ark_mem; ARKodeARKStepMem step_mem; N_Vector zcor0; + realtype* cvals; + N_Vector* Xvecs; /* access ARKodeARKStepMem structure */ retval = arkStep_AccessStepMem(arkode_mem, "arkStep_TakeStep", &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - ncf = nef = 0; - nflag = FIRST_CALL; - eflag = ARK_SUCCESS; - kflag = SOLVE_SUCCESS; - - /* Looping point for attempts to take a step */ - for(;;) { - - /* increment attempt counter */ - step_mem->nst_attempts++; - - /* call nonlinear solver setup if it exists */ - if (step_mem->NLS) - if ((step_mem->NLS)->ops->setup) { - zcor0 = ark_mem->tempv3; - N_VConst(ZERO, zcor0); /* set guess to all 0 (since ARKode uses predictor-corrector form) */ - retval = SUNNonlinSolSetup(step_mem->NLS, zcor0, ark_mem); - if (retval < 0) return(ARK_NLS_SETUP_FAIL); - if (retval > 0) return(ARK_NLS_SETUP_RECVR); - } + /* local shortcuts for use with fused vector operations */ + cvals = step_mem->cvals; + Xvecs = step_mem->Xvecs; - /* Loop over internal stages to the step */ - for (is=0; isstages; is++) { + /* if problem will involve no algebraic solvers, initialize nflagPtr to success */ + if (!step_mem->implicit && (step_mem->mass_mem == NULL)) + *nflagPtr = ARK_SUCCESS; - /* store current stage index */ - step_mem->istage = is; + /* call nonlinear solver setup if it exists */ + if (step_mem->NLS) + if ((step_mem->NLS)->ops->setup) { + zcor0 = ark_mem->tempv3; + N_VConst(ZERO, zcor0); /* set guess to all 0 (since ARKode uses predictor-corrector form) */ + retval = SUNNonlinSolSetup(step_mem->NLS, zcor0, ark_mem); + if (retval < 0) return(ARK_NLS_SETUP_FAIL); + if (retval > 0) return(ARK_NLS_SETUP_RECVR); + } - /* Set current stage time(s) */ - if (step_mem->implicit) - ark_mem->tcur = ark_mem->tn + step_mem->Bi->c[is]*ark_mem->h; - else - ark_mem->tcur = ark_mem->tn + step_mem->Be->c[is]*ark_mem->h; + /* Loop over internal stages to the step */ + for (is=0; isstages; is++) { + + /* store current stage index */ + step_mem->istage = is; + + /* Set current stage time(s) */ + if (step_mem->implicit) + ark_mem->tcur = ark_mem->tn + step_mem->Bi->c[is]*ark_mem->h; + else + ark_mem->tcur = ark_mem->tn + step_mem->Be->c[is]*ark_mem->h; #ifdef DEBUG_OUTPUT - printf("step %li, stage %i, h = %"RSYM", t_n = %"RSYM"\n", - ark_mem->nst, is, ark_mem->h, ark_mem->tcur); + printf("step %li, stage %i, h = %"RSYM", t_n = %"RSYM"\n", + ark_mem->nst, is, ark_mem->h, ark_mem->tcur); #endif - /* determine whether implicit solve is required */ - implicit_stage = SUNFALSE; - if (step_mem->implicit) - if (SUNRabs(step_mem->Bi->A[is][is]) > TINY) - implicit_stage = SUNTRUE; + /* determine whether implicit solve is required */ + implicit_stage = SUNFALSE; + if (step_mem->implicit) + if (SUNRabs(step_mem->Bi->A[is][is]) > TINY) + implicit_stage = SUNTRUE; - /* Call predictor for current stage solution (result placed in zpred) */ - if (implicit_stage) { - eflag = arkStep_Predict(ark_mem, is, step_mem->zpred); - if (eflag != ARK_SUCCESS) return (eflag); - } else { - N_VScale(ONE, ark_mem->yn, step_mem->zpred); - } + /* Call predictor for current stage solution (result placed in zpred) */ + if (implicit_stage) { + retval = arkStep_Predict(ark_mem, is, step_mem->zpred); + if (retval != ARK_SUCCESS) return (retval); + } else { + N_VScale(ONE, ark_mem->yn, step_mem->zpred); + } + + /* If a user-supplied predictor routine is provided, call that here */ + if (step_mem->stage_predict) { + retval = step_mem->stage_predict(ark_mem->tcur, step_mem->zpred, + ark_mem->user_data); + if (retval < 0) return(ARK_USER_PREDICT_FAIL); + if (retval > 0) return(TRY_AGAIN); + } #ifdef DEBUG_OUTPUT - printf("predictor:\n"); - N_VPrint_Serial(step_mem->zpred); + printf("predictor:\n"); + N_VPrint_Serial(step_mem->zpred); #endif - /* Set up data for evaluation of ARK stage residual (data stored in sdata) */ - eflag = arkStep_StageSetup(ark_mem); - if (eflag != ARK_SUCCESS) return (eflag); + /* Set up data for evaluation of ARK stage residual (data stored in sdata) */ + retval = arkStep_StageSetup(ark_mem); + if (retval != ARK_SUCCESS) return (retval); #ifdef DEBUG_OUTPUT - printf("rhs data:\n"); - N_VPrint_Serial(step_mem->sdata); + printf("rhs data:\n"); + N_VPrint_Serial(step_mem->sdata); #endif - /* Solver diagnostics reporting */ - if (ark_mem->report) - fprintf(ark_mem->diagfp, "ARKStep step %li %"RSYM" %i %"RSYM"\n", - ark_mem->nst, ark_mem->h, is, ark_mem->tcur); + /* Solver diagnostics reporting */ + if (ark_mem->report) + fprintf(ark_mem->diagfp, "ARKStep step %li %"RSYM" %i %"RSYM"\n", + ark_mem->nst, ark_mem->h, is, ark_mem->tcur); - /* perform implicit solve if required */ - if (implicit_stage) { + /* perform implicit solve if required */ + if (implicit_stage) { - /* perform implicit solve (result is stored in ark_mem->ycur) */ - nflag = arkStep_Nls(ark_mem, nflag); + /* perform implicit solve (result is stored in ark_mem->ycur); return + with positive value on anything but success */ + *nflagPtr = arkStep_Nls(ark_mem, *nflagPtr); + if (*nflagPtr != ARK_SUCCESS) return(TRY_AGAIN); #ifdef DEBUG_OUTPUT - printf("nonlinear solution:\n"); - N_VPrint_Serial(ark_mem->ycur); + printf("nonlinear solution:\n"); + N_VPrint_Serial(ark_mem->ycur); #endif - /* check for convergence (on failure, h will have been modified) */ - kflag = arkStep_HandleNFlag(ark_mem, &nflag, &ncf); - - /* If fixed time-stepping is used, then anything other than a - successful solve must result in an error */ - if (ark_mem->fixedstep && (kflag != SOLVE_SUCCESS)) - return(kflag); + /* otherwise no implicit solve is needed */ + } else { - /* If h reduced and step needs to be retried, break loop */ - if (kflag == PREDICT_AGAIN) break; + /* if M!=I, solve with M to compute update (place back in sdata) */ + if (step_mem->mass_mem != NULL) { - /* Return if nonlinear solve failed and recovery not possible. */ - if (kflag != SOLVE_SUCCESS) return(kflag); + /* perform mass matrix solve; return with positive value on + anything but success */ + *nflagPtr = step_mem->msolve((void *) ark_mem, step_mem->sdata, + step_mem->nlscoef); + if (*nflagPtr != ARK_SUCCESS) return(TRY_AGAIN); - /* otherwise no implicit solve is needed */ + /* if M==I, set y to be zpred + RHS data computed in arkStep_StageSetup */ } else { + N_VLinearSum(ONE, step_mem->sdata, ONE, step_mem->zpred, ark_mem->ycur); + } - /* if M!=I, solve with M to compute update (place back in sdata) */ - if (step_mem->mass_mem != NULL) { - - /* perform mass matrix solve */ - nflag = step_mem->msolve((void *) ark_mem, step_mem->sdata, - step_mem->nlscoef); - - /* check for convergence (on failure, h will have been modified) */ - kflag = arkStep_HandleNFlag(ark_mem, &nflag, &ncf); - - /* If fixed time-stepping is used, then anything other than a - successful solve must result in an error */ - if (ark_mem->fixedstep && (kflag != SOLVE_SUCCESS)) - return(kflag); +#ifdef DEBUG_OUTPUT + printf("explicit solution:\n"); + N_VPrint_Serial(ark_mem->ycur); +#endif - /* If h reduced and step needs to be retried, break loop */ - if (kflag == PREDICT_AGAIN) break; + } - /* Return if solve failed and recovery not possible. */ - if (kflag != SOLVE_SUCCESS) return(kflag); + /* apply user-supplied stage postprocessing function (if supplied) */ + /* With internally inconsistent IMEX methods (c_i^E != c_i^I) the value of + tcur corresponds to the stage time from the implicit table (c_i^I). */ + if (ark_mem->ProcessStage != NULL) { + retval = ark_mem->ProcessStage(ark_mem->tcur, + ark_mem->ycur, + ark_mem->user_data); + if (retval != 0) return(ARK_POSTPROCESS_STAGE_FAIL); + } - /* if M==I, set y to be zpred + RHS data computed in arkStep_StageSetup */ - } else { - N_VLinearSum(ONE, step_mem->sdata, ONE, - step_mem->zpred, ark_mem->ycur); + /* successful stage solve */ + /* store implicit RHS (value in Fi[is] is from preceding nonlinear iteration) */ + if (step_mem->implicit) { + retval = step_mem->fi(ark_mem->tcur, ark_mem->ycur, + step_mem->Fi[is], ark_mem->user_data); + step_mem->nfi++; + if (retval < 0) return(ARK_RHSFUNC_FAIL); + if (retval > 0) return(ARK_UNREC_RHSFUNC_ERR); + /* apply external polynomial forcing */ + if (step_mem->impforcing) { + cvals[0] = ONE; + Xvecs[0] = step_mem->Fi[is]; + nvec = 1; + cvals[1] = ONE; + Xvecs[1] = step_mem->forcing[0]; + nvec = 2; + /* compute normalized time tau and initialize tau^i */ + tau = (ark_mem->tcur - step_mem->tshift) / (step_mem->tscale); + taui = tau; + for (i = 1; i < step_mem->nforcing; i++) { + cvals[nvec] = taui; + Xvecs[nvec] = step_mem->forcing[i]; + taui *= tau; + nvec += 1; } - -#ifdef DEBUG_OUTPUT - printf("explicit solution:\n"); - N_VPrint_Serial(ark_mem->ycur); -#endif - + N_VLinearCombination(nvec, cvals, Xvecs, step_mem->Fi[is]); } + } - /* successful stage solve */ - /* store implicit RHS (value in Fi[is] is from preceding nonlinear iteration) */ - if (step_mem->implicit) { - retval = step_mem->fi(ark_mem->tcur, ark_mem->ycur, - step_mem->Fi[is], ark_mem->user_data); - step_mem->nfi++; + /* store explicit RHS */ + if (step_mem->explicit) { + retval = step_mem->fe(ark_mem->tn + step_mem->Be->c[is]*ark_mem->h, + ark_mem->ycur, step_mem->Fe[is], ark_mem->user_data); + step_mem->nfe++; if (retval < 0) return(ARK_RHSFUNC_FAIL); if (retval > 0) return(ARK_UNREC_RHSFUNC_ERR); - } - - /* store explicit RHS if necessary - (already computed at first stage of purely explicit runs) */ - if (step_mem->explicit) { - retval = step_mem->fe(ark_mem->tn + step_mem->Be->c[is]*ark_mem->h, - ark_mem->ycur, step_mem->Fe[is], ark_mem->user_data); - step_mem->nfe++; - if (retval < 0) return(ARK_RHSFUNC_FAIL); - if (retval > 0) return(ARK_UNREC_RHSFUNC_ERR); - } - - } /* loop over stages */ - - /* if h has changed due to convergence failure and a new - prediction is needed, continue to next attempt at step - (cannot occur if fixed time stepping is enabled) */ - if (kflag == PREDICT_AGAIN) continue; - - /* compute time-evolved solution (in ark_ycur), error estimate (in dsm) */ - retval = arkStep_ComputeSolutions(ark_mem, &dsm); - if (retval < 0) return(retval); - -#ifdef DEBUG_OUTPUT - printf("error estimate = %"RSYM"\n", dsm); -#endif + /* apply external polynomial forcing */ + if (step_mem->expforcing) { + cvals[0] = ONE; + Xvecs[0] = step_mem->Fe[is]; + nvec = 1; + cvals[1] = ONE; + Xvecs[1] = step_mem->forcing[0]; + nvec = 2; + /* compute normalized time tau and initialize tau^i */ + tau = ((ark_mem->tn + step_mem->Be->c[is]*ark_mem->h) - + step_mem->tshift) / (step_mem->tscale); + taui = tau; + for (i = 1; i < step_mem->nforcing; i++) { + cvals[nvec] = taui; + Xvecs[nvec] = step_mem->forcing[i]; + taui *= tau; + nvec += 1; + } + N_VLinearCombination(nvec, cvals, Xvecs, step_mem->Fe[is]); + } + } - /* Solver diagnostics reporting */ - if (ark_mem->report) - fprintf(ark_mem->diagfp, "ARKStep etest %li %"RSYM" %"RSYM"\n", - ark_mem->nst, ark_mem->h, dsm); + } /* loop over stages */ - /* Perform time accuracy error test (if failure, updates h for next try) */ - if (!ark_mem->fixedstep) - eflag = arkStep_DoErrorTest(ark_mem, &nflag, &nef, dsm); + /* compute time-evolved solution (in ark_ycur), error estimate (in dsm). + This can fail recoverably due to nonconvergence of the mass matrix solve, + so handle that appropriately. */ + retval = arkStep_ComputeSolutions(ark_mem, dsmPtr); + if (retval < 0) return(retval); + if (retval > 0) { + *nflagPtr = retval; + return(TRY_AGAIN); + } #ifdef DEBUG_OUTPUT - printf("error test flag = %i\n", eflag); + printf("error estimate = %"RSYM"\n", *dsmPtr); #endif - /* Restart step attempt (recompute all stages) if error test fails recoverably */ - if (eflag == TRY_AGAIN) continue; - - /* Return if error test failed and recovery not possible. */ - if (eflag != ARK_SUCCESS) return(eflag); - - /* Error test passed (eflag=ARK_SUCCESS), break from loop */ - break; - - } /* loop over step attempts */ - - - /* The step has completed successfully, clean up and - consider change of step size */ - retval = arkStep_PrepareNextStep(ark_mem, dsm); - if (retval != ARK_SUCCESS) return(retval); + /* Solver diagnostics reporting */ + if (ark_mem->report) + fprintf(ark_mem->diagfp, "ARKStep etest %li %"RSYM" %"RSYM"\n", + ark_mem->nst, ark_mem->h, *dsmPtr); return(ARK_SUCCESS); } @@ -1946,7 +2085,7 @@ int arkStep_Predict(ARKodeMem ark_mem, int istage, N_Vector yguess) return(ARK_MEM_NULL); } - /* local shortcuts to fused vector operations */ + /* local shortcuts for use with fused vector operations */ cvals = step_mem->cvals; Xvecs = step_mem->Xvecs; @@ -1966,14 +2105,14 @@ int arkStep_Predict(ARKodeMem ark_mem, int istage, N_Vector yguess) /***** Interpolatory Predictor 1 -- all to max order *****/ retval = arkPredict_MaximumOrder(ark_mem, tau, yguess); - if (retval == ARK_SUCCESS) return(ARK_SUCCESS); + if (retval != ARK_ILL_INPUT) return(retval); break; case 2: /***** Interpolatory Predictor 2 -- decrease order w/ increasing level of extrapolation *****/ retval = arkPredict_VariableOrder(ark_mem, tau, yguess); - if (retval == ARK_SUCCESS) return(ARK_SUCCESS); + if (retval != ARK_ILL_INPUT) return(retval); break; case 3: @@ -1981,7 +2120,7 @@ int arkStep_Predict(ARKodeMem ark_mem, int istage, N_Vector yguess) /***** Cutoff predictor: max order interpolatory output for stages "close" to previous step, first-order predictor for subsequent stages *****/ retval = arkPredict_CutoffOrder(ark_mem, tau, yguess); - if (retval == ARK_SUCCESS) return(ARK_SUCCESS); + if (retval != ARK_ILL_INPUT) return(retval); break; case 4: @@ -2026,7 +2165,7 @@ int arkStep_Predict(ARKodeMem ark_mem, int istage, N_Vector yguess) /* call predictor routine */ retval = arkPredict_Bootstrap(ark_mem, h, tau, nvec, cvals, Xvecs, yguess); - if (retval == ARK_SUCCESS) return(ARK_SUCCESS); + if (retval != ARK_ILL_INPUT) return(retval); break; case 5: @@ -2063,7 +2202,6 @@ int arkStep_Predict(ARKodeMem ark_mem, int istage, N_Vector yguess) /* compute predictor */ retval = N_VLinearCombination(nvec, cvals, Xvecs, yguess); if (retval != 0) return(ARK_VECTOROP_ERR); - return(ARK_SUCCESS); break; @@ -2099,6 +2237,7 @@ int arkStep_StageSetup(ARKodeMem ark_mem) /* local data */ ARKodeARKStepMem step_mem; int retval, i, j, nvec; + realtype tau, tauj; realtype* cvals; N_Vector* Xvecs; @@ -2120,13 +2259,29 @@ int arkStep_StageSetup(ARKodeMem ark_mem) /* If predictor==5, then sdata=0, otherwise set sdata appropriately */ if ( (step_mem->predictor == 5) && (step_mem->mass_mem == NULL) ) { - N_VConst(ZERO, step_mem->sdata); + /* apply external polynomial forcing */ + if (step_mem->impforcing) { + cvals[0] = ark_mem->h * step_mem->Bi->A[i][i]; + Xvecs[0] = step_mem->forcing[0]; + nvec = 1; + /* compute normalized time tau and initialize tau^j */ + tau = (ark_mem->tcur - step_mem->tshift) / (step_mem->tscale); + tauj = tau; + for (j = 1; j < step_mem->nforcing; j++) { + cvals[nvec] = ark_mem->h * step_mem->Bi->A[i][i] * tauj; + Xvecs[nvec] = step_mem->forcing[j]; + tauj *= tau; + nvec += 1; + } + N_VLinearCombination(nvec, cvals, Xvecs, step_mem->sdata); + } else { + N_VConst(ZERO, step_mem->sdata); + } } else { - /* Initialize sdata to ycur - zpred (here: ycur = yn and zpred = zp) */ - N_VLinearSum(ONE, ark_mem->yn, -ONE, step_mem->zpred, - step_mem->sdata); + /* Initialize sdata to yn - zpred (here: zpred = zp) */ + N_VLinearSum(ONE, ark_mem->yn, -ONE, step_mem->zpred, step_mem->sdata); /* If M!=I, replace sdata with M*sdata, so that sdata = M*(yn-zpred) */ if (step_mem->mass_mem != NULL) { @@ -2153,6 +2308,22 @@ int arkStep_StageSetup(ARKodeMem ark_mem) nvec += 1; } + /* apply external polynomial forcing */ + if (step_mem->impforcing) { + cvals[nvec] = ark_mem->h * step_mem->Bi->A[i][i]; + Xvecs[nvec] = step_mem->forcing[0]; + nvec += 1; + /* compute normalized time tau and initialize tau^j */ + tau = (ark_mem->tcur - step_mem->tshift) / (step_mem->tscale); + tauj = tau; + for (j = 1; j < step_mem->nforcing; j++) { + cvals[nvec] = ark_mem->h * step_mem->Bi->A[i][i] * tauj; + Xvecs[nvec] = step_mem->forcing[j]; + tauj *= tau; + nvec += 1; + } + } + /* call fused vector operation to do the work */ retval = N_VLinearCombination(nvec, cvals, Xvecs, step_mem->sdata); if (retval != 0) return(ARK_VECTOROP_ERR); @@ -2173,97 +2344,6 @@ int arkStep_StageSetup(ARKodeMem ark_mem) } -/*--------------------------------------------------------------- - arkStep_HandleNFlag - - This routine takes action on the return value nflag = *nflagPtr - returned by arkNls, as follows: - - If arkStep_Nls succeeded in solving the nonlinear system, then - arkHandleNFlag returns the constant SOLVE_SUCCESS, which tells - arkStep it is safe to continue with other stage solves, or to - perform the error test. - - If the nonlinear system was not solved successfully, then ncfn and - ncf = *ncfPtr are incremented. - - If the solution of the nonlinear system failed due to an - unrecoverable failure by setup, we return the value ARK_LSETUP_FAIL. - - If it failed due to an unrecoverable failure in solve, then we return - the value ARK_LSOLVE_FAIL. - - If it failed due to an unrecoverable failure in rhs, then we return - the value ARK_RHSFUNC_FAIL. - - Otherwise, a recoverable failure occurred when solving the - nonlinear system (arkNls returned nflag == CONV_FAIL or RHSFUNC_RECVR). - In this case, if using fixed time step sizes, or if ncf is now equal - to maxncf, or if |h| = hmin, then we return the value ARK_CONV_FAILURE - (if nflag=CONV_FAIL) or ARK_REPTD_RHSFUNC_ERR (if nflag=RHSFUNC_RECVR). - If not, we set *nflagPtr = PREV_CONV_FAIL and return the value - PREDICT_AGAIN, telling arkStep to reattempt the step. - ---------------------------------------------------------------*/ -int arkStep_HandleNFlag(ARKodeMem ark_mem, int *nflagPtr, int *ncfPtr) -{ - int nflag; - ARKodeHAdaptMem hadapt_mem; - ARKodeARKStepMem step_mem; - - /* access ARKodeARKStepMem structure */ - if (ark_mem->step_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "arkStep_HandleNFlag", MSG_ARKSTEP_NO_MEM); - return(ARK_MEM_NULL); - } - step_mem = (ARKodeARKStepMem) ark_mem->step_mem; - - nflag = *nflagPtr; - - if (nflag == ARK_SUCCESS) return(SOLVE_SUCCESS); - - /* The nonlinear soln. failed; increment ncfn */ - step_mem->ncfn++; - - /* If fixed time stepping, then return with convergence failure */ - if (ark_mem->fixedstep) return(ARK_CONV_FAILURE); - - /* Otherwise, access adaptivity structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", "arkStep_HandleNFlag", - MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* Return if lsetup, lsolve, or rhs failed unrecoverably */ - if (nflag == ARK_LSETUP_FAIL) return(ARK_LSETUP_FAIL); - if (nflag == ARK_LSOLVE_FAIL) return(ARK_LSOLVE_FAIL); - if (nflag == ARK_RHSFUNC_FAIL) return(ARK_RHSFUNC_FAIL); - - /* At this point, nflag = CONV_FAIL or RHSFUNC_RECVR; increment ncf */ - (*ncfPtr)++; - hadapt_mem->etamax = ONE; - - /* If we had maxncf failures, or if |h| = hmin, - return ARK_CONV_FAILURE or ARK_REPTD_RHSFUNC_ERR. */ - if ((*ncfPtr == step_mem->maxncf) || - (SUNRabs(ark_mem->h) <= ark_mem->hmin*ONEPSM)) { - if (nflag == CONV_FAIL) return(ARK_CONV_FAILURE); - if (nflag == RHSFUNC_RECVR) return(ARK_REPTD_RHSFUNC_ERR); - } - - /* Reduce step size; return to reattempt the step */ - ark_mem->eta = SUNMAX(hadapt_mem->etacf, - ark_mem->hmin / SUNRabs(ark_mem->h)); - ark_mem->h *= ark_mem->eta; - ark_mem->next_h = ark_mem->h; - *nflagPtr = PREV_CONV_FAIL; - - return(PREDICT_AGAIN); -} - - /*--------------------------------------------------------------- arkStep_ComputeSolutions @@ -2275,7 +2355,7 @@ int arkStep_HandleNFlag(ARKodeMem ark_mem, int *nflagPtr, int *ncfPtr) estimated error (y-ytilde) is stored in ark_mem->tempv1, in case the calling routine wishes to examine the error locations. ---------------------------------------------------------------*/ -int arkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsm) +int arkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsmPtr) { /* local data */ realtype tend; @@ -2303,7 +2383,7 @@ int arkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsm) Xvecs = step_mem->Xvecs; /* initialize output */ - *dsm = ZERO; + *dsmPtr = ZERO; /* Compute updated solution and error estimate based on whether a non-identity mass matrix is present */ @@ -2341,7 +2421,7 @@ int arkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsm) /* solve for y update (stored in y) */ retval = step_mem->msolve((void *) ark_mem, y, step_mem->nlscoef); if (retval < 0) { - *dsm = 2.0; /* indicate too much error, step with smaller step */ + *dsmPtr = RCONST(2.0); /* indicate too much error, step with smaller step */ N_VScale(ONE, ark_mem->yn, y); /* place old solution into y */ return(CONV_FAIL); } @@ -2376,11 +2456,11 @@ int arkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsm) /* solve for yerr */ retval = step_mem->msolve((void *) ark_mem, yerr, step_mem->nlscoef); if (retval < 0) { - *dsm = 2.0; /* indicate too much error, step with smaller step */ + *dsmPtr = RCONST(2.0); /* indicate too much error, step with smaller step */ return(CONV_FAIL); } /* fill error norm */ - *dsm = N_VWrmsNorm(yerr, ark_mem->ewt); + *dsmPtr = N_VWrmsNorm(yerr, ark_mem->ewt); } } else { /* M == I */ @@ -2430,7 +2510,7 @@ int arkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsm) if (retval != 0) return(ARK_VECTOROP_ERR); /* fill error norm */ - *dsm = N_VWrmsNorm(yerr, ark_mem->ewt); + *dsmPtr = N_VWrmsNorm(yerr, ark_mem->ewt); } } @@ -2439,170 +2519,100 @@ int arkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsm) } -/*--------------------------------------------------------------- - arkStep_DoErrorTest +/*------------------------------------------------------------------------------ + arkStep_SetInnerForcing - This routine performs the local error test for the ARK method. - The weighted local error norm dsm is passed in, and - the test dsm ?<= 1 is made. + Sets an array of coefficient vectors for a time-dependent external polynomial + forcing term in the ODE RHS i.e., y' = fe(t,y) + fi(t,y) + p(t). This + function is primarily intended for use with multirate integration methods + (e.g., MRIStep) where ARKStep is used to solve a modified ODE at a fast time + scale. The polynomial is of the form - If the test passes, arkDoErrorTest returns ARK_SUCCESS. + p(t) = sum_{i = 0}^{nvecs - 1} forcing[i] * ((t - tshift) / (tscale))^i - If the test fails, we revert to the last successful solution - time, and: - - if maxnef error test failures have occurred or if - SUNRabs(h) = hmin, we return ARK_ERR_FAILURE. - - otherwise: update time step factor eta based on local error - estimate and reduce h. Then set *nflagPtr to PREV_ERR_FAIL, - and return TRY_AGAIN. - ---------------------------------------------------------------*/ -int arkStep_DoErrorTest(ARKodeMem ark_mem, int *nflagPtr, - int *nefPtr, realtype dsm) + where tshift and tscale are used to normalize the time t (e.g., with MRIGARK + methods). + ----------------------------------------------------------------------------*/ + +int arkStep_SetInnerForcing(void* arkode_mem, realtype tshift, realtype tscale, + N_Vector* forcing, int nvecs) { - realtype ehist2, hhist2; - int retval; - ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; ARKodeARKStepMem step_mem; + int retval; /* access ARKodeARKStepMem structure */ - if (ark_mem->step_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "arkStep_DoErrorTest", MSG_ARKSTEP_NO_MEM); - return(ARK_MEM_NULL); - } - step_mem = (ARKodeARKStepMem) ark_mem->step_mem; - - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", "arkDoErrorTest", - MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* If est. local error norm dsm passes test, return ARK_SUCCESS */ - if (dsm <= ONE) return(ARK_SUCCESS); - - /* Test failed; increment counters, set nflag */ - (*nefPtr)++; - step_mem->netf++; - *nflagPtr = PREV_ERR_FAIL; - - /* At |h| = hmin or maxnef failures, return ARK_ERR_FAILURE */ - if ((SUNRabs(ark_mem->h) <= ark_mem->hmin*ONEPSM) || - (*nefPtr == step_mem->maxnef)) - return(ARK_ERR_FAILURE); - - /* Set etamax=1 to prevent step size increase at end of this step */ - hadapt_mem->etamax = ONE; - - /* Temporarily update error history array for recomputation of h */ - ehist2 = hadapt_mem->ehist[2]; - hadapt_mem->ehist[2] = hadapt_mem->ehist[1]; - hadapt_mem->ehist[1] = hadapt_mem->ehist[0]; - hadapt_mem->ehist[0] = dsm*hadapt_mem->bias; - - /* Temporarily update step history array for recomputation of h */ - hhist2 = hadapt_mem->hhist[2]; - hadapt_mem->hhist[2] = hadapt_mem->hhist[1]; - hadapt_mem->hhist[1] = hadapt_mem->hhist[0]; - hadapt_mem->hhist[0] = ark_mem->h; - - /* Compute accuracy-based time step estimate (updated ark_eta) */ - retval = arkAdapt((void*) ark_mem, step_mem->hadapt_mem, ark_mem->ycur, - ark_mem->tcur, ark_mem->h, step_mem->q, step_mem->p, - step_mem->hadapt_pq, ark_mem->nst); - if (retval != ARK_SUCCESS) return(ARK_ERR_FAILURE); - - /* Revert error history array */ - hadapt_mem->ehist[0] = hadapt_mem->ehist[1]; - hadapt_mem->ehist[1] = hadapt_mem->ehist[2]; - hadapt_mem->ehist[2] = ehist2; - - /* Revert step history array */ - hadapt_mem->hhist[0] = hadapt_mem->hhist[1]; - hadapt_mem->hhist[1] = hadapt_mem->hhist[2]; - hadapt_mem->hhist[2] = hhist2; - - /* Enforce failure bounds on eta, update h, and return for retry of step */ - if (*nefPtr >= hadapt_mem->small_nef) - ark_mem->eta = SUNMIN(ark_mem->eta, hadapt_mem->etamxf); - ark_mem->h *= ark_mem->eta; - ark_mem->next_h = ark_mem->h; - return(TRY_AGAIN); -} + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepResize", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + if (nvecs > 0) { -/*--------------------------------------------------------------- - arkStep_PrepareNextStep - - This routine handles ARK-specific updates following a successful - step: copying the ARK result to the current solution vector, - updating the error/step history arrays, and setting the - prospective step size, hprime, for the next step. Along with - hprime, it sets the ratio eta=hprime/h. It also updates other - state variables related to a change of step size. - ---------------------------------------------------------------*/ -int arkStep_PrepareNextStep(ARKodeMem ark_mem, realtype dsm) -{ - int retval; - ARKodeARKStepMem step_mem; + /* enable forcing */ + if (step_mem->implicit) { + step_mem->expforcing = SUNFALSE; + step_mem->impforcing = SUNTRUE; + } else { + step_mem->expforcing = SUNTRUE; + step_mem->impforcing = SUNFALSE; + } + step_mem->tshift = tshift; + step_mem->tscale = tscale; + step_mem->forcing = forcing; + step_mem->nforcing = nvecs; + + /* If cvals and Xvecs are not allocated then arkStep_Init has not been + called and the number of stages has not been set yet. These arrays will + be allocated in arkStep_Init and take into account the value of nforcing. + On subsequent calls will check if enough space has allocated in case + nforcing has increased since the original allocation. */ + if (step_mem->cvals != NULL && step_mem->Xvecs != NULL) { + + /* check if there are enough reusable arrays for fused operations */ + if ((step_mem->nfusedopvecs - nvecs) < (2 * step_mem->stages + 2)) { + + /* free current work space */ + if (step_mem->cvals != NULL) { + free(step_mem->cvals); + ark_mem->lrw -= step_mem->nfusedopvecs; + } + if (step_mem->Xvecs != NULL) { + free(step_mem->Xvecs); + ark_mem->liw -= step_mem->nfusedopvecs; + } - /* access ARKodeARKStepMem structure */ - if (ark_mem->step_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "arkStep_PrepareNextStep", MSG_ARKSTEP_NO_MEM); - return(ARK_MEM_NULL); - } - step_mem = (ARKodeARKStepMem) ark_mem->step_mem; + /* allocate reusable arrays for fused vector operations */ + step_mem->nfusedopvecs = 2 * step_mem->stages + 2 + nvecs; - /* Update step size and error history arrays */ - if (step_mem->hadapt_mem != NULL) { - step_mem->hadapt_mem->ehist[2] = step_mem->hadapt_mem->ehist[1]; - step_mem->hadapt_mem->ehist[1] = step_mem->hadapt_mem->ehist[0]; - step_mem->hadapt_mem->ehist[0] = dsm*step_mem->hadapt_mem->bias; - step_mem->hadapt_mem->hhist[2] = step_mem->hadapt_mem->hhist[1]; - step_mem->hadapt_mem->hhist[1] = step_mem->hadapt_mem->hhist[0]; - step_mem->hadapt_mem->hhist[0] = ark_mem->h; - } - - /* If fixed time-stepping requested, defer - step size changes until next step */ - if (ark_mem->fixedstep){ - ark_mem->hprime = ark_mem->h; - ark_mem->eta = ONE; - return(ARK_SUCCESS); - } + step_mem->cvals = NULL; + step_mem->cvals = (realtype *) calloc(step_mem->nfusedopvecs, + sizeof(realtype)); + if (step_mem->cvals == NULL) return(ARK_MEM_FAIL); + ark_mem->lrw += step_mem->nfusedopvecs; - /* If etamax = 1, defer step size changes until next step, - and reset etamax */ - if (step_mem->hadapt_mem != NULL) - if (step_mem->hadapt_mem->etamax == ONE) { - ark_mem->hprime = ark_mem->h; - ark_mem->eta = ONE; - step_mem->hadapt_mem->etamax = step_mem->hadapt_mem->growth; - return(ARK_SUCCESS); + step_mem->Xvecs = NULL; + step_mem->Xvecs = (N_Vector *) calloc(step_mem->nfusedopvecs, + sizeof(N_Vector)); + if (step_mem->Xvecs == NULL) return(ARK_MEM_FAIL); + ark_mem->liw += step_mem->nfusedopvecs; + } } - /* Adjust ark_eta in arkAdapt */ - if (step_mem->hadapt_mem != NULL) { - retval = arkAdapt((void*) ark_mem, step_mem->hadapt_mem, - ark_mem->ycur, ark_mem->tn + ark_mem->h, - ark_mem->h, step_mem->q, step_mem->p, - step_mem->hadapt_pq, ark_mem->nst+1); - if (retval != ARK_SUCCESS) return(ARK_ERR_FAILURE); - } + } else { - /* Set hprime value for next step size */ - ark_mem->hprime = ark_mem->h * ark_mem->eta; + /* disable forcing */ + step_mem->expforcing = SUNFALSE; + step_mem->impforcing = SUNFALSE; + step_mem->tshift = ZERO; + step_mem->tscale = ONE; + step_mem->forcing = NULL; + step_mem->nforcing = 0; - /* Reset growth factor for subsequent time step */ - if (step_mem->hadapt_mem != NULL) - step_mem->hadapt_mem->etamax = step_mem->hadapt_mem->growth; + } - return(ARK_SUCCESS); + return(0); } - /*=============================================================== EOF ===============================================================*/ diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep_impl.h b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep_impl.h index 789edd558..4e5d6f743 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep_impl.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -27,10 +27,22 @@ extern "C" { #endif /*=============================================================== - ARK time step module constants -- move many items here from - arkode_impl.h + ARK time step module constants ===============================================================*/ +#define MAXCOR 3 /* max number of nonlinear iterations */ +#define CRDOWN RCONST(0.3) /* constant to estimate the convergence + rate for the nonlinear equation */ +#define DGMAX RCONST(0.2) /* if |gamma/gammap-1| > DGMAX then call lsetup */ +#define RDIV RCONST(2.3) /* declare divergence if ratio del/delp > RDIV */ +#define MSBP 20 /* max no. of steps between lsetup calls */ + +/* Default solver tolerance factor */ +/* #define NLSCOEF RCONST(0.003) */ /* Hairer & Wanner constant */ +/* #define NLSCOEF RCONST(0.2) */ /* CVODE constant */ +#define NLSCOEF RCONST(0.1) + + /*=============================================================== ARK time step module data structure @@ -66,10 +78,8 @@ typedef struct ARKodeARKStepMemRec { ARKodeButcherTable Be; /* ERK Butcher table */ ARKodeButcherTable Bi; /* IRK Butcher table */ - /* Time step adaptivity data */ - ARKodeHAdaptMem hadapt_mem; /* time step adaptivity structure */ - booleantype hadapt_pq; /* choice of using p (0) vs q (1) */ - int maxnef; /* max error test fails in one step */ + /* User-supplied stage predictor routine */ + ARKStepStagePredictFn stage_predict; /* (Non)Linear solver parameters & data */ SUNNonlinearSolver NLS; /* generic SUNNonlinearSolver object */ @@ -95,7 +105,6 @@ typedef struct ARKodeARKStepMemRec { int maxcor; /* max num iterations for solving the nonlinear equation */ - int maxncf; /* max num nonlin. conv. fails in one step */ int convfail; /* NLS fail flag (for interface routines) */ booleantype jcur; /* is Jacobian info for lin solver current? */ @@ -119,16 +128,22 @@ typedef struct ARKodeARKStepMemRec { int msolve_type; /* interface type: 0=iterative; 1=direct; 2=custom */ /* Counters */ - long int nst_attempts; /* num attempted steps */ - long int nfe; /* num fe calls */ - long int nfi; /* num fi calls */ - long int ncfn; /* num corrector convergence failures */ - long int netf; /* num error test failures */ - long int nsetups; /* num setup calls */ + long int nfe; /* num fe calls */ + long int nfi; /* num fi calls */ + long int nsetups; /* num setup calls */ /* Reusable arrays for fused vector operations */ - realtype *cvals; - N_Vector *Xvecs; + realtype *cvals; /* scalar array for fused ops */ + N_Vector *Xvecs; /* array of vectors for fused ops */ + int nfusedopvecs; /* length of cvals and Xvecs arrays */ + + /* Data for using ARKStep with external polynomial forcing */ + booleantype expforcing; /* add forcing to explicit RHS */ + booleantype impforcing; /* add forcing to implicit RHS */ + realtype tshift; /* time normalization shift */ + realtype tscale; /* time normalization scaling */ + N_Vector* forcing; /* array of forcing vectors */ + int nforcing; /* number of forcing vectors */ } *ARKodeARKStepMem; @@ -160,7 +175,7 @@ int arkStep_GetGammas(void* arkode_mem, realtype *gamma, booleantype *dgamma_fail); int arkStep_FullRHS(void* arkode_mem, realtype t, N_Vector y, N_Vector f, int mode); -int arkStep_TakeStep(void* arkode_mem); +int arkStep_TakeStep(void* arkode_mem, realtype *dsmPtr, int *nflagPtr); /* Internal utility routines */ int arkStep_AccessStepMem(void* arkode_mem, const char *fname, @@ -172,22 +187,20 @@ int arkStep_Predict(ARKodeMem ark_mem, int istage, N_Vector yguess); int arkStep_StageSetup(ARKodeMem ark_mem); int arkStep_NlsInit(ARKodeMem ark_mem); int arkStep_Nls(ARKodeMem ark_mem, int nflag); -int arkStep_HandleNFlag(ARKodeMem ark_mem, int *nflagPtr, int *ncfPtr); - int arkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsm); -int arkStep_DoErrorTest(ARKodeMem ark_mem, int *nflagPtr, - int *nefPtr, realtype dsm); -int arkStep_PrepareNextStep(ARKodeMem ark_mem, realtype dsm); /* private functions passed to nonlinear solver */ int arkStep_NlsResidual(N_Vector yy, N_Vector res, void* arkode_mem); int arkStep_NlsFPFunction(N_Vector yy, N_Vector res, void* arkode_mem); -int arkStep_NlsLSetup(N_Vector yy, N_Vector res, booleantype jbad, - booleantype* jcur, void* arkode_mem); -int arkStep_NlsLSolve(N_Vector yy, N_Vector delta, void* arkode_mem); +int arkStep_NlsLSetup(booleantype jbad, booleantype* jcur, void* arkode_mem); +int arkStep_NlsLSolve(N_Vector delta, void* arkode_mem); int arkStep_NlsConvTest(SUNNonlinearSolver NLS, N_Vector y, N_Vector del, realtype tol, N_Vector ewt, void* arkode_mem); +/* private functions used by MRIStep */ +int arkStep_SetInnerForcing(void* arkode_mem, realtype tshift, realtype tscale, + N_Vector *f, int nvecs); + /*=============================================================== Reusable ARKStep Error Messages ===============================================================*/ @@ -196,6 +209,11 @@ int arkStep_NlsConvTest(SUNNonlinearSolver NLS, N_Vector y, N_Vector del, #define MSG_ARKSTEP_NO_MEM "Time step module memory is NULL." #define MSG_NLS_INIT_FAIL "The nonlinear solver's init routine failed." +/* Other error messages */ +#define MSG_ARK_MISSING_FE "Cannot specify that method is explicit without providing a function pointer to fe(t,y)." +#define MSG_ARK_MISSING_FI "Cannot specify that method is implicit without providing a function pointer to fi(t,y)." +#define MSG_ARK_MISSING_F "Cannot specify that method is ImEx without providing function pointers to fi(t,y) and fe(t,y)." + #ifdef __cplusplus } #endif diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep_io.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep_io.c index 1d4462792..e1f29d259 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep_io.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep_io.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -35,279 +35,149 @@ /*=============================================================== ARKStep Optional input functions (wrappers for generic ARKode - utility routines) + utility routines). All are documented in arkode_io.c. ===============================================================*/ - -/*--------------------------------------------------------------- - ARKStepSetDenseOrder: Specifies the polynomial order for dense - output. Positive values are sent to the interpolation module; - negative values imply to use the default. - ---------------------------------------------------------------*/ -int ARKStepSetDenseOrder(void *arkode_mem, int dord) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetDenseOrder", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetDenseOrder(ark_mem, dord)); -} - -/*--------------------------------------------------------------- - ARKStepSetErrHandlerFn: Specifies the error handler function - ---------------------------------------------------------------*/ +int ARKStepSetDenseOrder(void *arkode_mem, int dord) { + return(ARKStepSetInterpolantDegree(arkode_mem, dord)); } +int ARKStepSetInterpolantDegree(void *arkode_mem, int degree) { + if (degree < 0) degree = ARK_INTERP_MAX_DEGREE; + return(arkSetInterpolantDegree(arkode_mem, degree)); } +int ARKStepSetInterpolantType(void *arkode_mem, int itype) { + return(arkSetInterpolantType(arkode_mem, itype)); } int ARKStepSetErrHandlerFn(void *arkode_mem, ARKErrHandlerFn ehfun, - void *eh_data) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetErrHandlerFn", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetErrHandlerFn(ark_mem, ehfun, eh_data)); -} + void *eh_data) { + return(arkSetErrHandlerFn(arkode_mem, ehfun, eh_data)); } +int ARKStepSetErrFile(void *arkode_mem, FILE *errfp) { + return(arkSetErrFile(arkode_mem, errfp)); } +int ARKStepSetDiagnostics(void *arkode_mem, FILE *diagfp) { + return(arkSetDiagnostics(arkode_mem, diagfp)); } +int ARKStepSetMaxNumSteps(void *arkode_mem, long int mxsteps) { + return(arkSetMaxNumSteps(arkode_mem, mxsteps)); } +int ARKStepSetMaxHnilWarns(void *arkode_mem, int mxhnil) { + return(arkSetMaxHnilWarns(arkode_mem, mxhnil)); } +int ARKStepSetInitStep(void *arkode_mem, realtype hin) { + return(arkSetInitStep(arkode_mem, hin)); } +int ARKStepSetMinStep(void *arkode_mem, realtype hmin) { + return(arkSetMinStep(arkode_mem, hmin)); } +int ARKStepSetMaxStep(void *arkode_mem, realtype hmax) { + return(arkSetMaxStep(arkode_mem, hmax)); } +int ARKStepSetStopTime(void *arkode_mem, realtype tstop) { + return(arkSetStopTime(arkode_mem, tstop)); } +int ARKStepSetRootDirection(void *arkode_mem, int *rootdir) { + return(arkSetRootDirection(arkode_mem, rootdir)); } +int ARKStepSetNoInactiveRootWarn(void *arkode_mem) { + return(arkSetNoInactiveRootWarn(arkode_mem)); } +int ARKStepSetConstraints(void *arkode_mem, N_Vector constraints) { + return(arkSetConstraints(arkode_mem, constraints)); } +int ARKStepSetMaxNumConstrFails(void *arkode_mem, int maxfails) { + return(arkSetMaxNumConstrFails(arkode_mem, maxfails)); } +int ARKStepSetPostprocessStepFn(void *arkode_mem, + ARKPostProcessFn ProcessStep) { + return(arkSetPostprocessStepFn(arkode_mem, ProcessStep)); } +int ARKStepSetPostprocessStageFn(void *arkode_mem, + ARKPostProcessFn ProcessStage) { + return(arkSetPostprocessStageFn(arkode_mem, ProcessStage)); } +int ARKStepSetCFLFraction(void *arkode_mem, realtype cfl_frac) { + return(arkSetCFLFraction(arkode_mem, cfl_frac)); } +int ARKStepSetSafetyFactor(void *arkode_mem, realtype safety) { + return(arkSetSafetyFactor(arkode_mem, safety)); } +int ARKStepSetErrorBias(void *arkode_mem, realtype bias) { + return(arkSetErrorBias(arkode_mem, bias)); } +int ARKStepSetMaxGrowth(void *arkode_mem, realtype mx_growth) { + return(arkSetMaxGrowth(arkode_mem, mx_growth)); } +int ARKStepSetMinReduction(void *arkode_mem, realtype eta_min) { + return(arkSetMinReduction(arkode_mem, eta_min)); } +int ARKStepSetFixedStepBounds(void *arkode_mem, realtype lb, realtype ub) { + return(arkSetFixedStepBounds(arkode_mem, lb, ub)); } +int ARKStepSetAdaptivityMethod(void *arkode_mem, int imethod, int idefault, + int pq, realtype adapt_params[3]) { + return(arkSetAdaptivityMethod(arkode_mem, imethod, idefault, pq, adapt_params)); } +int ARKStepSetAdaptivityFn(void *arkode_mem, ARKAdaptFn hfun, void *h_data) { + return(arkSetAdaptivityFn(arkode_mem, hfun, h_data)); } +int ARKStepSetMaxFirstGrowth(void *arkode_mem, realtype etamx1) { + return(arkSetMaxFirstGrowth(arkode_mem, etamx1)); } +int ARKStepSetMaxEFailGrowth(void *arkode_mem, realtype etamxf) { + return(arkSetMaxEFailGrowth(arkode_mem, etamxf)); } +int ARKStepSetSmallNumEFails(void *arkode_mem, int small_nef) { + return(arkSetSmallNumEFails(arkode_mem, small_nef)); } +int ARKStepSetMaxCFailGrowth(void *arkode_mem, realtype etacf) { + return(arkSetMaxCFailGrowth(arkode_mem, etacf)); } +int ARKStepSetStabilityFn(void *arkode_mem, ARKExpStabFn EStab, void *estab_data) { + return(arkSetStabilityFn(arkode_mem, EStab, estab_data)); } +int ARKStepSetMaxErrTestFails(void *arkode_mem, int maxnef) { + return(arkSetMaxErrTestFails(arkode_mem, maxnef)); } +int ARKStepSetMaxConvFails(void *arkode_mem, int maxncf) { + return(arkSetMaxConvFails(arkode_mem, maxncf)); } +int ARKStepSetFixedStep(void *arkode_mem, realtype hfixed) { + return(arkSetFixedStep(arkode_mem, hfixed)); } -/*--------------------------------------------------------------- - ARKStepSetErrFile: Specifies the FILE pointer for output (NULL - means no messages) - ---------------------------------------------------------------*/ -int ARKStepSetErrFile(void *arkode_mem, FILE *errfp) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetErrFile", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetErrFile(ark_mem, errfp)); -} -/*--------------------------------------------------------------- - ARKStepSetUserData: Specifies the user data pointer for f - ---------------------------------------------------------------*/ -int ARKStepSetUserData(void *arkode_mem, void *user_data) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetUserData", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetUserData(ark_mem, user_data)); -} +/*=============================================================== + ARKStep Optional input functions (customized wrappers for + generic ARKode utility routines). All are documented in + arkode_io.c and arkode_ls.c. + ===============================================================*/ -/*--------------------------------------------------------------- - ARKStepSetDiagnostics: Specifies to enable solver diagnostics, - and specifies the FILE pointer for output (diagfp==NULL - disables output) - ---------------------------------------------------------------*/ -int ARKStepSetDiagnostics(void *arkode_mem, FILE *diagfp) +int ARKStepSetUserData(void *arkode_mem, void *user_data) { - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetDiagnostics", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetDiagnostics(ark_mem, diagfp)); -} + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; -/*--------------------------------------------------------------- - ARKStepSetMaxNumSteps: Specifies the maximum number of - integration steps - ---------------------------------------------------------------*/ -int ARKStepSetMaxNumSteps(void *arkode_mem, long int mxsteps) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetMaxNumSteps", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetMaxNumSteps(ark_mem, mxsteps)); -} + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetUserData", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); -/*--------------------------------------------------------------- - ARKStepSetMaxHnilWarns: Specifies the maximum number of warnings - for small h - ---------------------------------------------------------------*/ -int ARKStepSetMaxHnilWarns(void *arkode_mem, int mxhnil) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetMaxHnilWarns", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetMaxHnilWarns(ark_mem, mxhnil)); -} + /* set user_data in ARKode mem */ + retval = arkSetUserData(arkode_mem, user_data); + if (retval != ARK_SUCCESS) return(retval); -/*--------------------------------------------------------------- - ARKStepSetInitStep: Specifies the initial step size - ---------------------------------------------------------------*/ -int ARKStepSetInitStep(void *arkode_mem, realtype hin) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetInitStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); + /* set user data in ARKodeLS mem */ + if (step_mem->lmem != NULL) { + retval = arkLSSetUserData(arkode_mem, user_data); + if (retval != ARKLS_SUCCESS) return(retval); } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetInitStep(ark_mem, hin)); -} -/*--------------------------------------------------------------- - ARKStepSetMinStep: Specifies the minimum step size - ---------------------------------------------------------------*/ -int ARKStepSetMinStep(void *arkode_mem, realtype hmin) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetMinStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); + /* set user data in ARKodeLSMass mem */ + if (step_mem->mass_mem != NULL) { + retval = arkLSSetMassUserData(arkode_mem, user_data); + if (retval != ARKLS_SUCCESS) return(retval); } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetMinStep(ark_mem, hmin)); -} -/*--------------------------------------------------------------- - ARKStepSetMaxStep: Specifies the maximum step size - ---------------------------------------------------------------*/ -int ARKStepSetMaxStep(void *arkode_mem, realtype hmax) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetMaxStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetMaxStep(ark_mem, hmax)); + return(ARK_SUCCESS); } -/*--------------------------------------------------------------- - ARKStepSetStopTime: Specifies the time beyond which the - integration is not to proceed. - ---------------------------------------------------------------*/ -int ARKStepSetStopTime(void *arkode_mem, realtype tstop) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetStopTime", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetStopTime(ark_mem, tstop)); -} /*--------------------------------------------------------------- - ARKStepSetFixedStep: Specifies to use a fixed time step size - instead of performing any form of temporal adaptivity. ARKStep - will use this step size for all steps (unless tstop is set, in - which case it may need to modify that last step approaching - tstop. If any solver failure occurs in the timestepping - module, ARKStep will typically immediately return with an error - message indicating that the selected step size cannot be used. - - Any nonzero argument will result in the use of that fixed step - size; an argument of 0 will re-enable temporal adaptivity. + ARKStepSetStagePredictFn: Specifies a user-provided step + predictor function having type ARKStepStagePredictFn. A + NULL input function disables calls to this routine. ---------------------------------------------------------------*/ -int ARKStepSetFixedStep(void *arkode_mem, realtype hfixed) +int ARKStepSetStagePredictFn(void *arkode_mem, + ARKStepStagePredictFn PredictStage) { - ARKodeMem ark_mem; + ARKodeMem ark_mem; ARKodeARKStepMem step_mem; - int retval; + int retval; - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetFixedStep", + /* access ARKodeARKStepMem structure and set function pointer */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetStagePredictFn", &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* allocate or free adaptivity memory as needed */ - if (hfixed != ZERO) { - if (step_mem->hadapt_mem != NULL) { - free(step_mem->hadapt_mem); - step_mem->hadapt_mem = NULL; - } - } else if (step_mem->hadapt_mem == NULL) { - step_mem->hadapt_mem = arkAdaptInit(); - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ARKStep", - "ARKStepSetFixedStep", - "Allocation of Step Adaptivity Structure Failed"); - return(ARK_MEM_FAIL); - } - } - - return(arkSetFixedStep(ark_mem, hfixed)); -} + if (retval != ARK_SUCCESS) return(retval); -/*--------------------------------------------------------------- - ARKStepSetRootDirection: Specifies the direction of zero-crossings - to be monitored. The default is to monitor both crossings. - ---------------------------------------------------------------*/ -int ARKStepSetRootDirection(void *arkode_mem, int *rootdir) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetRootDirection", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); + /* override predictor method 5 if non-NULL PredictStage is supplied */ + if ((step_mem->predictor == 5) && (PredictStage != NULL)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetStagePredictFn", + "User-supplied predictor is incompatible with predictor method 5"); + return(ARK_ILL_INPUT); } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetRootDirection(ark_mem, rootdir)); -} -/*--------------------------------------------------------------- - ARKStepSetNoInactiveRootWarn: Disables issuing a warning if - some root function appears to be identically zero at the - beginning of the integration - ---------------------------------------------------------------*/ -int ARKStepSetNoInactiveRootWarn(void *arkode_mem) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetNoInactiveRootWarn", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetNoInactiveRootWarn(ark_mem)); + step_mem->stage_predict = PredictStage; + return(ARK_SUCCESS); } -/*--------------------------------------------------------------- - ARKStepSetPostprocessStepFn: Specifies a user-provided step - postprocessing function having type ARKPostProcessStepFn. A - NULL input function disables step postprocessing. - - IF THE SUPPLIED FUNCTION MODIFIES ANY OF THE ACTIVE STATE DATA, - THEN ALL THEORETICAL GUARANTEES OF SOLUTION ACCURACY AND - STABILITY ARE LOST. - ---------------------------------------------------------------*/ -int ARKStepSetPostprocessStepFn(void *arkode_mem, - ARKPostProcessStepFn ProcessStep) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetPostprocessStepFn", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetPostprocessStepFn(ark_mem, ProcessStep)); -} /*--------------------------------------------------------------- These wrappers for ARKLs module 'set' routines all are @@ -325,6 +195,8 @@ int ARKStepSetMassFn(void *arkode_mem, ARKLsMassFn mass) { return(arkLSSetMassFn(arkode_mem, mass)); } int ARKStepSetMaxStepsBetweenJac(void *arkode_mem, long int msbj) { return(arkLSSetMaxStepsBetweenJac(arkode_mem, msbj)); } +int ARKStepSetLinearSolutionScaling(void *arkode_mem, booleantype onoff) { + return(arkLSSetLinearSolutionScaling(arkode_mem, onoff)); } int ARKStepSetEpsLin(void *arkode_mem, realtype eplifac) { return(arkLSSetEpsLin(arkode_mem, eplifac)); } int ARKStepSetMassEpsLin(void *arkode_mem, realtype eplifac) { @@ -341,212 +213,54 @@ int ARKStepSetJacTimes(void *arkode_mem, ARKLsJacTimesSetupFn jtsetup, int ARKStepSetMassTimes(void *arkode_mem, ARKLsMassTimesSetupFn msetup, ARKLsMassTimesVecFn mtimes, void *mtimes_data) { return(arkLSSetMassTimes(arkode_mem, msetup, mtimes, mtimes_data)); } - +int ARKStepSetLinSysFn(void *arkode_mem, ARKLsLinSysFn linsys) { + return(arkLSSetLinSysFn(arkode_mem, linsys)); } /*=============================================================== ARKStep Optional output functions (wrappers for generic ARKode - utility routines) + utility routines). All are documented in arkode_io.c. ===============================================================*/ - -/*--------------------------------------------------------------- - ARKStepGetNumSteps: Returns the current number of integration - steps - ---------------------------------------------------------------*/ -int ARKStepGetNumSteps(void *arkode_mem, long int *nsteps) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepGetNumSteps", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetNumSteps(ark_mem, nsteps)); -} - -/*--------------------------------------------------------------- - ARKStepGetActualInitStep: Returns the step size used on the - first step - ---------------------------------------------------------------*/ -int ARKStepGetActualInitStep(void *arkode_mem, realtype *hinused) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepGetActualInitStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetActualInitStep(ark_mem, hinused)); -} - -/*--------------------------------------------------------------- - ARKStepGetLastStep: Returns the step size used on the last - successful step - ---------------------------------------------------------------*/ -int ARKStepGetLastStep(void *arkode_mem, realtype *hlast) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepGetLastStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetLastStep(ark_mem, hlast)); -} - -/*--------------------------------------------------------------- - ARKStepGetCurrentStep: Returns the step size to be attempted on - the next step - ---------------------------------------------------------------*/ -int ARKStepGetCurrentStep(void *arkode_mem, realtype *hcur) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepGetCurrentStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetCurrentStep(ark_mem, hcur)); -} - -/*--------------------------------------------------------------- - ARKStepGetCurrentTime: Returns the current value of the - independent variable - ---------------------------------------------------------------*/ -int ARKStepGetCurrentTime(void *arkode_mem, realtype *tcur) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepGetCurrentTime", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetCurrentTime(ark_mem, tcur)); -} - -/*--------------------------------------------------------------- - ARKStepGetTolScaleFactor: Returns a suggested factor for scaling - tolerances - ---------------------------------------------------------------*/ -int ARKStepGetTolScaleFactor(void *arkode_mem, realtype *tolsfact) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepGetTolScaleFactor", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetTolScaleFactor(ark_mem, tolsfact)); -} - -/*--------------------------------------------------------------- - ARKStepGetErrWeights: This routine returns the current error - weight vector. - ---------------------------------------------------------------*/ -int ARKStepGetErrWeights(void *arkode_mem, N_Vector eweight) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepGetErrWeights", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetErrWeights(ark_mem, eweight)); -} - -/*--------------------------------------------------------------- - ARKStepGetResWeights: This routine returns the current residual - weight vector. - ---------------------------------------------------------------*/ -int ARKStepGetResWeights(void *arkode_mem, N_Vector rweight) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepGetResWeights", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetResWeights(ark_mem, rweight)); -} - -/*--------------------------------------------------------------- - ARKStepGetWorkSpace: Returns integrator work space requirements - ---------------------------------------------------------------*/ -int ARKStepGetWorkSpace(void *arkode_mem, long int *lenrw, long int *leniw) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepGetWorkSpace", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetWorkSpace(ark_mem, lenrw, leniw)); -} - -/*--------------------------------------------------------------- - ARKStepGetNumGEvals: Returns the current number of calls to g - (for rootfinding) - ---------------------------------------------------------------*/ -int ARKStepGetNumGEvals(void *arkode_mem, long int *ngevals) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepGetNumGEvals", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetNumGEvals(ark_mem, ngevals)); -} - -/*--------------------------------------------------------------- - ARKStepGetRootInfo: Returns pointer to array rootsfound showing - roots found - ---------------------------------------------------------------*/ -int ARKStepGetRootInfo(void *arkode_mem, int *rootsfound) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepGetRootInfo", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetRootInfo(ark_mem, rootsfound)); -} - -/*--------------------------------------------------------------- - ARKStepGetStepStats: Returns step statistics - ---------------------------------------------------------------*/ +int ARKStepGetNumStepAttempts(void *arkode_mem, long int *nstep_attempts) { + return(arkGetNumStepAttempts(arkode_mem, nstep_attempts)); } +int ARKStepGetNumSteps(void *arkode_mem, long int *nsteps) { + return(arkGetNumSteps(arkode_mem, nsteps)); } +int ARKStepGetActualInitStep(void *arkode_mem, realtype *hinused) { + return(arkGetActualInitStep(arkode_mem, hinused)); } +int ARKStepGetLastStep(void *arkode_mem, realtype *hlast) { + return(arkGetLastStep(arkode_mem, hlast)); } +int ARKStepGetCurrentStep(void *arkode_mem, realtype *hcur) { + return(arkGetCurrentStep(arkode_mem, hcur)); } +int ARKStepGetCurrentTime(void *arkode_mem, realtype *tcur) { + return(arkGetCurrentTime(arkode_mem, tcur)); } +int ARKStepGetCurrentState(void *arkode_mem, N_Vector *ycur) { + return(arkGetCurrentState(arkode_mem, ycur)); } +int ARKStepGetTolScaleFactor(void *arkode_mem, realtype *tolsfact) { + return(arkGetTolScaleFactor(arkode_mem, tolsfact)); } +int ARKStepGetErrWeights(void *arkode_mem, N_Vector eweight) { + return(arkGetErrWeights(arkode_mem, eweight)); } +int ARKStepGetResWeights(void *arkode_mem, N_Vector rweight) { + return(arkGetResWeights(arkode_mem, rweight)); } +int ARKStepGetWorkSpace(void *arkode_mem, long int *lenrw, long int *leniw) { + return(arkGetWorkSpace(arkode_mem, lenrw, leniw)); } +int ARKStepGetNumGEvals(void *arkode_mem, long int *ngevals) { + return(arkGetNumGEvals(arkode_mem, ngevals)); } +int ARKStepGetRootInfo(void *arkode_mem, int *rootsfound) { + return(arkGetRootInfo(arkode_mem, rootsfound)); } int ARKStepGetStepStats(void *arkode_mem, long int *nsteps, realtype *hinused, realtype *hlast, - realtype *hcur, realtype *tcur) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepGetStepStats", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetStepStats(ark_mem, nsteps, hinused, hlast, hcur, tcur)); -} - -/*--------------------------------------------------------------- - ARKStepGetReturnFlagName: translates from return flags IDs to - names - ---------------------------------------------------------------*/ -char *ARKStepGetReturnFlagName(long int flag) -{ return(arkGetReturnFlagName(flag)); } + realtype *hcur, realtype *tcur) { + return(arkGetStepStats(arkode_mem, nsteps, hinused, hlast, hcur, tcur)); } +int ARKStepGetNumConstrFails(void *arkode_mem, long int *nconstrfails) { + return(arkGetNumConstrFails(arkode_mem, nconstrfails)); } +int ARKStepGetNumExpSteps(void *arkode_mem, long int *nsteps) { + return(arkGetNumExpSteps(arkode_mem, nsteps)); } +int ARKStepGetNumAccSteps(void *arkode_mem, long int *nsteps) { + return(arkGetNumAccSteps(arkode_mem, nsteps)); } +int ARKStepGetNumErrTestFails(void *arkode_mem, long int *netfails) { + return(arkGetNumErrTestFails(arkode_mem, netfails)); } +char *ARKStepGetReturnFlagName(long int flag) { + return(arkGetReturnFlagName(flag)); } /*--------------------------------------------------------------- These wrappers for ARKLs module 'get' routines all are @@ -569,7 +283,7 @@ int ARKStepGetNumJTSetupEvals(void *arkode_mem, long int *njtsetups) { int ARKStepGetNumJtimesEvals(void *arkode_mem, long int *njvevals) { return(arkLSGetNumJtimesEvals(arkode_mem, njvevals)); } int ARKStepGetNumLinRhsEvals(void *arkode_mem, long int *nfevalsLS) { - return(arkLSGetNumRhsEvals(arkode_mem, nfevalsLS)); } + return(arkLSGetNumRhsEvals(arkode_mem, nfevalsLS)); } int ARKStepGetLastLinFlag(void *arkode_mem, long int *flag) { return(arkLSGetLastFlag(arkode_mem, flag)); } @@ -577,6 +291,8 @@ int ARKStepGetMassWorkSpace(void *arkode_mem, long int *lenrwMLS, long int *leni return(arkLSGetMassWorkSpace(arkode_mem, lenrwMLS, leniwMLS)); } int ARKStepGetNumMassSetups(void *arkode_mem, long int *nmsetups) { return(arkLSGetNumMassSetups(arkode_mem, nmsetups)); } +int ARKStepGetNumMassMultSetups(void *arkode_mem, long int *nmvsetups) { + return(arkLSGetNumMassMatvecSetups(arkode_mem, nmvsetups)); } int ARKStepGetNumMassMult(void *arkode_mem, long int *nmvevals) { return(arkLSGetNumMassMult(arkode_mem, nmvevals)); } int ARKStepGetNumMassSolves(void *arkode_mem, long int *nmsolves) { @@ -610,7 +326,7 @@ char *ARKStepGetLinReturnFlagName(long int flag) { Does not change problem-defining function pointers or user_data pointer. Also leaves alone any data structures/options related to the ARKode infrastructure itself - (e.g. root-finding). + (e.g., root-finding and post-process step). ---------------------------------------------------------------*/ int ARKStepSetDefaults(void* arkode_mem) { @@ -635,33 +351,12 @@ int ARKStepSetDefaults(void* arkode_mem) /* Set default values for integrator optional inputs */ step_mem->q = Q_DEFAULT; /* method order */ step_mem->p = 0; /* embedding order */ - step_mem->hadapt_pq = SUNFALSE; /* use embedding order */ step_mem->predictor = 0; /* trivial predictor */ step_mem->linear = SUNFALSE; /* nonlinear problem */ step_mem->linear_timedep = SUNTRUE; /* dfi/dy depends on t */ step_mem->explicit = SUNTRUE; /* fe(t,y) will be used */ step_mem->implicit = SUNTRUE; /* fi(t,y) will be used */ - if (step_mem->hadapt_mem != NULL) { - step_mem->hadapt_mem->etamx1 = ETAMX1; /* max change on first step */ - step_mem->hadapt_mem->etamxf = ETAMXF; /* max change on error-failed step */ - step_mem->hadapt_mem->small_nef = SMALL_NEF; /* num error fails before ETAMXF enforced */ - step_mem->hadapt_mem->etacf = ETACF; /* max change on convergence failure */ - step_mem->hadapt_mem->HAdapt = NULL; /* step adaptivity fn */ - step_mem->hadapt_mem->HAdapt_data = NULL; /* step adaptivity data */ - step_mem->hadapt_mem->imethod = 0; /* PID controller */ - step_mem->hadapt_mem->cfl = CFLFAC; /* explicit stability factor */ - step_mem->hadapt_mem->safety = SAFETY; /* step adaptivity safety factor */ - step_mem->hadapt_mem->bias = BIAS; /* step adaptivity error bias */ - step_mem->hadapt_mem->growth = GROWTH; /* step adaptivity growth factor */ - step_mem->hadapt_mem->lbound = HFIXED_LB; /* step adaptivity no-change lower bound */ - step_mem->hadapt_mem->ubound = HFIXED_UB; /* step adaptivity no-change upper bound */ - step_mem->hadapt_mem->k1 = AD0_K1; /* step adaptivity parameter */ - step_mem->hadapt_mem->k2 = AD0_K2; /* step adaptivity parameter */ - step_mem->hadapt_mem->k3 = AD0_K3; /* step adaptivity parameter */ - } step_mem->maxcor = MAXCOR; /* max nonlinear iters/stage */ - step_mem->maxnef = MAXNEF; /* max error test fails */ - step_mem->maxncf = MAXNCF; /* max convergence fails */ step_mem->nlscoef = NLSCOEF; /* nonlinear tolerance coefficient */ step_mem->crdown = CRDOWN; /* nonlinear convergence estimate coeff. */ step_mem->rdiv = RDIV; /* nonlinear divergence tolerance */ @@ -674,6 +369,7 @@ int ARKStepSetDefaults(void* arkode_mem) step_mem->NLS = NULL; /* no nonlinear solver object */ step_mem->jcur = SUNFALSE; step_mem->convfail = ARK_NO_FAILURES; + step_mem->stage_predict = NULL; /* no user-supplied stage predictor */ return(ARK_SUCCESS); } @@ -701,13 +397,13 @@ int ARKStepSetOptimalParams(void *arkode_mem) if (retval != ARK_SUCCESS) return(retval); /* access ARKodeHAdaptMem structure */ - if (step_mem->hadapt_mem == NULL) { + if (ark_mem->hadapt_mem == NULL) { arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", "ARKStepSetOptimalParams", MSG_ARKADAPT_NO_MEM); return(ARK_MEM_NULL); } - hadapt_mem = step_mem->hadapt_mem; + hadapt_mem = ark_mem->hadapt_mem; /* Choose values based on method, order */ @@ -721,7 +417,7 @@ int ARKStepSetOptimalParams(void *arkode_mem) hadapt_mem->k2 = RCONST(0.31); hadapt_mem->etamxf = RCONST(0.3); - /* implicit */ + /* implicit */ } else if (step_mem->implicit && !step_mem->explicit) { switch (step_mem->q) { case 2: /* just use standard defaults since better ones unknown */ @@ -732,12 +428,12 @@ int ARKStepSetOptimalParams(void *arkode_mem) hadapt_mem->etamxf = ETAMXF; hadapt_mem->small_nef = SMALL_NEF; hadapt_mem->etacf = ETACF; - step_mem->nlscoef = RCONST(0.001); - step_mem->maxcor = 5; - step_mem->crdown = CRDOWN; - step_mem->rdiv = RDIV; - step_mem->dgmax = DGMAX; - step_mem->msbp = MSBP; + step_mem->nlscoef = RCONST(0.001); + step_mem->maxcor = 5; + step_mem->crdown = CRDOWN; + step_mem->rdiv = RDIV; + step_mem->dgmax = DGMAX; + step_mem->msbp = MSBP; break; case 3: hadapt_mem->imethod = 2; @@ -747,11 +443,11 @@ int ARKStepSetOptimalParams(void *arkode_mem) hadapt_mem->etamxf = RCONST(0.45); hadapt_mem->small_nef = SMALL_NEF; hadapt_mem->etacf = ETACF; - step_mem->nlscoef = RCONST(0.22); - step_mem->crdown = RCONST(0.17); - step_mem->rdiv = RCONST(2.3); - step_mem->dgmax = RCONST(0.19); - step_mem->msbp = 60; + step_mem->nlscoef = RCONST(0.22); + step_mem->crdown = RCONST(0.17); + step_mem->rdiv = RCONST(2.3); + step_mem->dgmax = RCONST(0.19); + step_mem->msbp = 60; break; case 4: hadapt_mem->imethod = 0; @@ -764,11 +460,11 @@ int ARKStepSetOptimalParams(void *arkode_mem) hadapt_mem->etamxf = RCONST(0.33); hadapt_mem->small_nef = SMALL_NEF; hadapt_mem->etacf = ETACF; - step_mem->nlscoef = RCONST(0.24); - step_mem->crdown = RCONST(0.26); - step_mem->rdiv = RCONST(2.3); - step_mem->dgmax = RCONST(0.16); - step_mem->msbp = 31; + step_mem->nlscoef = RCONST(0.24); + step_mem->crdown = RCONST(0.26); + step_mem->rdiv = RCONST(2.3); + step_mem->dgmax = RCONST(0.16); + step_mem->msbp = 31; break; case 5: hadapt_mem->imethod = 0; @@ -781,15 +477,15 @@ int ARKStepSetOptimalParams(void *arkode_mem) hadapt_mem->etamxf = RCONST(0.44); hadapt_mem->small_nef = SMALL_NEF; hadapt_mem->etacf = ETACF; - step_mem->nlscoef = RCONST(0.25); - step_mem->crdown = RCONST(0.4); - step_mem->rdiv = RCONST(2.3); - step_mem->dgmax = RCONST(0.32); - step_mem->msbp = 31; + step_mem->nlscoef = RCONST(0.25); + step_mem->crdown = RCONST(0.4); + step_mem->rdiv = RCONST(2.3); + step_mem->dgmax = RCONST(0.32); + step_mem->msbp = 31; break; } - /* imex */ + /* imex */ } else { switch (step_mem->q) { case 3: @@ -803,11 +499,11 @@ int ARKStepSetOptimalParams(void *arkode_mem) hadapt_mem->etamxf = RCONST(0.46); hadapt_mem->small_nef = SMALL_NEF; hadapt_mem->etacf = ETACF; - step_mem->nlscoef = RCONST(0.22); - step_mem->crdown = RCONST(0.17); - step_mem->rdiv = RCONST(2.3); - step_mem->dgmax = RCONST(0.19); - step_mem->msbp = 60; + step_mem->nlscoef = RCONST(0.22); + step_mem->crdown = RCONST(0.17); + step_mem->rdiv = RCONST(2.3); + step_mem->dgmax = RCONST(0.19); + step_mem->msbp = 60; break; case 4: hadapt_mem->imethod = 0; @@ -820,11 +516,11 @@ int ARKStepSetOptimalParams(void *arkode_mem) hadapt_mem->etamxf = RCONST(0.47); hadapt_mem->small_nef = SMALL_NEF; hadapt_mem->etacf = ETACF; - step_mem->nlscoef = RCONST(0.24); - step_mem->crdown = RCONST(0.26); - step_mem->rdiv = RCONST(2.3); - step_mem->dgmax = RCONST(0.16); - step_mem->msbp = 31; + step_mem->nlscoef = RCONST(0.24); + step_mem->crdown = RCONST(0.26); + step_mem->rdiv = RCONST(2.3); + step_mem->dgmax = RCONST(0.16); + step_mem->msbp = 31; break; case 5: hadapt_mem->imethod = 1; @@ -836,11 +532,11 @@ int ARKStepSetOptimalParams(void *arkode_mem) hadapt_mem->etamxf = RCONST(0.3); hadapt_mem->small_nef = SMALL_NEF; hadapt_mem->etacf = ETACF; - step_mem->nlscoef = RCONST(0.25); - step_mem->crdown = RCONST(0.4); - step_mem->rdiv = RCONST(2.3); - step_mem->dgmax = RCONST(0.32); - step_mem->msbp = 31; + step_mem->nlscoef = RCONST(0.25); + step_mem->crdown = RCONST(0.4); + step_mem->rdiv = RCONST(2.3); + step_mem->dgmax = RCONST(0.32); + step_mem->msbp = 31; break; } @@ -1012,6 +708,15 @@ int ARKStepSetImplicit(void *arkode_mem) step_mem->implicit = SUNTRUE; step_mem->explicit = SUNFALSE; + /* re-attach internal error weight functions if necessary */ + if (!ark_mem->user_efun) { + if (ark_mem->itol == ARK_SV && ark_mem->Vabstol != NULL) + retval = arkSVtolerances(ark_mem, ark_mem->reltol, ark_mem->Vabstol); + else + retval = arkSStolerances(ark_mem, ark_mem->reltol, ark_mem->Sabstol); + if (retval != ARK_SUCCESS) return(retval); + } + return(ARK_SUCCESS); } @@ -1049,6 +754,15 @@ int ARKStepSetImEx(void *arkode_mem) step_mem->explicit = SUNTRUE; step_mem->implicit = SUNTRUE; + /* re-attach internal error weight functions if necessary */ + if (!ark_mem->user_efun) { + if (ark_mem->itol == ARK_SV && ark_mem->Vabstol != NULL) + retval = arkSVtolerances(ark_mem, ark_mem->reltol, ark_mem->Vabstol); + else + retval = arkSStolerances(ark_mem, ark_mem->reltol, ark_mem->Sabstol); + if (retval != ARK_SUCCESS) return(retval); + } + return(ARK_SUCCESS); } @@ -1307,7 +1021,9 @@ int ARKStepSetTableNum(void *arkode_mem, int itable, int etable) /* ensure that tables match */ if ( !((etable == ARK324L2SA_ERK_4_2_3) && (itable == ARK324L2SA_DIRK_4_2_3)) && !((etable == ARK436L2SA_ERK_6_3_4) && (itable == ARK436L2SA_DIRK_6_3_4)) && - !((etable == ARK548L2SA_ERK_8_4_5) && (itable == ARK548L2SA_DIRK_8_4_5)) ) { + !((etable == ARK437L2SA_ERK_7_3_4) && (itable == ARK437L2SA_DIRK_7_3_4)) && + !((etable == ARK548L2SA_ERK_8_4_5) && (itable == ARK548L2SA_DIRK_8_4_5)) && + !((etable == ARK548L2SAb_ERK_8_4_5) && (itable == ARK548L2SAb_DIRK_8_4_5)) ) { arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", "ARKStepSetTableNum", "Incompatible Butcher tables for ARK method"); @@ -1347,498 +1063,20 @@ int ARKStepSetTableNum(void *arkode_mem, int itable, int etable) /*--------------------------------------------------------------- - ARKStepSetCFLFraction: + ARKStepSetNonlinCRDown: - Specifies the safety factor to use on the maximum explicitly- - stable step size. Allowable values must be within the open - interval (0,1). A non-positive input implies a reset to - the default value. + Specifies the user-provided nonlinear convergence constant + crdown. Legal values are strictly positive; illegal values + imply a reset to the default. ---------------------------------------------------------------*/ -int ARKStepSetCFLFraction(void *arkode_mem, realtype cfl_frac) +int ARKStepSetNonlinCRDown(void *arkode_mem, realtype crdown) { ARKodeMem ark_mem; ARKodeARKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; int retval; /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetCFLFraction", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetCFLFraction", - MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* check for allowable parameters */ - if (cfl_frac >= 1.0) { - arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", - "ARKStepSetCFLFraction", "Illegal CFL fraction"); - return(ARK_ILL_INPUT); - } - - /* set positive-valued parameters, otherwise set default */ - if (cfl_frac <= ZERO) { - hadapt_mem->cfl = CFLFAC; - } else { - hadapt_mem->cfl = cfl_frac; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetSafetyFactor: - - Specifies the safety factor to use on the error-based predicted - time step size. Allowable values must be within the open - interval (0,1). A non-positive input implies a reset to the - default value. - ---------------------------------------------------------------*/ -int ARKStepSetSafetyFactor(void *arkode_mem, realtype safety) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetSafetyFactor", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetSafetyFactoy",MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* check for allowable parameters */ - if (safety >= 1.0) { - arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", - "ARKStepSetSafetyFactor", "Illegal safety factor"); - return(ARK_ILL_INPUT); - } - - /* set positive-valued parameters, otherwise set default */ - if (safety <= ZERO) { - hadapt_mem->safety = SAFETY; - } else { - hadapt_mem->safety = safety; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetErrorBias: - - Specifies the error bias to use when performing adaptive-step - error control. Allowable values must be >= 1.0. Any illegal - value implies a reset to the default value. - ---------------------------------------------------------------*/ -int ARKStepSetErrorBias(void *arkode_mem, realtype bias) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetErrorBias", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access ARKodeHAdaptMem structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetErrorBias", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* set allowed value, otherwise set default */ - if (bias < 1.0) { - hadapt_mem->bias = BIAS; - } else { - hadapt_mem->bias = bias; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetMaxGrowth: - - Specifies the maximum step size growth factor to be allowed - between successive integration steps. Note: the first step uses - a separate maximum growth factor. Allowable values must be - > 1.0. Any illegal value implies a reset to the default. - ---------------------------------------------------------------*/ -int ARKStepSetMaxGrowth(void *arkode_mem, realtype mx_growth) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetMaxGrowth", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access ARKodeHAdaptMem structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetMaxGrowth", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* set allowed value, otherwise set default */ - if (mx_growth == ZERO) { - hadapt_mem->growth = GROWTH; - } else { - hadapt_mem->growth = mx_growth; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetFixedStepBounds: - - Specifies the step size growth interval within which the step - size will remain unchanged. Allowable values must enclose the - value 1.0. Any illegal interval implies a reset to the default. - ---------------------------------------------------------------*/ -int ARKStepSetFixedStepBounds(void *arkode_mem, realtype lb, realtype ub) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetFixedStepBounds", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access ARKodeHAdaptMem structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetFixedStepBounds", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* set allowable interval, otherwise set defaults */ - if ((lb <= 1.0) && (ub >= 1.0)) { - hadapt_mem->lbound = lb; - hadapt_mem->ubound = ub; - } else { - hadapt_mem->lbound = HFIXED_LB; - hadapt_mem->ubound = HFIXED_UB; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetAdaptivityMethod: - - Specifies the built-in time step adaptivity algorithm (and - optionally, its associated parameters) to use. All parameters - will be checked for validity when used by the solver. - ---------------------------------------------------------------*/ -int ARKStepSetAdaptivityMethod(void *arkode_mem, int imethod, - int idefault, int pq, - realtype *adapt_params) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetAdaptivityMethod", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access ARKodeHAdaptMem structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetAdaptivityMethod", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* check for allowable parameters */ - if ((imethod > 5) || (imethod < 0)) { - arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", - "ARKStepSetAdaptivityMethod", "Illegal imethod"); - return(ARK_ILL_INPUT); - } - - /* set adaptivity method */ - hadapt_mem->imethod = imethod; - - /* set flag whether to use p or q */ - step_mem->hadapt_pq = (pq != 0); - - /* set method parameters */ - if (idefault == 1) { - switch (hadapt_mem->imethod) { - case (0): - hadapt_mem->k1 = AD0_K1; - hadapt_mem->k2 = AD0_K2; - hadapt_mem->k3 = AD0_K3; break; - case (1): - hadapt_mem->k1 = AD1_K1; - hadapt_mem->k2 = AD1_K2; break; - case (2): - hadapt_mem->k1 = AD2_K1; break; - case (3): - hadapt_mem->k1 = AD3_K1; - hadapt_mem->k2 = AD3_K2; break; - case (4): - hadapt_mem->k1 = AD4_K1; - hadapt_mem->k2 = AD4_K2; break; - case (5): - hadapt_mem->k1 = AD5_K1; - hadapt_mem->k2 = AD5_K2; - hadapt_mem->k3 = AD5_K3; break; - } - } else { - hadapt_mem->k1 = adapt_params[0]; - hadapt_mem->k2 = adapt_params[1]; - hadapt_mem->k3 = adapt_params[2]; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetAdaptivityFn: - - Specifies the user-provided time step adaptivity function to use. - ---------------------------------------------------------------*/ -int ARKStepSetAdaptivityFn(void *arkode_mem, ARKAdaptFn hfun, - void *h_data) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetAdaptivityFn", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access ARKodeHAdaptMem structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetAdaptivityFn", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* NULL hfun sets default, otherwise set inputs */ - if (hfun == NULL) { - hadapt_mem->HAdapt = NULL; - hadapt_mem->HAdapt_data = NULL; - hadapt_mem->imethod = 0; - } else { - hadapt_mem->HAdapt = hfun; - hadapt_mem->HAdapt_data = h_data; - hadapt_mem->imethod = -1; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetMaxFirstGrowth: - - Specifies the user-provided time step adaptivity constant - etamx1. Legal values are greater than 1.0. Illegal values - imply a reset to the default value. - ---------------------------------------------------------------*/ -int ARKStepSetMaxFirstGrowth(void *arkode_mem, realtype etamx1) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetMaxFirstGrowth", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access ARKodeHAdaptMem structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetMaxFirstGrowth",MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* if argument legal set it, otherwise set default */ - if (etamx1 <= ONE) { - hadapt_mem->etamx1 = ETAMX1; - } else { - hadapt_mem->etamx1 = etamx1; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetMaxEFailGrowth: - - Specifies the user-provided time step adaptivity constant - etamxf. Legal values are in the interval (0,1]. Illegal values - imply a reset to the default value. - ---------------------------------------------------------------*/ -int ARKStepSetMaxEFailGrowth(void *arkode_mem, realtype etamxf) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetMaxEFailGrowth", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access ARKodeHAdaptMem structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetMaxEFailGrowth", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* if argument legal set it, otherwise set default */ - if ((etamxf <= ZERO) || (etamxf > ONE)) { - hadapt_mem->etamxf = ETAMXF; - } else { - hadapt_mem->etamxf = etamxf; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetSmallNumEFails: - - Specifies the user-provided time step adaptivity constant - small_nef. Legal values are > 0. Illegal values - imply a reset to the default value. - ---------------------------------------------------------------*/ -int ARKStepSetSmallNumEFails(void *arkode_mem, int small_nef) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetSmallNumEFails", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access ARKodeHAdaptMem structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetSmallNumEFails", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* if argument legal set it, otherwise set default */ - if (small_nef <= 0) { - hadapt_mem->small_nef = SMALL_NEF; - } else { - hadapt_mem->small_nef = small_nef; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetMaxCFailGrowth: - - Specifies the user-provided time step adaptivity constant - etacf. Legal values are in the interval (0,1]. Illegal values - imply a reset to the default value. - ---------------------------------------------------------------*/ -int ARKStepSetMaxCFailGrowth(void *arkode_mem, realtype etacf) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetMaxCFailGrowth", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access ARKodeHAdaptMem structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetMaxCFailGrowth", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* if argument legal set it, otherwise set default */ - if ((etacf <= ZERO) || (etacf > ONE)) { - hadapt_mem->etacf = ETACF; - } else { - hadapt_mem->etacf = etacf; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetNonlinCRDown: - - Specifies the user-provided nonlinear convergence constant - crdown. Legal values are strictly positive; illegal values - imply a reset to the default. - ---------------------------------------------------------------*/ -int ARKStepSetNonlinCRDown(void *arkode_mem, realtype crdown) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetNonlinCRDown", + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetNonlinCRDown", &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); @@ -1960,107 +1198,16 @@ int ARKStepSetPredictorMethod(void *arkode_mem, int pred_method) &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - /* set parameters */ - step_mem->predictor = pred_method; - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetStabilityFn: - - Specifies the user-provided explicit time step stability - function to use. A NULL input function implies a reset to - the default function (empty). - ---------------------------------------------------------------*/ -int ARKStepSetStabilityFn(void *arkode_mem, ARKExpStabFn EStab, - void *estab_data) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetStabilityFn", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access ARKodeHAdaptMem structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", - "ARKStepSetStabilityFn", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* NULL argument sets default, otherwise set inputs */ - if (EStab == NULL) { - hadapt_mem->expstab = arkExpStab; - hadapt_mem->estab_data = ark_mem; - } else { - hadapt_mem->expstab = EStab; - hadapt_mem->estab_data = estab_data; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetMaxErrTestFails: - - Specifies the maximum number of error test failures during one - step try. A non-positive input implies a reset to - the default value. - ---------------------------------------------------------------*/ -int ARKStepSetMaxErrTestFails(void *arkode_mem, int maxnef) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetMaxErrTestFails", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* argument <= 0 sets default, otherwise set input */ - if (maxnef <= 0) { - step_mem->maxnef = MAXNEF; - } else { - step_mem->maxnef = maxnef; + /* return error if pred_method==5 and a non-NULL stage predictor function + has been supplied */ + if ((pred_method == 5) && (step_mem->stage_predict != NULL)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", "ARKStepSetPredictorMethod", + "predictor 5 cannot be combined with user-supplied stage predictor"); + return(ARK_ILL_INPUT); } - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepSetMaxConvFails: - - Specifies the maximum number of nonlinear convergence failures - during one step try. A non-positive input implies a reset to - the default value. - ---------------------------------------------------------------*/ -int ARKStepSetMaxConvFails(void *arkode_mem, int maxncf) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetMaxConvFails", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* argument <= 0 sets default, otherwise set input */ - if (maxncf <= 0) { - step_mem->maxncf = MAXNCF; - } else { - step_mem->maxncf = maxncf; - } + /* set parameter */ + step_mem->predictor = pred_method; return(ARK_SUCCESS); } @@ -2145,79 +1292,17 @@ int ARKStepSetNonlinConvCoef(void *arkode_mem, realtype nlscoef) ===============================================================*/ /*--------------------------------------------------------------- - ARKStepGetNumExpSteps: - - Returns the current number of stability-limited steps - ---------------------------------------------------------------*/ -int ARKStepGetNumExpSteps(void *arkode_mem, long int *nsteps) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepGetNumExpSteps", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* if step adaptivity structure not allocated, just return 0 */ - if (step_mem->hadapt_mem == NULL) { - *nsteps = 0; - } else { - *nsteps = step_mem->hadapt_mem->nst_exp; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepGetNumAccSteps: - - Returns the current number of accuracy-limited steps + ARKStepGetCurrentGamma: Returns the current value of gamma ---------------------------------------------------------------*/ -int ARKStepGetNumAccSteps(void *arkode_mem, long int *nsteps) +int ARKStepGetCurrentGamma(void *arkode_mem, realtype *gamma) { - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepGetNumAccSteps", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* if step adaptivity structure not allocated, just return 0 */ - if (step_mem->hadapt_mem == NULL) { - *nsteps = 0; - } else { - *nsteps = step_mem->hadapt_mem->nst_acc; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ARKStepGetNumStepAttempts: - - Returns the current number of steps attempted by the solver - ---------------------------------------------------------------*/ -int ARKStepGetNumStepAttempts(void *arkode_mem, long int *nsteps) -{ ARKodeMem ark_mem; ARKodeARKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepGetNumStepAttempts", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* get value from step_mem */ - *nsteps = step_mem->nst_attempts; - - return(ARK_SUCCESS); + retval = arkStep_AccessStepMem(arkode_mem, NULL, &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + *gamma = step_mem->gamma; + return(retval); } @@ -2269,29 +1354,6 @@ int ARKStepGetNumLinSolvSetups(void *arkode_mem, long int *nlinsetups) } -/*--------------------------------------------------------------- - ARKStepGetNumErrTestFails: - - Returns the current number of error test failures - ---------------------------------------------------------------*/ -int ARKStepGetNumErrTestFails(void *arkode_mem, long int *netfails) -{ - ARKodeMem ark_mem; - ARKodeARKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = arkStep_AccessStepMem(arkode_mem, "ARKStepGetNumErrTestFails", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* get value from step_mem */ - *netfails = step_mem->netf; - - return(ARK_SUCCESS); -} - - /*--------------------------------------------------------------- ARKStepGetCurrentButcherTables: @@ -2362,22 +1424,16 @@ int ARKStepGetTimestepperStats(void *arkode_mem, long int *expsteps, &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - /* if step adaptivity structure not allocated, - just set expsteps and accsteps to 0 */ - if (step_mem->hadapt_mem == NULL) { - *expsteps = 0; - *accsteps = 0; - } else { - *expsteps = step_mem->hadapt_mem->nst_exp; - *accsteps = step_mem->hadapt_mem->nst_acc; - } + /* set expsteps and accsteps from adaptivity structure */ + *expsteps = ark_mem->hadapt_mem->nst_exp; + *accsteps = ark_mem->hadapt_mem->nst_acc; - /* set remaining outputs from step_mem */ - *step_attempts = step_mem->nst_attempts; + /* set remaining outputs */ + *step_attempts = ark_mem->nst_attempts; *fe_evals = step_mem->nfe; *fi_evals = step_mem->nfi; *nlinsetups = step_mem->nsetups; - *netfails = step_mem->netf; + *netfails = ark_mem->netf; return(ARK_SUCCESS); } @@ -2434,7 +1490,7 @@ int ARKStepGetNumNonlinSolvConvFails(void *arkode_mem, long int *nncfails) if (retval != ARK_SUCCESS) return(retval); /* set output from step_mem */ - *nncfails = step_mem->ncfn; + *nncfails = ark_mem->ncfn; return(ARK_SUCCESS); } @@ -2467,7 +1523,7 @@ int ARKStepGetNonlinSolvStats(void *arkode_mem, long int *nniters, "Error retrieving nniters from SUNNonlinearSolver"); return(ARK_NLS_OP_ERR); } - *nncfails = step_mem->ncfn; + *nncfails = ark_mem->ncfn; } else { *nniters = 0; *nncfails = 0; @@ -2524,42 +1580,8 @@ int ARKStepWriteParameters(void *arkode_mem, FILE *fp) } else { fprintf(fp, " Explicit integrator\n"); } - if (step_mem->hadapt_mem != NULL) { - fprintf(fp, " Maximum step increase (first step) = %"RSYM"\n", - step_mem->hadapt_mem->etamx1); - fprintf(fp, " Step reduction factor on multiple error fails = %"RSYM"\n", - step_mem->hadapt_mem->etamxf); - fprintf(fp, " Minimum error fails before above factor is used = %i\n", - step_mem->hadapt_mem->small_nef); - fprintf(fp, " Step reduction factor on nonlinear convergence failure = %"RSYM"\n", - step_mem->hadapt_mem->etacf); - if (step_mem->explicit) - fprintf(fp, " Explicit safety factor = %"RSYM"\n", - step_mem->hadapt_mem->cfl); - if (step_mem->hadapt_mem->HAdapt == NULL) { - fprintf(fp, " Time step adaptivity method %i\n", step_mem->hadapt_mem->imethod); - fprintf(fp, " Safety factor = %"RSYM"\n", step_mem->hadapt_mem->safety); - fprintf(fp, " Bias factor = %"RSYM"\n", step_mem->hadapt_mem->bias); - fprintf(fp, " Growth factor = %"RSYM"\n", step_mem->hadapt_mem->growth); - fprintf(fp, " Step growth lower bound = %"RSYM"\n", step_mem->hadapt_mem->lbound); - fprintf(fp, " Step growth upper bound = %"RSYM"\n", step_mem->hadapt_mem->ubound); - fprintf(fp, " k1 = %"RSYM"\n", step_mem->hadapt_mem->k1); - fprintf(fp, " k2 = %"RSYM"\n", step_mem->hadapt_mem->k2); - fprintf(fp, " k3 = %"RSYM"\n", step_mem->hadapt_mem->k3); - if (step_mem->hadapt_mem->expstab == arkExpStab) { - fprintf(fp, " Default explicit stability function\n"); - } else { - fprintf(fp, " User provided explicit stability function\n"); - } - } else { - fprintf(fp, " User provided time step adaptivity function\n"); - } - } - - fprintf(fp, " Maximum number of error test failures = %i\n",step_mem->maxnef); if (step_mem->implicit) { - fprintf(fp, " Maximum number of convergence test failures = %i\n",step_mem->maxncf); fprintf(fp, " Implicit predictor method = %i\n",step_mem->predictor); fprintf(fp, " Implicit solver tolerance coefficient = %"RSYM"\n",step_mem->nlscoef); fprintf(fp, " Maximum number of nonlinear corrections = %i\n",step_mem->maxcor); diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep_nls.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep_nls.c index 5382b2d7e..51a8efaa3 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep_nls.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_arkstep_nls.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -65,9 +65,7 @@ int ARKStepSetNonlinearSolver(void *arkode_mem, SUNNonlinearSolver NLS) /* check for required nonlinear solver functions */ if ( (NLS->ops->gettype == NULL) || - (NLS->ops->initialize == NULL) || (NLS->ops->solve == NULL) || - (NLS->ops->free == NULL) || (NLS->ops->setsysfn == NULL) ) { arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "ARKStepSetNonlinearSolver", @@ -102,7 +100,8 @@ int ARKStepSetNonlinearSolver(void *arkode_mem, SUNNonlinearSolver NLS) } /* set convergence test function */ - retval = SUNNonlinSolSetConvTestFn(step_mem->NLS, arkStep_NlsConvTest); + retval = SUNNonlinSolSetConvTestFn(step_mem->NLS, arkStep_NlsConvTest, + arkode_mem); if (retval != ARK_SUCCESS) { arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", "ARKStepSetNonlinearSolver", @@ -124,7 +123,7 @@ int ARKStepSetNonlinearSolver(void *arkode_mem, SUNNonlinearSolver NLS) /*--------------------------------------------------------------- - Utility routines called by ARKStep + Utility routines called by ARKStep ---------------------------------------------------------------*/ /*--------------------------------------------------------------- @@ -133,7 +132,7 @@ int ARKStepSetNonlinearSolver(void *arkode_mem, SUNNonlinearSolver NLS) This routine attaches the linear solver 'setup' and 'solve' routines to the nonlinear solver object, and then initializes the nonlinear solver object itself. This should only be - called at the start of a simulation, after a re-init, or after + called at the start of a simulation, after a re-init, or after a re-size. ---------------------------------------------------------------*/ int arkStep_NlsInit(ARKodeMem ark_mem) @@ -205,7 +204,6 @@ int arkStep_Nls(ARKodeMem ark_mem, int nflag) { ARKodeARKStepMem step_mem; booleantype callLSetup; - N_Vector zcor0; int retval; /* access ARKodeARKStepMem structure */ @@ -216,7 +214,7 @@ int arkStep_Nls(ARKodeMem ark_mem, int nflag) } step_mem = (ARKodeARKStepMem) ark_mem->step_mem; - /* If a linear solver 'setup' is supplied, set various flags for + /* If a linear solver 'setup' is supplied, set various flags for determining whether it should be called */ if (step_mem->lsetup) { @@ -227,7 +225,7 @@ int arkStep_Nls(ARKodeMem ark_mem, int nflag) step_mem->convfail = ((nflag == FIRST_CALL) || (nflag == PREV_ERR_FAIL)) ? ARK_NO_FAILURES : ARK_FAIL_OTHER; } - + /* Decide whether to recommend call to lsetup within nonlinear solver */ callLSetup = (ark_mem->firststage) || (step_mem->msbp < 0) || (SUNRabs(step_mem->gamrat-ONE) > step_mem->dgmax); @@ -242,37 +240,26 @@ int arkStep_Nls(ARKodeMem ark_mem, int nflag) step_mem->crate = ONE; callLSetup = SUNFALSE; } - - /* call nonlinear solver based on method type: - FP methods solve for the updated solution directly, but - Newton uses predictor-corrector form */ - if (SUNNonlinSolGetType(step_mem->NLS) == SUNNONLINEARSOLVER_FIXEDPOINT) { - - /* solve the nonlinear system, place solution directly in ycur */ - retval = SUNNonlinSolSolve(step_mem->NLS, step_mem->zpred, ark_mem->ycur, ark_mem->ewt, - step_mem->nlscoef, callLSetup, ark_mem); - - } else { - - /* set a zero guess for correction */ - zcor0 = ark_mem->tempv4; - N_VConst(ZERO, zcor0); - - /* Reset the stored residual norm (for iterative linear solvers) */ - step_mem->eRNrm = RCONST(0.1) * step_mem->nlscoef; - - /* solve the nonlinear system for the actual correction */ - retval = SUNNonlinSolSolve(step_mem->NLS, zcor0, step_mem->zcor, ark_mem->ewt, - step_mem->nlscoef, callLSetup, ark_mem); - - /* apply the correction to construct ycur */ - N_VLinearSum(ONE, step_mem->zcor, ONE, step_mem->zpred, ark_mem->ycur); - - } - + + /* set a zero guess for correction */ + N_VConst(ZERO, step_mem->zcor); + + /* Reset the stored residual norm (for iterative linear solvers) */ + step_mem->eRNrm = RCONST(0.1) * step_mem->nlscoef; + + /* solve the nonlinear system for the actual correction */ + retval = SUNNonlinSolSolve(step_mem->NLS, step_mem->zpred, step_mem->zcor, ark_mem->ewt, + step_mem->nlscoef, callLSetup, ark_mem); + + /* apply the correction to construct ycur */ + N_VLinearSum(ONE, step_mem->zcor, ONE, step_mem->zpred, ark_mem->ycur); + /* on successful solve, reset the jcur flag */ if (retval == ARK_SUCCESS) step_mem->jcur = SUNFALSE; - + + /* if convergence failure, return ARKode::CONV_FAIL */ + if (retval == SUN_NLS_CONV_RECVR) return(CONV_FAIL); + return(retval); } @@ -287,8 +274,7 @@ int arkStep_Nls(ARKodeMem ark_mem, int nflag) This routine wraps the ARKode linear solver interface 'setup' routine for use by the nonlinear solver object. ---------------------------------------------------------------*/ -int arkStep_NlsLSetup(N_Vector zcor, N_Vector res, booleantype jbad, - booleantype* jcur, void* arkode_mem) +int arkStep_NlsLSetup(booleantype jbad, booleantype* jcur, void* arkode_mem) { ARKodeMem ark_mem; ARKodeARKStepMem step_mem; @@ -333,7 +319,7 @@ int arkStep_NlsLSetup(N_Vector zcor, N_Vector res, booleantype jbad, This routine wraps the ARKode linear solver interface 'solve' routine for use by the nonlinear solver object. ---------------------------------------------------------------*/ -int arkStep_NlsLSolve(N_Vector zcor, N_Vector b, void* arkode_mem) +int arkStep_NlsLSolve(N_Vector b, void* arkode_mem) { ARKodeMem ark_mem; ARKodeARKStepMem step_mem; @@ -355,7 +341,7 @@ int arkStep_NlsLSolve(N_Vector zcor, N_Vector b, void* arkode_mem) step_mem->eRNrm, nonlin_iter); if (retval < 0) return(ARK_LSOLVE_FAIL); - if (retval > 0) return(retval); + if (retval > 0) return(CONV_FAIL); return(ARK_SUCCESS); } @@ -364,10 +350,10 @@ int arkStep_NlsLSolve(N_Vector zcor, N_Vector b, void* arkode_mem) /*--------------------------------------------------------------- arkStep_NlsResidual: - This routine evaluates the nonlinear residual for the additive - Runge-Kutta method. It assumes that any data from previous - time steps/stages is contained in step_mem, and merely combines - this old data with the current implicit ODE RHS vector to + This routine evaluates the nonlinear residual for the additive + Runge-Kutta method. It assumes that any data from previous + time steps/stages is contained in step_mem, and merely combines + this old data with the current implicit ODE RHS vector to compute the nonlinear residual r. At the ith stage, we compute the residual vector: @@ -447,27 +433,26 @@ int arkStep_NlsResidual(N_Vector zcor, N_Vector r, void* arkode_mem) + Ai(i,j)*Fi(j) ) <=> z = yn + gamma*Fi(z) + data - Our fixed-point problem is z=g(z), so the FP function is just: - g(z) = yn + gamma*Fi(z) + data - <=> - g(z) = zp - zp + gamma*Fi(z) + yn + data <=> - g(z) = zp + gamma*Fi(z) + (yn - zp + data) + zc = -zp + yn + gamma*Fi(zp+zc) + data + Where zp is the predicted stage and zc is the correction to + the prediction. + + Our fixed-point problem is zc=g(zc), so the FP function is just: + g(z) = gamma*Fi(z) + (yn - zp + data) where the current nonlinear guess is z = zp + zc, and where - z is stored in the input, z, + z is stored in the ycur, zp is stored in step_mem->zpred, (yn-zp+data) is stored in step_mem->sdata, so we really just compute: Fi(z) (store in step_mem->Fi[step_mem->istage]) - g = zp + gamma*Fi(z) + step_mem->sdata + g = gamma*Fi(z) + step_mem->sdata ---------------------------------------------------------------*/ -int arkStep_NlsFPFunction(N_Vector z, N_Vector g, void* arkode_mem) +int arkStep_NlsFPFunction(N_Vector zcor, N_Vector g, void* arkode_mem) { /* temporary variables */ ARKodeMem ark_mem; ARKodeARKStepMem step_mem; - realtype c[3]; - N_Vector X[3]; int retval; /* access ARKodeARKStepMem structure */ @@ -475,23 +460,21 @@ int arkStep_NlsFPFunction(N_Vector z, N_Vector g, void* arkode_mem) &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); + /* update 'ycur' value as stored predictor + current corrector */ + N_VLinearSum(ONE, step_mem->zpred, ONE, zcor, ark_mem->ycur); + /* compute implicit RHS and save for later */ - retval = step_mem->fi(ark_mem->tcur, z, + retval = step_mem->fi(ark_mem->tcur, ark_mem->ycur, step_mem->Fi[step_mem->istage], ark_mem->user_data); step_mem->nfi++; if (retval < 0) return(ARK_RHSFUNC_FAIL); if (retval > 0) return(RHSFUNC_RECVR); - /* combine parts: g = zpred + sdata + gamma*Fi(z) */ - c[0] = ONE; - X[0] = step_mem->zpred; - c[1] = ONE; - X[1] = step_mem->sdata; - c[2] = step_mem->gamma; - X[2] = step_mem->Fi[step_mem->istage]; - retval = N_VLinearCombination(3, c, X, g); - if (retval != 0) return(ARK_VECTOROP_ERR); + /* combine parts: g = gamma*Fi(z) + sdata */ + N_VLinearSum(step_mem->gamma, step_mem->Fi[step_mem->istage], + ONE, step_mem->sdata, g); + return(ARK_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bandpre.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bandpre.c index e1e6f4074..02d2d212a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bandpre.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bandpre.c @@ -1,10 +1,10 @@ /*--------------------------------------------------------------- * Programmer(s): Daniel R. Reynolds @ SMU - * Based off of cvode_bandpre.c by Scott D. Cohen, + * Based off of cvode_bandpre.c by Scott D. Cohen, * Alan C. Hindmarsh, Radu Serban, and Aaron Collier @ LLNL *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -32,11 +32,11 @@ /* Prototypes of ARKBandPrecSetup and ARKBandPrecSolve */ -static int ARKBandPrecSetup(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, +static int ARKBandPrecSetup(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, realtype gamma, void *bp_data); -static int ARKBandPrecSolve(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, +static int ARKBandPrecSolve(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, realtype delta, int lr, void *bp_data); @@ -45,7 +45,7 @@ static int ARKBandPrecFree(ARKodeMem ark_mem); /* Prototype for difference quotient Jacobian calculation routine */ static int ARKBandPDQJac(ARKBandPrecData pdata, - realtype t, N_Vector y, N_Vector fy, + realtype t, N_Vector y, N_Vector fy, N_Vector ftemp, N_Vector ytemp); @@ -53,11 +53,11 @@ static int ARKBandPDQJac(ARKBandPrecData pdata, Initialization, Free, and Get Functions NOTE: The band linear solver assumes a serial implementation of the NVECTOR package. Therefore, ARKBandPrecInit will - first test for a compatible N_Vector internal - representation by checking that the function + first test for a compatible N_Vector internal + representation by checking that the function N_VGetArrayPointer exists. ---------------------------------------------------------------*/ -int ARKBandPrecInit(void *arkode_mem, sunindextype N, +int ARKBandPrecInit(void *arkode_mem, sunindextype N, sunindextype mu, sunindextype ml) { ARKodeMem ark_mem; @@ -65,7 +65,7 @@ int ARKBandPrecInit(void *arkode_mem, sunindextype N, ARKBandPrecData pdata; sunindextype mup, mlp, storagemu; int retval; - + /* access ARKLsMem structure */ retval = arkLs_AccessLMem(arkode_mem, "ARKBandPrecInit", &ark_mem, &arkls_mem); @@ -73,7 +73,7 @@ int ARKBandPrecInit(void *arkode_mem, sunindextype N, /* Test compatibility of NVECTOR package with the BAND preconditioner */ if(ark_mem->tempv1->ops->nvgetarraypointer == NULL) { - arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKBANDPRE", + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKBANDPRE", "ARKBandPrecInit", MSG_BP_BAD_NVECTOR); return(ARKLS_ILL_INPUT); } @@ -82,7 +82,7 @@ int ARKBandPrecInit(void *arkode_mem, sunindextype N, pdata = NULL; pdata = (ARKBandPrecData) malloc(sizeof *pdata); if (pdata == NULL) { - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", "ARKBandPrecInit", MSG_BP_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -101,7 +101,7 @@ int ARKBandPrecInit(void *arkode_mem, sunindextype N, pdata->savedJ = SUNBandMatrixStorage(N, mup, mlp, mup); if (pdata->savedJ == NULL) { free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", "ARKBandPrecInit", MSG_BP_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -113,7 +113,7 @@ int ARKBandPrecInit(void *arkode_mem, sunindextype N, if (pdata->savedP == NULL) { SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", "ARKBandPrecInit", MSG_BP_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -125,11 +125,11 @@ int ARKBandPrecInit(void *arkode_mem, sunindextype N, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", "ARKBandPrecInit", MSG_BP_MEM_FAIL); return(ARKLS_MEM_FAIL); } - + /* allocate memory for temporary N_Vectors */ pdata->tmp1 = NULL; pdata->tmp1 = N_VClone(ark_mem->tempv1); @@ -138,7 +138,7 @@ int ARKBandPrecInit(void *arkode_mem, sunindextype N, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", "ARKBandPrecInit", MSG_BP_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -150,7 +150,7 @@ int ARKBandPrecInit(void *arkode_mem, sunindextype N, SUNMatDestroy(pdata->savedJ); N_VDestroy(pdata->tmp1); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", "ARKBandPrecInit", MSG_BP_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -164,11 +164,11 @@ int ARKBandPrecInit(void *arkode_mem, sunindextype N, N_VDestroy(pdata->tmp1); N_VDestroy(pdata->tmp2); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKBANDPRE", + arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKBANDPRE", "ARKBandPrecInit", MSG_BP_SUNLS_FAIL); return(ARKLS_SUNLS_FAIL); } - + /* make sure s_P_data is free from any previous allocations */ if (arkls_mem->pfree) arkls_mem->pfree(ark_mem); @@ -180,14 +180,14 @@ int ARKBandPrecInit(void *arkode_mem, sunindextype N, arkls_mem->pfree = ARKBandPrecFree; /* Attach preconditioner solve and setup functions */ - retval = arkLSSetPreconditioner(arkode_mem, - ARKBandPrecSetup, + retval = arkLSSetPreconditioner(arkode_mem, + ARKBandPrecSetup, ARKBandPrecSolve); return(retval); } -int ARKBandPrecGetWorkSpace(void *arkode_mem, long int *lenrwBP, +int ARKBandPrecGetWorkSpace(void *arkode_mem, long int *lenrwBP, long int *leniwBP) { ARKodeMem ark_mem; @@ -204,10 +204,10 @@ int ARKBandPrecGetWorkSpace(void *arkode_mem, long int *lenrwBP, /* Return immediately if ARKBandPrecData is NULL */ if (arkls_mem->P_data == NULL) { - arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBANDPRE", + arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBANDPRE", "ARKBandPrecGetWorkSpace", MSG_BP_PMEM_NULL); return(ARKLS_PMEM_NULL); - } + } pdata = (ARKBandPrecData) arkls_mem->P_data; /* sum space requirements for all objects in pdata */ @@ -258,10 +258,10 @@ int ARKBandPrecGetNumRhsEvals(void *arkode_mem, long int *nfevalsBP) /* Return immediately if ARKBandPrecData is NULL */ if (arkls_mem->P_data == NULL) { - arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBANDPRE", + arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBANDPRE", "ARKBandPrecGetNumRhsEvals", MSG_BP_PMEM_NULL); return(ARKLS_PMEM_NULL); - } + } pdata = (ARKBandPrecData) arkls_mem->P_data; /* set output */ @@ -312,14 +312,13 @@ int ARKBandPrecGetNumRhsEvals(void *arkode_mem, long int *nfevalsBP) 0 if successful, or 1 if the band factorization failed. ---------------------------------------------------------------*/ -static int ARKBandPrecSetup(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, +static int ARKBandPrecSetup(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, realtype gamma, void *bp_data) { ARKBandPrecData pdata; ARKodeMem ark_mem; int retval; - sunindextype ier; /* Assume matrix and lpivots have already been allocated. */ pdata = (ARKBandPrecData) bp_data; @@ -332,7 +331,7 @@ static int ARKBandPrecSetup(realtype t, N_Vector y, N_Vector fy, *jcurPtr = SUNFALSE; retval = SUNMatCopy(pdata->savedJ, pdata->savedP); if (retval < 0) { - arkProcessError(ark_mem, -1, "ARKBANDPRE", + arkProcessError(ark_mem, -1, "ARKBANDPRE", "ARKBandPrecSetup", MSG_BP_SUNMAT_FAIL); return(-1); } @@ -346,7 +345,7 @@ static int ARKBandPrecSetup(realtype t, N_Vector y, N_Vector fy, *jcurPtr = SUNTRUE; retval = SUNMatZero(pdata->savedJ); if (retval < 0) { - arkProcessError(ark_mem, -1, "ARKBANDPRE", + arkProcessError(ark_mem, -1, "ARKBANDPRE", "ARKBandPrecSetup", MSG_BP_SUNMAT_FAIL); return(-1); } @@ -354,10 +353,10 @@ static int ARKBandPrecSetup(realtype t, N_Vector y, N_Vector fy, return(1); } - retval = ARKBandPDQJac(pdata, t, y, fy, + retval = ARKBandPDQJac(pdata, t, y, fy, pdata->tmp1, pdata->tmp2); if (retval < 0) { - arkProcessError(ark_mem, -1, "ARKBANDPRE", + arkProcessError(ark_mem, -1, "ARKBANDPRE", "ARKBandPrecSetup", MSG_BP_RHSFUNC_FAILED); return(-1); } @@ -367,7 +366,7 @@ static int ARKBandPrecSetup(realtype t, N_Vector y, N_Vector fy, retval = SUNMatCopy(pdata->savedJ, pdata->savedP); if (retval < 0) { - arkProcessError(ark_mem, -1, "ARKBANDPRE", + arkProcessError(ark_mem, -1, "ARKBANDPRE", "ARKBandPrecSetup", MSG_BP_SUNMAT_FAIL); return(-1); } @@ -376,18 +375,18 @@ static int ARKBandPrecSetup(realtype t, N_Vector y, N_Vector fy, } } - + /* Scale and add identity to get savedP = I - gamma*J. */ retval = SUNMatScaleAddI(-gamma, pdata->savedP); if (retval) { - arkProcessError(ark_mem, -1, "ARKBANDPRE", + arkProcessError(ark_mem, -1, "ARKBANDPRE", "ARKBandPrecSetup", MSG_BP_SUNMAT_FAIL); return(-1); } /* Do LU factorization of matrix and return error flag */ - ier = SUNLinSolSetup_Band(pdata->LS, pdata->savedP); - return(ier); + retval = SUNLinSolSetup_Band(pdata->LS, pdata->savedP); + return(retval); } @@ -407,9 +406,9 @@ static int ARKBandPrecSetup(realtype t, N_Vector y, N_Vector fy, The value returned by the ARKBandPrecSolve function is always 0, indicating success. ----------------------------------------------------------------*/ -static int ARKBandPrecSolve(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, +---------------------------------------------------------------*/ +static int ARKBandPrecSolve(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, realtype delta, int lr, void *bp_data) { @@ -429,7 +428,7 @@ static int ARKBandPrecSolve(realtype t, N_Vector y, N_Vector fy, ARKBandPrecFree: Frees data associated with the ARKBand preconditioner. ----------------------------------------------------------------*/ +---------------------------------------------------------------*/ static int ARKBandPrecFree(ARKodeMem ark_mem) { ARKLsMem arkls_mem; @@ -467,15 +466,16 @@ static int ARKBandPrecFree(ARKodeMem ark_mem) of J via the macro BAND_COL and to write a simple for loop to set each of the elements of a column in succession. ---------------------------------------------------------------*/ -static int ARKBandPDQJac(ARKBandPrecData pdata, - realtype t, N_Vector y, N_Vector fy, +static int ARKBandPDQJac(ARKBandPrecData pdata, + realtype t, N_Vector y, N_Vector fy, N_Vector ftemp, N_Vector ytemp) { ARKodeMem ark_mem; ARKRhsFn fi; - realtype fnorm, minInc, inc, inc_inv, srur; + realtype fnorm, minInc, inc, inc_inv, yj, srur, conj; sunindextype group, i, j, width, ngroups, i1, i2; - realtype *col_j, *ewt_data, *fy_data, *ftemp_data, *y_data, *ytemp_data; + realtype *col_j, *ewt_data, *fy_data, *ftemp_data; + realtype *y_data, *ytemp_data, *cns_data; int retval; ark_mem = (ARKodeMem) pdata->arkode_mem; @@ -484,13 +484,15 @@ static int ARKBandPDQJac(ARKBandPrecData pdata, fi = NULL; fi = ark_mem->step_getimplicitrhs((void*) ark_mem); if (fi == NULL) return(-1); - - /* Obtain pointers to the data for ewt, fy, ftemp, y, ytemp. */ + + /* Obtain pointers to the data for various vectors */ ewt_data = N_VGetArrayPointer(ark_mem->ewt); fy_data = N_VGetArrayPointer(fy); ftemp_data = N_VGetArrayPointer(ftemp); y_data = N_VGetArrayPointer(y); ytemp_data = N_VGetArrayPointer(ytemp); + cns_data = (ark_mem->constraintsSet) ? + N_VGetArrayPointer(ark_mem->constraints) : NULL; /* Load ytemp with y = predicted y vector. */ N_VScale(ONE, y, ytemp); @@ -499,18 +501,27 @@ static int ARKBandPDQJac(ARKBandPrecData pdata, srur = SUNRsqrt(ark_mem->uround); fnorm = N_VWrmsNorm(fy, ark_mem->rwt); minInc = (fnorm != ZERO) ? - (MIN_INC_MULT * SUNRabs(ark_mem->h) * + (MIN_INC_MULT * SUNRabs(ark_mem->h) * ark_mem->uround * pdata->N * fnorm) : ONE; /* Set bandwidth and number of column groups for band differencing. */ width = pdata->ml + pdata->mu + 1; ngroups = SUNMIN(width, pdata->N); - + for (group = 1; group <= ngroups; group++) { - + /* Increment all y_j in group. */ for(j = group-1; j < pdata->N; j += width) { inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); + yj = y_data[j]; + + /* Adjust sign(inc) again if yj has an inequality constraint. */ + if (ark_mem->constraintsSet) { + conj = cns_data[j]; + if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} + else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} + } + ytemp_data[j] += inc; } @@ -521,9 +532,18 @@ static int ARKBandPDQJac(ARKBandPrecData pdata, /* Restore ytemp, then form and load difference quotients. */ for (j = group-1; j < pdata->N; j += width) { + yj = y_data[j]; ytemp_data[j] = y_data[j]; col_j = SUNBandMatrix_Column(pdata->savedJ,j); inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); + + /* Adjust sign(inc) as before. */ + if (ark_mem->constraintsSet) { + conj = cns_data[j]; + if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} + else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} + } + inc_inv = ONE/inc; i1 = SUNMAX(0, j-pdata->mu); i2 = SUNMIN(j+pdata->ml, pdata->N-1); @@ -539,4 +559,4 @@ static int ARKBandPDQJac(ARKBandPrecData pdata, /*--------------------------------------------------------------- EOF ----------------------------------------------------------------*/ +---------------------------------------------------------------*/ diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bandpre_impl.h b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bandpre_impl.h index ff203a466..67b0fbbd6 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bandpre_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bandpre_impl.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bbdpre.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bbdpre.c index e36461727..babef90bb 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bbdpre.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bbdpre.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -13,8 +13,8 @@ *--------------------------------------------------------------- * This file contains implementations of routines for a * band-block-diagonal preconditioner, i.e. a block-diagonal - * matrix with banded blocks, for use with ARKode, the ARKLS - * linear solver interface, and the MPI-parallel implementation + * matrix with banded blocks, for use with ARKode, the ARKLS + * linear solver interface, and the MPI-parallel implementation * of NVECTOR. *--------------------------------------------------------------*/ @@ -34,11 +34,11 @@ /* Prototypes of functions ARKBBDPrecSetup and ARKBBDPrecSolve */ -static int ARKBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, +static int ARKBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, realtype gamma, void *bbd_data); -static int ARKBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, +static int ARKBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, realtype delta, int lr, void *bbd_data); @@ -46,18 +46,18 @@ static int ARKBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, static int ARKBBDPrecFree(ARKodeMem ark_mem); /* Prototype for difference quotient Jacobian calculation routine */ -static int ARKBBDDQJac(ARKBBDPrecData pdata, realtype t, - N_Vector y, N_Vector gy, +static int ARKBBDDQJac(ARKBBDPrecData pdata, realtype t, + N_Vector y, N_Vector gy, N_Vector ytemp, N_Vector gtemp); /*--------------------------------------------------------------- User-Callable Functions: initialization, reinit and free ---------------------------------------------------------------*/ -int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, +int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, sunindextype mudq, sunindextype mldq, - sunindextype mukeep, sunindextype mlkeep, - realtype dqrely, + sunindextype mukeep, sunindextype mlkeep, + realtype dqrely, ARKLocalFn gloc, ARKCommFn cfn) { ARKodeMem ark_mem; @@ -74,16 +74,16 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, /* Test compatibility of NVECTOR package with the BBD preconditioner */ if(ark_mem->tempv1->ops->nvgetarraypointer == NULL) { - arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKBBDPRE", "ARKBBDPrecInit", MSG_BBD_BAD_NVECTOR); return(ARKLS_ILL_INPUT); } /* Allocate data memory */ pdata = NULL; - pdata = (ARKBBDPrecData) malloc(sizeof *pdata); + pdata = (ARKBBDPrecData) malloc(sizeof *pdata); if (pdata == NULL) { - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -101,11 +101,11 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, /* Allocate memory for saved Jacobian */ pdata->savedJ = SUNBandMatrixStorage(Nlocal, muk, mlk, muk); - if (pdata->savedJ == NULL) { - free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + if (pdata->savedJ == NULL) { + free(pdata); pdata = NULL; + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); - return(ARKLS_MEM_FAIL); + return(ARKLS_MEM_FAIL); } /* Allocate memory for preconditioner matrix */ @@ -115,7 +115,7 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, if (pdata->savedP == NULL) { SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -127,7 +127,7 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -138,7 +138,7 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -150,7 +150,7 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -163,7 +163,7 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -177,7 +177,7 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -194,7 +194,7 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); return(ARKLS_MEM_FAIL); } @@ -211,13 +211,13 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedJ); SUNLinSolFree(pdata->LS); free(pdata); pdata = NULL; - arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKBBDPRE", "ARKBBDPrecInit", MSG_BBD_SUNLS_FAIL); return(ARKLS_SUNLS_FAIL); } - + /* Set dqrely based on input dqrely (0 implies default). */ - pdata->dqrely = (dqrely > ZERO) ? + pdata->dqrely = (dqrely > ZERO) ? dqrely : SUNRsqrt(ark_mem->uround); /* Store Nlocal to be used in ARKBBDPrecSetup */ @@ -254,7 +254,7 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, pdata->nge = 0; /* make sure P_data is free from any previous allocations */ - if (arkls_mem->pfree) + if (arkls_mem->pfree) arkls_mem->pfree(ark_mem); /* Point to the new P_data field in the LS memory */ @@ -264,8 +264,8 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, arkls_mem->pfree = ARKBBDPrecFree; /* Attach preconditioner solve and setup functions */ - retval = arkLSSetPreconditioner(arkode_mem, - ARKBBDPrecSetup, + retval = arkLSSetPreconditioner(arkode_mem, + ARKBBDPrecSetup, ARKBBDPrecSolve); return(retval); @@ -273,7 +273,7 @@ int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, /*-------------------------------------------------------------*/ -int ARKBBDPrecReInit(void *arkode_mem, sunindextype mudq, +int ARKBBDPrecReInit(void *arkode_mem, sunindextype mudq, sunindextype mldq, realtype dqrely) { ARKodeMem ark_mem; @@ -281,7 +281,7 @@ int ARKBBDPrecReInit(void *arkode_mem, sunindextype mudq, ARKBBDPrecData pdata; sunindextype Nlocal; int retval; - + /* access ARKMilsMem structure */ retval = arkLs_AccessLMem(arkode_mem, "ARKBBDPrecReInit", &ark_mem, &arkls_mem); @@ -289,10 +289,10 @@ int ARKBBDPrecReInit(void *arkode_mem, sunindextype mudq, /* Return immediately ARKBBDPrecData is NULL */ if (arkls_mem->P_data == NULL) { - arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBBDPRE", "ARKBBDPrecReInit", MSG_BBD_PMEM_NULL); return(ARKLS_PMEM_NULL); - } + } pdata = (ARKBBDPrecData) arkls_mem->P_data; /* Load half-bandwidths */ @@ -301,7 +301,7 @@ int ARKBBDPrecReInit(void *arkode_mem, sunindextype mudq, pdata->mldq = SUNMIN(Nlocal-1, SUNMAX(0,mldq)); /* Set dqrely based on input dqrely (0 implies default). */ - pdata->dqrely = (dqrely > ZERO) ? + pdata->dqrely = (dqrely > ZERO) ? dqrely : SUNRsqrt(ark_mem->uround); /* Re-initialize nge */ @@ -312,15 +312,15 @@ int ARKBBDPrecReInit(void *arkode_mem, sunindextype mudq, /*-------------------------------------------------------------*/ -int ARKBBDPrecGetWorkSpace(void *arkode_mem, - long int *lenrwBBDP, +int ARKBBDPrecGetWorkSpace(void *arkode_mem, + long int *lenrwBBDP, long int *leniwBBDP) { ARKodeMem ark_mem; ARKLsMem arkls_mem; ARKBBDPrecData pdata; int retval; - + /* access ARKMilsMem structure */ retval = arkLs_AccessLMem(arkode_mem, "ARKBBDPrecGetWorkSpace", &ark_mem, &arkls_mem); @@ -328,10 +328,10 @@ int ARKBBDPrecGetWorkSpace(void *arkode_mem, /* Return immediately ARKBBDPrecData is NULL */ if (arkls_mem->P_data == NULL) { - arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBBDPRE", "ARKBBDPrecGetWorkSpace", MSG_BBD_PMEM_NULL); return(ARKLS_PMEM_NULL); - } + } pdata = (ARKBBDPrecData) arkls_mem->P_data; /* set outputs */ @@ -343,14 +343,14 @@ int ARKBBDPrecGetWorkSpace(void *arkode_mem, /*-------------------------------------------------------------*/ -int ARKBBDPrecGetNumGfnEvals(void *arkode_mem, +int ARKBBDPrecGetNumGfnEvals(void *arkode_mem, long int *ngevalsBBDP) { ARKodeMem ark_mem; ARKLsMem arkls_mem; ARKBBDPrecData pdata; int retval; - + /* access ARKMilsMem structure */ retval = arkLs_AccessLMem(arkode_mem, "ARKBBDPrecGetNumGfnEvals", &ark_mem, &arkls_mem); @@ -358,10 +358,10 @@ int ARKBBDPrecGetNumGfnEvals(void *arkode_mem, /* Return immediately if ARKBBDPrecData is NULL */ if (arkls_mem->P_data == NULL) { - arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBBDPRE", + arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBBDPRE", "ARKBBDPrecGetNumGfnEvals", MSG_BBD_PMEM_NULL); return(ARKLS_PMEM_NULL); - } + } pdata = (ARKBBDPrecData) arkls_mem->P_data; /* set output */ @@ -379,7 +379,7 @@ int ARKBBDPrecGetNumGfnEvals(void *arkode_mem, user-supplied gloc and cfn functions. It uses difference quotient approximations to the Jacobian elements. - ARKBBDPrecSetup calculates a new J, if necessary, then + ARKBBDPrecSetup calculates a new J, if necessary, then calculates P = M - gamma*J, and does an LU factorization of P. The parameters of ARKBBDPrecSetup used here are as follows: @@ -417,11 +417,10 @@ int ARKBBDPrecGetNumGfnEvals(void *arkode_mem, 0 if successful, 1 for a recoverable error (step will be retried). ---------------------------------------------------------------*/ -static int ARKBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, +static int ARKBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, realtype gamma, void *bbd_data) { - sunindextype ier; ARKBBDPrecData pdata; ARKodeMem ark_mem; int retval; @@ -435,7 +434,7 @@ static int ARKBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, *jcurPtr = SUNFALSE; retval = SUNMatCopy(pdata->savedJ, pdata->savedP); if (retval < 0) { - arkProcessError(ark_mem, -1, "ARKBBDPRE", + arkProcessError(ark_mem, -1, "ARKBBDPRE", "ARKBBDPrecSetup", MSG_BBD_SUNMAT_FAIL); return(-1); } @@ -445,11 +444,11 @@ static int ARKBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, /* Otherwise call ARKBBDDQJac for new J value */ } else { - + *jcurPtr = SUNTRUE; retval = SUNMatZero(pdata->savedJ); if (retval < 0) { - arkProcessError(ark_mem, -1, "ARKBBDPRE", + arkProcessError(ark_mem, -1, "ARKBBDPRE", "ARKBBDPrecSetup", MSG_BBD_SUNMAT_FAIL); return(-1); } @@ -457,10 +456,10 @@ static int ARKBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, return(1); } - retval = ARKBBDDQJac(pdata, t, y, pdata->tmp1, + retval = ARKBBDDQJac(pdata, t, y, pdata->tmp1, pdata->tmp2, pdata->tmp3); if (retval < 0) { - arkProcessError(ark_mem, -1, "ARKBBDPRE", "ARKBBDPrecSetup", + arkProcessError(ark_mem, -1, "ARKBBDPRE", "ARKBBDPrecSetup", MSG_BBD_FUNC_FAILED); return(-1); } @@ -470,7 +469,7 @@ static int ARKBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, retval = SUNMatCopy(pdata->savedJ, pdata->savedP); if (retval < 0) { - arkProcessError(ark_mem, -1, "ARKBBDPRE", + arkProcessError(ark_mem, -1, "ARKBBDPRE", "ARKBBDPrecSetup", MSG_BBD_SUNMAT_FAIL); return(-1); } @@ -479,18 +478,18 @@ static int ARKBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, } } - + /* Scale and add I to get P = I - gamma*J */ retval = SUNMatScaleAddI(-gamma, pdata->savedP); if (retval) { - arkProcessError(ark_mem, -1, "ARKBBDPRE", + arkProcessError(ark_mem, -1, "ARKBBDPRE", "ARKBBDPrecSetup", MSG_BBD_SUNMAT_FAIL); return(-1); } - + /* Do LU factorization of matrix and return error flag */ - ier = SUNLinSolSetup_Band(pdata->LS, pdata->savedP); - return(ier); + retval = SUNLinSolSetup_Band(pdata->LS, pdata->savedP); + return(retval); } @@ -510,11 +509,11 @@ static int ARKBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, z is the output vector computed by ARKBBDPrecSolve. - The value returned by the ARKBBDPrecSolve function is the same + The value returned by the ARKBBDPrecSolve function is the same as the value returned from the linear solver object. ---------------------------------------------------------------*/ -static int ARKBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, +static int ARKBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, realtype delta, int lr, void *bbd_data) { @@ -526,9 +525,9 @@ static int ARKBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, /* Attach local data arrays for r and z to rlocal and zlocal */ N_VSetArrayPointer(N_VGetArrayPointer(r), pdata->rlocal); N_VSetArrayPointer(N_VGetArrayPointer(z), pdata->zlocal); - + /* Call banded solver object to do the work */ - retval = SUNLinSolSolve(pdata->LS, pdata->savedP, pdata->zlocal, + retval = SUNLinSolSolve(pdata->LS, pdata->savedP, pdata->zlocal, pdata->rlocal, ZERO); /* Detach local data arrays from rlocal and zlocal */ @@ -545,7 +544,7 @@ static int ARKBBDPrecFree(ARKodeMem ark_mem) ARKLsMem arkls_mem; void* ark_step_lmem; ARKBBDPrecData pdata; - + /* Return immediately if ARKodeMem, ARKLsMem or ARKBandPrecData are NULL */ if (ark_mem == NULL) return(0); ark_step_lmem = ark_mem->step_getlinmem((void*) ark_mem); @@ -575,23 +574,24 @@ static int ARKBBDPrecFree(ARKodeMem ark_mem) This routine generates a banded difference quotient approximation to the local block of the Jacobian of g(t,y). It assumes that a - band matrix of type SUNMatrix is stored columnwise, and that - elements within each column are contiguous. All matrix elements - are generated as difference quotients, by way of calls to the - user routine gloc. By virtue of the band structure, the number + band matrix of type SUNMatrix is stored columnwise, and that + elements within each column are contiguous. All matrix elements + are generated as difference quotients, by way of calls to the + user routine gloc. By virtue of the band structure, the number of these calls is bandwidth + 1, where bandwidth = mldq + mudq + 1. But the band matrix kept has bandwidth = mlkeep + mukeep + 1. This routine also assumes that the local elements of a vector are stored contiguously. ---------------------------------------------------------------*/ -static int ARKBBDDQJac(ARKBBDPrecData pdata, realtype t, - N_Vector y, N_Vector gy, +static int ARKBBDDQJac(ARKBBDPrecData pdata, realtype t, + N_Vector y, N_Vector gy, N_Vector ytemp, N_Vector gtemp) { ARKodeMem ark_mem; - realtype gnorm, minInc, inc, inc_inv; + realtype gnorm, minInc, inc, inc_inv, yj, conj; sunindextype group, i, j, width, ngroups, i1, i2; - realtype *y_data, *ewt_data, *gy_data, *gtemp_data, *ytemp_data, *col_j; + realtype *y_data, *ewt_data, *gy_data, *gtemp_data; + realtype *ytemp_data, *col_j, *cns_data; int retval; ark_mem = (ARKodeMem) pdata->arkode_mem; @@ -605,7 +605,7 @@ static int ARKBBDDQJac(ARKBBDPrecData pdata, realtype t, if (retval != 0) return(retval); } - retval = pdata->gloc(pdata->n_local, t, ytemp, gy, + retval = pdata->gloc(pdata->n_local, t, ytemp, gy, ark_mem->user_data); pdata->nge++; if (retval != 0) return(retval); @@ -616,10 +616,12 @@ static int ARKBBDDQJac(ARKBBDPrecData pdata, realtype t, ewt_data = N_VGetArrayPointer(ark_mem->ewt); ytemp_data = N_VGetArrayPointer(ytemp); gtemp_data = N_VGetArrayPointer(gtemp); + cns_data = (ark_mem->constraintsSet) ? + N_VGetArrayPointer(ark_mem->constraints) : NULL; /* Set minimum increment based on uround and norm of g */ gnorm = N_VWrmsNorm(gy, ark_mem->rwt); - minInc = (gnorm != ZERO) ? + minInc = (gnorm != ZERO) ? (MIN_INC_MULT * SUNRabs(ark_mem->h) * ark_mem->uround * pdata->n_local * gnorm) : ONE; @@ -627,26 +629,43 @@ static int ARKBBDDQJac(ARKBBDPrecData pdata, realtype t, width = pdata->mldq + pdata->mudq + 1; ngroups = SUNMIN(width, pdata->n_local); - /* Loop over groups */ + /* Loop over groups */ for (group=1; group <= ngroups; group++) { - + /* Increment all y_j in group */ for(j=group-1; j < pdata->n_local; j+=width) { inc = SUNMAX(pdata->dqrely*SUNRabs(y_data[j]), minInc/ewt_data[j]); + yj = y_data[j]; + + /* Adjust sign(inc) again if yj has an inequality constraint. */ + if (ark_mem->constraintsSet) { + conj = cns_data[j]; + if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} + else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} + } + ytemp_data[j] += inc; } /* Evaluate g with incremented y */ - retval = pdata->gloc(pdata->n_local, t, ytemp, gtemp, + retval = pdata->gloc(pdata->n_local, t, ytemp, gtemp, ark_mem->user_data); pdata->nge++; if (retval != 0) return(retval); /* Restore ytemp, then form and load difference quotients */ for (j=group-1; j < pdata->n_local; j+=width) { + yj = y_data[j]; ytemp_data[j] = y_data[j]; col_j = SUNBandMatrix_Column(pdata->savedJ,j); inc = SUNMAX(pdata->dqrely*SUNRabs(y_data[j]), minInc/ewt_data[j]); + + if (ark_mem->constraintsSet) { + conj = cns_data[j]; + if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} + else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} + } + inc_inv = ONE/inc; i1 = SUNMAX(0, j-pdata->mukeep); i2 = SUNMIN(j+pdata->mlkeep, pdata->n_local-1); diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bbdpre_impl.h b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bbdpre_impl.h index 8d1c36a66..49b2a3253 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bbdpre_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_bbdpre_impl.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_butcher.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_butcher.c index ccb3856ed..b2d13c781 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_butcher.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_butcher.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_butcher_dirk.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_butcher_dirk.c index 7bd1021cc..c89c61c7d 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_butcher_dirk.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_butcher_dirk.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -56,8 +56,10 @@ SDIRK_5_3_4 SDIRK Y Y Y KVAERNO_5_3_4 ESDIRK Y N N ARK436L2SA_DIRK_6_3_4* ESDIRK Y Y N + ARK437L2SA_DIRK_7_3_4* ESDIRK Y Y N KVAERNO_7_4_5 ESDIRK Y Y N ARK548L2SA_DIRK_8_4_5* ESDIRK Y Y N + ARK548L2SAb_DIRK_8_4_5* ESDIRK Y Y N ---------------------------------------------------------- ---------------------------------------------------------------*/ @@ -383,6 +385,57 @@ ARKodeButcherTable ARKodeButcherTable_LoadDIRK(int imethod) B->d[5] = RCONST(61727.0)/RCONST(225920.0); break; + case(ARK437L2SA_DIRK_7_3_4): /* ARK4(3)7L[2]SA-ESDIRK */ + B = ARKodeButcherTable_Alloc(7, SUNTRUE); + B->q = 4; + B->p = 3; + + B->A[1][0] = RCONST(1235.0)/RCONST(10000.0); + B->A[1][1] = RCONST(1235.0)/RCONST(10000.0); + B->A[2][0] = RCONST(624185399699.0)/RCONST(4186980696204.0); + B->A[2][1] = RCONST(624185399699.0)/RCONST(4186980696204.0); + B->A[2][2] = RCONST(1235.0)/RCONST(10000.0); + B->A[3][0] = RCONST(1258591069120.0)/RCONST(10082082980243.0); + B->A[3][1] = RCONST(1258591069120.0)/RCONST(10082082980243.0); + B->A[3][2] = RCONST(-322722984531.0)/RCONST(8455138723562.0); + B->A[3][3] = RCONST(1235.0)/RCONST(10000.0); + B->A[4][0] = RCONST(-436103496990.0)/RCONST(5971407786587.0); + B->A[4][1] = RCONST(-436103496990.0)/RCONST(5971407786587.0); + B->A[4][2] = RCONST(-2689175662187.0)/RCONST(11046760208243.0); + B->A[4][3] = RCONST(4431412449334.0)/RCONST(12995360898505.0); + B->A[4][4] = RCONST(1235.0)/RCONST(10000.0); + B->A[5][0] = RCONST(-2207373168298.0)/RCONST(14430576638973.0); + B->A[5][1] = RCONST(-2207373168298.0)/RCONST(14430576638973.0); + B->A[5][2] = RCONST(242511121179.0)/RCONST(3358618340039.0); + B->A[5][3] = RCONST(3145666661981.0)/RCONST(7780404714551.0); + B->A[5][4] = RCONST(5882073923981.0)/RCONST(14490790706663.0); + B->A[5][5] = RCONST(1235.0)/RCONST(10000.0); + B->A[6][2] = RCONST(9164257142617.0)/RCONST(17756377923965.0); + B->A[6][3] = RCONST(-10812980402763.0)/RCONST(74029279521829.0); + B->A[6][4] = RCONST(1335994250573.0)/RCONST(5691609445217.0); + B->A[6][5] = RCONST(2273837961795.0)/RCONST(8368240463276.0); + B->A[6][6] = RCONST(1235.0)/RCONST(10000.0); + + B->b[2] = RCONST(9164257142617.0)/RCONST(17756377923965.0); + B->b[3] = RCONST(-10812980402763.0)/RCONST(74029279521829.0); + B->b[4] = RCONST(1335994250573.0)/RCONST(5691609445217.0); + B->b[5] = RCONST(2273837961795.0)/RCONST(8368240463276.0); + B->b[6] = RCONST(1235.0)/RCONST(10000.0); + + B->c[1] = RCONST(247.0)/RCONST(1000.0); + B->c[2] = RCONST(4276536705230.0)/RCONST(10142255878289.0); + B->c[3] = RCONST(67.0)/RCONST(200.0); + B->c[4] = RCONST(3.0)/RCONST(40.0); + B->c[5] = RCONST(7.0)/RCONST(10.0); + B->c[6] = RCONST(1.0); + + B->d[2] = RCONST(4469248916618.0)/RCONST(8635866897933.0); + B->d[3] = RCONST(-621260224600.0)/RCONST(4094290005349.0); + B->d[4] = RCONST(696572312987.0)/RCONST(2942599194819.0); + B->d[5] = RCONST(1532940081127.0)/RCONST(5565293938103.0); + B->d[6] = RCONST(2441.0)/RCONST(20000.0); + break; + case(KVAERNO_7_4_5): /* Kvaerno(7,4,5)-ESDIRK */ B = ARKodeButcherTable_Alloc(7, SUNTRUE); B->q = 5; @@ -491,6 +544,67 @@ ARKodeButcherTable ARKodeButcherTable_LoadDIRK(int imethod) B->c[7] = RCONST(1.0); break; + case(ARK548L2SAb_DIRK_8_4_5): /* ARK5(4)8L[2]SAb-ESDIRK */ + B = ARKodeButcherTable_Alloc(8, SUNTRUE); + B->q = 5; + B->p = 4; + B->A[1][0] = RCONST(2.0)/RCONST(9.0); + B->A[1][1] = RCONST(2.0)/RCONST(9.0); + B->A[2][0] = RCONST(2366667076620.0)/RCONST(8822750406821.0); + B->A[2][1] = RCONST(2366667076620.0)/RCONST(8822750406821.0); + B->A[2][2] = RCONST(2.0)/RCONST(9.0); + B->A[3][0] = RCONST(-257962897183.0)/RCONST(4451812247028.0); + B->A[3][1] = RCONST(-257962897183.0)/RCONST(4451812247028.0); + B->A[3][2] = RCONST(128530224461.0)/RCONST(14379561246022.0); + B->A[3][3] = RCONST(2.0)/RCONST(9.0); + B->A[4][0] = RCONST(-486229321650.0)/RCONST(11227943450093.0); + B->A[4][1] = RCONST(-486229321650.0)/RCONST(11227943450093.0); + B->A[4][2] = RCONST(-225633144460.0)/RCONST(6633558740617.0); + B->A[4][3] = RCONST(1741320951451.0)/RCONST(6824444397158.0); + B->A[4][4] = RCONST(2.0)/RCONST(9.0); + B->A[5][0] = RCONST(621307788657.0)/RCONST(4714163060173.0); + B->A[5][1] = RCONST(621307788657.0)/RCONST(4714163060173.0); + B->A[5][2] = RCONST(-125196015625.0)/RCONST(3866852212004.0); + B->A[5][3] = RCONST(940440206406.0)/RCONST(7593089888465.0); + B->A[5][4] = RCONST(961109811699.0)/RCONST(6734810228204.0); + B->A[5][5] = RCONST(2.0)/RCONST(9.0); + B->A[6][0] = RCONST(2036305566805.0)/RCONST(6583108094622.0); + B->A[6][1] = RCONST(2036305566805.0)/RCONST(6583108094622.0); + B->A[6][2] = RCONST(-3039402635899.0)/RCONST(4450598839912.0); + B->A[6][3] = RCONST(-1829510709469.0)/RCONST(31102090912115.0); + B->A[6][4] = RCONST(-286320471013.0)/RCONST(6931253422520.0); + B->A[6][5] = RCONST(8651533662697.0)/RCONST(9642993110008.0); + B->A[6][6] = RCONST(2.0)/RCONST(9.0); + B->A[7][2] = RCONST(3517720773327.0)/RCONST(20256071687669.0); + B->A[7][3] = RCONST(4569610470461.0)/RCONST(17934693873752.0); + B->A[7][4] = RCONST(2819471173109.0)/RCONST(11655438449929.0); + B->A[7][5] = RCONST(3296210113763.0)/RCONST(10722700128969.0); + B->A[7][6] = RCONST(-1142099968913.0)/RCONST(5710983926999.0); + B->A[7][7] = RCONST(2.0)/RCONST(9.0); + + B->b[2] = RCONST(3517720773327.0)/RCONST(20256071687669.0); + B->b[3] = RCONST(4569610470461.0)/RCONST(17934693873752.0); + B->b[4] = RCONST(2819471173109.0)/RCONST(11655438449929.0); + B->b[5] = RCONST(3296210113763.0)/RCONST(10722700128969.0); + B->b[6] = RCONST(-1142099968913.0)/RCONST(5710983926999.0); + B->b[7] = RCONST(2.0)/RCONST(9.0); + + B->d[2] = RCONST(520639020421.0)/RCONST(8300446712847.0); + B->d[3] = RCONST(4550235134915.0)/RCONST(17827758688493.0); + B->d[4] = RCONST(1482366381361.0)/RCONST(6201654941325.0); + B->d[5] = RCONST(5551607622171.0)/RCONST(13911031047899.0); + B->d[6] = RCONST(-5266607656330.0)/RCONST(36788968843917.0); + B->d[7] = RCONST(1074053359553.0)/RCONST(5740751784926.0); + + B->c[1] = RCONST(4.0)/RCONST(9.0); + B->c[2] = RCONST(6456083330201.0)/RCONST(8509243623797.0); + B->c[3] = RCONST(1632083962415.0)/RCONST(14158861528103.0); + B->c[4] = RCONST(6365430648612.0)/RCONST(17842476412687.0); + B->c[5] = RCONST(18.0)/RCONST(25.0); + B->c[6] = RCONST(191.0)/RCONST(200.0); + B->c[7] = RCONST(1.0); + break; + default: arkProcessError(NULL, ARK_ILL_INPUT, "ARKode", diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_butcher_erk.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_butcher_erk.c index 8642ce8cd..8fef470ba 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_butcher_erk.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_butcher_erk.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -57,11 +57,13 @@ ARK324L2SA_ERK_4_2_3* N ZONNEVELD_5_3_4 Y ARK436L2SA_ERK_6_3_4* N + ARK437L2SA_ERK_7_3_4* N SAYFY_ABURUB_6_3_4 N CASH_KARP_6_4_5 Y FEHLBERG_6_4_5 Y DORMAND_PRINCE_7_4_5 Y ARK548L2SA_ERK_8_4_5* N + ARK548L2SAb_ERK_8_4_5* N VERNER_8_5_6 Y FEHLBERG_13_7_8 Y -------------------------------- @@ -215,6 +217,52 @@ ARKodeButcherTable ARKodeButcherTable_LoadERK(int imethod) B->c[5] = RCONST(1.0); break; + case(ARK437L2SA_ERK_7_3_4): /* ARK4(3)7L[2]SA-ERK */ + B = ARKodeButcherTable_Alloc(7, SUNTRUE); + B->q = 4; + B->p = 3; + B->A[1][0] = RCONST(247.0)/RCONST(1000.0); + B->A[2][0] = RCONST(247.0)/RCONST(4000.0); + B->A[2][1] = RCONST(2694949928731.0)/RCONST(7487940209513.0); + B->A[3][0] = RCONST(464650059369.0)/RCONST(8764239774964.0); + B->A[3][1] = RCONST(878889893998.0)/RCONST(2444806327765.0); + B->A[3][2] = RCONST(-952945855348.0)/RCONST(12294611323341.0); + B->A[4][0] = RCONST(476636172619.0)/RCONST(8159180917465.0); + B->A[4][1] = RCONST(-1271469283451.0)/RCONST(7793814740893.0); + B->A[4][2] = RCONST(-859560642026.0)/RCONST(4356155882851.0); + B->A[4][3] = RCONST(1723805262919.0)/RCONST(4571918432560.0); + B->A[5][0] = RCONST(6338158500785.0)/RCONST(11769362343261.0); + B->A[5][1] = RCONST(-4970555480458.0)/RCONST(10924838743837.0); + B->A[5][2] = RCONST(3326578051521.0)/RCONST(2647936831840.0); + B->A[5][3] = RCONST(-880713585975.0)/RCONST(1841400956686.0); + B->A[5][4] = RCONST(-1428733748635.0)/RCONST(8843423958496.0); + B->A[6][0] = RCONST(760814592956.0)/RCONST(3276306540349.0); + B->A[6][1] = RCONST(760814592956.0)/RCONST(3276306540349.0); + B->A[6][2] = RCONST(-47223648122716.0)/RCONST(6934462133451.0); + B->A[6][3] = RCONST(71187472546993.0)/RCONST(9669769126921.0); + B->A[6][4] = RCONST(-13330509492149.0)/RCONST(9695768672337.0); + B->A[6][5] = RCONST(11565764226357.0)/RCONST(8513123442827.0); + + B->b[2] = RCONST(9164257142617.0)/RCONST(17756377923965.0); + B->b[3] = RCONST(-10812980402763.0)/RCONST(74029279521829.0); + B->b[4] = RCONST(1335994250573.0)/RCONST(5691609445217.0); + B->b[5] = RCONST(2273837961795.0)/RCONST(8368240463276.0); + B->b[6] = RCONST(247.0)/RCONST(2000.0); + + B->d[2] = RCONST(4469248916618.0)/RCONST(8635866897933.0); + B->d[3] = RCONST(-621260224600.0)/RCONST(4094290005349.0); + B->d[4] = RCONST(696572312987.0)/RCONST(2942599194819.0); + B->d[5] = RCONST(1532940081127.0)/RCONST(5565293938103.0); + B->d[6] = RCONST(2441.0)/RCONST(20000.0); + + B->c[1] = RCONST(247.0)/RCONST(1000.0); + B->c[2] = RCONST(4276536705230.0)/RCONST(10142255878289.0); + B->c[3] = RCONST(67.0)/RCONST(200.0); + B->c[4] = RCONST(3.0)/RCONST(40.0); + B->c[5] = RCONST(7.0)/RCONST(10.0); + B->c[6] = RCONST(1.0); + break; + case(SAYFY_ABURUB_6_3_4): /* Sayfy-Aburub-4-3-ERK */ B = ARKodeButcherTable_Alloc(6, SUNTRUE); B->q = 4; @@ -424,6 +472,62 @@ ARKodeButcherTable ARKodeButcherTable_LoadERK(int imethod) B->c[7] = RCONST(1.0); break; + case(ARK548L2SAb_ERK_8_4_5): /* ARK5(4)8L[2]SAb-ERK */ + B = ARKodeButcherTable_Alloc(8, SUNTRUE); + B->q = 5; + B->p = 4; + B->A[1][0] = RCONST(4.0)/RCONST(9.0); + B->A[2][0] = RCONST(1.0)/RCONST(9.0); + B->A[2][1] = RCONST(1183333538310.0)/RCONST(1827251437969.0); + B->A[3][0] = RCONST(895379019517.0)/RCONST(9750411845327.0); + B->A[3][1] = RCONST(477606656805.0)/RCONST(13473228687314.0); + B->A[3][2] = RCONST(-112564739183.0)/RCONST(9373365219272.0); + B->A[4][0] = RCONST(-4458043123994.0)/RCONST(13015289567637.0); + B->A[4][1] = RCONST(-2500665203865.0)/RCONST(9342069639922.0); + B->A[4][2] = RCONST(983347055801.0)/RCONST(8893519644487.0); + B->A[4][3] = RCONST(2185051477207.0)/RCONST(2551468980502.0); + B->A[5][0] = RCONST(-167316361917.0)/RCONST(17121522574472.0); + B->A[5][1] = RCONST(1605541814917.0)/RCONST(7619724128744.0); + B->A[5][2] = RCONST(991021770328.0)/RCONST(13052792161721.0); + B->A[5][3] = RCONST(2342280609577.0)/RCONST(11279663441611.0); + B->A[5][4] = RCONST(3012424348531.0)/RCONST(12792462456678.0); + B->A[6][0] = RCONST(6680998715867.0)/RCONST(14310383562358.0); + B->A[6][1] = RCONST(5029118570809.0)/RCONST(3897454228471.0); + B->A[6][2] = RCONST(2415062538259.0)/RCONST(6382199904604.0); + B->A[6][3] = RCONST(-3924368632305.0)/RCONST(6964820224454.0); + B->A[6][4] = RCONST(-4331110370267.0)/RCONST(15021686902756.0); + B->A[6][5] = RCONST(-3944303808049.0)/RCONST(11994238218192.0); + B->A[7][0] = RCONST(2193717860234.0)/RCONST(3570523412979.0); + B->A[7][1] = RCONST(2193717860234.0)/RCONST(3570523412979.0); + B->A[7][2] = RCONST(5952760925747.0)/RCONST(18750164281544.0); + B->A[7][3] = RCONST(-4412967128996.0)/RCONST(6196664114337.0); + B->A[7][4] = RCONST(4151782504231.0)/RCONST(36106512998704.0); + B->A[7][5] = RCONST(572599549169.0)/RCONST(6265429158920.0); + B->A[7][6] = RCONST(-457874356192.0)/RCONST(11306498036315.0); + + B->b[2] = RCONST(3517720773327.0)/RCONST(20256071687669.0); + B->b[3] = RCONST(4569610470461.0)/RCONST(17934693873752.0); + B->b[4] = RCONST(2819471173109.0)/RCONST(11655438449929.0); + B->b[5] = RCONST(3296210113763.0)/RCONST(10722700128969.0); + B->b[6] = RCONST(-1142099968913.0)/RCONST(5710983926999.0); + B->b[7] = RCONST(2.0)/RCONST(9.0); + + B->d[2] = RCONST(520639020421.0)/RCONST(8300446712847.0); + B->d[3] = RCONST(4550235134915.0)/RCONST(17827758688493.0); + B->d[4] = RCONST(1482366381361.0)/RCONST(6201654941325.0); + B->d[5] = RCONST(5551607622171.0)/RCONST(13911031047899.0); + B->d[6] = RCONST(-5266607656330.0)/RCONST(36788968843917.0); + B->d[7] = RCONST(1074053359553.0)/RCONST(5740751784926.0); + + B->c[1] = RCONST(4.0)/RCONST(9.0); + B->c[2] = RCONST(6456083330201.0)/RCONST(8509243623797.0); + B->c[3] = RCONST(1632083962415.0)/RCONST(14158861528103.0); + B->c[4] = RCONST(6365430648612.0)/RCONST(17842476412687.0); + B->c[5] = RCONST(18.0)/RCONST(25.0); + B->c[6] = RCONST(191.0)/RCONST(200.0); + B->c[7] = RCONST(1.0); + break; + case(VERNER_8_5_6): /* Verner-6-5 */ B = ARKodeButcherTable_Alloc(8, SUNTRUE); B->q = 6; diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_erkstep.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_erkstep.c index 06f1e8377..bd3bbb2e0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_erkstep.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_erkstep.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -21,6 +21,7 @@ #include "arkode_impl.h" #include "arkode_erkstep_impl.h" +#include "arkode_interp_impl.h" #include #if defined(SUNDIALS_EXTENDED_PRECISION) @@ -101,8 +102,7 @@ void* ERKStepCreate(ARKRhsFn f, realtype t0, N_Vector y0) /* Set default values for ERKStep optional inputs */ retval = ERKStepSetDefaults((void *) ark_mem); if (retval != ARK_SUCCESS) { - arkProcessError(ark_mem, retval, "ARKode::ERKStep", - "ERKStepCreate", + arkProcessError(ark_mem, retval, "ARKode::ERKStep", "ERKStepCreate", "Error setting default solver options"); return(NULL); } @@ -118,20 +118,8 @@ void* ERKStepCreate(ARKRhsFn f, realtype t0, N_Vector y0) ark_mem->liw += 41; /* fcn/data ptr, int, long int, sunindextype, booleantype */ ark_mem->lrw += 10; - /* Allocate step adaptivity structure, set default values, note storage */ - step_mem->hadapt_mem = arkAdaptInit(); - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ERKStep", "ERKStepCreate", - "Allocation of step adaptivity structure failed"); - return(NULL); - } - ark_mem->lrw += ARK_ADAPT_LRW; - ark_mem->liw += ARK_ADAPT_LIW; - /* Initialize all the counters */ - step_mem->nst_attempts = 0; - step_mem->nfe = 0; - step_mem->netf = 0; + step_mem->nfe = 0; /* Initialize main ARKode infrastructure */ retval = arkInit(ark_mem, t0, y0); @@ -218,6 +206,9 @@ int ERKStepReInit(void* arkode_mem, ARKRhsFn f, realtype t0, N_Vector y0) return(ARK_ILL_INPUT); } + /* Copy the input parameters into ARKode state */ + step_mem->f = f; + /* ReInitialize main ARKode infrastructure */ retval = arkReInit(arkode_mem, t0, y0); if (retval != ARK_SUCCESS) { @@ -226,24 +217,8 @@ int ERKStepReInit(void* arkode_mem, ARKRhsFn f, realtype t0, N_Vector y0) return(retval); } - /* Copy the input parameters into ARKode state */ - step_mem->f = f; - - /* Destroy/Reinitialize time step adaptivity structure (if present) */ - if (step_mem->hadapt_mem != NULL) { - free(step_mem->hadapt_mem); - step_mem->hadapt_mem = arkAdaptInit(); - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ERKStep", "ERKStepReInit", - "Allocation of Step Adaptivity Structure Failed"); - return(ARK_MEM_FAIL); - } - } - /* Initialize all the counters */ - step_mem->nst_attempts = 0; - step_mem->nfe = 0; - step_mem->netf = 0; + step_mem->nfe = 0; return(ARK_SUCCESS); } @@ -354,14 +329,6 @@ void ERKStepFree(void **arkode_mem) step_mem = (ARKodeERKStepMem) ark_mem->step_mem; - /* free the time step adaptivity module */ - if (step_mem->hadapt_mem != NULL) { - free(step_mem->hadapt_mem); - step_mem->hadapt_mem = NULL; - ark_mem->lrw -= ARK_ADAPT_LRW; - ark_mem->liw -= ARK_ADAPT_LIW; - } - /* free the Butcher table */ if (step_mem->B != NULL) { ARKodeButcherTable_Space(step_mem->B, &Bliw, &Blrw); @@ -428,23 +395,13 @@ void ERKStepPrintMem(void* arkode_mem, FILE* outfile) fprintf(outfile,"ERKStep: q = %i\n", step_mem->q); fprintf(outfile,"ERKStep: p = %i\n", step_mem->p); fprintf(outfile,"ERKStep: stages = %i\n", step_mem->stages); - fprintf(outfile,"ERKStep: maxnef = %i\n", step_mem->maxnef); /* output long integer quantities */ - fprintf(outfile,"ERKStep: nst_attempts = %li\n", step_mem->nst_attempts); fprintf(outfile,"ERKStep: nfe = %li\n", step_mem->nfe); - fprintf(outfile,"ERKStep: netf = %li\n", step_mem->netf); - - /* output boolean quantities */ - fprintf(outfile,"ERKStep: hadapt_pq = %i\n", step_mem->hadapt_pq); /* output realtype quantities */ fprintf(outfile,"ERKStep: Butcher table:\n"); ARKodeButcherTable_Write(step_mem->B, outfile); - if (step_mem->hadapt_mem != NULL) { - fprintf(outfile,"ERKStep: timestep adaptivity structure:\n"); - arkPrintAdaptMem(step_mem->hadapt_mem, outfile); - } #ifdef DEBUG_OUTPUT /* output vector quantities */ @@ -468,8 +425,8 @@ void ERKStepPrintMem(void* arkode_mem, FILE* outfile) /*--------------------------------------------------------------- erkStep_Init: - This routine is called just prior to performing internal time - steps (after all user "set" routines have been called) from + This routine is called just prior to performing internal time + steps (after all user "set" routines have been called) from within arkInitialSetup (init_type == 0) or arkPostResizeSetup (init_type == 1). @@ -487,24 +444,24 @@ int erkStep_Init(void* arkode_mem, int init_type) sunindextype Blrw, Bliw; int retval, j; - /* immediately return if init_type == 1 */ - if (init_type == 1) return(ARK_SUCCESS); - /* access ARKodeERKStepMem structure */ retval = erkStep_AccessStepMem(arkode_mem, "erkStep_Init", &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - /* destroy adaptivity structure if fixed-stepping is requested */ - if (ark_mem->fixedstep) - if (step_mem->hadapt_mem != NULL) { - free(step_mem->hadapt_mem); - step_mem->hadapt_mem = NULL; - } + /* immediately return if init_type == 1 */ + if (init_type == 1) { + ark_mem->call_fullrhs = SUNTRUE; + return(ARK_SUCCESS); + } - /* Set first step growth factor */ - if (step_mem->hadapt_mem != NULL) - step_mem->hadapt_mem->etamax = step_mem->hadapt_mem->etamx1; + /* enforce use of arkEwtSmallReal if using a fixed step size + and an internal error weight function */ + if ( ark_mem->fixedstep && !ark_mem->user_efun ) { + ark_mem->user_efun = SUNFALSE; + ark_mem->efun = arkEwtSetSmallReal; + ark_mem->e_data = ark_mem; + } /* Create Butcher table (if not already set) */ retval = erkStep_SetButcherTable(ark_mem); @@ -527,6 +484,17 @@ int erkStep_Init(void* arkode_mem, int init_type) ark_mem->liw += Bliw; ark_mem->lrw += Blrw; + /* Retrieve/store method and embedding orders now that table is finalized */ + step_mem->q = ark_mem->hadapt_mem->q = step_mem->B->q; + step_mem->p = ark_mem->hadapt_mem->p = step_mem->B->p; + + /* Ensure that if adaptivity is enabled, then method includes embedding coefficients */ + if (!ark_mem->fixedstep && (step_mem->p == 0)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", "erkStep_Init", + "Adaptive timestepping cannot be performed without embedding coefficients"); + return(ARK_ILL_INPUT); + } + /* Allocate ARK RHS vector memory, update storage requirements */ /* Allocate F[0] ... F[stages-1] if needed */ if (step_mem->F == NULL) @@ -549,6 +517,20 @@ int erkStep_Init(void* arkode_mem, int init_type) ark_mem->liw += (step_mem->stages + 1); /* pointers */ } + /* Limit interpolant degree based on method order (use negative + argument to specify update instead of overwrite) */ + if (ark_mem->interp != NULL) { + retval = arkInterpSetDegree(ark_mem, ark_mem->interp, -(step_mem->q-1)); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", "erkStep_Init", + "Unable to update interpolation polynomial degree"); + return(ARK_ILL_INPUT); + } + } + + /* Signal to shared arkode module that fullrhs is required after each step */ + ark_mem->call_fullrhs = SUNTRUE; + return(ARK_SUCCESS); } @@ -670,20 +652,33 @@ int erkStep_FullRHS(void* arkode_mem, realtype t, erkStep_TakeStep: This routine serves the primary purpose of the ERKStep module: - it performs a single successful embedded ERK step (if possible). - Multiple attempts may be taken in this process -- once a step - passes the error estimate, the routine returns successfully. - If it cannot do so, it returns with an appropriate error flag. + it performs a single ERK step (with embedding, if possible). + + The output variable dsmPtr should contain estimate of the + weighted local error if an embedding is present; otherwise it + should be 0. + + The input/output variable nflagPtr is used to gauge convergence + of any algebraic solvers within the step. As this routine + involves no algebraic solve, it is set to 0 (success). + + The return value from this routine is: + 0 => step completed successfully + >0 => step encountered recoverable failure; + reduce step and retry (if possible) + <0 => step encountered unrecoverable failure ---------------------------------------------------------------*/ -int erkStep_TakeStep(void* arkode_mem) +int erkStep_TakeStep(void* arkode_mem, realtype *dsmPtr, int *nflagPtr) { - realtype dsm; - int retval, nef, is, eflag, js, nvec; + int retval, is, js, nvec; realtype* cvals; N_Vector* Xvecs; ARKodeMem ark_mem; ARKodeERKStepMem step_mem; + /* initialize algebraic solver convergence flag to success */ + *nflagPtr = ARK_SUCCESS; + /* access ARKodeERKStepMem structure */ retval = erkStep_AccessStepMem(arkode_mem, "erkStep_TakeStep", &ark_mem, &step_mem); @@ -693,105 +688,79 @@ int erkStep_TakeStep(void* arkode_mem) cvals = step_mem->cvals; Xvecs = step_mem->Xvecs; - nef = 0; - eflag = ARK_SUCCESS; - - /* Looping point for attempts to take a step */ - for(;;) { - - /* increment attempt counter */ - step_mem->nst_attempts++; - #ifdef DEBUG_OUTPUT - printf("stage 0 RHS:\n"); - N_VPrint_Serial(step_mem->F[0]); + printf("stage 0 RHS:\n"); + N_VPrint_Serial(step_mem->F[0]); #endif - /* Loop over internal stages to the step; since the method is explicit - the first stage RHS is just the full RHS from the start of the step */ - for (is=1; isstages; is++) { + /* Loop over internal stages to the step; since the method is explicit + the first stage RHS is just the full RHS from the start of the step */ + for (is=1; isstages; is++) { - /* Set current stage time(s) */ - ark_mem->tcur = ark_mem->tn + step_mem->B->c[is]*ark_mem->h; + /* Set current stage time(s) */ + ark_mem->tcur = ark_mem->tn + step_mem->B->c[is]*ark_mem->h; #ifdef DEBUG_OUTPUT - printf("step %li, stage %i, h = %"RSYM", t_n = %"RSYM"\n", - ark_mem->nst, is, ark_mem->h, ark_mem->tcur); + printf("step %li, stage %i, h = %"RSYM", t_n = %"RSYM"\n", + ark_mem->nst, is, ark_mem->h, ark_mem->tcur); #endif - /* Solver diagnostics reporting */ - if (ark_mem->report) - fprintf(ark_mem->diagfp, "ERKStep step %li %"RSYM" %i %"RSYM"\n", - ark_mem->nst, ark_mem->h, is, ark_mem->tcur); - - /* Set ycur to current stage solution */ - nvec = 0; - for (js=0; jsh * step_mem->B->A[is][js]; - Xvecs[nvec] = step_mem->F[js]; - nvec += 1; - } - cvals[nvec] = ONE; - Xvecs[nvec] = ark_mem->yn; - nvec += 1; - - /* call fused vector operation to do the work */ - retval = N_VLinearCombination(nvec, cvals, Xvecs, ark_mem->ycur); - if (retval != 0) return(ARK_VECTOROP_ERR); + /* Solver diagnostics reporting */ + if (ark_mem->report) + fprintf(ark_mem->diagfp, "ERKStep step %li %"RSYM" %i %"RSYM"\n", + ark_mem->nst, ark_mem->h, is, ark_mem->tcur); - /* compute updated RHS */ - retval = step_mem->f(ark_mem->tcur, ark_mem->ycur, - step_mem->F[is], ark_mem->user_data); - step_mem->nfe++; - if (retval < 0) return(ARK_RHSFUNC_FAIL); - if (retval > 0) return(ARK_UNREC_RHSFUNC_ERR); + /* Set ycur to current stage solution */ + nvec = 0; + for (js=0; jsh * step_mem->B->A[is][js]; + Xvecs[nvec] = step_mem->F[js]; + nvec += 1; + } + cvals[nvec] = ONE; + Xvecs[nvec] = ark_mem->yn; + nvec += 1; -#ifdef DEBUG_OUTPUT - printf("RHS:\n"); - N_VPrint_Serial(step_mem->F[is]); -#endif + /* call fused vector operation to do the work */ + retval = N_VLinearCombination(nvec, cvals, Xvecs, ark_mem->ycur); + if (retval != 0) return(ARK_VECTOROP_ERR); - } /* loop over stages */ + /* apply user-supplied stage postprocessing function (if supplied) */ + if (ark_mem->ProcessStage != NULL) { + retval = ark_mem->ProcessStage(ark_mem->tcur, + ark_mem->ycur, + ark_mem->user_data); + if (retval != 0) return(ARK_POSTPROCESS_STAGE_FAIL); + } - /* compute time-evolved solution (in ark_ycur), error estimate (in dsm) */ - retval = erkStep_ComputeSolutions(ark_mem, &dsm); - if (retval < 0) return(retval); /* msetup failure */ + /* compute updated RHS */ + retval = step_mem->f(ark_mem->tcur, ark_mem->ycur, + step_mem->F[is], ark_mem->user_data); + step_mem->nfe++; + if (retval < 0) return(ARK_RHSFUNC_FAIL); + if (retval > 0) return(ARK_UNREC_RHSFUNC_ERR); #ifdef DEBUG_OUTPUT - printf("error estimate = %"RSYM"\n", dsm); - printf("updated solution:\n"); - N_VPrint_Serial(ark_mem->ycur); + printf("RHS:\n"); + N_VPrint_Serial(step_mem->F[is]); #endif - /* Solver diagnostics reporting */ - if (ark_mem->report) - fprintf(ark_mem->diagfp, "ERKStep etest %li %"RSYM" %"RSYM"\n", - ark_mem->nst, ark_mem->h, dsm); + } /* loop over stages */ - /* Perform time accuracy error test (if failure, updates h for next try) */ - if (!ark_mem->fixedstep) - eflag = erkStep_DoErrorTest(ark_mem, &nef, dsm); + /* compute time-evolved solution (in ark_ycur), error estimate (in dsm) */ + retval = erkStep_ComputeSolutions(ark_mem, dsmPtr); + if (retval < 0) return(retval); #ifdef DEBUG_OUTPUT - printf("error test flag = %i\n", eflag); + printf("error estimate = %"RSYM"\n", *dsmPtr); + printf("updated solution:\n"); + N_VPrint_Serial(ark_mem->ycur); #endif - /* Restart step attempt (recompute all stages) if error test fails recoverably */ - if (eflag == TRY_AGAIN) continue; - - /* Return if error test failed and recovery not possible. */ - if (eflag != ARK_SUCCESS) return(eflag); - - /* Error test passed (eflag=ARK_SUCCESS), break from loop */ - break; - - } /* loop over step attempts */ - - - /* The step has completed successfully, clean up and - consider change of step size */ - retval = erkStep_PrepareNextStep(ark_mem, dsm); - if (retval != ARK_SUCCESS) return(retval); + /* Solver diagnostics reporting */ + if (ark_mem->report) + fprintf(ark_mem->diagfp, "ERKStep etest %li %"RSYM" %"RSYM"\n", + ark_mem->nst, ark_mem->h, *dsmPtr); return(ARK_SUCCESS); } @@ -1008,7 +977,7 @@ int erkStep_CheckButcherTable(ARKodeMem ark_mem) Note: at this point in the step, the vector ark_tempv1 may be used as a temporary vector. ---------------------------------------------------------------*/ -int erkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsm) +int erkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsmPtr) { /* local data */ int retval, j, nvec; @@ -1034,7 +1003,7 @@ int erkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsm) Xvecs = step_mem->Xvecs; /* initialize output */ - *dsm = ZERO; + *dsmPtr = ZERO; /* Compute time step solution */ @@ -1069,170 +1038,9 @@ int erkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsm) if (retval != 0) return(ARK_VECTOROP_ERR); /* fill error norm */ - *dsm = N_VWrmsNorm(yerr, ark_mem->ewt); - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - erkStep_DoErrorTest - - This routine performs the local error test for the ARK method. - The weighted local error norm dsm is passed in, and - the test dsm ?<= 1 is made. - - If the test passes, arkDoErrorTest returns ARK_SUCCESS. - - If the test fails, we revert to the last successful solution - time, and: - - if maxnef error test failures have occurred or if - SUNRabs(h) = hmin, we return ARK_ERR_FAILURE. - - otherwise: update time step factor eta based on local error - estimate and reduce h. - ---------------------------------------------------------------*/ -int erkStep_DoErrorTest(ARKodeMem ark_mem, int *nefPtr, realtype dsm) -{ - realtype ehist2, hhist2; - int retval; - ARKodeHAdaptMem hadapt_mem; - ARKodeERKStepMem step_mem; - - /* access ARKodeERKStepMem structure */ - if (ark_mem->step_mem==NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "erkStep_DoErrorTest", MSG_ERKSTEP_NO_MEM); - return(ARK_MEM_NULL); - } - step_mem = (ARKodeERKStepMem) ark_mem->step_mem; - - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", "arkDoErrorTest", - MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* If est. local error norm dsm passes test, return ARK_SUCCESS */ - if (dsm <= ONE) return(ARK_SUCCESS); - - /* Test failed; increment counters */ - (*nefPtr)++; - step_mem->netf++; - - /* At |h| = hmin or maxnef failures, return ARK_ERR_FAILURE */ - if ((SUNRabs(ark_mem->h) <= ark_mem->hmin*ONEPSM) || - (*nefPtr == step_mem->maxnef)) - return(ARK_ERR_FAILURE); - - /* Set etamax=1 to prevent step size increase at end of this step */ - hadapt_mem->etamax = ONE; - - /* Temporarily update error history array for recomputation of h */ - ehist2 = hadapt_mem->ehist[2]; - hadapt_mem->ehist[2] = hadapt_mem->ehist[1]; - hadapt_mem->ehist[1] = hadapt_mem->ehist[0]; - hadapt_mem->ehist[0] = dsm*hadapt_mem->bias; - - /* Temporarily update step history array for recomputation of h */ - hhist2 = hadapt_mem->hhist[2]; - hadapt_mem->hhist[2] = hadapt_mem->hhist[1]; - hadapt_mem->hhist[1] = hadapt_mem->hhist[0]; - hadapt_mem->hhist[0] = ark_mem->h; - - /* Compute accuracy-based time step estimate (updated ark_eta) */ - retval = arkAdapt((void*) ark_mem, step_mem->hadapt_mem, ark_mem->ycur, - ark_mem->tcur, ark_mem->h, step_mem->q, step_mem->p, - step_mem->hadapt_pq, ark_mem->nst); - if (retval != ARK_SUCCESS) return(ARK_ERR_FAILURE); - - /* Revert error history array */ - hadapt_mem->ehist[0] = hadapt_mem->ehist[1]; - hadapt_mem->ehist[1] = hadapt_mem->ehist[2]; - hadapt_mem->ehist[2] = ehist2; - - /* Revert step history array */ - hadapt_mem->hhist[0] = hadapt_mem->hhist[1]; - hadapt_mem->hhist[1] = hadapt_mem->hhist[2]; - hadapt_mem->hhist[2] = hhist2; - - /* Enforce failure bounds on eta, update h, and return for retry of step */ - if (*nefPtr >= hadapt_mem->small_nef) - ark_mem->eta = SUNMIN(ark_mem->eta, hadapt_mem->etamxf); - ark_mem->h *= ark_mem->eta; - ark_mem->next_h = ark_mem->h; - return(TRY_AGAIN); -} - - -/*--------------------------------------------------------------- - erkStep_PrepareNextStep - - This routine handles ARK-specific updates following a successful - step: copying the ARK result to the current solution vector, - updating the error/step history arrays, and setting the - prospective step size, hprime, for the next step. Along with - hprime, it sets the ratio eta=hprime/h. It also updates other - state variables related to a change of step size. - ---------------------------------------------------------------*/ -int erkStep_PrepareNextStep(ARKodeMem ark_mem, realtype dsm) -{ - int retval; - ARKodeERKStepMem step_mem; - - /* access ARKodeERKStepMem structure */ - if (ark_mem->step_mem==NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "erkStep_PrepareNextStep", MSG_ERKSTEP_NO_MEM); - return(ARK_MEM_NULL); - } - step_mem = (ARKodeERKStepMem) ark_mem->step_mem; - - /* Update step size and error history arrays */ - if (step_mem->hadapt_mem != NULL) { - step_mem->hadapt_mem->ehist[2] = step_mem->hadapt_mem->ehist[1]; - step_mem->hadapt_mem->ehist[1] = step_mem->hadapt_mem->ehist[0]; - step_mem->hadapt_mem->ehist[0] = dsm*step_mem->hadapt_mem->bias; - step_mem->hadapt_mem->hhist[2] = step_mem->hadapt_mem->hhist[1]; - step_mem->hadapt_mem->hhist[1] = step_mem->hadapt_mem->hhist[0]; - step_mem->hadapt_mem->hhist[0] = ark_mem->h; - } - - /* If fixed time-stepping requested, defer - step size changes until next step */ - if (ark_mem->fixedstep){ - ark_mem->hprime = ark_mem->h; - ark_mem->eta = ONE; - return(ARK_SUCCESS); + *dsmPtr = N_VWrmsNorm(yerr, ark_mem->ewt); } - /* If etamax = 1, defer step size changes until next step, - and reset etamax */ - if (step_mem->hadapt_mem != NULL) - if (step_mem->hadapt_mem->etamax == ONE) { - ark_mem->hprime = ark_mem->h; - ark_mem->eta = ONE; - step_mem->hadapt_mem->etamax = step_mem->hadapt_mem->growth; - return(ARK_SUCCESS); - } - - /* Adjust ark_eta in arkAdapt */ - if (step_mem->hadapt_mem != NULL) { - retval = arkAdapt((void*) ark_mem, step_mem->hadapt_mem, - ark_mem->ycur, ark_mem->tn + ark_mem->h, - ark_mem->h, step_mem->q, step_mem->p, - step_mem->hadapt_pq, ark_mem->nst+1); - if (retval != ARK_SUCCESS) return(ARK_ERR_FAILURE); - } - - /* Set hprime value for next step size */ - ark_mem->hprime = ark_mem->h * ark_mem->eta; - - /* Reset growth factor for subsequent time step */ - if (step_mem->hadapt_mem != NULL) - step_mem->hadapt_mem->etamax = step_mem->hadapt_mem->growth; - return(ARK_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_erkstep_impl.h b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_erkstep_impl.h index 017ef4169..502276d0f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_erkstep_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_erkstep_impl.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -55,15 +55,8 @@ typedef struct ARKodeERKStepMemRec { int stages; /* number of stages */ ARKodeButcherTable B; /* ERK Butcher table */ - /* Time step adaptivity data */ - ARKodeHAdaptMem hadapt_mem; /* time step adaptivity structure */ - booleantype hadapt_pq; /* choice of using p (0) vs q (1) */ - int maxnef; /* max error test fails in one step */ - /* Counters */ - long int nst_attempts; /* num attempted steps */ - long int nfe; /* num fe calls */ - long int netf; /* num error test failures */ + long int nfe; /* num fe calls */ /* Reusable arrays for fused vector operations */ realtype* cvals; @@ -80,7 +73,7 @@ typedef struct ARKodeERKStepMemRec { int erkStep_Init(void* arkode_mem, int init_type); int erkStep_FullRHS(void* arkode_mem, realtype t, N_Vector y, N_Vector f, int mode); -int erkStep_TakeStep(void* arkode_mem); +int erkStep_TakeStep(void* arkode_mem, realtype *dsmPtr, int *nflagPtr); /* Internal utility routines */ int erkStep_AccessStepMem(void* arkode_mem, const char *fname, @@ -88,11 +81,7 @@ int erkStep_AccessStepMem(void* arkode_mem, const char *fname, booleantype erkStep_CheckNVector(N_Vector tmpl); int erkStep_SetButcherTable(ARKodeMem ark_mem); int erkStep_CheckButcherTable(ARKodeMem ark_mem); - int erkStep_ComputeSolutions(ARKodeMem ark_mem, realtype *dsm); -int erkStep_DoErrorTest(ARKodeMem ark_mem, int *nefPtr, - realtype dsm); -int erkStep_PrepareNextStep(ARKodeMem ark_mem, realtype dsm); /*=============================================================== Reusable ERKStep Error Messages diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_erkstep_io.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_erkstep_io.c index 750beadb5..ee1a3588a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_erkstep_io.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_erkstep_io.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -35,1176 +35,300 @@ /*=============================================================== ERKStep Optional input functions (wrappers for generic ARKode - utility routines) + utility routines). All are documented in arkode_io.c. ===============================================================*/ +int ERKStepSetDenseOrder(void *arkode_mem, int dord) { + return(ERKStepSetInterpolantDegree(arkode_mem, dord)); } +int ERKStepSetInterpolantDegree(void *arkode_mem, int degree) { + if (degree < 0) degree = ARK_INTERP_MAX_DEGREE; + return(arkSetInterpolantDegree(arkode_mem, degree)); } +int ERKStepSetInterpolantType(void *arkode_mem, int itype) { + return(arkSetInterpolantType(arkode_mem, itype)); } +int ERKStepSetErrHandlerFn(void *arkode_mem, ARKErrHandlerFn ehfun, + void *eh_data) { + return(arkSetErrHandlerFn(arkode_mem, ehfun, eh_data)); } +int ERKStepSetErrFile(void *arkode_mem, FILE *errfp) { + return(arkSetErrFile(arkode_mem, errfp)); } +int ERKStepSetUserData(void *arkode_mem, void *user_data) { + return(arkSetUserData(arkode_mem, user_data)); } +int ERKStepSetDiagnostics(void *arkode_mem, FILE *diagfp) { + return(arkSetDiagnostics(arkode_mem, diagfp)); } +int ERKStepSetMaxNumSteps(void *arkode_mem, long int mxsteps) { + return(arkSetMaxNumSteps(arkode_mem, mxsteps)); } +int ERKStepSetMaxHnilWarns(void *arkode_mem, int mxhnil) { + return(arkSetMaxHnilWarns(arkode_mem, mxhnil)); } +int ERKStepSetInitStep(void *arkode_mem, realtype hin) { + return(arkSetInitStep(arkode_mem, hin)); } +int ERKStepSetMinStep(void *arkode_mem, realtype hmin) { + return(arkSetMinStep(arkode_mem, hmin)); } +int ERKStepSetMaxStep(void *arkode_mem, realtype hmax) { + return(arkSetMaxStep(arkode_mem, hmax)); } +int ERKStepSetStopTime(void *arkode_mem, realtype tstop) { + return(arkSetStopTime(arkode_mem, tstop)); } +int ERKStepSetRootDirection(void *arkode_mem, int *rootdir) { + return(arkSetRootDirection(arkode_mem, rootdir)); } +int ERKStepSetNoInactiveRootWarn(void *arkode_mem) { + return(arkSetNoInactiveRootWarn(arkode_mem)); } +int ERKStepSetConstraints(void *arkode_mem, N_Vector constraints) { + return(arkSetConstraints(arkode_mem, constraints)); } +int ERKStepSetMaxNumConstrFails(void *arkode_mem, int maxfails) { + return(arkSetMaxNumConstrFails(arkode_mem, maxfails)); } +int ERKStepSetPostprocessStepFn(void *arkode_mem, + ARKPostProcessFn ProcessStep) { + return(arkSetPostprocessStepFn(arkode_mem, ProcessStep)); } +int ERKStepSetPostprocessStageFn(void *arkode_mem, + ARKPostProcessFn ProcessStage) { + return(arkSetPostprocessStageFn(arkode_mem, ProcessStage)); } +int ERKStepSetCFLFraction(void *arkode_mem, realtype cfl_frac) { + return(arkSetCFLFraction(arkode_mem, cfl_frac)); } +int ERKStepSetSafetyFactor(void *arkode_mem, realtype safety) { + return(arkSetSafetyFactor(arkode_mem, safety)); } +int ERKStepSetErrorBias(void *arkode_mem, realtype bias) { + return(arkSetErrorBias(arkode_mem, bias)); } +int ERKStepSetMaxGrowth(void *arkode_mem, realtype mx_growth) { + return(arkSetMaxGrowth(arkode_mem, mx_growth)); } +int ERKStepSetMinReduction(void *arkode_mem, realtype eta_min) { + return(arkSetMinReduction(arkode_mem, eta_min)); } +int ERKStepSetFixedStepBounds(void *arkode_mem, realtype lb, realtype ub) { + return(arkSetFixedStepBounds(arkode_mem, lb, ub)); } +int ERKStepSetAdaptivityMethod(void *arkode_mem, int imethod, int idefault, + int pq, realtype adapt_params[3]) { + return(arkSetAdaptivityMethod(arkode_mem, imethod, idefault, pq, adapt_params)); } +int ERKStepSetAdaptivityFn(void *arkode_mem, ARKAdaptFn hfun, void *h_data) { + return(arkSetAdaptivityFn(arkode_mem, hfun, h_data)); } +int ERKStepSetMaxFirstGrowth(void *arkode_mem, realtype etamx1) { + return(arkSetMaxFirstGrowth(arkode_mem, etamx1)); } +int ERKStepSetMaxEFailGrowth(void *arkode_mem, realtype etamxf) { + return(arkSetMaxEFailGrowth(arkode_mem, etamxf)); } +int ERKStepSetSmallNumEFails(void *arkode_mem, int small_nef) { + return(arkSetSmallNumEFails(arkode_mem, small_nef)); } +int ERKStepSetStabilityFn(void *arkode_mem, ARKExpStabFn EStab, void *estab_data) { + return(arkSetStabilityFn(arkode_mem, EStab, estab_data)); } +int ERKStepSetMaxErrTestFails(void *arkode_mem, int maxnef) { + return(arkSetMaxErrTestFails(arkode_mem, maxnef)); } +int ERKStepSetFixedStep(void *arkode_mem, realtype hfixed) { + return(arkSetFixedStep(arkode_mem, hfixed)); } -/*--------------------------------------------------------------- - ERKStepSetDenseOrder: Specifies the polynomial order for dense - output. Positive values are sent to the interpolation module; - negative values imply to use the default. - ---------------------------------------------------------------*/ -int ERKStepSetDenseOrder(void *arkode_mem, int dord) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetDenseOrder", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetDenseOrder(ark_mem, dord)); -} - -/*--------------------------------------------------------------- - ERKStepSetErrHandlerFn: Specifies the error handler function - ---------------------------------------------------------------*/ -int ERKStepSetErrHandlerFn(void *arkode_mem, ARKErrHandlerFn ehfun, - void *eh_data) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetErrHandlerFn", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetErrHandlerFn(ark_mem, ehfun, eh_data)); -} - -/*--------------------------------------------------------------- - ERKStepSetErrFile: Specifies the FILE pointer for output (NULL - means no messages) - ---------------------------------------------------------------*/ -int ERKStepSetErrFile(void *arkode_mem, FILE *errfp) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetErrFile", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetErrFile(ark_mem, errfp)); -} - -/*--------------------------------------------------------------- - ERKStepSetUserData: Specifies the user data pointer for f - ---------------------------------------------------------------*/ -int ERKStepSetUserData(void *arkode_mem, void *user_data) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetUserData", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetUserData(ark_mem, user_data)); -} - -/*--------------------------------------------------------------- - ERKStepSetDiagnostics: Specifies to enable solver diagnostics, - and specifies the FILE pointer for output (diagfp==NULL - disables output) ----------------------------------------------------------------*/ -int ERKStepSetDiagnostics(void *arkode_mem, FILE *diagfp) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetDiagnostics", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetDiagnostics(ark_mem, diagfp)); -} - -/*--------------------------------------------------------------- - ERKStepSetMaxNumSteps: Specifies the maximum number of - integration steps - ---------------------------------------------------------------*/ -int ERKStepSetMaxNumSteps(void *arkode_mem, long int mxsteps) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetMaxNumSteps", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetMaxNumSteps(ark_mem, mxsteps)); -} - -/*--------------------------------------------------------------- - ERKStepSetMaxHnilWarns: Specifies the maximum number of warnings - for small h ----------------------------------------------------------------*/ -int ERKStepSetMaxHnilWarns(void *arkode_mem, int mxhnil) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetMaxHnilWarns", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetMaxHnilWarns(ark_mem, mxhnil)); -} - -/*--------------------------------------------------------------- - ERKStepSetInitStep: Specifies the initial step size - ---------------------------------------------------------------*/ -int ERKStepSetInitStep(void *arkode_mem, realtype hin) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetInitStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetInitStep(ark_mem, hin)); -} - -/*--------------------------------------------------------------- - ERKStepSetMinStep: Specifies the minimum step size - ---------------------------------------------------------------*/ -int ERKStepSetMinStep(void *arkode_mem, realtype hmin) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetMinStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetMinStep(ark_mem, hmin)); -} - -/*--------------------------------------------------------------- - ERKStepSetMaxStep: Specifies the maximum step size - ---------------------------------------------------------------*/ -int ERKStepSetMaxStep(void *arkode_mem, realtype hmax) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetMaxStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetMaxStep(ark_mem, hmax)); -} - -/*--------------------------------------------------------------- - ERKStepSetStopTime: Specifies the time beyond which the - integration is not to proceed. - ---------------------------------------------------------------*/ -int ERKStepSetStopTime(void *arkode_mem, realtype tstop) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetStopTime", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetStopTime(ark_mem, tstop)); -} - -/*--------------------------------------------------------------- - ERKStepSetFixedStep: Specifies to use a fixed time step size - instead of performing any form of temporal adaptivity. ERKStep - will use this step size for all steps (unless tstop is set, in - which case it may need to modify that last step approaching - tstop. If any solver failure occurs in the timestepping - module, ERKStep will typically immediately return with an error - message indicating that the selected step size cannot be used. - - Any nonzero argument will result in the use of that fixed step - size; an argument of 0 will re-enable temporal adaptivity. - ---------------------------------------------------------------*/ -int ERKStepSetFixedStep(void *arkode_mem, realtype hfixed) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - int retval; - - /* access ARKodeERKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetFixedStep", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* allocate or free adaptivity memory as needed */ - if (hfixed != ZERO) { - if (step_mem->hadapt_mem != NULL) { - free(step_mem->hadapt_mem); - step_mem->hadapt_mem = NULL; - } - } else if (step_mem->hadapt_mem == NULL) { - step_mem->hadapt_mem = arkAdaptInit(); - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ERKStep", - "ERKStepSetFixedStep", - "Allocation of Step Adaptivity Structure Failed"); - return(ARK_MEM_FAIL); - } - } - - return(arkSetFixedStep(ark_mem, hfixed)); -} - -/*--------------------------------------------------------------- - ERKStepSetRootDirection: Specifies the direction of zero-crossings - to be monitored. The default is to monitor both crossings. - ---------------------------------------------------------------*/ -int ERKStepSetRootDirection(void *arkode_mem, int *rootdir) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetRootDirection", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetRootDirection(ark_mem, rootdir)); -} - -/*--------------------------------------------------------------- - ERKStepSetNoInactiveRootWarn: Disables issuing a warning if - some root function appears to be identically zero at the - beginning of the integration - ---------------------------------------------------------------*/ -int ERKStepSetNoInactiveRootWarn(void *arkode_mem) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetNoInactiveRootWarn", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetNoInactiveRootWarn(ark_mem)); -} - -/*--------------------------------------------------------------- - ERKStepSetPostprocessStepFn: Specifies a user-provided step - postprocessing function having type ARKPostProcessStepFn. A - NULL input function disables step postprocessing. - - IF THE SUPPLIED FUNCTION MODIFIES ANY OF THE ACTIVE STATE DATA, - THEN ALL THEORETICAL GUARANTEES OF SOLUTION ACCURACY AND - STABILITY ARE LOST. - ---------------------------------------------------------------*/ -int ERKStepSetPostprocessStepFn(void *arkode_mem, - ARKPostProcessStepFn ProcessStep) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetPostprocessStepFn", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetPostprocessStepFn(ark_mem, ProcessStep)); -} - - - -/*=============================================================== - ERKStep Optional output functions (wrappers for generic ARKode - utility routines) - ===============================================================*/ - -/*--------------------------------------------------------------- - ERKStepGetNumSteps: Returns the current number of integration - steps - ---------------------------------------------------------------*/ -int ERKStepGetNumSteps(void *arkode_mem, long int *nsteps) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepGetNumSteps", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetNumSteps(ark_mem, nsteps)); -} - -/*--------------------------------------------------------------- - ERKStepGetActualInitStep: Returns the step size used on the - first step - ---------------------------------------------------------------*/ -int ERKStepGetActualInitStep(void *arkode_mem, realtype *hinused) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepGetActualInitStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetActualInitStep(ark_mem, hinused)); -} - -/*--------------------------------------------------------------- - ERKStepGetLastStep: Returns the step size used on the last - successful step - ---------------------------------------------------------------*/ -int ERKStepGetLastStep(void *arkode_mem, realtype *hlast) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepGetLastStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetLastStep(ark_mem, hlast)); -} - -/*--------------------------------------------------------------- - ERKStepGetCurrentStep: Returns the step size to be attempted on - the next step - ---------------------------------------------------------------*/ -int ERKStepGetCurrentStep(void *arkode_mem, realtype *hcur) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepGetCurrentStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetCurrentStep(ark_mem, hcur)); -} - -/*--------------------------------------------------------------- - ERKStepGetCurrentTime: Returns the current value of the - independent variable - ---------------------------------------------------------------*/ -int ERKStepGetCurrentTime(void *arkode_mem, realtype *tcur) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepGetCurrentTime", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetCurrentTime(ark_mem, tcur)); -} - -/*--------------------------------------------------------------- - ERKStepGetTolScaleFactor: Returns a suggested factor for scaling - tolerances - ---------------------------------------------------------------*/ -int ERKStepGetTolScaleFactor(void *arkode_mem, realtype *tolsfact) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepGetTolScaleFactor", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetTolScaleFactor(ark_mem, tolsfact)); -} - -/*--------------------------------------------------------------- - ERKStepGetErrWeights: This routine returns the current error - weight vector. - ---------------------------------------------------------------*/ -int ERKStepGetErrWeights(void *arkode_mem, N_Vector eweight) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepGetErrWeights", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetErrWeights(ark_mem, eweight)); -} - -/*--------------------------------------------------------------- - ERKStepGetWorkSpace: Returns integrator work space requirements - ---------------------------------------------------------------*/ -int ERKStepGetWorkSpace(void *arkode_mem, long int *lenrw, long int *leniw) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepGetWorkSpace", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetWorkSpace(ark_mem, lenrw, leniw)); -} - -/*--------------------------------------------------------------- - ERKStepGetNumGEvals: Returns the current number of calls to g - (for rootfinding) - ---------------------------------------------------------------*/ -int ERKStepGetNumGEvals(void *arkode_mem, long int *ngevals) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepGetNumGEvals", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetNumGEvals(ark_mem, ngevals)); -} - -/*--------------------------------------------------------------- - ERKStepGetRootInfo: Returns pointer to array rootsfound showing - roots found - ---------------------------------------------------------------*/ -int ERKStepGetRootInfo(void *arkode_mem, int *rootsfound) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepGetRootInfo", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetRootInfo(ark_mem, rootsfound)); -} - -/*--------------------------------------------------------------- - ERKStepGetStepStats: Returns step statistics - ---------------------------------------------------------------*/ -int ERKStepGetStepStats(void *arkode_mem, long int *nsteps, - realtype *hinused, realtype *hlast, - realtype *hcur, realtype *tcur) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepGetStepStats", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetStepStats(ark_mem, nsteps, hinused, hlast, hcur, tcur)); -} - -/*--------------------------------------------------------------- - ERKStepGetReturnFlagName: translates from return flags IDs to - names - ---------------------------------------------------------------*/ -char *ERKStepGetReturnFlagName(long int flag) -{ return(arkGetReturnFlagName(flag)); } - - - -/*=============================================================== - ERKStep optional input functions -- stepper-specific - ===============================================================*/ - -/*--------------------------------------------------------------- - ERKStepSetDefaults: - - Resets all ERKStep optional inputs to their default values. - Does not change problem-defining function pointers or - user_data pointer. - ---------------------------------------------------------------*/ -int ERKStepSetDefaults(void* arkode_mem) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetDefaults", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* Set default ARKode infrastructure parameters */ - retval = arkSetDefaults(arkode_mem); - if (retval != ARK_SUCCESS) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetDefaults", - "Error setting ARKode infrastructure defaults"); - return(retval); - } - - /* Set default values for integrator optional inputs */ - step_mem->q = Q_DEFAULT; /* method order */ - step_mem->p = 0; /* embedding order */ - step_mem->hadapt_pq = SUNFALSE; /* use embedding order */ - if (step_mem->hadapt_mem != NULL) { - step_mem->hadapt_mem->etamx1 = ETAMX1; /* max change on first step */ - step_mem->hadapt_mem->etamxf = RCONST(0.3); /* max change on error-failed step */ - step_mem->hadapt_mem->small_nef = SMALL_NEF ; /* num error fails before ETAMXF enforced */ - step_mem->hadapt_mem->etacf = ETACF; /* max change on convergence failure */ - step_mem->hadapt_mem->HAdapt = NULL; /* step adaptivity fn */ - step_mem->hadapt_mem->HAdapt_data = NULL; /* step adaptivity data */ - step_mem->hadapt_mem->imethod = 1; /* PI controller */ - step_mem->hadapt_mem->cfl = CFLFAC; /* explicit stability factor */ - step_mem->hadapt_mem->safety = RCONST(0.99); /* step adaptivity safety factor */ - step_mem->hadapt_mem->bias = RCONST(1.2); /* step adaptivity error bias */ - step_mem->hadapt_mem->growth = RCONST(25.0); /* step adaptivity growth factor */ - step_mem->hadapt_mem->lbound = HFIXED_LB; /* step adaptivity no-change lower bound */ - step_mem->hadapt_mem->ubound = HFIXED_UB; /* step adaptivity no-change upper bound */ - step_mem->hadapt_mem->k1 = RCONST(0.8); /* step adaptivity parameter */ - step_mem->hadapt_mem->k2 = RCONST(0.31); /* step adaptivity parameter */ - step_mem->hadapt_mem->k3 = AD0_K3; /* step adaptivity parameter */ - } - step_mem->maxnef = MAXNEF; /* max error test fails */ - step_mem->stages = 0; /* no stages */ - step_mem->B = NULL; /* no Butcher table */ - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepSetOrder: - - Specifies the method order - - ** Note in documentation that this should not be called along - with ERKStepSetTable or ERKStepSetTableNum. This - routine is used to specify a desired method order using - default Butcher tables, whereas any user-supplied table will - have their own order associated with them. - ---------------------------------------------------------------*/ -int ERKStepSetOrder(void *arkode_mem, int ord) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetOrder", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* set user-provided value, or default, depending on argument */ - if (ord <= 0) { - step_mem->q = Q_DEFAULT; - } else { - step_mem->q = ord; - } - - /* clear Butcher tables, since user is requesting a change in method - or a reset to defaults. Tables will be set in ARKInitialSetup. */ - step_mem->stages = 0; - step_mem->p = 0; - ARKodeButcherTable_Free(step_mem->B); step_mem->B = NULL; - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepSetTable: - - Specifies to use a customized Butcher table for the explicit - portion of the system. - - If d==NULL, then the method is automatically flagged as a - fixed-step method; a user MUST also call either - ERKStepSetFixedStep or ERKStepSetInitStep to set the desired - time step size. - ---------------------------------------------------------------*/ -int ERKStepSetTable(void *arkode_mem, ARKodeButcherTable B) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetTable", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* check for legal inputs */ - if (B == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetTable", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - - /* clear any existing parameters and Butcher tables */ - step_mem->stages = 0; - step_mem->q = 0; - step_mem->p = 0; - ARKodeButcherTable_Free(step_mem->B); step_mem->B = NULL; - - /* set the relevant parameters */ - step_mem->stages = B->stages; - step_mem->q = B->q; - step_mem->p = B->p; - - /* copy the table into step memory */ - step_mem->B = ARKodeButcherTable_Copy(B); - if (step_mem->B == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetTable", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepSetTableNum: - - Specifies to use a pre-existing Butcher table for the problem, - based on the integer flag passed to ARKodeButcherTable_LoadERK() - within the file arkode_butcher_erk.c. - ---------------------------------------------------------------*/ -int ERKStepSetTableNum(void *arkode_mem, int itable) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetTableNum", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* check that argument specifies an explicit table */ - if (itableMAX_ERK_NUM) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetTableNum", - "Illegal ERK table number"); - return(ARK_ILL_INPUT); - } - - /* clear any existing parameters and Butcher tables */ - step_mem->stages = 0; - step_mem->q = 0; - step_mem->p = 0; - ARKodeButcherTable_Free(step_mem->B); step_mem->B = NULL; - - /* fill in table based on argument */ - step_mem->B = ARKodeButcherTable_LoadERK(itable); - if (step_mem->B == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetTableNum", - "Error setting table with that index"); - return(ARK_ILL_INPUT); - } - step_mem->stages = step_mem->B->stages; - step_mem->q = step_mem->B->q; - step_mem->p = step_mem->B->p; - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepSetCFLFraction: - - Specifies the safety factor to use on the maximum explicitly- - stable step size. Allowable values must be within the open - interval (0,1). A non-positive input implies a reset to - the default value. - ---------------------------------------------------------------*/ -int ERKStepSetCFLFraction(void *arkode_mem, realtype cfl_frac) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetCFLFraction", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetCFLFraction", - MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* check for allowable parameters */ - if (cfl_frac >= 1.0) { - arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", - "ERKStepSetCFLFraction", "Illegal CFL fraction"); - return(ARK_ILL_INPUT); - } - - /* set positive-valued parameters, otherwise set default */ - if (cfl_frac <= ZERO) { - hadapt_mem->cfl = CFLFAC; - } else { - hadapt_mem->cfl = cfl_frac; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepSetSafetyFactor: - - Specifies the safety factor to use on the error-based predicted - time step size. Allowable values must be within the open - interval (0,1). A non-positive input implies a reset to the - default value. - ---------------------------------------------------------------*/ -int ERKStepSetSafetyFactor(void *arkode_mem, realtype safety) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetSafetyFactor", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetSafetyFactoy",MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* check for allowable parameters */ - if (safety >= 1.0) { - arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", - "ERKStepSetSafetyFactor", "Illegal safety factor"); - return(ARK_ILL_INPUT); - } - - /* set positive-valued parameters, otherwise set default */ - if (safety <= ZERO) { - hadapt_mem->safety = SAFETY; - } else { - hadapt_mem->safety = safety; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepSetErrorBias: - - Specifies the error bias to use when performing adaptive-step - error control. Allowable values must be >= 1.0. Any illegal - value implies a reset to the default value. - ---------------------------------------------------------------*/ -int ERKStepSetErrorBias(void *arkode_mem, realtype bias) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetErrorBias", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetErrorBias", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* set allowed value, otherwise set default */ - if (bias < 1.0) { - hadapt_mem->bias = BIAS; - } else { - hadapt_mem->bias = bias; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepSetMaxGrowth: - - Specifies the maximum step size growth factor to be allowed - between successive integration steps. Note: the first step uses - a separate maximum growth factor. Allowable values must be - > 1.0. Any illegal value implies a reset to the default. - ---------------------------------------------------------------*/ -int ERKStepSetMaxGrowth(void *arkode_mem, realtype mx_growth) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetMaxGrowth", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetMaxGrowth", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* set allowed value, otherwise set default */ - if (mx_growth == ZERO) { - hadapt_mem->growth = GROWTH; - } else { - hadapt_mem->growth = mx_growth; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepSetFixedStepBounds: - - Specifies the step size growth interval within which the step - size will remain unchanged. Allowable values must enclose the - value 1.0. Any illegal interval implies a reset to the default. - ---------------------------------------------------------------*/ -int ERKStepSetFixedStepBounds(void *arkode_mem, realtype lb, realtype ub) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetFixedStepBounds", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - /* access structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetFixedStepBounds", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; +/*=============================================================== + ERKStep Optional output functions (wrappers for generic ARKode + utility routines). All are documented in arkode_io.c. + ===============================================================*/ - /* set allowable interval, otherwise set defaults */ - if ((lb <= 1.0) && (ub >= 1.0)) { - hadapt_mem->lbound = lb; - hadapt_mem->ubound = ub; - } else { - hadapt_mem->lbound = HFIXED_LB; - hadapt_mem->ubound = HFIXED_UB; - } +int ERKStepGetNumStepAttempts(void *arkode_mem, long int *nstep_attempts) { + return(arkGetNumStepAttempts(arkode_mem, nstep_attempts)); } +int ERKStepGetNumSteps(void *arkode_mem, long int *nsteps) { + return(arkGetNumSteps(arkode_mem, nsteps)); } +int ERKStepGetActualInitStep(void *arkode_mem, realtype *hinused) { + return(arkGetActualInitStep(arkode_mem, hinused)); } +int ERKStepGetLastStep(void *arkode_mem, realtype *hlast) { + return(arkGetLastStep(arkode_mem, hlast)); } +int ERKStepGetCurrentStep(void *arkode_mem, realtype *hcur) { + return(arkGetCurrentStep(arkode_mem, hcur)); } +int ERKStepGetCurrentTime(void *arkode_mem, realtype *tcur) { + return(arkGetCurrentTime(arkode_mem, tcur)); } +int ERKStepGetTolScaleFactor(void *arkode_mem, realtype *tolsfact) { + return(arkGetTolScaleFactor(arkode_mem, tolsfact)); } +int ERKStepGetErrWeights(void *arkode_mem, N_Vector eweight) { + return(arkGetErrWeights(arkode_mem, eweight)); } +int ERKStepGetWorkSpace(void *arkode_mem, long int *lenrw, long int *leniw) { + return(arkGetWorkSpace(arkode_mem, lenrw, leniw)); } +int ERKStepGetNumGEvals(void *arkode_mem, long int *ngevals) { + return(arkGetNumGEvals(arkode_mem, ngevals)); } +int ERKStepGetRootInfo(void *arkode_mem, int *rootsfound) { + return(arkGetRootInfo(arkode_mem, rootsfound)); } +int ERKStepGetStepStats(void *arkode_mem, long int *nsteps, + realtype *hinused, realtype *hlast, + realtype *hcur, realtype *tcur) { + return(arkGetStepStats(arkode_mem, nsteps, hinused, hlast, hcur, tcur)); } +int ERKStepGetNumConstrFails(void *arkode_mem, long int *nconstrfails) { + return(arkGetNumConstrFails(arkode_mem, nconstrfails)); } +int ERKStepGetNumExpSteps(void *arkode_mem, long int *nsteps) { + return(arkGetNumExpSteps(arkode_mem, nsteps)); } +int ERKStepGetNumAccSteps(void *arkode_mem, long int *nsteps) { + return(arkGetNumAccSteps(arkode_mem, nsteps)); } +int ERKStepGetNumErrTestFails(void *arkode_mem, long int *netfails) { + return(arkGetNumErrTestFails(arkode_mem, netfails)); } +char *ERKStepGetReturnFlagName(long int flag) { + return(arkGetReturnFlagName(flag)); } - return(ARK_SUCCESS); -} +/*=============================================================== + ERKStep optional input functions -- stepper-specific + ===============================================================*/ /*--------------------------------------------------------------- - ERKStepSetAdaptivityMethod: + ERKStepSetDefaults: - Specifies the built-in time step adaptivity algorithm (and - optionally, its associated parameters) to use. All parameters - will be checked for validity when used by the solver. + Resets all ERKStep optional inputs to their default values. + Does not change problem-defining function pointers or + user_data pointer. ---------------------------------------------------------------*/ -int ERKStepSetAdaptivityMethod(void *arkode_mem, int imethod, - int idefault, int pq, - realtype *adapt_params) +int ERKStepSetDefaults(void* arkode_mem) { ARKodeMem ark_mem; ARKodeERKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; int retval; /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetAdaptivityMethod", + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetDefaults", &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - /* access structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetAdaptivityMethod", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* check for allowable parameters */ - if ((imethod > 5) || (imethod < 0)) { - arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", - "ERKStepSetAdaptivityMethod", "Illegal imethod"); - return(ARK_ILL_INPUT); - } - - /* set adaptivity method */ - hadapt_mem->imethod = imethod; - - /* set flag whether to use p or q */ - step_mem->hadapt_pq = (pq != 0); - - /* set method parameters */ - if (idefault == 1) { - switch (hadapt_mem->imethod) { - case (0): - hadapt_mem->k1 = AD0_K1; - hadapt_mem->k2 = AD0_K2; - hadapt_mem->k3 = AD0_K3; break; - case (1): - hadapt_mem->k1 = AD1_K1; - hadapt_mem->k2 = AD1_K2; break; - case (2): - hadapt_mem->k1 = AD2_K1; break; - case (3): - hadapt_mem->k1 = AD3_K1; - hadapt_mem->k2 = AD3_K2; break; - case (4): - hadapt_mem->k1 = AD4_K1; - hadapt_mem->k2 = AD4_K2; break; - case (5): - hadapt_mem->k1 = AD5_K1; - hadapt_mem->k2 = AD5_K2; - hadapt_mem->k3 = AD5_K3; break; - } - } else { - hadapt_mem->k1 = adapt_params[0]; - hadapt_mem->k2 = adapt_params[1]; - hadapt_mem->k3 = adapt_params[2]; + /* Set default ARKode infrastructure parameters */ + retval = arkSetDefaults(arkode_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", + "ERKStepSetDefaults", + "Error setting ARKode infrastructure defaults"); + return(retval); } + /* Set default values for integrator optional inputs + (overwrite some adaptivity params for ERKStep use) */ + step_mem->q = Q_DEFAULT; /* method order */ + step_mem->p = 0; /* embedding order */ + ark_mem->hadapt_mem->etamxf = RCONST(0.3); /* max change on error-failed step */ + ark_mem->hadapt_mem->imethod = 1; /* PI controller */ + ark_mem->hadapt_mem->safety = RCONST(0.99); /* step adaptivity safety factor */ + ark_mem->hadapt_mem->bias = RCONST(1.2); /* step adaptivity error bias */ + ark_mem->hadapt_mem->growth = RCONST(25.0); /* step adaptivity growth factor */ + ark_mem->hadapt_mem->k1 = RCONST(0.8); /* step adaptivity parameter */ + ark_mem->hadapt_mem->k2 = RCONST(0.31); /* step adaptivity parameter */ + step_mem->stages = 0; /* no stages */ + step_mem->B = NULL; /* no Butcher table */ return(ARK_SUCCESS); } /*--------------------------------------------------------------- - ERKStepSetAdaptivityFn: + ERKStepSetOrder: - Specifies the user-provided time step adaptivity function to use. + Specifies the method order ---------------------------------------------------------------*/ -int ERKStepSetAdaptivityFn(void *arkode_mem, ARKAdaptFn hfun, - void *h_data) +int ERKStepSetOrder(void *arkode_mem, int ord) { ARKodeMem ark_mem; ARKodeERKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; int retval; /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetAdaptivityFn", + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetOrder", &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - /* access structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetAdaptivityFn", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* NULL hfun sets default, otherwise set inputs */ - if (hfun == NULL) { - hadapt_mem->HAdapt = NULL; - hadapt_mem->HAdapt_data = NULL; - hadapt_mem->imethod = 0; + /* set user-provided value, or default, depending on argument */ + if (ord <= 0) { + step_mem->q = Q_DEFAULT; } else { - hadapt_mem->HAdapt = hfun; - hadapt_mem->HAdapt_data = h_data; - hadapt_mem->imethod = -1; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepSetMaxFirstGrowth: - - Specifies the user-provided time step adaptivity constant - etamx1. Legal values are greater than 1.0. Illegal values - imply a reset to the default value. - ---------------------------------------------------------------*/ -int ERKStepSetMaxFirstGrowth(void *arkode_mem, realtype etamx1) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetMaxFirstGrowth", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* access structure */ - if (step_mem->hadapt_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetMaxFirstGrowth",MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); + step_mem->q = ord; } - hadapt_mem = step_mem->hadapt_mem; - /* if argument legal set it, otherwise set default */ - if (etamx1 <= ONE) { - hadapt_mem->etamx1 = ETAMX1; - } else { - hadapt_mem->etamx1 = etamx1; - } + /* clear Butcher tables, since user is requesting a change in method + or a reset to defaults. Tables will be set in ARKInitialSetup. */ + step_mem->stages = 0; + step_mem->p = 0; + ARKodeButcherTable_Free(step_mem->B); step_mem->B = NULL; return(ARK_SUCCESS); } /*--------------------------------------------------------------- - ERKStepSetMaxEFailGrowth: + ERKStepSetTable: + + Specifies to use a customized Butcher table for the explicit + portion of the system. - Specifies the user-provided time step adaptivity constant - etamxf. Legal values are in the interval (0,1]. Illegal values - imply a reset to the default value. + If d==NULL, then the method is automatically flagged as a + fixed-step method; a user MUST also call either + ERKStepSetFixedStep or ERKStepSetInitStep to set the desired + time step size. ---------------------------------------------------------------*/ -int ERKStepSetMaxEFailGrowth(void *arkode_mem, realtype etamxf) +int ERKStepSetTable(void *arkode_mem, ARKodeButcherTable B) { ARKodeMem ark_mem; ARKodeERKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; int retval; /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetMaxEFailGrowth", + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetTable", &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - /* access structure */ - if (step_mem->hadapt_mem == NULL) { + /* check for legal inputs */ + if (B == NULL) { arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetMaxEFailGrowth", MSG_ARKADAPT_NO_MEM); + "ERKStepSetTable", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } - hadapt_mem = step_mem->hadapt_mem; - - /* if argument legal set it, otherwise set default */ - if ((etamxf <= ZERO) || (etamxf > ONE)) { - hadapt_mem->etamxf = ETAMXF; - } else { - hadapt_mem->etamxf = etamxf; - } - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepSetSmallNumEFails: - - Specifies the user-provided time step adaptivity constant - small_nef. Legal values are > 0. Illegal values - imply a reset to the default value. - ---------------------------------------------------------------*/ -int ERKStepSetSmallNumEFails(void *arkode_mem, int small_nef) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; - int retval; + /* clear any existing parameters and Butcher tables */ + step_mem->stages = 0; + step_mem->q = 0; + step_mem->p = 0; + ARKodeButcherTable_Free(step_mem->B); step_mem->B = NULL; - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetSmallNumEFails", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); + /* set the relevant parameters */ + step_mem->stages = B->stages; + step_mem->q = B->q; + step_mem->p = B->p; - /* access structure */ - if (step_mem->hadapt_mem == NULL) { + /* copy the table into step memory */ + step_mem->B = ARKodeButcherTable_Copy(B); + if (step_mem->B == NULL) { arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetSmallNumEFails", MSG_ARKADAPT_NO_MEM); + "ERKStepSetTable", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } - hadapt_mem = step_mem->hadapt_mem; - - /* if argument legal set it, otherwise set default */ - if (small_nef <= 0) { - hadapt_mem->small_nef = SMALL_NEF; - } else { - hadapt_mem->small_nef = small_nef; - } return(ARK_SUCCESS); } /*--------------------------------------------------------------- - ERKStepSetStabilityFn: + ERKStepSetTableNum: - Specifies the user-provided explicit time step stability - function to use. A NULL input function implies a reset to - the default function (empty). + Specifies to use a pre-existing Butcher table for the problem, + based on the integer flag passed to ARKodeButcherTable_LoadERK() + within the file arkode_butcher_erk.c. ---------------------------------------------------------------*/ -int ERKStepSetStabilityFn(void *arkode_mem, ARKExpStabFn EStab, - void *estab_data) +int ERKStepSetTableNum(void *arkode_mem, int itable) { ARKodeMem ark_mem; ARKodeERKStepMem step_mem; - ARKodeHAdaptMem hadapt_mem; int retval; /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetStabilityFn", + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetTableNum", &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - /* access structure */ - if (step_mem->hadapt_mem == NULL) { + /* check that argument specifies an explicit table */ + if (itableMAX_ERK_NUM) { arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", - "ERKStepSetStabilityFn", MSG_ARKADAPT_NO_MEM); - return(ARK_MEM_NULL); - } - hadapt_mem = step_mem->hadapt_mem; - - /* NULL argument sets default, otherwise set inputs */ - if (EStab == NULL) { - hadapt_mem->expstab = arkExpStab; - hadapt_mem->estab_data = ark_mem; - } else { - hadapt_mem->expstab = EStab; - hadapt_mem->estab_data = estab_data; + "ERKStepSetTableNum", + "Illegal ERK table number"); + return(ARK_ILL_INPUT); } - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepSetMaxErrTestFails: - - Specifies the maximum number of error test failures during one - step try. A non-positive input implies a reset to - the default value. - ---------------------------------------------------------------*/ -int ERKStepSetMaxErrTestFails(void *arkode_mem, int maxnef) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetMaxErrTestFails", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); + /* clear any existing parameters and Butcher tables */ + step_mem->stages = 0; + step_mem->q = 0; + step_mem->p = 0; + ARKodeButcherTable_Free(step_mem->B); step_mem->B = NULL; - /* argument <= 0 sets default, otherwise set input */ - if (maxnef <= 0) { - step_mem->maxnef = MAXNEF; - } else { - step_mem->maxnef = maxnef; + /* fill in table based on argument */ + step_mem->B = ARKodeButcherTable_LoadERK(itable); + if (step_mem->B == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", + "ERKStepSetTableNum", + "Error setting table with that index"); + return(ARK_ILL_INPUT); } + step_mem->stages = step_mem->B->stages; + step_mem->q = step_mem->B->q; + step_mem->p = step_mem->B->p; return(ARK_SUCCESS); } @@ -1214,83 +338,6 @@ int ERKStepSetMaxErrTestFails(void *arkode_mem, int maxnef) ERKStep optional output functions -- stepper-specific ===============================================================*/ -/*--------------------------------------------------------------- - ERKStepGetNumExpSteps: - - Returns the current number of stability-limited steps - ---------------------------------------------------------------*/ -int ERKStepGetNumExpSteps(void *arkode_mem, long int *nsteps) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepGetNumExpSteps", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* if step adaptivity structure not allocated, just return 0 */ - if (step_mem->hadapt_mem == NULL) { - *nsteps = 0; - } else { - *nsteps = step_mem->hadapt_mem->nst_exp; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepGetNumAccSteps: - - Returns the current number of accuracy-limited steps - ---------------------------------------------------------------*/ -int ERKStepGetNumAccSteps(void *arkode_mem, long int *nsteps) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepGetNumAccSteps", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* if step adaptivity structure not allocated, just return 0 */ - if (step_mem->hadapt_mem == NULL) { - *nsteps = 0; - } else { - *nsteps = step_mem->hadapt_mem->nst_acc; - } - - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - ERKStepGetNumStepAttempts: - - Returns the current number of steps attempted by the solver - ---------------------------------------------------------------*/ -int ERKStepGetNumStepAttempts(void *arkode_mem, long int *nsteps) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepGetNumStepAttempts", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* get value from step_mem */ - *nsteps = step_mem->nst_attempts; - - return(ARK_SUCCESS); -} - - /*--------------------------------------------------------------- ERKStepGetNumRhsEvals: @@ -1314,29 +361,6 @@ int ERKStepGetNumRhsEvals(void *arkode_mem, long int *fevals) } -/*--------------------------------------------------------------- - ERKStepGetNumErrTestFails: - - Returns the current number of error test failures - ---------------------------------------------------------------*/ -int ERKStepGetNumErrTestFails(void *arkode_mem, long int *netfails) -{ - ARKodeMem ark_mem; - ARKodeERKStepMem step_mem; - int retval; - - /* access ARKodeARKStepMem structure */ - retval = erkStep_AccessStepMem(arkode_mem, "ERKStepGetNumErrTestFails", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* get value from step_mem */ - *netfails = step_mem->netf; - - return(ARK_SUCCESS); -} - - /*--------------------------------------------------------------- ERKStepGetCurrentButcherTable: @@ -1403,20 +427,14 @@ int ERKStepGetTimestepperStats(void *arkode_mem, long int *expsteps, &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - /* if step adaptivity structure not allocated, - just set expsteps and accsteps to 0 */ - if (step_mem->hadapt_mem == NULL) { - *expsteps = 0; - *accsteps = 0; - } else { - *expsteps = step_mem->hadapt_mem->nst_exp; - *accsteps = step_mem->hadapt_mem->nst_acc; - } + /* set expsteps and accsteps from adaptivity structure */ + *expsteps = ark_mem->hadapt_mem->nst_exp; + *accsteps = ark_mem->hadapt_mem->nst_acc; /* set remaining outputs from step_mem */ - *attempts = step_mem->nst_attempts; + *attempts = ark_mem->nst_attempts; *fevals = step_mem->nfe; - *netfails = step_mem->netf; + *netfails = ark_mem->netf; return(ARK_SUCCESS); } @@ -1454,38 +472,6 @@ int ERKStepWriteParameters(void *arkode_mem, FILE *fp) /* print integrator parameters to file */ fprintf(fp, "ERKStep time step module parameters:\n"); fprintf(fp, " Method order %i\n",step_mem->q); - if (step_mem->hadapt_mem != NULL) { - fprintf(fp, " Maximum step increase (first step) = %"RSYM"\n", - step_mem->hadapt_mem->etamx1); - fprintf(fp, " Step reduction factor on multiple error fails = %"RSYM"\n", - step_mem->hadapt_mem->etamxf); - fprintf(fp, " Minimum error fails before above factor is used = %i\n", - step_mem->hadapt_mem->small_nef); - fprintf(fp, " Step reduction factor on nonlinear convergence failure = %"RSYM"\n", - step_mem->hadapt_mem->etacf); - fprintf(fp, " Explicit safety factor = %"RSYM"\n", - step_mem->hadapt_mem->cfl); - if (step_mem->hadapt_mem->HAdapt == NULL) { - fprintf(fp, " Time step adaptivity method %i\n", step_mem->hadapt_mem->imethod); - fprintf(fp, " Safety factor = %"RSYM"\n", step_mem->hadapt_mem->safety); - fprintf(fp, " Bias factor = %"RSYM"\n", step_mem->hadapt_mem->bias); - fprintf(fp, " Growth factor = %"RSYM"\n", step_mem->hadapt_mem->growth); - fprintf(fp, " Step growth lower bound = %"RSYM"\n", step_mem->hadapt_mem->lbound); - fprintf(fp, " Step growth upper bound = %"RSYM"\n", step_mem->hadapt_mem->ubound); - fprintf(fp, " k1 = %"RSYM"\n", step_mem->hadapt_mem->k1); - fprintf(fp, " k2 = %"RSYM"\n", step_mem->hadapt_mem->k2); - fprintf(fp, " k3 = %"RSYM"\n", step_mem->hadapt_mem->k3); - if (step_mem->hadapt_mem->expstab == arkExpStab) { - fprintf(fp, " Default explicit stability function\n"); - } else { - fprintf(fp, " User provided explicit stability function\n"); - } - } else { - fprintf(fp, " User provided time step adaptivity function\n"); - } - } - - fprintf(fp, " Maximum number of error test failures = %i\n",step_mem->maxnef); fprintf(fp, "\n"); return(ARK_SUCCESS); diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_impl.h b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_impl.h index cb868cac5..bda128258 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_impl.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -21,7 +21,6 @@ #include #include #include "arkode_adapt_impl.h" -#include "arkode_interp_impl.h" #include "arkode_root_impl.h" #ifdef __cplusplus /* wrapper to enable C++ usage */ @@ -33,56 +32,23 @@ extern "C" { ARKode Private Constants ===============================================================*/ -/* Basic ARKode constants */ -#define Q_DEFAULT 4 /* default RK order */ -#define MXSTEP_DEFAULT 500 /* mxstep default value */ -#define MAXNEF 7 /* maxnef default value */ -#define MAXNCF 10 /* maxncf default value */ -#define MXHNIL 10 /* mxhnil default value */ -#define MAXCOR 3 /* maxcor default value */ +/* Basic ARKode defaults */ +#define Q_DEFAULT 4 /* method order */ +#define MXSTEP_DEFAULT 500 /* max steps between returns */ +#define MAXNEF 7 /* max number of error failures */ +#define MAXNCF 10 /* max number of convergence failures */ +#define MAXCONSTRFAILS 10 /* max number of constraint failures */ +#define MXHNIL 10 /* max number of t+h==h warnings */ /* Numeric constants */ #define ZERO RCONST(0.0) /* real 0.0 */ #define TINY RCONST(1.0e-10) /* small number */ #define TENTH RCONST(0.1) /* real 0.1 */ -#define POINT2 RCONST(0.2) /* real 0.2 */ -#define FOURTH RCONST(0.25) /* real 0.25 */ #define HALF RCONST(0.5) /* real 0.5 */ #define ONE RCONST(1.0) /* real 1.0 */ #define TWO RCONST(2.0) /* real 2.0 */ -#define THREE RCONST(3.0) /* real 3.0 */ #define FOUR RCONST(4.0) /* real 4.0 */ #define FIVE RCONST(5.0) /* real 5.0 */ -#define SIX RCONST(6.0) /* real 6.0 */ -#define SEVEN RCONST(7.0) /* real 7.0 */ -#define TWELVE RCONST(12.0) /* real 12.0 */ -#define HUND RCONST(100.0) /* real 100.0 */ - -/* Time step controller default values */ -#define CFLFAC RCONST(0.5) -#define SAFETY RCONST(0.96) /* CVODE uses 1.0 */ -#define BIAS RCONST(1.5) /* CVODE uses 6.0 */ -#define GROWTH RCONST(20.0) /* CVODE uses 10.0 */ -#define HFIXED_LB RCONST(1.0) /* CVODE uses 1.0 */ -#define HFIXED_UB RCONST(1.5) /* CVODE uses 1.5 */ -#define AD0_K1 RCONST(0.58) /* PID controller constants */ -#define AD0_K2 RCONST(0.21) -#define AD0_K3 RCONST(0.1) -#define AD1_K1 RCONST(0.8) /* PI controller constants */ -#define AD1_K2 RCONST(0.31) -#define AD2_K1 RCONST(1.0) /* I controller constants */ -#define AD3_K1 RCONST(0.367) /* explicit Gustafsson controller */ -#define AD3_K2 RCONST(0.268) -#define AD4_K1 RCONST(0.98) /* implicit Gustafsson controller */ -#define AD4_K2 RCONST(0.95) -#define AD5_K1 RCONST(0.367) /* imex Gustafsson controller */ -#define AD5_K2 RCONST(0.268) -#define AD5_K3 RCONST(0.95) - -/* Default solver tolerance factor */ -/* #define NLSCOEF RCONST(0.003) /\* Hairer & Wanner constant *\/ */ -/* #define NLSCOEF RCONST(0.2) /\* CVODE constant *\/ */ -#define NLSCOEF RCONST(0.1) /* Control constants for tolerances */ #define ARK_SS 0 @@ -95,50 +61,19 @@ extern "C" { ===============================================================*/ /*--------------------------------------------------------------- - Control constants for lower-level functions used by arkStep: - --------------------------------------------------------------- - arkHin return values: ARK_SUCCESS, ARK_RHSFUNC_FAIL, or - ARK_TOO_CLOSE - - arkStep control constants: SOLVE_SUCCESS or PREDICT_AGAIN - - arkStep return values: ARK_SUCCESS, ARK_LSETUP_FAIL, - ARK_LSOLVE_FAIL, ARK_RHSFUNC_FAIL, ARK_RTFUNC_FAIL, - ARK_CONV_FAILURE, ARK_ERR_FAILURE or ARK_FIRST_RHSFUNC_ERR - - arkNls input nflag values: FIRST_CALL, PREV_CONV_FAIL or - PREV_ERR_FAIL - - arkNls return values: ARK_SUCCESS, ARK_LSETUP_FAIL, - ARK_LSOLVE_FAIL, ARK_RHSFUNC_FAIL, CONV_FAIL or - RHSFUNC_RECVR - - arkNewtonIteration return values: ARK_SUCCESS, ARK_LSOLVE_FAIL, - ARK_RHSFUNC_FAIL, CONV_FAIL, RHSFUNC_RECVR or TRY_AGAIN + Control constants for lower-level time-stepping functions ---------------------------------------------------------------*/ -#define SOLVE_SUCCESS +2 #define PREDICT_AGAIN +3 - #define CONV_FAIL +4 #define TRY_AGAIN +5 - #define FIRST_CALL +6 #define PREV_CONV_FAIL +7 #define PREV_ERR_FAIL +8 - #define RHSFUNC_RECVR +9 - +#define CONSTR_RECVR +10 /*--------------------------------------------------------------- Return values for lower-level rootfinding functions - --------------------------------------------------------------- - arkRootCheck1: ARK_SUCCESS or ARK_RTFUNC_FAIL - - arkRootCheck2: ARK_SUCCESS, ARK_RTFUNC_FAIL, CLOSERT or RTFOUND - - arkRootCheck3: ARK_SUCCESS, ARK_RTFUNC_FAIL or RTFOUND - - arkRootfind: ARK_SUCCESS, ARK_RTFUNC_FAIL or RTFOUND ---------------------------------------------------------------*/ #define RTFOUND +1 #define CLOSERT +3 @@ -151,26 +86,9 @@ extern "C" { arkHin: H0_LBFACTOR, H0_UBFACTOR, H0_BIAS and H0_ITERS - arkStep: - ETAMX1 maximum step size change on first step - ETAMXF step size reduction factor on multiple error - test failures (multiple implies >= SMALL_NEF) - ETAMIN smallest allowable step size reduction factor - on an error test failure - ETACF step size reduction factor on nonlinear - convergence failure + time comparison factors: ONEPSM safety factor for floating point comparisons ONEMSM safety factor for floating point comparisons - SMALL_NEF if an error failure occurs and SMALL_NEF <= nef, - then reset eta = MIN(eta, ETAMXF) - - arkNls: - CRDOWN constant used in the estimation of the - convergence rate (crate) of the iterates for - the nonlinear equation - DGMAX if |gamma/gammap-1| > DGMAX then call lsetup - RDIV declare divergence if ratio del/delp > RDIV - MSBP max no. of steps between lsetup calls ---------------------------------------------------------------*/ #define FUZZ_FACTOR RCONST(100.0) @@ -179,18 +97,8 @@ extern "C" { #define H0_BIAS HALF #define H0_ITERS 4 -#define ETAMX1 RCONST(10000.0) /* default */ -#define ETAMXF RCONST(0.3) /* default */ -#define ETAMIN RCONST(0.1) /* default */ -#define ETACF RCONST(0.25) /* default */ #define ONEPSM RCONST(1.000001) #define ONEMSM RCONST(0.999999) -#define SMALL_NEF 2 /* default */ - -#define CRDOWN RCONST(0.3) /* default */ -#define DGMAX RCONST(0.2) /* default */ -#define RDIV RCONST(2.3) /* default */ -#define MSBP 20 /* default */ /*=============================================================== @@ -253,7 +161,54 @@ typedef int (*ARKTimestepGetGammasFn)(void* arkode_mem, booleantype *dgamma_fail); typedef int (*ARKTimestepFullRHSFn)(void* arkode_mem, realtype t, N_Vector y, N_Vector f, int mode); -typedef int (*ARKTimestepStepFn)(void* arkode_mem); +typedef int (*ARKTimestepStepFn)(void* arkode_mem, realtype *dsm, + int *nflag); + + +/*=============================================================== + ARKode interpolation module definition + ===============================================================*/ + +/* Forward reference for pointer to ARKInterp_Ops object */ +typedef struct _generic_ARKInterpOps *ARKInterpOps; + +/* Forward reference for pointer to ARKInterp object */ +typedef struct _generic_ARKInterp *ARKInterp; + +/* Structure containing function pointers to interpolation operations */ +struct _generic_ARKInterpOps { + int (*resize)(void* arkode_mem, ARKInterp interp, + ARKVecResizeFn resize, void *resize_data, + sunindextype lrw_diff, sunindextype liw_diff, + N_Vector tmpl); + void (*free)(void* arkode_mem, ARKInterp interp); + void (*print)(ARKInterp interp, FILE *outfile); + int (*setdegree)(void *arkode_mem, ARKInterp interp, int degree); + int (*init)(void* arkode_mem, ARKInterp interp, realtype tnew); + int (*update)(void* arkode_mem, ARKInterp interp, realtype tnew); + int (*evaluate)(void* arkode_mem, ARKInterp interp, + realtype tau, int d, int order, N_Vector yout); +}; + +/* An interpolation module consists of an implementation-dependent 'content' + structure, and a pointer to a structure of implementation-dependent operations. */ +struct _generic_ARKInterp { + void *content; + ARKInterpOps ops; +}; + +/* ARKInterp module functions */ +int arkInterpResize(void* arkode_mem, ARKInterp interp, + ARKVecResizeFn resize, void *resize_data, + sunindextype lrw_diff, sunindextype liw_diff, + N_Vector tmpl); +void arkInterpFree(void* arkode_mem, ARKInterp interp); +void arkInterpPrintMem(ARKInterp interp, FILE *outfile); +int arkInterpSetDegree(void *arkode_mem, ARKInterp interp, int degree); +int arkInterpInit(void* arkode_mem, ARKInterp interp, realtype tnew); +int arkInterpUpdate(void* arkode_mem, ARKInterp interp, realtype tnew); +int arkInterpEvaluate(void* arkode_mem, ARKInterp interp, + realtype tau, int d, int order, N_Vector yout); /*=============================================================== @@ -290,27 +245,30 @@ typedef struct ARKodeMassMemRec { ---------------------------------------------------------------*/ typedef struct ARKodeMemRec { - realtype uround; /* machine unit roundoff */ + realtype uround; /* machine unit roundoff */ /* Problem specification data */ - void *user_data; /* user ptr passed to supplied functions */ - int itol; /* itol = ARK_SS (scalar, default), - ARK_SV (vector), - ARK_WF (user weight function) */ - int ritol; /* itol = ARK_SS (scalar, default), - ARK_SV (vector), - ARK_WF (user weight function) */ - realtype reltol; /* relative tolerance */ - realtype Sabstol; /* scalar absolute solution tolerance */ - N_Vector Vabstol; /* vector absolute solution tolerance */ - realtype SRabstol; /* scalar absolute residual tolerance */ - N_Vector VRabstol; /* vector absolute residual tolerance */ - booleantype user_efun; /* SUNTRUE if user sets efun */ - ARKEwtFn efun; /* function to set ewt */ - void *e_data; /* user pointer passed to efun */ - booleantype user_rfun; /* SUNTRUE if user sets rfun */ - ARKRwtFn rfun; /* function to set rwt */ - void *r_data; /* user pointer passed to rfun */ + void *user_data; /* user ptr passed to supplied functions */ + int itol; /* itol = ARK_SS (scalar, default), + ARK_SV (vector), + ARK_WF (user weight function) */ + int ritol; /* itol = ARK_SS (scalar, default), + ARK_SV (vector), + ARK_WF (user weight function) */ + realtype reltol; /* relative tolerance */ + realtype Sabstol; /* scalar absolute solution tolerance */ + N_Vector Vabstol; /* vector absolute solution tolerance */ + booleantype atolmin0; /* flag indicating that min(abstol) = 0 */ + realtype SRabstol; /* scalar absolute residual tolerance */ + N_Vector VRabstol; /* vector absolute residual tolerance */ + booleantype Ratolmin0; /* flag indicating that min(Rabstol) = 0 */ + booleantype user_efun; /* SUNTRUE if user sets efun */ + ARKEwtFn efun; /* function to set ewt */ + void *e_data; /* user pointer passed to efun */ + booleantype user_rfun; /* SUNTRUE if user sets rfun */ + ARKRwtFn rfun; /* function to set rwt */ + void *r_data; /* user pointer passed to rfun */ + booleantype constraintsSet; /* check inequality constraints */ /* Time stepper module */ ARKTimestepAttachLinsolFn step_attachlinsol; @@ -328,48 +286,60 @@ typedef struct ARKodeMemRec { void *step_mem; /* N_Vector storage */ - N_Vector ewt; /* error weight vector */ - N_Vector rwt; /* residual weight vector */ - booleantype rwt_is_ewt; /* SUNTRUE if rwt is a pointer to ewt */ - N_Vector ycur; /* pointer to user-provided solution memory; used as - evolving solution by the timestepper modules */ - N_Vector yn; /* solution from the last successful step */ - N_Vector tempv1; /* temporary storage vectors (for local use and by */ - N_Vector tempv2; /* time-stepping modules) */ + N_Vector ewt; /* error weight vector */ + N_Vector rwt; /* residual weight vector */ + booleantype rwt_is_ewt; /* SUNTRUE if rwt is a pointer to ewt */ + N_Vector ycur; /* pointer to user-provided solution memory; used + as evolving solution by the timestepper modules */ + N_Vector yn; /* solution from the last successful step */ + N_Vector fn; /* full IVP right-hand side from last step */ + N_Vector tempv1; /* temporary storage vectors (for local use and by */ + N_Vector tempv2; /* time-stepping modules) */ N_Vector tempv3; N_Vector tempv4; + N_Vector constraints; /* vector of inequality constraint options */ + /* Temporal interpolation module */ - ARKodeInterpMem interp; - int dense_q; /* interpolation order (user request) */ + ARKInterp interp; /* Tstop information */ booleantype tstopset; realtype tstop; /* Time step data */ - realtype hin; /* initial step size */ - realtype h; /* current step size */ - realtype hmin; /* |h| >= hmin */ - realtype hmax_inv; /* |h| <= 1/hmax_inv */ - realtype hprime; /* next step size (used internally) */ - realtype next_h; /* next step size (for user output) */ - realtype eta; /* eta = hprime / h */ - realtype tcur; /* current internal value of t - (changes with each stage) */ - realtype tretlast; /* value of tret last returned by ARKode */ - booleantype fixedstep; /* flag to disable temporal adaptivity */ + realtype hin; /* initial step size */ + realtype h; /* current step size */ + realtype hmin; /* |h| >= hmin */ + realtype hmax_inv; /* |h| <= 1/hmax_inv */ + realtype hprime; /* next actual step size to be used */ + realtype next_h; /* next dynamical step size (only used in + getCurrenStep); note that this could + overtake tstop */ + realtype eta; /* eta = hprime / h */ + realtype tcur; /* current internal value of t + (changes with each stage) */ + realtype tretlast; /* value of tret last returned by ARKode */ + booleantype fixedstep; /* flag to disable temporal adaptivity */ + ARKodeHAdaptMem hadapt_mem; /* time step adaptivity structure */ /* Limits and various solver parameters */ - long int mxstep; /* max number of internal steps for one user call */ - int mxhnil; /* max number of warning messages issued to the - user that t+h == t for the next internal step */ + long int mxstep; /* max number of internal steps for one user call */ + int mxhnil; /* max number of warning messages issued to the + user that t+h == t for the next internal step */ + int maxconstrfails; /* max number of constraint check failures */ + int maxnef; /* max error test fails in one step */ + int maxncf; /* max num alg. solver conv. fails in one step */ /* Counters */ - long int nst; /* number of internal steps taken */ - int nhnil; /* number of messages issued to the user that - t+h == t for the next iternal step */ + long int nst_attempts; /* number of attempted steps */ + long int nst; /* number of internal steps taken */ + int nhnil; /* number of messages issued to the user that + t+h == t for the next iternal step */ + long int ncfn; /* num corrector convergence failures */ + long int netf; /* num error test failures */ + long int nconstrfails; /* number of constraint failures */ /* Diagnostic output */ booleantype report; /* flag to enable/disable diagnostic output */ @@ -388,9 +358,12 @@ typedef struct ARKodeMemRec { realtype tolsf; /* tolerance scale factor (suggestion to user) */ booleantype VabstolMallocDone; booleantype VRabstolMallocDone; + booleantype ConstraintsMallocDone; booleantype MallocDone; booleantype resized; /* denotes first step after ARKodeResize */ booleantype firststage; /* denotes first stage in simulation */ + booleantype initialized; /* denotes arkInitialSetup has been done */ + booleantype call_fullrhs; /* denotes fn needs updating after each step */ /* Error handler function and error ouput file */ ARKErrHandlerFn ehfun; /* error messages are handled by ehfun */ @@ -401,7 +374,11 @@ typedef struct ARKodeMemRec { ARKodeRootMem root_mem; /* root-finding structure */ /* User-supplied step solution post-processing function */ - ARKPostProcessStepFn ProcessStep; + ARKPostProcessFn ProcessStep; + void* ps_data; /* pointer to user_data */ + + /* User-supplied stage solution post-processing function */ + ARKPostProcessFn ProcessStage; } *ARKodeMem; @@ -626,8 +603,7 @@ typedef struct ARKodeMemRec { solver interface routines, linear solver interface data structure, and system linear solver type to the ARKode time stepping module pointed to in ark_mem->step_mem. This will - be called by one of the various ARKode linear solver interfaces - (SPILS, DLS). + be called by the ARKode linear solver interface. This routine should return 0 if it has successfully attached these items and a negative value otherwise. If an error does @@ -641,8 +617,8 @@ typedef struct ARKodeMemRec { This routine should attach the various set of mass matrix linear solver interface routines, data structure, and solver type to the ARKode time stepping module pointed to in - ark_mem->step_mem. This will be called by one of the - various ARKode linear solver interfaces (SPILS, DLS). + ark_mem->step_mem. This will be called by the ARKode linear + solver interface. This routine should return 0 if it has successfully attached these items, and a negative value otherwise. If an error does @@ -655,8 +631,7 @@ typedef struct ARKodeMemRec { --------------------------------------------------------------- This routine should NULLify any ARKLinsolSetupFn function pointer stored in the ARKode time stepping module (initially set - in a call to ARKTimestepAttachLinsolFn). This can be called by - ARKSPILS when preconditioning is disabled. + in a call to ARKTimestepAttachLinsolFn). This routine has no return value. ---------------------------------------------------------------*/ @@ -666,8 +641,7 @@ typedef struct ARKodeMemRec { --------------------------------------------------------------- This routine should NULLify any ARKMassSetupFn function pointer stored in the ARKode time stepping module (initially set in a - call to ARKTimestepAttachMasssolFn). This can be called by - ARKSPILS when preconditioning is disabled. + call to ARKTimestepAttachMasssolFn). This routine has no return value. ---------------------------------------------------------------*/ @@ -677,8 +651,8 @@ typedef struct ARKodeMemRec { --------------------------------------------------------------- This routine should return the linear solver memory structure used by the ARKode time stepping module pointed to in - ark_mem->step_mem. This will be called by one of the - various ARKode linear solver interfaces (SPILS, DLS). + ark_mem->step_mem. This will be called by the ARKode linear + solver interface. This routine should return NULL if no linear solver memory structure is attached. @@ -689,8 +663,8 @@ typedef struct ARKodeMemRec { --------------------------------------------------------------- This routine should return the mass matrix linear solver memory structure used by the ARKode time stepping module pointed to in - ark_mem->step_mem. This will be called by one of the - various ARKode mass matrix solver interfaces (SPILS, DLS). + ark_mem->step_mem. This will be called the ARKode mass matrix + solver interface. This routine should return NULL if no mass matrix solver memory structure is attached. @@ -724,11 +698,11 @@ typedef struct ARKodeMemRec { The time step module must contain a booleantype variable to provide for the boolentype pointer (jcur). This is only used - by the ARKSPILS interface, so could be NULL for time step - modules that only work with ARKDLS. Optionally, the value of - this parameter could be set to SUNFALSE prior to return from - the ARKTimestepGetGammasFn to force recalculation of - preconditioner information. + by iterative linear solvers, so could be NULL for time step + modules that only work with direct linear solvers. Optionally, + the value of this parameter could be set to SUNFALSE prior to + return from the ARKTimestepGetGammasFn to force recalculation + of preconditioner information. The value of the logic flag is used as follows: if a previous Newton iteration failed due to a bad Jacobian/preconditioner, @@ -744,13 +718,13 @@ typedef struct ARKodeMemRec { /*--------------------------------------------------------------- ARKTimestepInitFn --------------------------------------------------------------- - This routine is called just prior to performing internal time - steps (after all user "set" routines have been called) from + This routine is called just prior to performing internal time + steps (after all user "set" routines have been called) from within arkInitialSetup (init_type == 0) or arkPostResizeSetup - (init_type == 1). It should complete initializations for a - specific ARKode time stepping module, such as verifying - compatibility of user-specified linear and nonlinear solver - objects. + (init_type == 1). It should complete initializations for a + specific ARKode time stepping module, such as verifying + compatibility of user-specified linear and nonlinear solver + objects. This routine should return 0 if it has successfully initialized the ARKode time stepper module and a negative value otherwise. @@ -782,12 +756,9 @@ typedef struct ARKodeMemRec { /*--------------------------------------------------------------- ARKTimestepStepFn --------------------------------------------------------------- - This is the primary computational routine for any ARKode - time-stepping module. It must attempt to advance the solution - vector one internal time step, from tn to tn+h. The routine may - internally adjust the value of h if needed to complete the step - successfully (e.g. to meet error goals or to converge the - (non)linear solution). + This routine serves the primary purpose of any ARKode + time-stepping module: it performs a single time step of the + method (with embedding, if possible). It is assumed that this routine uses/modifies general problem data directly out of the main ARKodeMem structure, but that all @@ -802,7 +773,6 @@ typedef struct ARKodeMemRec { should be stored here - tn -- "t" value at end of the last successful step - nst -- the counter for overall successful steps - - nst_attempts -- the counter for overall step attempts - user_data -- the (void *) pointer returned to user for RHS calls - report / diagfp -- if any diagnostic information is @@ -810,32 +780,24 @@ typedef struct ARKodeMemRec { this is enabled, and diagfp provides the file pointer where this information should be written - Possible return values (not all must be used by the stepper): - - ARK_SUCCESS -- the step completed successfully (although - perhaps with a shortened h) - - ARK_ERR_FAILURE -- the error test failed repeatedly or - with |h| = hmin - - ARK_CONV_FAILURE -- the solver convergence test failed - repeatedly or with |h| = hmin - - ARK_LSETUP_FAIL -- the linear solver setup routine failed - in an unrecoverable manner - - ARK_LSOLVE_FAIL -- the linear solve routine failed in an - unrecoverable manner - - ARK_RHSFUNC_FAIL -- the ODE right-hand side routine failed - in an unrecoverable manner - - ARK_UNREC_RHSFUNC_ERR -- the right-hand side failed in a - recoverable manner, but no recovery is possible - - ARK_REPTD_RHSFUNC_ERR -- repeated recoverable right-hand - side function errors - - ARK_RTFUNC_FAIL -- the rootfinding routine failed in an - unrecoverable manner - - ARK_TOO_CLOSE -- tout too close to t0 to start integration - - ARK_MASSSOLVE_FAIL -- the mass matrix solver failed - - If additional failure modes need to be added for future - steppers, the relevant flags should be added to - include/arkode/arkode.h, and the routine arkHandleFailure (in - src/arkode/arkode.c) must be modified to handle the new flags. + The output variable dsmPtr should contain estimate of the + weighted local error if an embedding is present; otherwise it + should be 0. + + The input/output variable nflagPtr is used to gauge convergence + of any algebraic solvers within the step. At the start of a new + time step, this will initially have the value FIRST_CALL. On + return from this function, nflagPtr should have a value: + 0 => algebraic solve completed successfully + >0 => solve did not converge at this step size + (but may with a smaller stepsize) + <0 => solve encountered an unrecoverable failure + + The return value from this routine is: + 0 => step completed successfully + >0 => step encountered recoverable failure; + reduce step and retry (if possible) + <0 => step encountered unrecoverable failure ---------------------------------------------------------------*/ @@ -843,9 +805,6 @@ typedef struct ARKodeMemRec { ARKode PROTOTYPE FUNCTIONS (MAY BE REPLACED BY USER) ===============================================================*/ -/* Prototype of internal ewtSet function */ -int arkEwtSet(N_Vector ycur, N_Vector weight, void *data); - /* Prototype of internal rwtSet function */ int arkRwtSet(N_Vector ycur, N_Vector weight, void *data); @@ -903,19 +862,17 @@ realtype arkUpperBoundH0(ARKodeMem ark_mem, int arkYddNorm(ARKodeMem ark_mem, realtype hg, realtype *yddnrm); -int arkCompleteStep(ARKodeMem ark_mem); +int arkCompleteStep(ARKodeMem ark_mem, realtype dsm); int arkHandleFailure(ARKodeMem ark_mem,int flag); -int arkEwtSetSS(ARKodeMem ark_mem, N_Vector ycur, - N_Vector weight); -int arkEwtSetSV(ARKodeMem ark_mem, N_Vector ycur, - N_Vector weight); +int arkEwtSetSS(N_Vector ycur, N_Vector weight, void* arkode_mem); +int arkEwtSetSV(N_Vector ycur, N_Vector weight, void* arkode_mem); +int arkEwtSetSmallReal(N_Vector ycur, N_Vector weight, void* arkode_mem); int arkRwtSetSS(ARKodeMem ark_mem, N_Vector My, N_Vector weight); int arkRwtSetSV(ARKodeMem ark_mem, N_Vector My, N_Vector weight); - ARKodeMem arkCreate(); int arkResize(ARKodeMem ark_mem, N_Vector ynew, realtype hscale, realtype t0, ARKVecResizeFn resize, void *resize_data); @@ -930,40 +887,7 @@ int arkEvolve(ARKodeMem ark_mem, realtype tout, N_Vector yout, realtype *tret, int itask); int arkGetDky(ARKodeMem ark_mem, realtype t, int k, N_Vector dky); void arkFree(void **arkode_mem); -int arkSetDefaults(ARKodeMem ark_mem); -int arkSetDenseOrder(ARKodeMem ark_mem, int dord); -int arkSetErrHandlerFn(ARKodeMem ark_mem, - ARKErrHandlerFn ehfun, - void *eh_data); -int arkSetErrFile(ARKodeMem ark_mem, FILE *errfp); -int arkSetUserData(ARKodeMem ark_mem, void *user_data); -int arkSetDiagnostics(ARKodeMem ark_mem, FILE *diagfp); -int arkSetMaxNumSteps(ARKodeMem ark_mem, long int mxsteps); -int arkSetMaxHnilWarns(ARKodeMem ark_mem, int mxhnil); -int arkSetInitStep(ARKodeMem ark_mem, realtype hin); -int arkSetMinStep(ARKodeMem ark_mem, realtype hmin); -int arkSetMaxStep(ARKodeMem ark_mem, realtype hmax); -int arkSetStopTime(ARKodeMem ark_mem, realtype tstop); -int arkSetFixedStep(ARKodeMem ark_mem, realtype hfixed); -int arkSetRootDirection(ARKodeMem ark_mem, int *rootdir); -int arkSetNoInactiveRootWarn(ARKodeMem ark_mem); -int arkSetPostprocessStepFn(ARKodeMem ark_mem, - ARKPostProcessStepFn ProcessStep); -int arkGetWorkSpace(ARKodeMem ark_mem, long int *lenrw, long int *leniw); -int arkGetNumSteps(ARKodeMem ark_mem, long int *nsteps); -int arkGetActualInitStep(ARKodeMem ark_mem, realtype *hinused); -int arkGetLastStep(ARKodeMem ark_mem, realtype *hlast); -int arkGetCurrentStep(ARKodeMem ark_mem, realtype *hcur); -int arkGetCurrentTime(ARKodeMem ark_mem, realtype *tcur); -int arkGetTolScaleFactor(ARKodeMem ark_mem, realtype *tolsfac); -int arkGetErrWeights(ARKodeMem ark_mem, N_Vector eweight); -int arkGetResWeights(ARKodeMem ark_mem, N_Vector rweight); -int arkGetNumGEvals(ARKodeMem ark_mem, long int *ngevals); -int arkGetRootInfo(ARKodeMem ark_mem, int *rootsfound); -int arkGetStepStats(ARKodeMem ark_mem, long int *nsteps, - realtype *hinused, realtype *hlast, - realtype *hcur, realtype *tcur); -char *arkGetReturnFlagName(long int flag); + int arkWriteParameters(ARKodeMem ark_mem, FILE *fp); int arkPredict_MaximumOrder(ARKodeMem ark_mem, realtype tau, N_Vector yguess); @@ -974,6 +898,74 @@ int arkPredict_CutoffOrder(ARKodeMem ark_mem, realtype tau, int arkPredict_Bootstrap(ARKodeMem ark_mem, realtype hj, realtype tau, int nvec, realtype *cvals, N_Vector *Xvecs, N_Vector yguess); +int arkCheckConvergence(ARKodeMem ark_mem, int *nflagPtr, int *ncfPtr); +int arkCheckConstraints(ARKodeMem ark_mem, int *nflag, int *constrfails); +int arkCheckTemporalError(ARKodeMem ark_mem, int *nflagPtr, int *nefPtr, realtype dsm); +int arkAccessHAdaptMem(void* arkode_mem, const char *fname, + ARKodeMem *ark_mem, ARKodeHAdaptMem *hadapt_mem); + +int arkSetDefaults(void *arkode_mem); +int arkSetDenseOrder(void *arkode_mem, int dord); +int arkSetInterpolantType(void *arkode_mem, int itype); +int arkSetInterpolantDegree(void *arkode_mem, int degree); +int arkSetErrHandlerFn(void *arkode_mem, + ARKErrHandlerFn ehfun, + void *eh_data); +int arkSetErrFile(void *arkode_mem, FILE *errfp); +int arkSetUserData(void *arkode_mem, void *user_data); +int arkSetDiagnostics(void *arkode_mem, FILE *diagfp); +int arkSetMaxNumSteps(void *arkode_mem, long int mxsteps); +int arkSetMaxHnilWarns(void *arkode_mem, int mxhnil); +int arkSetInitStep(void *arkode_mem, realtype hin); +int arkSetMinStep(void *arkode_mem, realtype hmin); +int arkSetMaxStep(void *arkode_mem, realtype hmax); +int arkSetStopTime(void *arkode_mem, realtype tstop); +int arkSetFixedStep(void *arkode_mem, realtype hfixed); +int arkSetRootDirection(void *arkode_mem, int *rootdir); +int arkSetNoInactiveRootWarn(void *arkode_mem); +int arkSetPostprocessStepFn(void *arkode_mem, + ARKPostProcessFn ProcessStep); +int arkSetPostprocessStageFn(void *arkode_mem, + ARKPostProcessFn ProcessStage); +int arkSetConstraints(void *arkode_mem, N_Vector constraints); +int arkSetMaxNumConstrFails(void *arkode_mem, int maxfails); +int arkSetCFLFraction(void *arkode_mem, realtype cfl_frac); +int arkSetSafetyFactor(void *arkode_mem, realtype safety); +int arkSetErrorBias(void *arkode_mem, realtype bias); +int arkSetMaxGrowth(void *arkode_mem, realtype mx_growth); +int arkSetMinReduction(void *arkode_mem, realtype eta_min); +int arkSetFixedStepBounds(void *arkode_mem, realtype lb, realtype ub); +int arkSetAdaptivityMethod(void *arkode_mem, int imethod, int idefault, + int pq, realtype adapt_params[3]); +int arkSetAdaptivityFn(void *arkode_mem, ARKAdaptFn hfun, void *h_data); +int arkSetMaxFirstGrowth(void *arkode_mem, realtype etamx1); +int arkSetMaxEFailGrowth(void *arkode_mem, realtype etamxf); +int arkSetSmallNumEFails(void *arkode_mem, int small_nef); +int arkSetMaxCFailGrowth(void *arkode_mem, realtype etacf); +int arkSetStabilityFn(void *arkode_mem, ARKExpStabFn EStab, void *estab_data); +int arkSetMaxErrTestFails(void *arkode_mem, int maxnef); +int arkSetMaxConvFails(void *arkode_mem, int maxncf); +int arkGetWorkSpace(void *arkode_mem, long int *lenrw, long int *leniw); +int arkGetNumStepAttempts(void *arkode_mem, long int *nstep_attempts); +int arkGetNumSteps(void *arkode_mem, long int *nsteps); +int arkGetActualInitStep(void *arkode_mem, realtype *hinused); +int arkGetLastStep(void *arkode_mem, realtype *hlast); +int arkGetCurrentStep(void *arkode_mem, realtype *hcur); +int arkGetCurrentState(void *arkode_mem, N_Vector *ycur); +int arkGetCurrentTime(void *arkode_mem, realtype *tcur); +int arkGetTolScaleFactor(void *arkode_mem, realtype *tolsfac); +int arkGetErrWeights(void *arkode_mem, N_Vector eweight); +int arkGetResWeights(void *arkode_mem, N_Vector rweight); +int arkGetNumGEvals(void *arkode_mem, long int *ngevals); +int arkGetRootInfo(void *arkode_mem, int *rootsfound); +int arkGetNumConstrFails(void *arkode_mem, long int *nconstrfails); +int arkGetNumExpSteps(void *arkode_mem, long int *nsteps); +int arkGetNumAccSteps(void *arkode_mem, long int *nsteps); +int arkGetNumErrTestFails(void *arkode_mem, long int *netfails); +int arkGetStepStats(void *arkode_mem, long int *nsteps, + realtype *hinused, realtype *hlast, + realtype *hcur, realtype *tcur); +char *arkGetReturnFlagName(long int flag); /*=============================================================== @@ -1007,31 +999,27 @@ int arkPredict_Bootstrap(ARKodeMem ark_mem, realtype hj, #endif /* Initialization and I/O error messages */ -#define MSG_ARK_NO_MEM "arkode_mem = NULL illegal." -#define MSG_ARK_ARKMEM_FAIL "Allocation of arkode_mem failed." -#define MSG_ARK_MEM_FAIL "A memory request failed." -#define MSG_ARK_NO_MALLOC "Attempt to call before ARKodeInit." -#define MSG_ARK_NEG_MAXORD "maxord <= 0 illegal." -#define MSG_ARK_BAD_MAXORD "Illegal attempt to increase maximum method order." -#define MSG_ARK_NEG_HMIN "hmin < 0 illegal." -#define MSG_ARK_NEG_HMAX "hmax < 0 illegal." -#define MSG_ARK_BAD_HMIN_HMAX "Inconsistent step size limits: hmin > hmax." -#define MSG_ARK_BAD_RELTOL "reltol < 0 illegal." -#define MSG_ARK_BAD_ABSTOL "abstol has negative component(s) (illegal)." -#define MSG_ARK_NULL_ABSTOL "abstol = NULL illegal." -#define MSG_ARK_BAD_RABSTOL "rabstol has negative component(s) (illegal)." -#define MSG_ARK_NULL_RABSTOL "rabstol = NULL illegal." -#define MSG_ARK_NULL_Y0 "y0 = NULL illegal." -#define MSG_ARK_NULL_F "Must specify at least one of fe, fi (both NULL)." -#define MSG_ARK_NULL_G "g = NULL illegal." -#define MSG_ARK_BAD_NVECTOR "A required vector operation is not implemented." -#define MSG_ARK_BAD_K "Illegal value for k." -#define MSG_ARK_NULL_DKY "dky = NULL illegal." -#define MSG_ARK_BAD_T "Illegal value for t." MSG_TIME_INT -#define MSG_ARK_NO_ROOT "Rootfinding was not initialized." +#define MSG_ARK_NO_MEM "arkode_mem = NULL illegal." +#define MSG_ARK_ARKMEM_FAIL "Allocation of arkode_mem failed." +#define MSG_ARK_MEM_FAIL "A memory request failed." +#define MSG_ARK_NO_MALLOC "Attempt to call before ARKodeInit." +#define MSG_ARK_BAD_HMIN_HMAX "Inconsistent step size limits: hmin > hmax." +#define MSG_ARK_BAD_RELTOL "reltol < 0 illegal." +#define MSG_ARK_BAD_ABSTOL "abstol has negative component(s) (illegal)." +#define MSG_ARK_NULL_ABSTOL "abstol = NULL illegal." +#define MSG_ARK_BAD_RABSTOL "rabstol has negative component(s) (illegal)." +#define MSG_ARK_NULL_RABSTOL "rabstol = NULL illegal." +#define MSG_ARK_NULL_Y0 "y0 = NULL illegal." +#define MSG_ARK_Y0_FAIL_CONSTR "y0 fails to satisfy constraints." +#define MSG_ARK_NULL_F "Must specify at least one of fe, fi (both NULL)." +#define MSG_ARK_NULL_G "g = NULL illegal." +#define MSG_ARK_BAD_NVECTOR "A required vector operation is not implemented." +#define MSG_ARK_BAD_CONSTR "Illegal values in constraints vector." +#define MSG_ARK_NULL_DKY "dky = NULL illegal." +#define MSG_ARK_BAD_T "Illegal value for t." MSG_TIME_INT +#define MSG_ARK_NO_ROOT "Rootfinding was not initialized." /* ARKode Error Messages */ -#define MSG_ARK_LSOLVE_NULL "The linear solver object is NULL." #define MSG_ARK_YOUT_NULL "yout = NULL illegal." #define MSG_ARK_TRET_NULL "tret = NULL illegal." #define MSG_ARK_BAD_EWT "Initial ewt has component(s) equal to zero (illegal)." @@ -1046,7 +1034,6 @@ int arkPredict_Bootstrap(ARKodeMem ark_mem, realtype hj, #define MSG_ARK_RWT_FAIL "The user-provide RwtSet function failed." #define MSG_ARK_RWT_NOW_FAIL "At " MSG_TIME ", the user-provide RwtSet function failed." #define MSG_ARK_LINIT_FAIL "The linear solver's init routine failed." -#define MSG_ARK_LFREE_FAIL "The linear solver's free routine failed." #define MSG_ARK_HNIL_DONE "The above warning has been issued mxhnil times and will not be issued again for this problem." #define MSG_ARK_TOO_CLOSE "tout too close to t0 to start integration." #define MSG_ARK_MAX_STEPS "At " MSG_TIME ", mxstep steps taken before reaching tout." @@ -1056,27 +1043,25 @@ int arkPredict_Bootstrap(ARKodeMem ark_mem, realtype hj, #define MSG_ARK_CONV_FAILS "At " MSG_TIME_H ", the solver convergence test failed repeatedly or with |h| = hmin." #define MSG_ARK_SETUP_FAILED "At " MSG_TIME ", the setup routine failed in an unrecoverable manner." #define MSG_ARK_SOLVE_FAILED "At " MSG_TIME ", the solve routine failed in an unrecoverable manner." +#define MSG_ARK_FAILED_CONSTR "At " MSG_TIME ", unable to satisfy inequality constraints." #define MSG_ARK_RHSFUNC_FAILED "At " MSG_TIME ", the right-hand side routine failed in an unrecoverable manner." #define MSG_ARK_RHSFUNC_UNREC "At " MSG_TIME ", the right-hand side failed in a recoverable manner, but no recovery is possible." #define MSG_ARK_RHSFUNC_REPTD "At " MSG_TIME " repeated recoverable right-hand side function errors." -#define MSG_ARK_RHSFUNC_FIRST "The right-hand side routine failed at the first call." #define MSG_ARK_RTFUNC_FAILED "At " MSG_TIME ", the rootfinding routine failed in an unrecoverable manner." #define MSG_ARK_CLOSE_ROOTS "Root found at and very near " MSG_TIME "." #define MSG_ARK_BAD_TSTOP "The value " MSG_TIME_TSTOP " is behind current " MSG_TIME " in the direction of integration." #define MSG_ARK_INACTIVE_ROOTS "At the end of the first step, there are still some root functions identically 0. This warning will not be issued again." -#define MSG_ARK_MISSING_FE "Cannot specify that method is explicit without providing a function pointer to fe(t,y)." -#define MSG_ARK_MISSING_FI "Cannot specify that method is implicit without providing a function pointer to fi(t,y)." -#define MSG_ARK_MISSING_F "Cannot specify that method is ImEx without providing function pointers to fi(t,y) and fe(t,y)." #define MSG_ARK_RESIZE_FAIL "Error in user-supplied resize() function." -#define MSG_ARK_MASSSOLVE_NULL "The mass matrix linear solver object is NULL." #define MSG_ARK_MASSINIT_FAIL "The mass matrix solver's init routine failed." #define MSG_ARK_MASSSETUP_FAIL "The mass matrix solver's setup routine failed." #define MSG_ARK_MASSSOLVE_FAIL "The mass matrix solver failed." -#define MSG_ARK_MASSFREE_FAIL "The mass matrixsolver's free routine failed." - +#define MSG_ARK_NLS_FAIL "At " MSG_TIME " the nonlinear solver failed in an unrecoverable manner." +#define MSG_ARK_USER_PREDICT_FAIL "At " MSG_TIME " the user-supplied predictor failed in an unrecoverable manner." #define MSG_ARKADAPT_NO_MEM "Adaptivity memory structure not allocated." #define MSG_ARK_VECTOROP_ERR "At " MSG_TIME ", a vector operation failed." #define MSG_ARK_INNERSTEP_FAILED "At " MSG_TIME ", the inner stepper failed in an unrecoverable manner." +#define MSG_ARK_POSTPROCESS_STEP_FAIL "At " MSG_TIME ", the step postprocessing routine failed in an unrecoverable manner." +#define MSG_ARK_POSTPROCESS_STAGE_FAIL "At " MSG_TIME ", the stage postprocessing routine failed in an unrecoverable manner." #ifdef __cplusplus } diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_interp.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_interp.c index f0bf53832..ec01e9fb0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_interp.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_interp.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -22,6 +22,7 @@ #include #include "arkode_impl.h" +#include "arkode_interp_impl.h" #include #include @@ -38,81 +39,157 @@ /*--------------------------------------------------------------- - arkInterpCreate: + Section I: generic ARKInterp functions provided by all + interpolation modules + ---------------------------------------------------------------*/ - This routine creates an ARKodeInterpMem structure, through +int arkInterpResize(void* arkode_mem, ARKInterp interp, + ARKVecResizeFn resize, void *resize_data, + sunindextype lrw_diff, sunindextype liw_diff, + N_Vector tmpl) +{ + if (interp == NULL) return(ARK_SUCCESS); + return((int) interp->ops->resize(arkode_mem, interp, + resize, resize_data, + lrw_diff, liw_diff, tmpl)); +} + +void arkInterpFree(void* arkode_mem, ARKInterp interp) +{ + if (interp == NULL) return; + interp->ops->free(arkode_mem, interp); + return; +} + +void arkInterpPrintMem(ARKInterp interp, FILE *outfile) +{ + if (interp == NULL) return; + interp->ops->print(interp, outfile); + return; +} + +int arkInterpSetDegree(void* arkode_mem, ARKInterp interp, + int degree) +{ + if (interp == NULL) return(ARK_SUCCESS); + return((int) interp->ops->setdegree(arkode_mem, interp, degree)); +} + +int arkInterpInit(void* arkode_mem, ARKInterp interp, + realtype tnew) +{ + if (interp == NULL) return(ARK_SUCCESS); + return((int) interp->ops->init(arkode_mem, interp, tnew)); +} + +int arkInterpUpdate(void* arkode_mem, ARKInterp interp, realtype tnew) +{ + if (interp == NULL) return(ARK_SUCCESS); + return((int) interp->ops->update(arkode_mem, interp, tnew)); +} + +int arkInterpEvaluate(void* arkode_mem, ARKInterp interp, + realtype tau, int d, int order, N_Vector yout) +{ + if (interp == NULL) return(ARK_SUCCESS); + return((int) interp->ops->evaluate(arkode_mem, interp, + tau, d, order, yout)); +} + + + +/*--------------------------------------------------------------- + Section II: Hermite interpolation module implementation + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + arkInterpCreate_Hermite: + + This routine creates an ARKInterp structure, through cloning an input template N_Vector. This returns a non-NULL structure if no errors occurred, or a NULL value otherwise. ---------------------------------------------------------------*/ -ARKodeInterpMem arkInterpCreate(void* arkode_mem) +ARKInterp arkInterpCreate_Hermite(void* arkode_mem, int degree) { + ARKInterp interp; + ARKInterpContent_Hermite content; + ARKInterpOps ops; ARKodeMem ark_mem; - ARKodeInterpMem interp_mem; /* access ARKodeMem structure */ if (arkode_mem == NULL) return(NULL); ark_mem = (ARKodeMem) arkode_mem; - /* allocate structure */ - interp_mem = (ARKodeInterpMem) malloc(sizeof(struct ARKodeInterpMemRec)); - if (interp_mem == NULL) return(NULL); - memset(interp_mem, 0, sizeof(struct ARKodeInterpMemRec)); - - /* set interpolation order based on user request (if possible) */ - if ((ark_mem->dense_q < 0) || (ark_mem->dense_q > 5)) { - interp_mem->order = QDENSE_DEF; - } else { - interp_mem->order = ark_mem->dense_q; - } - - /* vector allocation */ - if (!arkAllocVec(ark_mem, ark_mem->yn, &interp_mem->fold)) { - arkInterpFree(&interp_mem); return(NULL); - } - if (!arkAllocVec(ark_mem, ark_mem->yn, &interp_mem->fnew)) { - arkInterpFree(&interp_mem); return(NULL); - } - if (!arkAllocVec(ark_mem, ark_mem->yn, &interp_mem->yold)) { - arkInterpFree(&interp_mem); return(NULL); - } - if (!arkAllocVec(ark_mem, ark_mem->yn, &interp_mem->fa)) { - arkInterpFree(&interp_mem); return(NULL); - } - if (!arkAllocVec(ark_mem, ark_mem->yn, &interp_mem->fb)) { - arkInterpFree(&interp_mem); return(NULL); - } - - /* set ynew pointer to ark_mem->yn */ - interp_mem->ynew = ark_mem->yn; + /* check for valid degree */ + if (degree < 0 || degree > ARK_INTERP_MAX_DEGREE) return(NULL); + + /* allocate overall structure */ + interp = NULL; + interp = (ARKInterp) malloc(sizeof *interp); + if (interp == NULL) return(NULL); + + /* allocate ops structure and set entries */ + ops = NULL; + ops = (ARKInterpOps) malloc(sizeof *ops); + if (ops == NULL) { free(interp); return(NULL); } + ops->resize = arkInterpResize_Hermite; + ops->free = arkInterpFree_Hermite; + ops->print = arkInterpPrintMem_Hermite; + ops->setdegree = arkInterpSetDegree_Hermite; + ops->init = arkInterpInit_Hermite; + ops->update = arkInterpUpdate_Hermite; + ops->evaluate = arkInterpEvaluate_Hermite; + + /* create content, and initialize everything to zero/NULL */ + content = NULL; + content = (ARKInterpContent_Hermite) malloc(sizeof *content); + if (content == NULL) { free(ops); free(interp); return(NULL); } + memset(content, 0, sizeof(struct _ARKInterpContent_Hermite)); + + /* attach ops and content structures to overall structure */ + interp->ops = ops; + interp->content = content; + + /* fill content */ + + /* initialize local N_Vectors to NULL */ + content->fold = NULL; + content->yold = NULL; + content->fa = NULL; + content->fb = NULL; + + /* set maximum interpolant degree */ + content->degree = SUNMIN(ARK_INTERP_MAX_DEGREE, degree); + + /* set ynew and fnew pointers to ark_mem->yn and ark_mem->fn, respectively */ + content->ynew = ark_mem->yn; + content->fnew = ark_mem->fn; /* update workspace sizes */ - ark_mem->lrw += ARK_INTERP_LRW; - ark_mem->liw += ARK_INTERP_LIW; - - /* copy ark_mem->yn into yold */ - N_VScale(ONE, ark_mem->yn, interp_mem->yold); + ark_mem->lrw += 2; + ark_mem->liw += 5; /* initialize time values */ - interp_mem->told = ark_mem->tcur; - interp_mem->tnew = ark_mem->tcur; - interp_mem->t_fa = RCONST(0.0); - interp_mem->t_fb = RCONST(0.0); - interp_mem->h = RCONST(0.0); + content->told = ark_mem->tcur; + content->tnew = ark_mem->tcur; + content->h = RCONST(0.0); + + /* signal that fullrhs is required after each step */ + ark_mem->call_fullrhs = SUNTRUE; - return(interp_mem); + return(interp); } /*--------------------------------------------------------------- - arkInterpResize: + arkInterpResize_Hermite: - This routine resizes the internal vectors in an ARKodeInterpMem - structure. + This routine resizes the internal vectors. ---------------------------------------------------------------*/ -int arkInterpResize(void* arkode_mem, ARKodeInterpMem interp_mem, - ARKVecResizeFn resize, void *resize_data, - sunindextype lrw_diff, sunindextype liw_diff, - N_Vector y0) +int arkInterpResize_Hermite(void* arkode_mem, ARKInterp interp, + ARKVecResizeFn resize, void *resize_data, + sunindextype lrw_diff, sunindextype liw_diff, + N_Vector y0) { int ier; ARKodeMem ark_mem; @@ -122,107 +199,133 @@ int arkInterpResize(void* arkode_mem, ARKodeInterpMem interp_mem, ark_mem = (ARKodeMem) arkode_mem; /* resize vectors */ - if (interp_mem == NULL) return(ARK_SUCCESS); - if (interp_mem->fold != NULL) { - ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, - liw_diff, y0, &interp_mem->fold); - if (ier != ARK_SUCCESS) return(ier); - } - if (interp_mem->fnew != NULL) { + if (interp == NULL) return(ARK_SUCCESS); + if (HINT_FOLD(interp) != NULL) { ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, - liw_diff, y0, &interp_mem->fnew); + liw_diff, y0, &HINT_FOLD(interp)); if (ier != ARK_SUCCESS) return(ier); } - if (interp_mem->yold != NULL) { + if (HINT_YOLD(interp) != NULL) { ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, - liw_diff, y0, &interp_mem->yold); + liw_diff, y0, &HINT_YOLD(interp)); if (ier != ARK_SUCCESS) return(ier); } - if (interp_mem->fa != NULL) { + if (HINT_FA(interp) != NULL) { ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, - liw_diff, y0, &interp_mem->fa); + liw_diff, y0, &HINT_FA(interp)); if (ier != ARK_SUCCESS) return(ier); } - if (interp_mem->fb != NULL) { + if (HINT_FB(interp) != NULL) { ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, - liw_diff, y0, &interp_mem->fb); + liw_diff, y0, &HINT_FB(interp)); if (ier != ARK_SUCCESS) return(ier); } - /* update yold with current solution */ - N_VScale(ONE, y0, interp_mem->yold); - - /* update ynew pointer to point to current ark_mem->yn */ - interp_mem->ynew = ark_mem->yn; + /* update ynew and fnew pointers */ + HINT_YNEW(interp) = ark_mem->yn; + HINT_FNEW(interp) = ark_mem->fn; /* reinitialize time values */ - interp_mem->told = ark_mem->tcur; - interp_mem->tnew = ark_mem->tcur; - interp_mem->t_fa = RCONST(0.0); - interp_mem->t_fb = RCONST(0.0); - interp_mem->h = RCONST(0.0); + HINT_TOLD(interp) = ark_mem->tcur; + HINT_TNEW(interp) = ark_mem->tcur; + HINT_H(interp) = RCONST(0.0); return(ARK_SUCCESS); } /*--------------------------------------------------------------- - arkInterpFree: + arkInterpFree_Hermite: - This routine frees an ARKodeInterpMem structure. + This routine frees the Hermite ARKInterp structure. ---------------------------------------------------------------*/ -void arkInterpFree(ARKodeInterpMem *interp_mem) +void arkInterpFree_Hermite(void* arkode_mem, ARKInterp interp) { - if (*interp_mem != NULL) { - if ((*interp_mem)->fold != NULL) N_VDestroy((*interp_mem)->fold); - if ((*interp_mem)->fnew != NULL) N_VDestroy((*interp_mem)->fnew); - if ((*interp_mem)->yold != NULL) N_VDestroy((*interp_mem)->yold); - if ((*interp_mem)->fa != NULL) N_VDestroy((*interp_mem)->fa); - if ((*interp_mem)->fb != NULL) N_VDestroy((*interp_mem)->fb); - free(*interp_mem); + ARKodeMem ark_mem; + + /* access ARKodeMem structure */ + if (arkode_mem == NULL) return; + ark_mem = (ARKodeMem) arkode_mem; + + /* if interpolation structure is NULL, just return */ + if (interp == NULL) return; + + /* free content */ + if (interp->content != NULL) { + if (HINT_FOLD(interp) != NULL) { + arkFreeVec(ark_mem, &(HINT_FOLD(interp))); + HINT_FOLD(interp) = NULL; + } + if (HINT_YOLD(interp) != NULL) { + arkFreeVec(ark_mem, &(HINT_YOLD(interp))); + HINT_YOLD(interp) = NULL; + } + if (HINT_FA(interp) != NULL) { + arkFreeVec(ark_mem, &(HINT_FA(interp))); + HINT_FA(interp) = NULL; + } + if (HINT_FB(interp) != NULL) { + arkFreeVec(ark_mem, &(HINT_FB(interp))); + HINT_FB(interp) = NULL; + } + + /* update work space sizes */ + ark_mem->lrw -= 2; + ark_mem->liw -= 5; + + free(interp->content); + interp->content = NULL; + } + + /* free ops and interpolation structures */ + if (interp->ops) { + free(interp->ops); + interp->ops = NULL; } + free(interp); + interp = NULL; + + return; } /*--------------------------------------------------------------- - arkPrintInterpMem + arkInterpPrintMem_Hermite - This routine outputs the temporal interpolation memory structure - to a specified file pointer. + This routine outputs the Hermite temporal interpolation memory + structure to a specified file pointer. ---------------------------------------------------------------*/ -void arkPrintInterpMem(ARKodeInterpMem interp_mem, FILE *outfile) +void arkInterpPrintMem_Hermite(ARKInterp interp, FILE *outfile) { - if (interp_mem != NULL) { - fprintf(outfile, "ark_interp: order = %d\n", interp_mem->order); - fprintf(outfile, "ark_interp: told = %"RSYM"\n", interp_mem->told); - fprintf(outfile, "ark_interp: tnew = %"RSYM"\n", interp_mem->tnew); - fprintf(outfile, "ark_interp: t_fa = %"RSYM"\n", interp_mem->t_fa); - fprintf(outfile, "ark_interp: t_fb = %"RSYM"\n", interp_mem->t_fb); - fprintf(outfile, "ark_interp: h = %"RSYM"\n", interp_mem->h); + if (interp != NULL) { + fprintf(outfile, "arkode_interp (Hermite): degree = %d\n", HINT_DEGREE(interp)); + fprintf(outfile, "arkode_interp (Hermite): told = %"RSYM"\n", HINT_TOLD(interp)); + fprintf(outfile, "arkode_interp (Hermite): tnew = %"RSYM"\n", HINT_TNEW(interp)); + fprintf(outfile, "arkode_interp (Hermite): h = %"RSYM"\n", HINT_H(interp)); #ifdef DEBUG_OUTPUT - if (interp_mem->fold != NULL) { - fprintf(outfile, "ark_interp: fold:\n"); - N_VPrint_Serial(interp_mem->fold); + if (HINT_FOLD(interp) != NULL) { + fprintf(outfile, "arkode_interp (Hermite): fold:\n"); + N_VPrint_Serial(HINT_FOLD(interp)); } - if (interp_mem->fnew != NULL) { - fprintf(outfile, "ark_interp: fnew:\n"); - N_VPrint_Serial(interp_mem->fnew); + if (HINT_FNEW(interp) != NULL) { + fprintf(outfile, "arkode_interp (Hermite): fnew:\n"); + N_VPrint_Serial(HINT_FNEW(interp)); } - if (interp_mem->yold != NULL) { - fprintf(outfile, "ark_interp: yold:\n"); - N_VPrint_Serial(interp_mem->yold); + if (HINT_YOLD(interp) != NULL) { + fprintf(outfile, "arkode_interp (Hermite): yold:\n"); + N_VPrint_Serial(HINT_YOLD(interp)); } - if (interp_mem->ynew != NULL) { - fprintf(outfile, "ark_interp: ynew:\n"); - N_VPrint_Serial(interp_mem->ynew); + if (HINT_YNEW(interp) != NULL) { + fprintf(outfile, "arkode_interp (Hermite): ynew:\n"); + N_VPrint_Serial(HINT_YNEW(interp)); } - if (interp_mem->fa != NULL) { - fprintf(outfile, "ark_interp: fa:\n"); - N_VPrint_Serial(interp_mem->fa); + if (HINT_FA(interp) != NULL) { + fprintf(outfile, "arkode_interp (Hermite): fa:\n"); + N_VPrint_Serial(HINT_FA(interp)); } - if (interp_mem->fb != NULL) { - fprintf(outfile, "ark_interp: fb:\n"); - N_VPrint_Serial(interp_mem->fb); + if (HINT_FB(interp) != NULL) { + fprintf(outfile, "arkode_interp (Hermite): fb:\n"); + N_VPrint_Serial(HINT_FB(interp)); } #endif } @@ -230,42 +333,111 @@ void arkPrintInterpMem(ARKodeInterpMem interp_mem, FILE *outfile) /*--------------------------------------------------------------- - arkInterpInit + arkInterpSetDegree_Hermite + + This routine sets a supplied interpolation degree. If the + argument is positive, then we require that + 0 <= degree <= ARK_INTERP_MAX_DEGREE + and use this value as the user-specified (or default) degree. + + If the argument is negative, then we assume that this has been + called by a time-step module to limit the interpolant degree + based on the temporal method order. In this case we set the + Hermite polynomial degree to be the minimum of (-degree), + ARK_INTERP_MAX_DEGREE, and the previously-set value [i.e., in + case the user has already specified use of a lower-degree + polynomial]. + + Return values: + ARK_MEM_NULL -- if either arkode_mem or interp are NULL + ARK_ILL_INPUT -- if the input is outside of allowable bounds + ARK_INTERP_FAIL -- if the interpolation module has already + been initialized, + ARK_SUCCESS -- successful completion. + ---------------------------------------------------------------*/ +int arkInterpSetDegree_Hermite(void* arkode_mem, ARKInterp interp, + int degree) +{ + ARKodeMem ark_mem; + + /* access ARKodeMem structure */ + if (arkode_mem == NULL) return(ARK_MEM_NULL); + ark_mem = (ARKodeMem) arkode_mem; + + /* if this degree is already stored, just return */ + if (abs(degree) == HINT_DEGREE(interp)) return(ARK_SUCCESS); + + /* on positive degree, check for allowable value and overwrite stored degree */ + if (degree >= 0) { + if (degree > ARK_INTERP_MAX_DEGREE) { + arkProcessError(ark_mem, ARK_INTERP_FAIL, "ARKode", + "arkInterpSetDegree_Hermite", + "Illegal degree specified."); + return(ARK_ILL_INPUT); + } + + HINT_DEGREE(interp) = degree; + return(ARK_SUCCESS); + } + + /* on negative degree, check for allowable value and update stored degree */ + degree = -degree; + if (degree > ARK_INTERP_MAX_DEGREE) degree = ARK_INTERP_MAX_DEGREE; + HINT_DEGREE(interp) = SUNMIN(HINT_DEGREE(interp), degree); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkInterpInit_Hermite This routine performs the following steps: 1. Sets tnew and told to the input time - 1. Copies ark_mem->yn into yold - 2. Calls the full RHS routine to fill fnew - 3. Copies fnew into fold + 2. Allocates any missing/needed N_Vector storage (for reinit) + 3. Copies ark_mem->yn into yold + 4. Calls the full RHS routine to fill fnew + 5. Copies fnew into fold ---------------------------------------------------------------*/ -int arkInterpInit(void* arkode_mem, ARKodeInterpMem interp, - realtype tnew) +int arkInterpInit_Hermite(void* arkode_mem, ARKInterp interp, + realtype tnew) { - int ier; ARKodeMem ark_mem; /* access ARKodeMem structure */ if (arkode_mem == NULL) return(ARK_MEM_NULL); ark_mem = (ARKodeMem) arkode_mem; - /* return with success if no interpolation structure is allocated */ - if (interp == NULL) return(ARK_SUCCESS); - /* initialize time values */ - interp->told = tnew; - interp->tnew = tnew; - interp->h = RCONST(0.0); + HINT_TOLD(interp) = tnew; + HINT_TNEW(interp) = tnew; + HINT_H(interp) = RCONST(0.0); + + /* allocate vectors based on interpolant degree */ + if (HINT_FOLD(interp) == NULL) + if (!arkAllocVec(ark_mem, ark_mem->yn, &(HINT_FOLD(interp)))) { + arkInterpFree(ark_mem, interp); return(ARK_MEM_FAIL); + } + if (HINT_YOLD(interp) == NULL) + if (!arkAllocVec(ark_mem, ark_mem->yn, &(HINT_YOLD(interp)))) { + arkInterpFree(ark_mem, interp); return(ARK_MEM_FAIL); + } + if ((HINT_DEGREE(interp) > 3) && (HINT_FA(interp) == NULL)) { + if (!arkAllocVec(ark_mem, ark_mem->yn, &(HINT_FA(interp)))) { + arkInterpFree(ark_mem, interp); return(ARK_MEM_FAIL); + } + } + if ((HINT_DEGREE(interp) > 4) && (HINT_FB(interp) == NULL)) { + if (!arkAllocVec(ark_mem, ark_mem->yn, &(HINT_FB(interp)))) { + arkInterpFree(ark_mem, interp); return(ARK_MEM_FAIL); + } + } /* copy current solution into yold */ - N_VScale(ONE, ark_mem->yn, interp->yold); - - /* fill fnew */ - ier = ark_mem->step_fullrhs(ark_mem, tnew, interp->ynew, - interp->fnew, 0); - if (ier != 0) return(ARK_RHSFUNC_FAIL); + N_VScale(ONE, ark_mem->yn, HINT_YOLD(interp)); /* copy fnew into fold */ - N_VScale(ONE, interp->fnew, interp->fold); + N_VScale(ONE, HINT_FNEW(interp), HINT_FOLD(interp)); /* return with success */ return(ARK_SUCCESS); @@ -273,54 +445,27 @@ int arkInterpInit(void* arkode_mem, ARKodeInterpMem interp, /*--------------------------------------------------------------- - arkInterpUpdate + arkInterpUpdate_Hermite - This routine performs the following steps: - 1. Copies ynew into yold, and swaps the fnew <-> fold pointers, - so that yold and fold contain the previous values - 2. Calls the full RHS routine to fill fnew, using ark_mem->ycur - for the time-evolved solution (since ynew==ark_mem->yn - has not been updated yet). - - Note: if forceRHS==SUNTRUE, then any previously-stored RHS - function data in the time step module is suspect, and all RHS - function(s) require recomputation; we therefore signal the - fullrhs function with a corresponding flag. + This routine copies ynew into yold, and fnew into fold, so that + yold and fold contain the previous values. ---------------------------------------------------------------*/ -int arkInterpUpdate(void* arkode_mem, ARKodeInterpMem interp, - realtype tnew, booleantype forceRHS) +int arkInterpUpdate_Hermite(void* arkode_mem, ARKInterp interp, realtype tnew) { - int ier, mode; - N_Vector tempvec; ARKodeMem ark_mem; /* access ARKodeMem structure */ if (arkode_mem == NULL) return(ARK_MEM_NULL); ark_mem = (ARKodeMem) arkode_mem; - /* return with success if no interpolation structure is allocated */ - if (interp == NULL) return(ARK_SUCCESS); - - /* copy ynew into yold */ - N_VScale(ONE, interp->ynew, interp->yold); - - /* swap fold & fnew N_Vector pointers */ - tempvec = interp->fold; - interp->fold = interp->fnew; - interp->fnew = tempvec; + /* copy ynew and fnew into yold and fold, respectively */ + N_VScale(ONE, HINT_YNEW(interp), HINT_YOLD(interp)); + N_VScale(ONE, HINT_FNEW(interp), HINT_FOLD(interp)); /* update time values */ - interp->told = interp->tnew; - interp->tnew = tnew; - interp->h = ark_mem->h; - - /* determine mode for calling fullrhs */ - mode = (forceRHS) ? 0 : 1; - - /* fill fnew */ - ier = ark_mem->step_fullrhs(ark_mem, tnew, ark_mem->ycur, - interp->fnew, mode); - if (ier != 0) return(ARK_RHSFUNC_FAIL); + HINT_TOLD(interp) = HINT_TNEW(interp); + HINT_TNEW(interp) = tnew; + HINT_H(interp) = ark_mem->h; /* return with success */ return(ARK_SUCCESS); @@ -328,7 +473,7 @@ int arkInterpUpdate(void* arkode_mem, ARKodeInterpMem interp, /*--------------------------------------------------------------- - arkInterpEvaluate + arkInterpEvaluate_Hermite This routine evaluates a temporal interpolation/extrapolation based on the data in the interpolation structure: @@ -337,9 +482,9 @@ int arkInterpUpdate(void* arkode_mem, ARKodeInterpMem interp, fold = f(told, yold) fnew = f(told, ynew) This typically consists of using a cubic Hermite interpolating - formula with this data. If greater polynomial order than 3 is - requested, then we can bootstrap up to a 5th-order accurate - interpolant. For lower order interpolants than cubic, we use: + formula with this data. If greater polynomial degree than 3 is + requested, then we can bootstrap up to a 5th-order interpolant. + For lower order interpolants than cubic, we use: {yold,ynew,fnew} for quadratic {yold,ynew} for linear {0.5*(yold+ynew)} for constant. @@ -348,21 +493,23 @@ int arkInterpUpdate(void* arkode_mem, ARKodeInterpMem interp, itself, losing one order per derivative. We will provide derivatives up to d = min(5,q). - The input 'tau' specifies the time at which to return derivative - information, the formula is - t = told + tau*(tnew-told), - where h = tnew-told, i.e. values 0h; + h = HINT_H(interp); h2 = h*h; h3 = h*h2; h4 = h*h3; h5 = h*h4; /* determine polynomial order q */ - q = SUNMAX(order, 0); /* respect lower bound */ - q = SUNMIN(q, 5); /* respect max possible */ + q = SUNMAX(order, 0); /* respect lower bound */ + q = SUNMIN(q, HINT_DEGREE(interp)); /* respect max possible */ /* error on illegal d */ if (d < 0) { arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", - "arkInterpEvaluate", "Requested illegal derivative."); + "arkInterpEvaluate_Hermite", + "Requested illegal derivative."); return (ARK_ILL_INPUT); } @@ -402,7 +550,7 @@ int arkInterpEvaluate(void* arkode_mem, ARKodeInterpMem interp, switch (q) { case(0): /* constant interpolant, yout = 0.5*(yn+yp) */ - N_VLinearSum(HALF, interp->yold, HALF, interp->ynew, yout); + N_VLinearSum(HALF, HINT_YOLD(interp), HALF, HINT_YNEW(interp), yout); break; case(1): /* linear interpolant */ @@ -413,7 +561,7 @@ int arkInterpEvaluate(void* arkode_mem, ARKodeInterpMem interp, a0 = -ONE/h; a1 = ONE/h; } - N_VLinearSum(a0, interp->yold, a1, interp->ynew, yout); + N_VLinearSum(a0, HINT_YOLD(interp), a1, HINT_YNEW(interp), yout); break; case(2): /* quadratic interpolant */ @@ -430,9 +578,9 @@ int arkInterpEvaluate(void* arkode_mem, ARKodeInterpMem interp, a[1] = -TWO/h/h; a[2] = TWO/h; } - X[0] = interp->yold; - X[1] = interp->ynew; - X[2] = interp->fnew; + X[0] = HINT_YOLD(interp); + X[1] = HINT_YNEW(interp); + X[2] = HINT_FNEW(interp); retval = N_VLinearCombination(3, a, X, yout); if (retval != 0) return(ARK_VECTOROP_ERR); break; @@ -459,10 +607,10 @@ int arkInterpEvaluate(void* arkode_mem, ARKodeInterpMem interp, a[2] = SIX/h2; a[3] = SIX/h2; } - X[0] = interp->yold; - X[1] = interp->ynew; - X[2] = interp->fold; - X[3] = interp->fnew; + X[0] = HINT_YOLD(interp); + X[1] = HINT_YNEW(interp); + X[2] = HINT_FOLD(interp); + X[3] = HINT_FNEW(interp); retval = N_VLinearCombination(4, a, X, yout); if (retval != 0) return(ARK_VECTOROP_ERR); break; @@ -475,8 +623,8 @@ int arkInterpEvaluate(void* arkode_mem, ARKodeInterpMem interp, if (retval != 0) return(ARK_RHSFUNC_FAIL); /* second, evaluate RHS at tau=-1/3, storing the result in fa */ - tval = interp->tnew - h/THREE; - retval = ark_mem->step_fullrhs(ark_mem, tval, yout, interp->fa, 2); + tval = HINT_TNEW(interp) - h/THREE; + retval = ark_mem->step_fullrhs(ark_mem, tval, yout, HINT_FA(interp), 2); if (retval != 0) return(ARK_RHSFUNC_FAIL); /* evaluate desired function */ @@ -511,11 +659,11 @@ int arkInterpEvaluate(void* arkode_mem, ARKodeInterpMem interp, a[3] = ZERO; a[4] = -RCONST(162.0)/h3; } - X[0] = interp->yold; - X[1] = interp->ynew; - X[2] = interp->fold; - X[3] = interp->fnew; - X[4] = interp->fa; + X[0] = HINT_YOLD(interp); + X[1] = HINT_YNEW(interp); + X[2] = HINT_FOLD(interp); + X[3] = HINT_FNEW(interp); + X[4] = HINT_FA(interp); retval = N_VLinearCombination(5, a, X, yout); if (retval != 0) return(ARK_VECTOROP_ERR); break; @@ -528,8 +676,8 @@ int arkInterpEvaluate(void* arkode_mem, ARKodeInterpMem interp, if (retval != 0) return(ARK_RHSFUNC_FAIL); /* second, evaluate RHS at tau=-1/3, storing the result in fa */ - tval = interp->tnew - h/THREE; - retval = ark_mem->step_fullrhs(ark_mem, tval, yout, interp->fa, 2); + tval = HINT_TNEW(interp) - h/THREE; + retval = ark_mem->step_fullrhs(ark_mem, tval, yout, HINT_FA(interp), 2); if (retval != 0) return(ARK_RHSFUNC_FAIL); /* third, evaluate quartic interpolant at tau=-2/3 */ @@ -538,8 +686,8 @@ int arkInterpEvaluate(void* arkode_mem, ARKodeInterpMem interp, if (retval != 0) return(ARK_RHSFUNC_FAIL); /* fourth, evaluate RHS at tau=-2/3, storing the result in fb */ - tval = interp->tnew - h*TWO/THREE; - retval = ark_mem->step_fullrhs(ark_mem, tval, yout, interp->fb, 2); + tval = HINT_TNEW(interp) - h*TWO/THREE; + retval = ark_mem->step_fullrhs(ark_mem, tval, yout, HINT_FB(interp), 2); if (retval != 0) return(ARK_RHSFUNC_FAIL); /* evaluate desired function */ @@ -586,18 +734,19 @@ int arkInterpEvaluate(void* arkode_mem, ARKodeInterpMem interp, a[4] = RCONST(2430.0)/h4; a[5] = a[4]; } - X[0] = interp->yold; - X[1] = interp->ynew; - X[2] = interp->fold; - X[3] = interp->fnew; - X[4] = interp->fa; - X[5] = interp->fb; + X[0] = HINT_YOLD(interp); + X[1] = HINT_YNEW(interp); + X[2] = HINT_FOLD(interp); + X[3] = HINT_FNEW(interp); + X[4] = HINT_FA(interp); + X[5] = HINT_FB(interp); retval = N_VLinearCombination(6, a, X, yout); if (retval != 0) return(ARK_VECTOROP_ERR); break; default: - arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkInterpEvaluate", + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkInterpEvaluate_Hermite", "Illegal polynomial order"); return (ARK_ILL_INPUT); } @@ -606,6 +755,623 @@ int arkInterpEvaluate(void* arkode_mem, ARKodeInterpMem interp, } + + +/*--------------------------------------------------------------- + Section III: Lagrange interpolation module implementation + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + arkInterpCreate_Lagrange: + + This routine creates an ARKInterp structure, through + cloning an input template N_Vector. This returns a non-NULL + structure if no errors occurred, or a NULL value otherwise. + ---------------------------------------------------------------*/ +ARKInterp arkInterpCreate_Lagrange(void* arkode_mem, int degree) +{ + ARKInterp interp; + ARKInterpContent_Lagrange content; + ARKInterpOps ops; + ARKodeMem ark_mem; + + /* access ARKodeMem structure */ + if (arkode_mem == NULL) return(NULL); + ark_mem = (ARKodeMem) arkode_mem; + + /* check for valid degree */ + if (degree < 0 || degree > ARK_INTERP_MAX_DEGREE) return(NULL); + + /* allocate overall structure */ + interp = NULL; + interp = (ARKInterp) malloc(sizeof *interp); + if (interp == NULL) return(NULL); + + /* allocate ops structure and set entries */ + ops = NULL; + ops = (ARKInterpOps) malloc(sizeof *ops); + if (ops == NULL) { free(interp); return(NULL); } + ops->resize = arkInterpResize_Lagrange; + ops->free = arkInterpFree_Lagrange; + ops->print = arkInterpPrintMem_Lagrange; + ops->setdegree = arkInterpSetDegree_Lagrange; + ops->init = arkInterpInit_Lagrange; + ops->update = arkInterpUpdate_Lagrange; + ops->evaluate = arkInterpEvaluate_Lagrange; + + /* create content, and initialize everything to zero/NULL */ + content = NULL; + content = (ARKInterpContent_Lagrange) malloc(sizeof *content); + if (content == NULL) { free(ops); free(interp); return(NULL); } + memset(content, 0, sizeof(struct _ARKInterpContent_Lagrange)); + + /* attach ops and content structures to overall structure */ + interp->ops = ops; + interp->content = content; + + /* fill content */ + + /* maximum/current history length */ + content->nmax = SUNMIN(degree+1, ARK_INTERP_MAX_DEGREE+1); /* respect maximum possible */ + content->nmaxalloc = 0; + content->nhist = 0; + + /* initialize time/solution history arrays to NULL */ + content->thist = NULL; + content->yhist = NULL; + + /* initial t roundoff value */ + content->tround = FUZZ_FACTOR*ark_mem->uround; + + /* update workspace sizes */ + ark_mem->lrw += content->nmax + 1; + ark_mem->liw += content->nmax + 2; + + /* signal that fullrhs is not required after each step */ + ark_mem->call_fullrhs = SUNFALSE; + + return(interp); +} + + +/*--------------------------------------------------------------- + arkInterpResize_Lagrange: + + This routine resizes the internal vectors. + ---------------------------------------------------------------*/ +int arkInterpResize_Lagrange(void* arkode_mem, ARKInterp I, + ARKVecResizeFn resize, void *resize_data, + sunindextype lrw_diff, sunindextype liw_diff, + N_Vector y0) +{ + int ier, i; + ARKodeMem ark_mem; + + /* access ARKodeMem structure */ + if (arkode_mem == NULL) return(ARK_MEM_NULL); + ark_mem = (ARKodeMem) arkode_mem; + + /* resize vectors */ + if (I == NULL) return(ARK_SUCCESS); + if (LINT_YHIST(I) != NULL) { + for (i=0; icontent != NULL) { + if (LINT_YHIST(I) != NULL) { + for (i=0; ilrw -= (LINT_NMAX(I) + 1); + ark_mem->liw -= (LINT_NMAX(I) + 2); + + free(I->content); + I->content = NULL; + } + + /* free ops and interpolation structures */ + if (I->ops) { + free(I->ops); + I->ops = NULL; + } + free(I); + I = NULL; + + return; +} + + +/*--------------------------------------------------------------- + arkInterpPrintMem_Lagrange + + This routine outputs the Lagrange temporal interpolation memory + structure to a specified file pointer. + ---------------------------------------------------------------*/ +void arkInterpPrintMem_Lagrange(ARKInterp I, FILE *outfile) +{ + int i; + if (I != NULL) { + fprintf(outfile, "arkode_interp (Lagrange): nmax = %i\n", LINT_NMAX(I)); + fprintf(outfile, "arkode_interp (Lagrange): nhist = %i\n", LINT_NHIST(I)); + if (LINT_THIST(I) != NULL) { + fprintf(outfile, "arkode_interp (Lagrange): thist ="); + for (i=0; i= 0) { + if (degree > ARK_INTERP_MAX_DEGREE) { + arkProcessError(ark_mem, ARK_INTERP_FAIL, "ARKode", + "arkInterpSetDegree_Lagrange", + "Illegal degree specified."); + return(ARK_ILL_INPUT); + } + + LINT_NMAX(I) = degree+1; + return(ARK_SUCCESS); + } + + /* on negative degree, check for allowable value and update stored degree */ + degree = -degree; + if (degree > ARK_INTERP_MAX_DEGREE) degree = ARK_INTERP_MAX_DEGREE; + LINT_NMAX(I) = SUNMIN(LINT_NMAX(I), degree+1); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkInterpInit_Lagrange + + This routine performs the following steps: + 1. allocates any missing/needed (t,y) history arrays + 2. zeros out stored (t,y) history + 3. copies current (t,y) from main ARKode memory into history + 4. updates the 'active' history counter to 1 + ---------------------------------------------------------------*/ +int arkInterpInit_Lagrange(void* arkode_mem, ARKInterp I, + realtype tnew) +{ + int i; + ARKodeMem ark_mem; + + /* access ARKodeMem structure */ + if (arkode_mem == NULL) return(ARK_MEM_NULL); + ark_mem = (ARKodeMem) arkode_mem; + + /* check if storage has increased since the last init */ + if (LINT_NMAX(I) > LINT_NMAXALLOC(I)) { + if (LINT_THIST(I) != NULL) { + free(LINT_THIST(I)); + LINT_THIST(I) = NULL; + } + if (LINT_YHIST(I) != NULL) { + for (i=0; iyn, &(LINT_YJ(I,i)))) { + arkInterpFree(ark_mem, I); return(ARK_MEM_FAIL); + } + } + } + + /* update allocated size if necesary */ + if (LINT_NMAX(I) > LINT_NMAXALLOC(I)) + LINT_NMAXALLOC(I) = LINT_NMAX(I); + + /* zero out history (to be safe) */ + for (i=0; iyn, LINT_YJ(I,0)); + LINT_NHIST(I) = 1; + + /* return with success */ + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkInterpUpdate_Lagrange + + If the current time is 'different enough' from the stored + values, then this routine performs the following steps: + 1. shifts the t-history array values, and prepends the current + time + 2. shifts the y-history pointers, and copies the current state + into the first history vector + Otherwise it just returns with success. + ---------------------------------------------------------------*/ +int arkInterpUpdate_Lagrange(void* arkode_mem, ARKInterp I, realtype tnew) +{ + int i; + ARKodeMem ark_mem; + realtype tdiff; + N_Vector ytmp; + int nhist, nmax; + realtype *thist; + N_Vector *yhist; + + /* access ARKodeMem structure */ + if (arkode_mem == NULL) return(ARK_MEM_NULL); + ark_mem = (ARKodeMem) arkode_mem; + + /* set readability shortcuts */ + nhist = LINT_NHIST(I); + nmax = LINT_NMAX(I); + thist = LINT_THIST(I); + yhist = LINT_YHIST(I); + + /* update t roundoff value */ + LINT_TROUND(I) = FUZZ_FACTOR*ark_mem->uround * + (SUNRabs(ark_mem->tcur) + SUNRabs(ark_mem->h)); + + /* determine if tnew differs sufficiently from stored values */ + tdiff = SUNRabs(tnew - thist[0]); + for (i=1; i0; i--) { + thist[i] = thist[i-1]; + yhist[i] = yhist[i-1]; + } + yhist[0] = ytmp; + + /* copy tnew and ycur into first entry of history arrays */ + thist[0] = tnew; + N_VScale(ONE, ark_mem->ycur, yhist[0]); + + /* update 'nhist' (first few steps) */ + LINT_NHIST(I) = nhist = SUNMIN(nhist+1, nmax); + + /* return with success */ + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkInterpEvaluate_Lagrange + + This routine evaluates a temporal interpolation/extrapolation + based on the stored solution data in the interpolation structure. + + Derivatives have lower accuracy than the interpolant + itself, losing one order per derivative. This module can provide + up to 3rd derivatives. + + The input 'tau' specifies the time at which to evaluate the + Lagrange polynomial. The formula for tau is defined using the + most-recently-completed solution interval [t1,t0], and is + given by: + t = t0 + tau*(t0-t1), + here t0 and t1 are the 2 most-recent entries in the 'thist' + array within the interpolation structure. Thus values + -(nhist-1) <= tau < = 0 + provide interpolation, others result in extrapolation (assuming + fixed step sizes, otherwise the stated lower bound is only + approximate). + ---------------------------------------------------------------*/ +int arkInterpEvaluate_Lagrange(void* arkode_mem, ARKInterp I, + realtype tau, int deriv, int degree, + N_Vector yout) +{ + /* local variables */ + int q, retval, i, j; + realtype tval; + realtype a[6]; + N_Vector X[6]; + ARKodeMem ark_mem; + int nhist; + realtype *thist; + N_Vector *yhist; + + /* access ARKodeMem structure */ + if (arkode_mem == NULL) return(ARK_MEM_NULL); + ark_mem = (ARKodeMem) arkode_mem; + + /* set readability shortcuts */ + nhist = LINT_NHIST(I); + thist = LINT_THIST(I); + yhist = LINT_YHIST(I); + + /* determine polynomial degree q */ + q = SUNMAX(degree, 0); /* respect lower bound */ + q = SUNMIN(q, nhist-1); /* respect max possible */ + + /* error on illegal deriv */ + if ((deriv < 0) || (deriv > 3)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkInterpEvaluate_Lagrange", + "Requested illegal derivative."); + return (ARK_ILL_INPUT); + } + + /* if deriv is too high, just return zeros */ + if (deriv > q) { + N_VConst(ZERO, yout); + return(ARK_SUCCESS); + } + + /* if constant interpolant is requested, just return ynew */ + if (q == 0) { + N_VScale(ONE, yhist[0], yout); + return(ARK_SUCCESS); + } + + /* convert from tau back to t (both tnew and told are valid since q>0 => NHIST>1) */ + tval = thist[0] + tau*(thist[0]-thist[1]); + + /* linear interpolant */ + if (q == 1) { + if (deriv == 0) { + a[0] = LBasis(I,0,tval); + a[1] = LBasis(I,1,tval); + } else { /* deriv == 1 */ + a[0] = LBasisD(I,0,tval); + a[1] = LBasisD(I,1,tval); + } + N_VLinearSum(a[0], yhist[0], a[1], yhist[1], yout); + return(ARK_SUCCESS); + } + + /* higher-degree interpolant */ + /* initialize arguments for N_VLinearCombination */ + for (i=0; i #include +#include "arkode_impl.h" #ifdef __cplusplus /* wrapper to enable C++ usage */ extern "C" { @@ -29,24 +30,22 @@ extern "C" { ARKode temporal interpolation constants ===============================================================*/ -#define QDENSE_DEF 3 /* default dense output order */ -#define ARK_INTERP_LRW 2 /* real workspace size */ -#define ARK_INTERP_LIW 5 /* int/ptr workspace size */ +/* Numeric constants */ +#define FOURTH RCONST(0.25) +#define THREE RCONST(3.0) +#define SIX RCONST(6.0) +#define TWELVE RCONST(12.0) + /*=============================================================== - ARKode Temporal Interpolation Data Structure + ARKode Hermite Temporal Interpolation Data Structure ===============================================================*/ -/*--------------------------------------------------------------- - Types : struct ARKodeInterpMemRec, ARKodeInterpMem ------------------------------------------------------------------ - The type ARKodeInterpMem is type pointer to struct - ARKodeInterpMemRec. This structure contains fields to - perform temporal interpolation. ----------------------------------------------------------------*/ -typedef struct ARKodeInterpMemRec { +/* Hermite interpolation structure */ +struct _ARKInterpContent_Hermite { + int degree; /* maximum interpolant degree to use */ N_Vector fold; /* f(t,y) at beginning of last successful step */ N_Vector fnew; /* f(t,y) at end of last successful step */ N_Vector yold; /* y at beginning of last successful step */ @@ -55,32 +54,102 @@ typedef struct ARKodeInterpMemRec { N_Vector fb; /* f(t,y) used in higher-order interpolation */ realtype told; /* t at beginning of last successful step */ realtype tnew; /* t at end of last successful step */ - realtype t_fa; /* t when fa was last evaluated */ - realtype t_fb; /* t when fb was last evaluated */ realtype h; /* last successful step size */ - int order; /* interpolation order */ +}; + +typedef struct _ARKInterpContent_Hermite *ARKInterpContent_Hermite; + + +/* Hermite structure accessor macros */ + +#define HINT_CONTENT(I) ( (ARKInterpContent_Hermite)(I->content) ) +#define HINT_DEGREE(I) ( HINT_CONTENT(I)->degree ) +#define HINT_FOLD(I) ( HINT_CONTENT(I)->fold ) +#define HINT_FNEW(I) ( HINT_CONTENT(I)->fnew ) +#define HINT_YOLD(I) ( HINT_CONTENT(I)->yold ) +#define HINT_YNEW(I) ( HINT_CONTENT(I)->ynew ) +#define HINT_FA(I) ( HINT_CONTENT(I)->fa ) +#define HINT_FB(I) ( HINT_CONTENT(I)->fb ) +#define HINT_TOLD(I) ( HINT_CONTENT(I)->told ) +#define HINT_TNEW(I) ( HINT_CONTENT(I)->tnew ) +#define HINT_H(I) ( HINT_CONTENT(I)->h ) + + +/* Hermite structure operations */ + +ARKInterp arkInterpCreate_Hermite(void* arkode_mem, int degree); + +int arkInterpResize_Hermite(void* arkode_mem, ARKInterp interp, + ARKVecResizeFn resize, void *resize_data, + sunindextype lrw_diff, sunindextype liw_diff, + N_Vector tmpl); +void arkInterpFree_Hermite(void* arkode_mem, ARKInterp interp); +void arkInterpPrintMem_Hermite(ARKInterp interp, FILE *outfile); +int arkInterpSetDegree_Hermite(void *arkode_mem, ARKInterp interp, int degree); +int arkInterpInit_Hermite(void* arkode_mem, ARKInterp interp, + realtype tnew); +int arkInterpUpdate_Hermite(void* arkode_mem, ARKInterp interp, realtype tnew); +int arkInterpEvaluate_Hermite(void* arkode_mem, ARKInterp interp, + realtype tau, int d, int order, N_Vector yout); + + -} *ARKodeInterpMem; /*=============================================================== - ARKode Temporal Interpolation Routines -===============================================================*/ - -ARKodeInterpMem arkInterpCreate(void* arkode_mem); -int arkInterpResize(void* arkode_mem, ARKodeInterpMem interp_mem, - ARKVecResizeFn resize, void *resize_data, - sunindextype lrw_diff, sunindextype liw_diff, - N_Vector tmpl); -void arkInterpFree(ARKodeInterpMem *interp_mem); -void arkPrintInterpMem(ARKodeInterpMem interp_mem, FILE *outfile); -int arkInterpInit(void* arkode_mem, ARKodeInterpMem interp_mem, - realtype tnew); -int arkInterpUpdate(void* arkode_mem, ARKodeInterpMem interp_mem, - realtype tnew, booleantype forceRHS); -int arkInterpEvaluate(void* arkode_mem, ARKodeInterpMem interp_mem, - realtype tau, int d, int order, N_Vector yout); + ARKode Lagrange Temporal Interpolation Data Structure + ===============================================================*/ + +/* Lagrange interpolation structure */ + +struct _ARKInterpContent_Lagrange { + int nmax; /* number of previous solutions to use */ + int nmaxalloc; /* vectors allocated for previous solutions */ + N_Vector *yhist; /* previous solution vectors */ + realtype *thist; /* 't' values associated with yhist */ + int nhist; /* number of 'active' vectors in yhist */ + realtype tround; /* unit roundoff for 't' values */ +}; + +typedef struct _ARKInterpContent_Lagrange *ARKInterpContent_Lagrange; + + +/* Lagrange structure accessor macros */ + +#define LINT_CONTENT(I) ( (ARKInterpContent_Lagrange)(I->content) ) +#define LINT_NMAX(I) ( LINT_CONTENT(I)->nmax ) +#define LINT_NMAXALLOC(I) ( LINT_CONTENT(I)->nmaxalloc ) +#define LINT_YHIST(I) ( LINT_CONTENT(I)->yhist ) +#define LINT_THIST(I) ( LINT_CONTENT(I)->thist ) +#define LINT_YJ(I,j) ( (LINT_YHIST(I))[j] ) +#define LINT_TJ(I,j) ( (LINT_THIST(I))[j] ) +#define LINT_NHIST(I) ( LINT_CONTENT(I)->nhist ) +#define LINT_TROUND(I) ( LINT_CONTENT(I)->tround ) + + +/* Lagrange structure operations */ + +ARKInterp arkInterpCreate_Lagrange(void* arkode_mem, int degree); + +int arkInterpResize_Lagrange(void* arkode_mem, ARKInterp interp, + ARKVecResizeFn resize, void *resize_data, + sunindextype lrw_diff, sunindextype liw_diff, + N_Vector tmpl); +void arkInterpFree_Lagrange(void* arkode_mem, ARKInterp interp); +void arkInterpPrintMem_Lagrange(ARKInterp interp, FILE *outfile); +int arkInterpSetDegree_Lagrange(void *arkode_mem, ARKInterp interp, int degree); +int arkInterpInit_Lagrange(void* arkode_mem, ARKInterp interp, + realtype tnew); +int arkInterpUpdate_Lagrange(void* arkode_mem, ARKInterp interp, realtype tnew); +int arkInterpEvaluate_Lagrange(void* arkode_mem, ARKInterp interp, + realtype tau, int d, int order, N_Vector yout); + +/* Lagrange structure utility routines */ +realtype LBasis(ARKInterp interp, int idx, realtype t); +realtype LBasisD(ARKInterp interp, int idx, realtype t); +realtype LBasisD2(ARKInterp interp, int idx, realtype t); +realtype LBasisD3(ARKInterp interp, int idx, realtype t); #ifdef __cplusplus } diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_io.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_io.c index 8c2a46640..63d676293 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_io.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_io.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -22,6 +22,7 @@ #include #include "arkode_impl.h" +#include "arkode_interp_impl.h" #include #include @@ -43,85 +44,195 @@ change problem-defining function pointers fe and fi or user_data pointer. Also leaves alone any data structures/options related to root-finding (those can be reset - using ARKodeRootInit). + using ARKodeRootInit) or post-processing a step (ProcessStep). ---------------------------------------------------------------*/ -int arkSetDefaults(ARKodeMem ark_mem) +int arkSetDefaults(void *arkode_mem) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetDefaults", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; /* Set default values for integrator optional inputs */ - ark_mem->dense_q = QDENSE_DEF; /* dense output order */ - ark_mem->fixedstep = SUNFALSE; /* default to use adaptive steps */ - ark_mem->reltol = 1.e-4; /* relative tolerance */ - ark_mem->itol = ARK_SS; /* scalar-scalar solution tolerances */ - ark_mem->ritol = ARK_SS; /* scalar-scalar residual tolerances */ - ark_mem->Sabstol = 1.e-9; /* solution absolute tolerance */ - ark_mem->SRabstol = 1.e-9; /* residual absolute tolerance */ - ark_mem->user_efun = SUNFALSE; /* no user-supplied ewt function */ - ark_mem->efun = arkEwtSet; /* built-in ewt function */ - ark_mem->e_data = NULL; /* ewt function data */ - ark_mem->user_rfun = SUNFALSE; /* no user-supplied rwt function */ - ark_mem->rfun = arkRwtSet; /* built-in rwt function */ - ark_mem->r_data = NULL; /* rwt function data */ - ark_mem->ehfun = arkErrHandler; /* default error handler fn */ - ark_mem->eh_data = ark_mem; /* error handler data */ - ark_mem->errfp = stderr; /* output stream for errors */ - ark_mem->mxstep = MXSTEP_DEFAULT; /* max number of steps */ - ark_mem->mxhnil = MXHNIL; /* max warns of t+h==t */ - ark_mem->hin = ZERO; /* determine initial step on-the-fly */ - ark_mem->hmin = ZERO; /* no minimum step size */ - ark_mem->hmax_inv = ZERO; /* no maximum step size */ - ark_mem->tstopset = SUNFALSE; /* no stop time set */ - ark_mem->tstop = ZERO; /* no fixed stop time */ - ark_mem->diagfp = NULL; /* no solver diagnostics file */ - ark_mem->report = SUNFALSE; /* don't report solver diagnostics */ - return(ARK_SUCCESS); -} - - -/*--------------------------------------------------------------- - arkSetDenseOrder: - - Specifies the polynomial order for dense output. Positive - values are sent to the interpolation module; negative values - imply to use the default. - ---------------------------------------------------------------*/ -int arkSetDenseOrder(ARKodeMem ark_mem, int dord) + ark_mem->fixedstep = SUNFALSE; /* default to use adaptive steps */ + ark_mem->reltol = RCONST(1.e-4); /* relative tolerance */ + ark_mem->itol = ARK_SS; /* scalar-scalar solution tolerances */ + ark_mem->ritol = ARK_SS; /* scalar-scalar residual tolerances */ + ark_mem->Sabstol = RCONST(1.e-9); /* solution absolute tolerance */ + ark_mem->atolmin0 = SUNFALSE; /* min(abstol) > 0 */ + ark_mem->SRabstol = RCONST(1.e-9); /* residual absolute tolerance */ + ark_mem->Ratolmin0 = SUNFALSE; /* min(Rabstol) > 0 */ + ark_mem->user_efun = SUNFALSE; /* no user-supplied ewt function */ + ark_mem->efun = arkEwtSetSS; /* built-in scalar-scalar ewt function */ + ark_mem->e_data = ark_mem; /* ewt function data */ + ark_mem->user_rfun = SUNFALSE; /* no user-supplied rwt function */ + ark_mem->rfun = arkRwtSet; /* built-in rwt function */ + ark_mem->r_data = ark_mem; /* rwt function data */ + ark_mem->ehfun = arkErrHandler; /* default error handler fn */ + ark_mem->eh_data = ark_mem; /* error handler data */ + ark_mem->errfp = stderr; /* output stream for errors */ + ark_mem->mxstep = MXSTEP_DEFAULT; /* max number of steps */ + ark_mem->mxhnil = MXHNIL; /* max warns of t+h==t */ + ark_mem->maxnef = MAXNEF; /* max error test fails */ + ark_mem->maxncf = MAXNCF; /* max convergence fails */ + ark_mem->maxconstrfails = MAXCONSTRFAILS; /* max number of constraint fails */ + ark_mem->hin = ZERO; /* determine initial step on-the-fly */ + ark_mem->hmin = ZERO; /* no minimum step size */ + ark_mem->hmax_inv = ZERO; /* no maximum step size */ + ark_mem->tstopset = SUNFALSE; /* no stop time set */ + ark_mem->tstop = ZERO; /* no fixed stop time */ + ark_mem->diagfp = NULL; /* no solver diagnostics file */ + ark_mem->report = SUNFALSE; /* don't report solver diagnostics */ + ark_mem->hadapt_mem->etamx1 = ETAMX1; /* max change on first step */ + ark_mem->hadapt_mem->etamxf = ETAMXF; /* max change on error-failed step */ + ark_mem->hadapt_mem->etamin = ETAMIN; /* min bound on time step reduction */ + ark_mem->hadapt_mem->small_nef = SMALL_NEF; /* num error fails before ETAMXF enforced */ + ark_mem->hadapt_mem->etacf = ETACF; /* max change on convergence failure */ + ark_mem->hadapt_mem->HAdapt = NULL; /* step adaptivity fn */ + ark_mem->hadapt_mem->HAdapt_data = NULL; /* step adaptivity data */ + ark_mem->hadapt_mem->imethod = 0; /* PID controller */ + ark_mem->hadapt_mem->cfl = CFLFAC; /* explicit stability factor */ + ark_mem->hadapt_mem->safety = SAFETY; /* step adaptivity safety factor */ + ark_mem->hadapt_mem->bias = BIAS; /* step adaptivity error bias */ + ark_mem->hadapt_mem->growth = GROWTH; /* step adaptivity growth factor */ + ark_mem->hadapt_mem->lbound = HFIXED_LB; /* step adaptivity no-change lower bound */ + ark_mem->hadapt_mem->ubound = HFIXED_UB; /* step adaptivity no-change upper bound */ + ark_mem->hadapt_mem->k1 = AD0_K1; /* step adaptivity parameter */ + ark_mem->hadapt_mem->k2 = AD0_K2; /* step adaptivity parameter */ + ark_mem->hadapt_mem->k3 = AD0_K3; /* step adaptivity parameter */ + ark_mem->hadapt_mem->pq = SUNFALSE; /* use embedding order */ + ark_mem->hadapt_mem->expstab = arkExpStab; /* internal explicit stability fn */ + ark_mem->hadapt_mem->estab_data = NULL; /* no explicit stability fn data */ + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetInterpolantType: + + Specifies use of the Lagrange or Hermite interpolation modules. + itype == ARK_INTERP_HERMITE specifies the Hermite (nonstiff) + interpolation module. + itype == ARK_INTERP_LAGRANGE specifies the Lagrange (stiff) + interpolation module. + + Return values: + ARK_SUCCESS on success. + ARK_MEM_NULL on NULL-valued arkode_mem input. + ARK_MEM_FAIL if the interpolation module cannot be allocated. + ARK_ILL_INPUT if the itype argument is not recognized. + ---------------------------------------------------------------*/ +int arkSetInterpolantType(void *arkode_mem, int itype) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", - "arkSetDenseOrder", MSG_ARK_NO_MEM); + "arkSetInterpolantType", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; + + /* check for legal itype input */ + if ((itype != ARK_INTERP_HERMITE) && (itype != ARK_INTERP_LAGRANGE)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSetInterpolantType", + "Illegal interpolation type input."); + return(ARK_ILL_INPUT); + } + + /* do not change type once the module has been initialized */ + if (ark_mem->initialized) { + arkProcessError(ark_mem, ARK_INTERP_FAIL, "ARKode", + "arkSetInterpolantType", + "Type cannot be specified after module initialization."); + return(ARK_ILL_INPUT); + } + + /* delete any existing interpolation module */ + if (ark_mem->interp != NULL) { + arkInterpFree(ark_mem, ark_mem->interp); + ark_mem->interp = NULL; + } - /* set user-provided value, or default, depending on argument */ - if (dord < 0) { - ark_mem->dense_q = QDENSE_DEF; + /* create requested interpolation module, initially specifying + the maximum possible interpolant degree. */ + if (itype == ARK_INTERP_HERMITE) { + ark_mem->interp = arkInterpCreate_Hermite(arkode_mem, ARK_INTERP_MAX_DEGREE); } else { - ark_mem->dense_q = dord; + ark_mem->interp = arkInterpCreate_Lagrange(arkode_mem, ARK_INTERP_MAX_DEGREE); + } + if (ark_mem->interp == NULL) { + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode", "arkSetInterpolantType", + "Unable to allocate interpolation structure"); + return(ARK_MEM_FAIL); } return(ARK_SUCCESS); } +/*--------------------------------------------------------------- + arkSetInterpolantDegree: + + Specifies the polynomial degree for the dense output + interpolation module. + + Return values: + ARK_SUCCESS on success. + ARK_MEM_NULL on NULL-valued arkode_mem input or nonexistent + interpolation module. + ARK_INTERP_FAIL if the interpolation module is already + initialized. + ARK_ILL_INPUT if the degree is illegal. + ---------------------------------------------------------------*/ +int arkSetInterpolantDegree(void *arkode_mem, int degree) +{ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetInterpolantDegree", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + if (ark_mem->interp == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", + "arkSetInterpolantDegree", + "Interpolation module is not yet allocated"); + return(ARK_MEM_NULL); + } + + /* do not change degree once the module has been initialized */ + if (ark_mem->initialized) { + arkProcessError(ark_mem, ARK_INTERP_FAIL, "ARKode", + "arkSetInterpolantType", + "Degree cannot be specified after module initialization."); + return(ARK_ILL_INPUT); + } + + /* pass 'degree' to interpolation module, returning its value */ + return(arkInterpSetDegree(ark_mem, ark_mem->interp, degree)); +} + + /*--------------------------------------------------------------- arkSetErrHandlerFn: Specifies the error handler function ---------------------------------------------------------------*/ -int arkSetErrHandlerFn(ARKodeMem ark_mem, ARKErrHandlerFn ehfun, +int arkSetErrHandlerFn(void *arkode_mem, ARKErrHandlerFn ehfun, void *eh_data) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetErrHandlerFn", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; /* set user-provided values, or defaults, depending on argument */ if (ehfun == NULL) { @@ -141,13 +252,15 @@ int arkSetErrHandlerFn(ARKodeMem ark_mem, ARKErrHandlerFn ehfun, Specifies the FILE pointer for output (NULL means no messages) ---------------------------------------------------------------*/ -int arkSetErrFile(ARKodeMem ark_mem, FILE *errfp) +int arkSetErrFile(void *arkode_mem, FILE *errfp) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetErrFile", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; ark_mem->errfp = errfp; return(ARK_SUCCESS); } @@ -158,14 +271,33 @@ int arkSetErrFile(ARKodeMem ark_mem, FILE *errfp) Specifies the user data pointer for f ---------------------------------------------------------------*/ -int arkSetUserData(ARKodeMem ark_mem, void *user_data) +int arkSetUserData(void *arkode_mem, void *user_data) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetUserData", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; ark_mem->user_data = user_data; + + /* Set data for efun */ + if (ark_mem->user_efun) + ark_mem->e_data = user_data; + + /* Set data for rfun */ + if (ark_mem->user_rfun) + ark_mem->r_data = user_data; + + /* Set data for root finding */ + if (ark_mem->root_mem != NULL) + ark_mem->root_mem->root_data = user_data; + + /* Set data for post-processing a step */ + if (ark_mem->ProcessStep != NULL) + ark_mem->ps_data = user_data; + return(ARK_SUCCESS); } @@ -176,14 +308,15 @@ int arkSetUserData(ARKodeMem ark_mem, void *user_data) Specifies to enable solver diagnostics, and specifies the FILE pointer for output (diagfp==NULL disables output) ---------------------------------------------------------------*/ -int arkSetDiagnostics(ARKodeMem ark_mem, FILE *diagfp) +int arkSetDiagnostics(void *arkode_mem, FILE *diagfp) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetDiagnostics", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } - + ark_mem = (ARKodeMem) arkode_mem; ark_mem->diagfp = diagfp; if (diagfp != NULL) { ark_mem->report = SUNTRUE; @@ -200,13 +333,15 @@ int arkSetDiagnostics(ARKodeMem ark_mem, FILE *diagfp) Specifies the maximum number of integration steps ---------------------------------------------------------------*/ -int arkSetMaxNumSteps(ARKodeMem ark_mem, long int mxsteps) +int arkSetMaxNumSteps(void *arkode_mem, long int mxsteps) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetMaxNumSteps", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; /* Passing mxsteps=0 sets the default. Passing mxsteps<0 disables the test. */ if (mxsteps == 0) @@ -223,13 +358,15 @@ int arkSetMaxNumSteps(ARKodeMem ark_mem, long int mxsteps) Specifies the maximum number of warnings for small h ---------------------------------------------------------------*/ -int arkSetMaxHnilWarns(ARKodeMem ark_mem, int mxhnil) +int arkSetMaxHnilWarns(void *arkode_mem, int mxhnil) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetMaxHnilWarns", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; /* Passing mxhnil=0 sets the default, otherwise use input. */ if (mxhnil == 0) { @@ -247,13 +384,15 @@ int arkSetMaxHnilWarns(ARKodeMem ark_mem, int mxhnil) Specifies the initial step size ---------------------------------------------------------------*/ -int arkSetInitStep(ARKodeMem ark_mem, realtype hin) +int arkSetInitStep(void *arkode_mem, realtype hin) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetInitStep", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; /* Passing hin=0 sets the default, otherwise use input. */ if (hin == ZERO) { @@ -271,15 +410,17 @@ int arkSetInitStep(ARKodeMem ark_mem, realtype hin) Specifies the minimum step size ---------------------------------------------------------------*/ -int arkSetMinStep(ARKodeMem ark_mem, realtype hmin) +int arkSetMinStep(void *arkode_mem, realtype hmin) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetMinStep", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; - /* Passing a value <= 0 sets hmax = infinity */ + /* Passing a value <= 0 sets hmin = 0 */ if (hmin <= ZERO) { ark_mem->hmin = ZERO; return(ARK_SUCCESS); @@ -304,14 +445,16 @@ int arkSetMinStep(ARKodeMem ark_mem, realtype hmin) Specifies the maximum step size ---------------------------------------------------------------*/ -int arkSetMaxStep(ARKodeMem ark_mem, realtype hmax) +int arkSetMaxStep(void *arkode_mem, realtype hmax) { realtype hmax_inv; - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetMaxStep", MSG_ARK_NO_MEM); return (ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; /* Passing a value <= 0 sets hmax = infinity */ if (hmax <= ZERO) { @@ -339,13 +482,15 @@ int arkSetMaxStep(ARKodeMem ark_mem, realtype hmax) Specifies the time beyond which the integration is not to proceed. ---------------------------------------------------------------*/ -int arkSetStopTime(ARKodeMem ark_mem, realtype tstop) +int arkSetStopTime(void *arkode_mem, realtype tstop) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetStopTime", MSG_ARK_NO_MEM); return (ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; /* If ARKode was called at least once, test if tstop is legal (i.e. if it was not already passed). @@ -381,13 +526,25 @@ int arkSetStopTime(ARKodeMem ark_mem, realtype tstop) Any nonzero argument will result in the use of that fixed step size; an argument of 0 will re-enable temporal adaptivity. ---------------------------------------------------------------*/ -int arkSetFixedStep(ARKodeMem ark_mem, realtype hfixed) +int arkSetFixedStep(void *arkode_mem, realtype hfixed) { - if (ark_mem==NULL) { + int retval; + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetFixedStep", MSG_ARK_NO_MEM); return (ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; + + /* re-attach internal error weight functions if necessary */ + if ((hfixed == ZERO) && (!ark_mem->user_efun)) { + if (ark_mem->itol == ARK_SV && ark_mem->Vabstol != NULL) + retval = arkSVtolerances(ark_mem, ark_mem->reltol, ark_mem->Vabstol); + else + retval = arkSStolerances(ark_mem, ark_mem->reltol, ark_mem->Sabstol); + if (retval != ARK_SUCCESS) return(retval); + } /* set ark_mem entry */ if (hfixed != ZERO) { @@ -407,16 +564,18 @@ int arkSetFixedStep(ARKodeMem ark_mem, realtype hfixed) Specifies the direction of zero-crossings to be monitored. The default is to monitor both crossings. ---------------------------------------------------------------*/ -int arkSetRootDirection(ARKodeMem ark_mem, int *rootdir) +int arkSetRootDirection(void *arkode_mem, int *rootdir) { + ARKodeMem ark_mem; ARKodeRootMem ark_root_mem; int i; - if (ark_mem == NULL) { + if (arkode_mem == NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetRootDirection", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; if (ark_mem->root_mem == NULL) { arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", "arkSetRootDirection", MSG_ARK_NO_MEM); @@ -429,10 +588,8 @@ int arkSetRootDirection(ARKodeMem ark_mem, int *rootdir) "arkSetRootDirection", MSG_ARK_NO_ROOT); return(ARK_ILL_INPUT); } - for(i=0; inrtfn; i++) ark_root_mem->rootdir[i] = rootdir[i]; - return(ARK_SUCCESS); } @@ -443,23 +600,23 @@ int arkSetRootDirection(ARKodeMem ark_mem, int *rootdir) Disables issuing a warning if some root function appears to be identically zero at the beginning of the integration ---------------------------------------------------------------*/ -int arkSetNoInactiveRootWarn(ARKodeMem ark_mem) +int arkSetNoInactiveRootWarn(void *arkode_mem) { + ARKodeMem ark_mem; ARKodeRootMem ark_root_mem; - if (ark_mem==NULL) { + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetNoInactiveRootWarn", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; if (ark_mem->root_mem == NULL) { arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", "arkSetNoInactiveRootWarn", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } ark_root_mem = (ARKodeRootMem) ark_mem->root_mem; - ark_root_mem->mxgnull = 0; - return(ARK_SUCCESS); } @@ -468,44 +625,655 @@ int arkSetNoInactiveRootWarn(ARKodeMem ark_mem) arkSetPostprocessStepFn: Specifies a user-provided step postprocessing function having - type ARKPostProcessStepFn. A NULL input function disables step + type ARKPostProcessFn. A NULL input function disables step postprocessing. IF THE SUPPLIED FUNCTION MODIFIES ANY OF THE ACTIVE STATE DATA, THEN ALL THEORETICAL GUARANTEES OF SOLUTION ACCURACY AND STABILITY ARE LOST. ---------------------------------------------------------------*/ -int arkSetPostprocessStepFn(ARKodeMem ark_mem, - ARKPostProcessStepFn ProcessStep) +int arkSetPostprocessStepFn(void *arkode_mem, + ARKPostProcessFn ProcessStep) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkSetPostprocessStepFn", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; /* NULL argument sets default, otherwise set inputs */ ark_mem->ProcessStep = ProcessStep; + ark_mem->ps_data = ark_mem->user_data; + return(ARK_SUCCESS); } +/*--------------------------------------------------------------- + arkSetPostprocessStageFn: + + Specifies a user-provided stage postprocessing function having + type ARKPostProcessFn. A NULL input function disables + stage postprocessing. + + IF THE SUPPLIED FUNCTION MODIFIES ANY OF THE ACTIVE STATE DATA, + THEN ALL THEORETICAL GUARANTEES OF SOLUTION ACCURACY AND + STABILITY ARE LOST. + ---------------------------------------------------------------*/ +int arkSetPostprocessStageFn(void *arkode_mem, + ARKPostProcessFn ProcessStage) +{ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetPostprocessStageFn", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + /* NULL argument sets default, otherwise set inputs */ + ark_mem->ProcessStage = ProcessStage; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetConstraints: + + Activates or Deactivates inequality constraint checking. + ---------------------------------------------------------------*/ +int arkSetConstraints(void *arkode_mem, N_Vector constraints) +{ + realtype temptest; + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetConstraints", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + /* If there are no constarints, destroy data structures */ + if (constraints == NULL) { + if (ark_mem->ConstraintsMallocDone) { + N_VDestroy(ark_mem->constraints); + ark_mem->lrw -= ark_mem->lrw1; + ark_mem->liw -= ark_mem->liw1; + } + ark_mem->ConstraintsMallocDone = SUNFALSE; + ark_mem->constraintsSet = SUNFALSE; + return(ARK_SUCCESS); + } + + /* Test if required vector ops. are defined */ + if (constraints->ops->nvdiv == NULL || + constraints->ops->nvmaxnorm == NULL || + constraints->ops->nvcompare == NULL || + constraints->ops->nvconstrmask == NULL || + constraints->ops->nvminquotient == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetConstraints", MSG_ARK_BAD_NVECTOR); + return(ARK_ILL_INPUT); + } + + /* Check the constraints vector */ + temptest = N_VMaxNorm(constraints); + if ((temptest > RCONST(2.5)) || (temptest < HALF)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetConstraints", MSG_ARK_BAD_CONSTR); + return(ARK_ILL_INPUT); + } + + if ( !(ark_mem->ConstraintsMallocDone) ) { + ark_mem->constraints = N_VClone(constraints); + ark_mem->lrw += ark_mem->lrw1; + ark_mem->liw += ark_mem->liw1; + ark_mem->ConstraintsMallocDone = SUNTRUE; + } + + /* Load the constraints vector */ + N_VScale(ONE, constraints, ark_mem->constraints); + + ark_mem->constraintsSet = SUNTRUE; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetMaxNumConstrFails: + + Set max number of allowed constraint failures in a step before + returning an error + ---------------------------------------------------------------*/ +int arkSetMaxNumConstrFails(void *arkode_mem, int maxfails) +{ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetMaxNumConstrFails", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + /* Passing maxfails = 0 sets the default, otherwise set to input */ + if (maxfails <= 0) + ark_mem->maxconstrfails = MAXCONSTRFAILS; + else + ark_mem->maxconstrfails = maxfails; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetCFLFraction: + + Specifies the safety factor to use on the maximum explicitly- + stable step size. Allowable values must be within the open + interval (0,1). A non-positive input implies a reset to + the default value. + ---------------------------------------------------------------*/ +int arkSetCFLFraction(void *arkode_mem, realtype cfl_frac) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetCFLFraction", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* check for allowable parameters */ + if (cfl_frac >= ONE) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSetCFLFraction", "Illegal CFL fraction"); + return(ARK_ILL_INPUT); + } + + /* set positive-valued parameters, otherwise set default */ + if (cfl_frac <= ZERO) { + hadapt_mem->cfl = CFLFAC; + } else { + hadapt_mem->cfl = cfl_frac; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetSafetyFactor: + + Specifies the safety factor to use on the error-based predicted + time step size. Allowable values must be within the open + interval (0,1). A non-positive input implies a reset to the + default value. + ---------------------------------------------------------------*/ +int arkSetSafetyFactor(void *arkode_mem, realtype safety) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetSafetyFactor", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* check for allowable parameters */ + if (safety >= ONE) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSetSafetyFactor", "Illegal safety factor"); + return(ARK_ILL_INPUT); + } + + /* set positive-valued parameters, otherwise set default */ + if (safety <= ZERO) { + hadapt_mem->safety = SAFETY; + } else { + hadapt_mem->safety = safety; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetErrorBias: + + Specifies the error bias to use when performing adaptive-step + error control. Allowable values must be >= 1.0. Any illegal + value implies a reset to the default value. + ---------------------------------------------------------------*/ +int arkSetErrorBias(void *arkode_mem, realtype bias) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetErrorBias", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* set allowed value, otherwise set default */ + if (bias < ONE) { + hadapt_mem->bias = BIAS; + } else { + hadapt_mem->bias = bias; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetMaxGrowth: + + Specifies the maximum step size growth factor to be allowed + between successive integration steps. Note: the first step uses + a separate maximum growth factor. Allowable values must be + > 1.0. Any illegal value implies a reset to the default. + ---------------------------------------------------------------*/ +int arkSetMaxGrowth(void *arkode_mem, realtype mx_growth) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetMaxGrowth", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* set allowed value, otherwise set default */ + if (mx_growth <= ONE) { + hadapt_mem->growth = GROWTH; + } else { + hadapt_mem->growth = mx_growth; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetMinReduction: + + Specifies the minimum possible step size reduction factor to be + allowed between successive integration steps. Allowable values + must be > 0.0 and < 1.0. Any illegal value implies a reset to + the default. + ---------------------------------------------------------------*/ +int arkSetMinReduction(void *arkode_mem, realtype eta_min) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetMinReduction", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* set allowed value, otherwise set default */ + if (eta_min >= ONE || eta_min <= ZERO) { + hadapt_mem->etamin = ETAMIN; + } else { + hadapt_mem->etamin = eta_min; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetFixedStepBounds: + + Specifies the step size growth interval within which the step + size will remain unchanged. Allowable values must enclose the + value 1.0. Any illegal interval implies a reset to the default. + ---------------------------------------------------------------*/ +int arkSetFixedStepBounds(void *arkode_mem, realtype lb, realtype ub) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetFixedStepBounds", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* set allowable interval, otherwise set defaults */ + if ((lb <= ONE) && (ub >= ONE)) { + hadapt_mem->lbound = lb; + hadapt_mem->ubound = ub; + } else { + hadapt_mem->lbound = HFIXED_LB; + hadapt_mem->ubound = HFIXED_UB; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetAdaptivityMethod: + + Specifies the built-in time step adaptivity algorithm (and + optionally, its associated parameters) to use. All parameters + will be checked for validity when used by the solver. + ---------------------------------------------------------------*/ +int arkSetAdaptivityMethod(void *arkode_mem, int imethod, int idefault, + int pq, realtype adapt_params[3]) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetAdaptivityMethod", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* check for allowable parameters */ + if ((imethod > 5) || (imethod < 0)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSetAdaptivityMethod", "Illegal imethod"); + return(ARK_ILL_INPUT); + } + + /* set adaptivity method */ + hadapt_mem->imethod = imethod; + + /* set flag whether to use p or q */ + hadapt_mem->pq = (pq != 0); + + /* set method parameters */ + if (idefault == 1) { + switch (hadapt_mem->imethod) { + case (0): + hadapt_mem->k1 = AD0_K1; + hadapt_mem->k2 = AD0_K2; + hadapt_mem->k3 = AD0_K3; break; + case (1): + hadapt_mem->k1 = AD1_K1; + hadapt_mem->k2 = AD1_K2; break; + case (2): + hadapt_mem->k1 = AD2_K1; break; + case (3): + hadapt_mem->k1 = AD3_K1; + hadapt_mem->k2 = AD3_K2; break; + case (4): + hadapt_mem->k1 = AD4_K1; + hadapt_mem->k2 = AD4_K2; break; + case (5): + hadapt_mem->k1 = AD5_K1; + hadapt_mem->k2 = AD5_K2; + hadapt_mem->k3 = AD5_K3; break; + } + } else { + hadapt_mem->k1 = adapt_params[0]; + hadapt_mem->k2 = adapt_params[1]; + hadapt_mem->k3 = adapt_params[2]; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetAdaptivityFn: + + Specifies the user-provided time step adaptivity function to use. + ---------------------------------------------------------------*/ +int arkSetAdaptivityFn(void *arkode_mem, ARKAdaptFn hfun, void *h_data) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetAdaptivityFn", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* NULL hfun sets default, otherwise set inputs */ + if (hfun == NULL) { + hadapt_mem->HAdapt = NULL; + hadapt_mem->HAdapt_data = NULL; + hadapt_mem->imethod = 0; + } else { + hadapt_mem->HAdapt = hfun; + hadapt_mem->HAdapt_data = h_data; + hadapt_mem->imethod = -1; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetMaxFirstGrowth: + + Specifies the user-provided time step adaptivity constant + etamx1. Legal values are greater than 1.0. Illegal values + imply a reset to the default value. + ---------------------------------------------------------------*/ +int arkSetMaxFirstGrowth(void *arkode_mem, realtype etamx1) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetMaxFirstGrowth", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* if argument legal set it, otherwise set default */ + if (etamx1 <= ONE) { + hadapt_mem->etamx1 = ETAMX1; + } else { + hadapt_mem->etamx1 = etamx1; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetMaxEFailGrowth: + + Specifies the user-provided time step adaptivity constant + etamxf. Legal values are in the interval (0,1]. Illegal values + imply a reset to the default value. + ---------------------------------------------------------------*/ +int arkSetMaxEFailGrowth(void *arkode_mem, realtype etamxf) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetMaxEFailGrowth", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* if argument legal set it, otherwise set default */ + if ((etamxf <= ZERO) || (etamxf > ONE)) { + hadapt_mem->etamxf = ETAMXF; + } else { + hadapt_mem->etamxf = etamxf; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetSmallNumEFails: + + Specifies the user-provided time step adaptivity constant + small_nef. Legal values are > 0. Illegal values + imply a reset to the default value. + ---------------------------------------------------------------*/ +int arkSetSmallNumEFails(void *arkode_mem, int small_nef) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetSmallNumEFails", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* if argument legal set it, otherwise set default */ + if (small_nef <= 0) { + hadapt_mem->small_nef = SMALL_NEF; + } else { + hadapt_mem->small_nef = small_nef; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetMaxCFailGrowth: + + Specifies the user-provided time step adaptivity constant + etacf. Legal values are in the interval (0,1]. Illegal values + imply a reset to the default value. + ---------------------------------------------------------------*/ +int arkSetMaxCFailGrowth(void *arkode_mem, realtype etacf) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetMaxCFailGrowth", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* if argument legal set it, otherwise set default */ + if ((etacf <= ZERO) || (etacf > ONE)) { + hadapt_mem->etacf = ETACF; + } else { + hadapt_mem->etacf = etacf; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetStabilityFn: + + Specifies the user-provided explicit time step stability + function to use. A NULL input function implies a reset to + the default function (empty). + ---------------------------------------------------------------*/ +int arkSetStabilityFn(void *arkode_mem, ARKExpStabFn EStab, void *estab_data) +{ + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeMem ark_mem; + retval = arkAccessHAdaptMem(arkode_mem, "arkSetStabilityFn", + &ark_mem, &hadapt_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* NULL argument sets default, otherwise set inputs */ + if (EStab == NULL) { + hadapt_mem->expstab = arkExpStab; + hadapt_mem->estab_data = ark_mem; + } else { + hadapt_mem->expstab = EStab; + hadapt_mem->estab_data = estab_data; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetMaxErrTestFails: + + Specifies the maximum number of error test failures during one + step try. A non-positive input implies a reset to + the default value. + ---------------------------------------------------------------*/ +int arkSetMaxErrTestFails(void *arkode_mem, int maxnef) +{ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetMaxErrTestFails", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + /* argument <= 0 sets default, otherwise set input */ + if (maxnef <= 0) { + ark_mem->maxnef = MAXNEF; + } else { + ark_mem->maxnef = maxnef; + } + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetMaxConvFails: + + Specifies the maximum number of nonlinear convergence failures + during one step try. A non-positive input implies a reset to + the default value. + ---------------------------------------------------------------*/ +int arkSetMaxConvFails(void *arkode_mem, int maxncf) +{ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetMaxConvFails", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + /* argument <= 0 sets default, otherwise set input */ + if (maxncf <= 0) { + ark_mem->maxncf = MAXNCF; + } else { + ark_mem->maxncf = maxncf; + } + return(ARK_SUCCESS); +} + + + /*=============================================================== ARKode optional output utility functions ===============================================================*/ +/*--------------------------------------------------------------- + arkGetNumStepAttempts: + + Returns the current number of steps attempted by the solver + ---------------------------------------------------------------*/ +int arkGetNumStepAttempts(void *arkode_mem, long int *nstep_attempts) +{ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetNumStepAttempts", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + *nstep_attempts = ark_mem->nst_attempts; + return(ARK_SUCCESS); +} + + /*--------------------------------------------------------------- arkGetNumSteps: Returns the current number of integration steps ---------------------------------------------------------------*/ -int arkGetNumSteps(ARKodeMem ark_mem, long int *nsteps) +int arkGetNumSteps(void *arkode_mem, long int *nsteps) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetNumSteps", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; + *nsteps = ark_mem->nst; return(ARK_SUCCESS); } @@ -516,13 +1284,16 @@ int arkGetNumSteps(ARKodeMem ark_mem, long int *nsteps) Returns the step size used on the first step ---------------------------------------------------------------*/ -int arkGetActualInitStep(ARKodeMem ark_mem, realtype *hinused) +int arkGetActualInitStep(void *arkode_mem, realtype *hinused) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetActualInitStep", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; + *hinused = ark_mem->h0u; return(ARK_SUCCESS); } @@ -533,13 +1304,16 @@ int arkGetActualInitStep(ARKodeMem ark_mem, realtype *hinused) Returns the step size used on the last successful step ---------------------------------------------------------------*/ -int arkGetLastStep(ARKodeMem ark_mem, realtype *hlast) +int arkGetLastStep(void *arkode_mem, realtype *hlast) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetLastStep", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; + *hlast = ark_mem->hold; return(ARK_SUCCESS); } @@ -550,30 +1324,56 @@ int arkGetLastStep(ARKodeMem ark_mem, realtype *hlast) Returns the step size to be attempted on the next step ---------------------------------------------------------------*/ -int arkGetCurrentStep(ARKodeMem ark_mem, realtype *hcur) +int arkGetCurrentStep(void *arkode_mem, realtype *hcur) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetCurrentStep", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; + *hcur = ark_mem->next_h; return(ARK_SUCCESS); } +/*--------------------------------------------------------------- + arkGetCurrentState: + + Returns the current solution + ---------------------------------------------------------------*/ +int arkGetCurrentState(void *arkode_mem, N_Vector *ycur) +{ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetCurrentState", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + *ycur = ark_mem->ycur; + return(ARK_SUCCESS); +} + + /*--------------------------------------------------------------- arkGetCurrentTime: Returns the current value of the independent variable ---------------------------------------------------------------*/ -int arkGetCurrentTime(ARKodeMem ark_mem, realtype *tcur) +int arkGetCurrentTime(void *arkode_mem, realtype *tcur) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetCurrentTime", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; + *tcur = ark_mem->tcur; return(ARK_SUCCESS); } @@ -584,13 +1384,16 @@ int arkGetCurrentTime(ARKodeMem ark_mem, realtype *tcur) Returns a suggested factor for scaling tolerances ---------------------------------------------------------------*/ -int arkGetTolScaleFactor(ARKodeMem ark_mem, realtype *tolsfact) +int arkGetTolScaleFactor(void *arkode_mem, realtype *tolsfact) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetTolScaleFactor", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; + *tolsfact = ark_mem->tolsf; return(ARK_SUCCESS); } @@ -601,13 +1404,16 @@ int arkGetTolScaleFactor(ARKodeMem ark_mem, realtype *tolsfact) This routine returns the current error weight vector. ---------------------------------------------------------------*/ -int arkGetErrWeights(ARKodeMem ark_mem, N_Vector eweight) +int arkGetErrWeights(void *arkode_mem, N_Vector eweight) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetErrWeights", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; + N_VScale(ONE, ark_mem->ewt, eweight); return(ARK_SUCCESS); } @@ -618,13 +1424,16 @@ int arkGetErrWeights(ARKodeMem ark_mem, N_Vector eweight) This routine returns the current residual weight vector. ---------------------------------------------------------------*/ -int arkGetResWeights(ARKodeMem ark_mem, N_Vector rweight) +int arkGetResWeights(void *arkode_mem, N_Vector rweight) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetResWeights", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; + N_VScale(ONE, ark_mem->rwt, rweight); return(ARK_SUCCESS); } @@ -635,13 +1444,16 @@ int arkGetResWeights(ARKodeMem ark_mem, N_Vector rweight) Returns integrator work space requirements ---------------------------------------------------------------*/ -int arkGetWorkSpace(ARKodeMem ark_mem, long int *lenrw, long int *leniw) +int arkGetWorkSpace(void *arkode_mem, long int *lenrw, long int *leniw) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetWorkSpace", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; + *leniw = ark_mem->liw; *lenrw = ark_mem->lrw; return(ARK_SUCCESS); @@ -653,23 +1465,23 @@ int arkGetWorkSpace(ARKodeMem ark_mem, long int *lenrw, long int *leniw) Returns the current number of calls to g (for rootfinding) ---------------------------------------------------------------*/ -int arkGetNumGEvals(ARKodeMem ark_mem, long int *ngevals) +int arkGetNumGEvals(void *arkode_mem, long int *ngevals) { + ARKodeMem ark_mem; ARKodeRootMem ark_root_mem; - if (ark_mem==NULL) { + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetNumGEvals", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; if (ark_mem->root_mem == NULL) { arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", "arkGetNumGEvals", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } ark_root_mem = (ARKodeRootMem) ark_mem->root_mem; - *ngevals = ark_root_mem->nge; - return(ARK_SUCCESS); } @@ -679,25 +1491,25 @@ int arkGetNumGEvals(ARKodeMem ark_mem, long int *ngevals) Returns pointer to array rootsfound showing roots found ---------------------------------------------------------------*/ -int arkGetRootInfo(ARKodeMem ark_mem, int *rootsfound) +int arkGetRootInfo(void *arkode_mem, int *rootsfound) { int i; + ARKodeMem ark_mem; ARKodeRootMem ark_root_mem; - if (ark_mem==NULL) { + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetRootInfo", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; if (ark_mem->root_mem == NULL) { arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", "arkGetRootInfo", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } ark_root_mem = (ARKodeRootMem) ark_mem->root_mem; - for (i=0; inrtfn; i++) rootsfound[i] = ark_root_mem->iroots[i]; - return(ARK_SUCCESS); } @@ -707,15 +1519,18 @@ int arkGetRootInfo(ARKodeMem ark_mem, int *rootsfound) Returns step statistics ---------------------------------------------------------------*/ -int arkGetStepStats(ARKodeMem ark_mem, long int *nsteps, +int arkGetStepStats(void *arkode_mem, long int *nsteps, realtype *hinused, realtype *hlast, realtype *hcur, realtype *tcur) { - if (ark_mem==NULL) { + ARKodeMem ark_mem; + if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetStepStats", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } + ark_mem = (ARKodeMem) arkode_mem; + *nsteps = ark_mem->nst; *hinused = ark_mem->h0u; *hlast = ark_mem->hold; @@ -725,12 +1540,91 @@ int arkGetStepStats(ARKodeMem ark_mem, long int *nsteps, } +/*--------------------------------------------------------------- + arkGetNumConstrFails: + + Returns the current number of constraint fails + ---------------------------------------------------------------*/ +int arkGetNumConstrFails(void *arkode_mem, long int *nconstrfails) +{ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetNumConstrFails", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + *nconstrfails = ark_mem->nconstrfails; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetNumExpSteps: + + Returns the current number of stability-limited steps + ---------------------------------------------------------------*/ +int arkGetNumExpSteps(void *arkode_mem, long int *nsteps) +{ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetNumExpSteps", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + *nsteps = ark_mem->hadapt_mem->nst_exp; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetNumAccSteps: + + Returns the current number of accuracy-limited steps + ---------------------------------------------------------------*/ +int arkGetNumAccSteps(void *arkode_mem, long int *nsteps) +{ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetNumAccSteps", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + *nsteps = ark_mem->hadapt_mem->nst_acc; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetNumErrTestFails: + + Returns the current number of error test failures + ---------------------------------------------------------------*/ +int arkGetNumErrTestFails(void *arkode_mem, long int *netfails) +{ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetNumErrTestFails", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + *netfails = ark_mem->netf; + return(ARK_SUCCESS); +} + /*-----------------------------------------------------------------*/ char *arkGetReturnFlagName(long int flag) { char *name; - name = (char *)malloc(24*sizeof(char)); + name = (char *)malloc(27*sizeof(char)); switch(flag) { case ARK_SUCCESS: @@ -820,8 +1714,11 @@ char *arkGetReturnFlagName(long int flag) case ARK_TOO_CLOSE: sprintf(name,"ARK_TOO_CLOSE"); break; - case ARK_POSTPROCESS_FAIL: - sprintf(name,"ARK_POSTPROCESS_FAIL"); + case ARK_POSTPROCESS_STEP_FAIL: + sprintf(name,"ARK_POSTPROCESS_STEP_FAIL"); + break; + case ARK_POSTPROCESS_STAGE_FAIL: + sprintf(name,"ARK_POSTPROCESS_STAGE_FAIL"); break; case ARK_VECTOROP_ERR: sprintf(name,"ARK_VECTOROP_ERR"); @@ -835,6 +1732,9 @@ char *arkGetReturnFlagName(long int flag) case ARK_NLS_OP_ERR: sprintf(name,"ARK_NLS_OP_ERR"); break; + case ARK_INNERSTEP_ATTACH_ERR: + sprintf(name,"ARK_INNERSTEP_ATTACH_ERR"); + break; case ARK_INNERSTEP_FAIL: sprintf(name,"ARK_INNERSTEP_FAIL"); break; @@ -866,7 +1766,6 @@ int arkWriteParameters(ARKodeMem ark_mem, FILE *fp) /* print integrator parameters to file */ fprintf(fp, "ARKode solver parameters:\n"); - fprintf(fp, " Dense output order %i\n",ark_mem->dense_q); if (ark_mem->hmin != ZERO) fprintf(fp, " Minimum step size = %" RSYM"\n",ark_mem->hmin); if (ark_mem->hmax_inv != ZERO) @@ -897,6 +1796,37 @@ int arkWriteParameters(ARKodeMem ark_mem, FILE *fp) if (ark_mem->hin != ZERO) fprintf(fp, " Initial step size = %" RSYM"\n",ark_mem->hin); fprintf(fp, "\n"); + fprintf(fp, " Maximum step increase (first step) = %"RSYM"\n", + ark_mem->hadapt_mem->etamx1); + fprintf(fp, " Step reduction factor on multiple error fails = %"RSYM"\n", + ark_mem->hadapt_mem->etamxf); + fprintf(fp, " Minimum error fails before above factor is used = %i\n", + ark_mem->hadapt_mem->small_nef); + fprintf(fp, " Step reduction factor on nonlinear convergence failure = %"RSYM"\n", + ark_mem->hadapt_mem->etacf); + fprintf(fp, " Explicit safety factor = %"RSYM"\n", + ark_mem->hadapt_mem->cfl); + if (ark_mem->hadapt_mem->HAdapt == NULL) { + fprintf(fp, " Time step adaptivity method %i\n", ark_mem->hadapt_mem->imethod); + fprintf(fp, " Safety factor = %"RSYM"\n", ark_mem->hadapt_mem->safety); + fprintf(fp, " Bias factor = %"RSYM"\n", ark_mem->hadapt_mem->bias); + fprintf(fp, " Growth factor = %"RSYM"\n", ark_mem->hadapt_mem->growth); + fprintf(fp, " Step growth lower bound = %"RSYM"\n", ark_mem->hadapt_mem->lbound); + fprintf(fp, " Step growth upper bound = %"RSYM"\n", ark_mem->hadapt_mem->ubound); + fprintf(fp, " k1 = %"RSYM"\n", ark_mem->hadapt_mem->k1); + fprintf(fp, " k2 = %"RSYM"\n", ark_mem->hadapt_mem->k2); + fprintf(fp, " k3 = %"RSYM"\n", ark_mem->hadapt_mem->k3); + if (ark_mem->hadapt_mem->expstab == arkExpStab) { + fprintf(fp, " Default explicit stability function\n"); + } else { + fprintf(fp, " User provided explicit stability function\n"); + } + } else { + fprintf(fp, " User provided time step adaptivity function\n"); + } + + fprintf(fp, " Maximum number of error test failures = %i\n",ark_mem->maxnef); + fprintf(fp, " Maximum number of convergence test failures = %i\n",ark_mem->maxncf); return(ARK_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_ls.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_ls.c index 6508c22bc..28f7d0428 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_ls.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_ls.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -17,7 +17,6 @@ #include #include #include - #include "arkode_impl.h" #include "arkode_ls_impl.h" #include @@ -38,6 +37,11 @@ #define PT25 RCONST(0.25) #define ONE RCONST(1.0) +/* Prototypes for internal functions */ +static int arkLsLinSys(realtype t, N_Vector y, N_Vector fy, SUNMatrix A, + SUNMatrix M, booleantype jok, booleantype *jcur, + realtype gamma, void *user_data, N_Vector tmp1, + N_Vector tmp2, N_Vector tmp3); /*=============================================================== ARKLS utility routines (called by time-stepper modules) @@ -49,9 +53,11 @@ int arkLSSetLinearSolver(void *arkode_mem, SUNLinearSolver LS, SUNMatrix A) { - ARKodeMem ark_mem; - ARKLsMem arkls_mem; - int retval, LSType; + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval, LSType; + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ /* Return immediately if either arkode_mem or LS inputs are NULL */ if (arkode_mem == NULL) { @@ -69,44 +75,56 @@ int arkLSSetLinearSolver(void *arkode_mem, SUNLinearSolver LS, } /* Test if solver is compatible with LS interface */ - if ( (LS->ops->gettype == NULL) || - (LS->ops->initialize == NULL) || - (LS->ops->setup == NULL) || - (LS->ops->solve == NULL) ) { + if ( (LS->ops->gettype == NULL) || (LS->ops->solve == NULL) ) { arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetLinearSolver", "LS object is missing a required operation"); return(ARKLS_ILL_INPUT); } + /* Retrieve the LS type */ + LSType = SUNLinSolGetType(LS); + + /* Set flags based on LS type */ + iterative = (LSType != SUNLINEARSOLVER_DIRECT); + matrixbased = (LSType != SUNLINEARSOLVER_ITERATIVE); + /* Test if vector is compatible with LS interface */ if ( (ark_mem->tempv1->ops->nvconst == NULL) || - (ark_mem->tempv1->ops->nvdotprod == NULL) ) { + (ark_mem->tempv1->ops->nvwrmsnorm == NULL) ) { arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetLinearSolver", MSG_LS_BAD_NVECTOR); return(ARKLS_ILL_INPUT); } - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(LS); - /* Check for compatible LS type, matrix and "atimes" support */ - if ((LSType == SUNLINEARSOLVER_ITERATIVE) && (LS->ops->setatimes == NULL)) { - arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetLinearSolver", - "Incompatible inputs: iterative LS must support ATimes routine"); - return(ARKLS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_DIRECT) && (A == NULL)) { + if (iterative) { + + if (ark_mem->tempv1->ops->nvgetlength == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetLinearSolver", MSG_LS_BAD_NVECTOR); + return(ARKLS_ILL_INPUT); + } + + if (!matrixbased && LS->ops->setatimes == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetLinearSolver", + "Incompatible inputs: iterative LS must support ATimes routine"); + return(ARKLS_ILL_INPUT); + } + + if (matrixbased && A == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetLinearSolver", + "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); + return(ARKLS_ILL_INPUT); + } + + } else if (A == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetLinearSolver", "Incompatible inputs: direct LS requires non-NULL matrix"); return(ARKLS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) && (A == NULL)) { - arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetLinearSolver", - "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); - return(ARKLS_ILL_INPUT); - } + } /* Test whether time stepper module is supplied, with required routines */ if ( (ark_mem->step_attachlinsol == NULL) || @@ -132,6 +150,10 @@ int arkLSSetLinearSolver(void *arkode_mem, SUNLinearSolver LS, /* set SUNLinearSolver pointer */ arkls_mem->LS = LS; + /* Linear solver type information */ + arkls_mem->iterative = iterative; + arkls_mem->matrixbased = matrixbased; + /* Set defaults for Jacobian-related fields */ if (A != NULL) { arkls_mem->jacDQ = SUNTRUE; @@ -142,11 +164,16 @@ int arkLSSetLinearSolver(void *arkode_mem, SUNLinearSolver LS, arkls_mem->jac = NULL; arkls_mem->J_data = NULL; } + arkls_mem->jtimesDQ = SUNTRUE; arkls_mem->jtsetup = NULL; arkls_mem->jtimes = arkLsDQJtimes; arkls_mem->Jt_data = ark_mem; + arkls_mem->user_linsys = SUNFALSE; + arkls_mem->linsys = arkLsLinSys; + arkls_mem->A_data = ark_mem; + /* Set defaults for preconditioner-related fields */ arkls_mem->pset = NULL; arkls_mem->psolve = NULL; @@ -186,16 +213,10 @@ int arkLSSetLinearSolver(void *arkode_mem, SUNLinearSolver LS, } } - /* When using a non-NULL SUNMatrix object, store pointer to A and create saved_J */ + /* When using a SUNMatrix object, store pointer to A and initialize savedJ */ if (A != NULL) { arkls_mem->A = A; - arkls_mem->savedJ = SUNMatClone(A); - if (arkls_mem->savedJ == NULL) { - arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKLS", - "arkLSSetLinearSolver", MSG_LS_MEM_FAIL); - free(arkls_mem); arkls_mem = NULL; - return(ARKLS_MEM_FAIL); - } + arkls_mem->savedJ = NULL; /* allocated in arkLsInitialize */ } /* Allocate memory for ytemp and x */ @@ -203,7 +224,6 @@ int arkLSSetLinearSolver(void *arkode_mem, SUNLinearSolver LS, if (arkls_mem->ytemp == NULL) { arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKLS", "arkLSSetLinearSolver", MSG_LS_MEM_FAIL); - SUNMatDestroy(arkls_mem->savedJ); free(arkls_mem); arkls_mem = NULL; return(ARKLS_MEM_FAIL); } @@ -213,29 +233,29 @@ int arkLSSetLinearSolver(void *arkode_mem, SUNLinearSolver LS, arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKLS", "arkLSSetLinearSolver", MSG_LS_MEM_FAIL); N_VDestroy(arkls_mem->ytemp); - SUNMatDestroy(arkls_mem->savedJ); free(arkls_mem); arkls_mem = NULL; return(ARKLS_MEM_FAIL); } - /* For iterative LS, compute sqrtN from a dot product */ - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { - N_VConst(ONE, arkls_mem->ytemp); - arkls_mem->sqrtN = SUNRsqrt( N_VDotProd(arkls_mem->ytemp, - arkls_mem->ytemp) ); - } + /* For iterative LS, compute sqrtN */ + if (iterative) + arkls_mem->sqrtN = SUNRsqrt( N_VGetLength(arkls_mem->ytemp) ); + + /* For matrix-based LS, enable soltuion scaling */ + if (matrixbased) + arkls_mem->scalesol = SUNTRUE; + else + arkls_mem->scalesol = SUNFALSE; /* Attach ARKLs interface to time stepper module */ retval = ark_mem->step_attachlinsol(arkode_mem, arkLsInitialize, arkLsSetup, arkLsSolve, - arkLsFree, 2, arkls_mem); + arkLsFree, LSType, arkls_mem); if (retval != ARK_SUCCESS) { arkProcessError(ark_mem, retval, "ARKLS", "arkLSSetLinearSolver", "Failed to attach to time stepper module"); N_VDestroy(arkls_mem->x); N_VDestroy(arkls_mem->ytemp); - SUNMatDestroy(arkls_mem->savedJ); free(arkls_mem); arkls_mem = NULL; return(retval); } @@ -255,6 +275,8 @@ int arkLSSetMassLinearSolver(void *arkode_mem, SUNLinearSolver LS, ARKodeMem ark_mem; ARKLsMassMem arkls_mem; int retval, LSType; + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ /* Return immediately if either arkode_mem or LS inputs are NULL */ if (arkode_mem == NULL) { @@ -273,42 +295,55 @@ int arkLSSetMassLinearSolver(void *arkode_mem, SUNLinearSolver LS, } /* Test if solver is compatible with LS interface */ - if ( (LS->ops->gettype == NULL) || - (LS->ops->initialize == NULL) || - (LS->ops->setup == NULL) || - (LS->ops->solve == NULL) ) { + if ( (LS->ops->gettype == NULL) || (LS->ops->solve == NULL) ) { arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetMassLinearSolver", "LS object is missing a required operation"); return(ARKLS_ILL_INPUT); } + /* Retrieve the LS type */ + LSType = SUNLinSolGetType(LS); + + /* Set flags based on LS type */ + iterative = (LSType != SUNLINEARSOLVER_DIRECT); + matrixbased = (LSType != SUNLINEARSOLVER_ITERATIVE); + /* Test if vector is compatible with LS interface */ if ( (ark_mem->tempv1->ops->nvconst == NULL) || - (ark_mem->tempv1->ops->nvdotprod == NULL) ){ + (ark_mem->tempv1->ops->nvwrmsnorm == NULL) ){ arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetMassLinearSolver", MSG_LS_BAD_NVECTOR); return(ARKLS_ILL_INPUT); } - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(LS); - /* Check for compatible LS type, matrix and "atimes" support */ - if ((LSType == SUNLINEARSOLVER_ITERATIVE) && (LS->ops->setatimes == NULL)) { - arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetMassLinearSolver", - "Incompatible inputs: iterative LS must support ATimes routine"); - return(ARKLS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_DIRECT) && (M == NULL)) { + if (iterative) { + + if (ark_mem->tempv1->ops->nvgetlength == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetLinearSolver", MSG_LS_BAD_NVECTOR); + return(ARKLS_ILL_INPUT); + } + + if (!matrixbased && LS->ops->setatimes == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetMassLinearSolver", + "Incompatible inputs: iterative LS must support ATimes routine"); + return(ARKLS_ILL_INPUT); + } + + if (matrixbased && M == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetMassLinearSolver", + "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); + return(ARKLS_ILL_INPUT); + } + + } else if (M == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetMassLinearSolver", "Incompatible inputs: direct LS requires non-NULL matrix"); return(ARKLS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) && (M == NULL)) { - arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetMassLinearSolver", - "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); - return(ARKLS_ILL_INPUT); + } /* Test whether time stepper module is supplied, with required routines */ @@ -330,12 +365,19 @@ int arkLSSetMassLinearSolver(void *arkode_mem, SUNLinearSolver LS, } memset(arkls_mem, 0, sizeof(struct ARKLsMassMemRec)); - /* set SUNLinearSolver pointer; flag indicating time-dependence */ + /* set SUNLinearSolver pointer */ arkls_mem->LS = LS; + + /* Linear solver type information */ + arkls_mem->iterative = iterative; + arkls_mem->matrixbased = matrixbased; + + /* Set flag indicating time-dependence */ arkls_mem->time_dependent = time_dep; /* Set mass-matrix routines to NULL */ arkls_mem->mass = NULL; + arkls_mem->M_data = NULL; arkls_mem->mtsetup = NULL; arkls_mem->mtimes = NULL; arkls_mem->mt_data = NULL; @@ -399,19 +441,15 @@ int arkLSSetMassLinearSolver(void *arkode_mem, SUNLinearSolver LS, return(ARKLS_MEM_FAIL); } - /* For iterative LS, compute sqrtN from a dot product */ - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { - N_VConst(ONE, arkls_mem->x); - arkls_mem->sqrtN = SUNRsqrt( N_VDotProd(arkls_mem->x, - arkls_mem->x) ); - } + /* For iterative LS, compute sqrtN */ + if (iterative) + arkls_mem->sqrtN = SUNRsqrt( N_VGetLength(arkls_mem->x) ); /* Attach ARKLs interface to time stepper module */ retval = ark_mem->step_attachmasssol(arkode_mem, arkLsMassInitialize, arkLsMassSetup, arkLsMTimes, arkLsMassSolve, arkLsMassFree, - 2, arkls_mem); + LSType, arkls_mem); if (retval != ARK_SUCCESS) { arkProcessError(ark_mem, retval, "ARKLS", "arkLSSetMassLinearSolver", "Failed to attach to time stepper module"); @@ -450,7 +488,7 @@ int arkLSSetJacFn(void *arkode_mem, ARKLsJacFn jac) return(ARKLS_ILL_INPUT); } - /* set Jacobian routine pointer, and update relevant flags */ + /* set the Jacobian routine pointer, and update relevant flags */ if (jac != NULL) { arkls_mem->jacDQ = SUNFALSE; arkls_mem->jac = jac; @@ -461,6 +499,11 @@ int arkLSSetJacFn(void *arkode_mem, ARKLsJacFn jac) arkls_mem->J_data = ark_mem; } + /* ensure the internal linear system function is used */ + arkls_mem->user_linsys = SUNFALSE; + arkls_mem->linsys = arkLsLinSys; + arkls_mem->A_data = ark_mem; + return(ARKLS_SUCCESS); } @@ -492,7 +535,9 @@ int arkLSSetMassFn(void *arkode_mem, ARKLsMassFn mass) } /* set mass matrix routine pointer and return */ - arkls_mem->mass = mass; + arkls_mem->mass = mass; + arkls_mem->M_data = ark_mem->user_data; + return(ARKLS_SUCCESS); } @@ -538,6 +583,31 @@ int arkLSSetMaxStepsBetweenJac(void *arkode_mem, long int msbj) } +/*--------------------------------------------------------------- + arkLSSetLinearSolutionScaling enables or disables scaling the + linear solver solution to account for changes in gamma. + ---------------------------------------------------------------*/ +int arkLSSetLinearSolutionScaling(void *arkode_mem, booleantype onoff) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure; store input and return */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSSetLinearSolutionScaling", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* check for valid solver type */ + if (!(arkls_mem->matrixbased)) return(ARKLS_ILL_INPUT); + + /* set solution scaling flag */ + arkls_mem->scalesol = onoff; + + return(ARKLS_SUCCESS); +} + + /*--------------------------------------------------------------- arkLSSetPreconditioner specifies the user-supplied preconditioner setup and solve routines. @@ -628,6 +698,70 @@ int arkLSSetJacTimes(void *arkode_mem, } +/* arkLSSetLinSysFn specifies the linear system setup function. */ +int arkLSSetLinSysFn(void *arkode_mem, ARKLsLinSysFn linsys) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSSetJacFn", + &ark_mem, &arkls_mem); + if (retval != ARKLS_SUCCESS) return(retval); + + /* return with failure if linsys cannot be used */ + if ((linsys != NULL) && (arkls_mem->A == NULL)) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetLinSysFn", + "Linear system setup routine cannot be supplied for NULL SUNMatrix"); + return(ARKLS_ILL_INPUT); + } + + /* set the linear system routine pointer, and update relevant flags */ + if (linsys != NULL) { + arkls_mem->user_linsys = SUNTRUE; + arkls_mem->linsys = linsys; + arkls_mem->A_data = ark_mem->user_data; + } else { + arkls_mem->user_linsys = SUNFALSE; + arkls_mem->linsys = arkLsLinSys; + arkls_mem->A_data = ark_mem; + } + + return(ARKLS_SUCCESS); +} + + +/* arkLSSetUserData sets user_data pointers in arkLS */ +int arkLSSetUserData(void *arkode_mem, void* user_data) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSSetUserData", + &ark_mem, &arkls_mem); + if (retval != ARKLS_SUCCESS) return(retval); + + /* Set data for Jacobian */ + if (!arkls_mem->jacDQ) + arkls_mem->J_data = user_data; + + /* Set data for Jtimes */ + if (!arkls_mem->jtimesDQ) + arkls_mem->Jt_data = user_data; + + /* Set data for LinSys */ + if (arkls_mem->user_linsys) + arkls_mem->A_data = user_data; + + /* Set data for Preconditioner */ + arkls_mem->P_data = user_data; + + return(ARKLS_SUCCESS); +} + /*--------------------------------------------------------------- arkLSGetWorkSpace returns the length of workspace allocated for the ARKLS linear solver interface. @@ -831,6 +965,24 @@ int arkLSGetNumJtimesEvals(void *arkode_mem, long int *njvevals) return(ARKLS_SUCCESS); } +/*--------------------------------------------------------------- + arkLSGetNumMassMatvecSetups returns the number of calls to the + mass matrix-vector setup routine. + ---------------------------------------------------------------*/ +int arkLSGetNumMassMatvecSetups(void *arkode_mem, long int *nmvsetups) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKMassMem structure; set output value and return */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSGetNumMassMatvecSetups", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *nmvsetups = arkls_mem->nmvsetup; + return(ARKLS_SUCCESS); +} + /*--------------------------------------------------------------- arkLSGetLastFlag returns the last flag set in a ARKLS @@ -1025,6 +1177,31 @@ int arkLSSetMassTimes(void *arkode_mem, } +/* arkLSMassSetUserData sets user_data pointers in arkLSMass */ +int arkLSSetMassUserData(void *arkode_mem, void* user_data) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSSetMassUserData", + &ark_mem, &arkls_mem); + if (retval != ARKLS_SUCCESS) return(retval); + + /* Set data for mass matrix */ + if (arkls_mem->mass != NULL) + arkls_mem->M_data = user_data; + + /* Data for Mtimes is set in arkLSSetMassTimes */ + + /* Set data for Preconditioner */ + arkls_mem->P_data = user_data; + + return(ARKLS_SUCCESS); +} + + /*--------------------------------------------------------------- arkLSGetMassWorkSpace ---------------------------------------------------------------*/ @@ -1593,8 +1770,8 @@ int arkLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, ARKLsMem arkls_mem, ARKRhsFn fi, N_Vector tmp1) { - realtype fnorm, minInc, inc, inc_inv, yjsaved, srur; - realtype *y_data, *ewt_data; + realtype fnorm, minInc, inc, inc_inv, yjsaved, srur, conj; + realtype *y_data, *ewt_data, *cns_data; N_Vector ftemp, jthCol; sunindextype j, N; int retval = 0; @@ -1608,9 +1785,11 @@ int arkLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, /* Create an empty vector for matrix column calculations */ jthCol = N_VCloneEmpty(tmp1); - /* Obtain pointers to the data for ewt, y */ + /* Obtain pointers to the data for various vectors */ ewt_data = N_VGetArrayPointer(ark_mem->ewt); y_data = N_VGetArrayPointer(y); + cns_data = (ark_mem->constraintsSet) ? + N_VGetArrayPointer(ark_mem->constraints) : NULL; /* Set minimum increment based on uround and norm of f */ srur = SUNRsqrt(ark_mem->uround); @@ -1625,6 +1804,14 @@ int arkLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, yjsaved = y_data[j]; inc = SUNMAX(srur*SUNRabs(yjsaved), minInc/ewt_data[j]); + + /* Adjust sign(inc) if y_j has an inequality constraint. */ + if (ark_mem->constraintsSet) { + conj = cns_data[j]; + if (SUNRabs(conj) == ONE) {if ((yjsaved+inc)*conj < ZERO) inc = -inc;} + else if (SUNRabs(conj) == TWO) {if ((yjsaved+inc)*conj <= ZERO) inc = -inc;} + } + y_data[j] += inc; retval = fi(t, y, ftemp, ark_mem->user_data); @@ -1663,8 +1850,9 @@ int arkLsBandDQJac(realtype t, N_Vector y, N_Vector fy, N_Vector tmp1, N_Vector tmp2) { N_Vector ftemp, ytemp; - realtype fnorm, minInc, inc, inc_inv, srur; + realtype fnorm, minInc, inc, inc_inv, srur, conj; realtype *col_j, *ewt_data, *fy_data, *ftemp_data, *y_data, *ytemp_data; + realtype *cns_data; sunindextype group, i, j, width, ngroups, i1, i2; sunindextype N, mupper, mlower; int retval = 0; @@ -1684,6 +1872,8 @@ int arkLsBandDQJac(realtype t, N_Vector y, N_Vector fy, ftemp_data = N_VGetArrayPointer(ftemp); y_data = N_VGetArrayPointer(y); ytemp_data = N_VGetArrayPointer(ytemp); + cns_data = (ark_mem->constraintsSet) ? + N_VGetArrayPointer(ark_mem->constraints) : NULL; /* Load ytemp with y = predicted y vector */ N_VScale(ONE, y, ytemp); @@ -1704,6 +1894,14 @@ int arkLsBandDQJac(realtype t, N_Vector y, N_Vector fy, /* Increment all y_j in group */ for(j=group-1; j < N; j+=width) { inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); + + /* Adjust sign(inc) if yj has an inequality constraint. */ + if (ark_mem->constraintsSet) { + conj = cns_data[j]; + if (SUNRabs(conj) == ONE) {if ((ytemp_data[j]+inc)*conj < ZERO) inc = -inc;} + else if (SUNRabs(conj) == TWO) {if ((ytemp_data[j]+inc)*conj <= ZERO) inc = -inc;} + } + ytemp_data[j] += inc; } @@ -1717,6 +1915,14 @@ int arkLsBandDQJac(realtype t, N_Vector y, N_Vector fy, ytemp_data[j] = y_data[j]; col_j = SUNBandMatrix_Column(Jac, j); inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); + + /* Adjust sign(inc) as before. */ + if (ark_mem->constraintsSet) { + conj = cns_data[j]; + if (SUNRabs(conj) == ONE) {if ((ytemp_data[j]+inc)*conj < ZERO) inc = -inc;} + else if (SUNRabs(conj) == TWO) {if ((ytemp_data[j]+inc)*conj <= ZERO) inc = -inc;} + } + inc_inv = ONE/inc; i1 = SUNMAX(0, j-mupper); i2 = SUNMIN(j+mlower, N-1); @@ -1791,6 +1997,99 @@ int arkLsDQJtimes(N_Vector v, N_Vector Jv, realtype t, } +/*----------------------------------------------------------------- + arkLsLinSys + + Setup the linear system A = I - gamma J or A = M - gamma J + -----------------------------------------------------------------*/ +static int arkLsLinSys(realtype t, N_Vector y, N_Vector fy, SUNMatrix A, + SUNMatrix M, booleantype jok, booleantype *jcur, + realtype gamma, void *arkode_mem, N_Vector vtemp1, + N_Vector vtemp2, N_Vector vtemp3) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLsLinSys", + &ark_mem, &arkls_mem); + if (retval != ARKLS_SUCCESS) return(retval); + + /* Check if Jacobian needs to be updated */ + if (jok) { + + /* Use saved copy of J */ + *jcur = SUNFALSE; + + /* Overwrite linear system matrix with saved J */ + retval = SUNMatCopy(arkls_mem->savedJ, A); + if (retval) { + arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", "arkLsSetup", + MSG_LS_SUNMAT_FAILED); + arkls_mem->last_flag = ARKLS_SUNMAT_FAIL; + return(arkls_mem->last_flag); + } + + } else { + + /* Call jac() routine to update J */ + *jcur = SUNTRUE; + + /* Clear the linear system matrix if necessary */ + if (SUNLinSolGetType(arkls_mem->LS) == SUNLINEARSOLVER_DIRECT) { + retval = SUNMatZero(A); + if (retval) { + arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", + "arkLsSetup", MSG_LS_SUNMAT_FAILED); + arkls_mem->last_flag = ARKLS_SUNMAT_FAIL; + return(arkls_mem->last_flag); + } + } + + /* Compute new Jacobian matrix */ + retval = arkls_mem->jac(t, y, fy, A, arkls_mem->J_data, + vtemp1, vtemp2, vtemp3); + if (retval < 0) { + arkProcessError(ark_mem, ARKLS_JACFUNC_UNRECVR, "ARKLS", + "arkLsSetup", MSG_LS_JACFUNC_FAILED); + arkls_mem->last_flag = ARKLS_JACFUNC_UNRECVR; + return(-1); + } + if (retval > 0) { + arkls_mem->last_flag = ARKLS_JACFUNC_RECVR; + return(1); + } + + /* Update saved copy of the Jacobian matrix */ + retval = SUNMatCopy(A, arkls_mem->savedJ); + if (retval) { + arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", + "arkLsSetup", MSG_LS_SUNMAT_FAILED); + arkls_mem->last_flag = ARKLS_SUNMAT_FAIL; + return(arkls_mem->last_flag); + } + + } + + /* Perform linear combination A = I - gamma*J or A = M - gamma*J */ + if (M == NULL) + retval = SUNMatScaleAddI(-gamma, A); + else + retval = SUNMatScaleAdd(-gamma, A, M); + + /* Check matrix operation return value */ + if (retval) { + arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", "arkLsSetup", + MSG_LS_SUNMAT_FAILED); + arkls_mem->last_flag = ARKLS_SUNMAT_FAIL; + return(arkls_mem->last_flag); + } + + return(ARKLS_SUCCESS); +} + + /*--------------------------------------------------------------- arkLsInitialize performs remaining initializations specific to the iterative linear solver interface (and solver itself) @@ -1816,46 +2115,68 @@ int arkLsInitialize(void* arkode_mem) if (retval != ARK_SUCCESS) return(retval); } - /* Test for valid combinations of matrix & Jacobian routines: */ - if (arkls_mem->A == NULL) { + if (arkls_mem->A != NULL) { - /* If SUNMatrix A is NULL: ensure 'jac' function pointer is still NULL */ - arkls_mem->jacDQ = SUNFALSE; - arkls_mem->jac = NULL; - arkls_mem->J_data = NULL; + /* Matrix-based case */ - } else if (arkls_mem->jacDQ) { + if (!arkls_mem->user_linsys) { - /* If A is non-NULL, and 'jac' is not user-supplied: - - if A is dense or band, ensure that our DQ approx. is used - - otherwise => error */ - retval = 0; - if (arkls_mem->A->ops->getid) { + /* Internal linear system function, reset pointers (just in case) */ + arkls_mem->linsys = arkLsLinSys; + arkls_mem->A_data = ark_mem; - if ( (SUNMatGetID(arkls_mem->A) == SUNMATRIX_DENSE) || - (SUNMatGetID(arkls_mem->A) == SUNMATRIX_BAND) ) { - arkls_mem->jac = arkLsDQJac; - arkls_mem->J_data = ark_mem; - } else { - retval++; + /* Check if an internal or user-supplied Jacobian function is used */ + if (arkls_mem->jacDQ) { + + /* Internal difference quotient Jacobian. Check that A is dense or band, + otherwise return an error */ + retval = 0; + if (arkls_mem->A->ops->getid) { + + if ( (SUNMatGetID(arkls_mem->A) == SUNMATRIX_DENSE) || + (SUNMatGetID(arkls_mem->A) == SUNMATRIX_BAND) ) { + arkls_mem->jac = arkLsDQJac; + arkls_mem->J_data = ark_mem; + } else { + retval++; + } + + } else { + retval++; + } + if (retval) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLsInitialize", + "No Jacobian constructor available for SUNMatrix type"); + arkls_mem->last_flag = ARKLS_ILL_INPUT; + return(ARKLS_ILL_INPUT); + } } - } else { - retval++; - } - if (retval) { - arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLsInitialize", - "No Jacobian constructor available for SUNMatrix type"); - arkls_mem->last_flag = ARKLS_ILL_INPUT; - return(ARKLS_ILL_INPUT); - } + /* Allocate internally saved Jacobian if not already done */ + if (arkls_mem->savedJ == NULL) { + arkls_mem->savedJ = SUNMatClone(arkls_mem->A); + if (arkls_mem->savedJ == NULL) { + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKLS", + "arkLsInitialize", MSG_LS_MEM_FAIL); + arkls_mem->last_flag = ARKLS_MEM_FAIL; + return(ARKLS_MEM_FAIL); + } + } + + } /* end matrix-based case */ } else { - /* If A is non-NULL, and 'jac' is user-supplied, - reset J_data pointer (just in case) */ - arkls_mem->J_data = ark_mem->user_data; + /* Matrix-free case: ensure 'jac' and 'linsys' function pointers are NULL */ + arkls_mem->jacDQ = SUNFALSE; + arkls_mem->jac = NULL; + arkls_mem->J_data = NULL; + + arkls_mem->user_linsys = SUNFALSE; + arkls_mem->linsys = NULL; + arkls_mem->A_data = NULL; + } @@ -1897,13 +2218,11 @@ int arkLsInitialize(void* arkode_mem) /* reset counters */ arkLsInitializeCounters(arkls_mem); - /* Set Jacobian-vector product fields, based on jtimesDQ */ + /* Set Jacobian-vector product related fields, based on jtimesDQ */ if (arkls_mem->jtimesDQ) { arkls_mem->jtsetup = NULL; arkls_mem->jtimes = arkLsDQJtimes; arkls_mem->Jt_data = ark_mem; - } else { - arkls_mem->Jt_data = ark_mem->user_data; } /* if A is NULL and psetup is not present, then arkLsSetup does @@ -1936,10 +2255,10 @@ int arkLsSetup(void* arkode_mem, int convfail, realtype tpred, N_Vector ypred, N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) { - ARKodeMem ark_mem; - ARKLsMem arkls_mem; - ARKLsMassMem arkls_massmem; - void* ark_step_massmem; + ARKodeMem ark_mem = NULL; + ARKLsMem arkls_mem = NULL; + void* ark_step_massmem = NULL; + SUNMatrix M = NULL; realtype gamma, gamrat; booleantype dgamma_fail, *jcur; int retval; @@ -1959,7 +2278,7 @@ int arkLsSetup(void* arkode_mem, int convfail, realtype tpred, arkls_mem->last_flag = ark_mem->step_getgammas(arkode_mem, &gamma, &gamrat, &jcur, &dgamma_fail); if (arkls_mem->last_flag) { - arkProcessError(ark_mem, retval, "ARKLS", "arkLsSetup", + arkProcessError(ark_mem, arkls_mem->last_flag, "ARKLS", "arkLsSetup", "An error occurred in ark_step_getgammas"); return(arkls_mem->last_flag); } @@ -1973,91 +2292,60 @@ int arkLsSetup(void* arkode_mem, int convfail, realtype tpred, ((convfail == ARK_FAIL_BAD_J) && (!dgamma_fail)) || (convfail == ARK_FAIL_OTHER); - /* If using a NULL SUNMatrix, set jcur to jbad; otherwise update J as appropriate */ - if (arkls_mem->A == NULL) { + /* Check for mass matrix module and setup mass matrix */ + if (ark_mem->step_getmassmem) + ark_step_massmem = ark_mem->step_getmassmem(arkode_mem); - *jcurPtr = arkls_mem->jbad; + if (ark_step_massmem) { - } else { + /* Set shortcut to the mass matrix (NULL if matrix-free) */ + M = ((ARKLsMassMem) ark_step_massmem)->M; - /* If jbad = SUNFALSE, use saved copy of J */ - if (!arkls_mem->jbad) { + /* Setup mass matrix linear solver (including recomputation of mass matrix) */ + arkls_mem->last_flag = arkLsMassSetup(arkode_mem, vtemp1, vtemp2, vtemp3); + if (arkls_mem->last_flag) { + arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", "arkLsSetup", + "Error setting up mass-matrix linear solver"); + return(arkls_mem->last_flag); + } - *jcurPtr = SUNFALSE; - retval = SUNMatCopy(arkls_mem->savedJ, arkls_mem->A); - if (retval) { - arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", - "arkLsSetup", MSG_LS_SUNMAT_FAILED); - arkls_mem->last_flag = ARKLS_SUNMAT_FAIL; - return(arkls_mem->last_flag); - } + } + + /* Setup the linear system if necessary */ + if (arkls_mem->A != NULL) { - /* If jbad = SUNTRUE, clear out J and call jac routine for new value */ - } else { + /* Update J if appropriate and evaluate A = I-gamma*J or A = M-gamma*J */ + retval = arkls_mem->linsys(tpred, ypred, fpred, arkls_mem->A, M, + !(arkls_mem->jbad), jcurPtr, gamma, + arkls_mem->A_data, vtemp1, vtemp2, vtemp3); + /* Update J eval count and step when J was last updated */ + if (*jcurPtr) { arkls_mem->nje++; arkls_mem->nstlj = ark_mem->nst; - *jcurPtr = SUNTRUE; - retval = SUNMatZero(arkls_mem->A); - if (retval) { - arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", - "arkLsSetup", MSG_LS_SUNMAT_FAILED); - arkls_mem->last_flag = ARKLS_SUNMAT_FAIL; - return(arkls_mem->last_flag); - } - - retval = arkls_mem->jac(tpred, ypred, fpred, arkls_mem->A, - arkls_mem->J_data, vtemp1, vtemp2, vtemp3); - if (retval < 0) { - arkProcessError(ark_mem, ARKLS_JACFUNC_UNRECVR, "ARKLS", - "arkLsSetup", MSG_LS_JACFUNC_FAILED); - arkls_mem->last_flag = ARKLS_JACFUNC_UNRECVR; - return(-1); - } - if (retval > 0) { - arkls_mem->last_flag = ARKLS_JACFUNC_RECVR; - return(1); - } - - retval = SUNMatCopy(arkls_mem->A, arkls_mem->savedJ); - if (retval) { - arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", - "arkLsSetup", MSG_LS_SUNMAT_FAILED); - arkls_mem->last_flag = ARKLS_SUNMAT_FAIL; - return(arkls_mem->last_flag); - } - } - /* Scale and add mass matrix to get A = M-gamma*J*/ - ark_step_massmem = NULL; - if (ark_mem->step_getmassmem) - ark_step_massmem = ark_mem->step_getmassmem(arkode_mem); - if (ark_step_massmem) { - - arkls_massmem = (ARKLsMassMem) ark_step_massmem; - - /* Setup mass matrix linear solver (including recomputation of mass matrix) */ - arkls_mem->last_flag = arkLsMassSetup(arkode_mem, vtemp1, vtemp2, vtemp3); - if (retval) { - arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", "arkLsSetup", - "Error setting up mass-matrix linear solver"); - return(arkls_mem->last_flag); + /* Check linsys() return value and return if necessary */ + if (retval != ARKLS_SUCCESS) { + if (arkls_mem->user_linsys) { + if (retval < 0) { + arkProcessError(ark_mem, ARKLS_JACFUNC_UNRECVR, "ARKLS", + "arkLsSetup", MSG_LS_JACFUNC_FAILED); + arkls_mem->last_flag = ARKLS_JACFUNC_UNRECVR; + return(-1); + } else { + arkls_mem->last_flag = ARKLS_JACFUNC_RECVR; + return(1); + } + } else { + return(retval); } + } - /* Perform linear combination A = M-gamma*A */ - retval = SUNMatScaleAdd(-gamma, arkls_mem->A, arkls_massmem->M); + } else { - /* or if M==I, set A = I-gamma*J*/ - } else { - retval = SUNMatScaleAddI(-gamma, arkls_mem->A); - } - if (retval) { - arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", - "arkLsSetup", MSG_LS_SUNMAT_FAILED); - arkls_mem->last_flag = ARKLS_SUNMAT_FAIL; - return(arkls_mem->last_flag); - } + /* Matrix-free case, set jcur to jbad */ + *jcurPtr = arkls_mem->jbad; } @@ -2081,6 +2369,7 @@ int arkLsSetup(void* arkode_mem, int convfail, realtype tpred, return(arkls_mem->last_flag); } + /*--------------------------------------------------------------- arkLsSolve: interfaces between ARKode and the generic SUNLinearSolver object LS, by setting the appropriate tolerance @@ -2096,9 +2385,11 @@ int arkLsSolve(void* arkode_mem, N_Vector b, realtype tnow, realtype bnorm, resnorm; ARKodeMem ark_mem; ARKLsMem arkls_mem; - realtype gamma, gamrat, delta, deltar, ewt_mean; + realtype gamma, gamrat, delta, deltar, rwt_mean; booleantype dgamma_fail, *jcur; - int nli_inc, nps_inc, retval, LSType; + long int nps_inc; + int nli_inc, retval; + /* access ARKLsMem structure */ retval = arkLs_AccessLMem(arkode_mem, "arkLsSolve", @@ -2111,14 +2402,10 @@ int arkLsSolve(void* arkode_mem, N_Vector b, realtype tnow, arkls_mem->ycur = ynow; arkls_mem->fcur = fnow; - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(arkls_mem->LS); - /* If the linear solver is iterative: test norm(b), if small, return x = 0 or x = b; set linear solver tolerance (in left/right scaled 2-norm) */ - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (arkls_mem->iterative) { deltar = arkls_mem->eplifac * eRNrm; bnorm = N_VWrmsNorm(b, ark_mem->rwt); if (bnorm <= deltar) { @@ -2128,17 +2415,14 @@ int arkLsSolve(void* arkode_mem, N_Vector b, realtype tnow, } delta = deltar * arkls_mem->sqrtN; } else { - delta = ZERO; + delta = bnorm = ZERO; } - /* Set initial guess x = 0 to LS */ - N_VConst(ZERO, arkls_mem->x); - /* Set scaling vectors for LS to use (if applicable) */ if (arkls_mem->LS->ops->setscalingvectors) { retval = SUNLinSolSetScalingVectors(arkls_mem->LS, - ark_mem->ewt, - ark_mem->rwt); + ark_mem->rwt, + ark_mem->ewt); if (retval != SUNLS_SUCCESS) { arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKLS", "arkLsSolve", "Error in call to SUNLinSolSetScalingVectors"); @@ -2149,27 +2433,28 @@ int arkLsSolve(void* arkode_mem, N_Vector b, realtype tnow, /* If solver is iterative and does not support scaling vectors, update the tolerance in an attempt to account for ewt/rwt vectors. We make the following assumptions: - 1. rwt = ewt (i.e. the units of solution and residual are the same) - 2. ewt_i = ewt_mean, for i=0,...,n-1 (i.e. the solution units are identical) - 3. the linear solver uses a basic 2-norm to measure convergence - Hence (using the notation from sunlinsol_spgmr.h, with S = diag(ewt)), + 1. rwt_i = rwt_mean, for i=0,...,n-1 (i.e. the residual units are identical) + 2. the linear solver uses a basic 2-norm to measure convergence + Hence (using the notation from sunlinsol_spgmr.h, with S = diag(rwt)), || bbar - Abar xbar ||_2 < tol <=> || S b - S A x ||_2 < tol <=> || S (b - A x) ||_2 < tol - <=> \sum_{i=0}^{n-1} (ewt_i (b - A x)_i)^2 < tol^2 - <=> ewt_mean^2 \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 - <=> \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 / ewt_mean^2 - <=> || b - A x ||_2 < tol / ewt_mean - So we compute ewt_mean = ||ewt||_RMS = ||ewt||_2 / sqrt(n), and scale - the desired tolerance accordingly. */ - } else if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + <=> \sum_{i=0}^{n-1} (rwt_i (b - A x)_i)^2 < tol^2 + <=> rwt_mean^2 \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 + <=> \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 / rwt_mean^2 + <=> || b - A x ||_2 < tol / rwt_mean + So we compute rwt_mean = ||rwt||_RMS and scale the desired tolerance accordingly. */ + } else if (arkls_mem->iterative) { - ewt_mean = SUNRsqrt( N_VDotProd(ark_mem->ewt, ark_mem->ewt) ) / arkls_mem->sqrtN; - delta /= ewt_mean; + N_VConst(ONE, arkls_mem->x); + rwt_mean = N_VWrmsNorm(ark_mem->rwt, arkls_mem->x); + delta /= rwt_mean; } + /* Set initial guess x = 0 to LS */ + N_VConst(ZERO, arkls_mem->x); + /* Store previous nps value in nps_inc */ nps_inc = arkls_mem->nps; @@ -2179,7 +2464,7 @@ int arkLsSolve(void* arkode_mem, N_Vector b, realtype tnow, arkls_mem->Jt_data); arkls_mem->njtsetup++; if (arkls_mem->last_flag) { - arkProcessError(ark_mem, retval, "ARKLS", + arkProcessError(ark_mem, arkls_mem->last_flag, "ARKLS", "arkLsSolve", MSG_LS_JTSETUP_FAILED); return(arkls_mem->last_flag); } @@ -2192,8 +2477,7 @@ int arkLsSolve(void* arkode_mem, N_Vector b, realtype tnow, /* If using a direct or matrix-iterative solver, scale the correction to account for change in gamma (this is only beneficial if M==I) */ - if ( (LSType == SUNLINEARSOLVER_DIRECT) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (arkls_mem->scalesol) { arkls_mem->last_flag = ark_mem->step_getgammas(arkode_mem, &gamma, &gamrat, &jcur, &dgamma_fail); if (arkls_mem->last_flag != ARK_SUCCESS) { @@ -2207,8 +2491,7 @@ int arkLsSolve(void* arkode_mem, N_Vector b, realtype tnow, /* Retrieve statistics from iterative linear solvers */ resnorm = ZERO; nli_inc = 0; - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (arkls_mem->iterative) { if (arkls_mem->LS->ops->resnorm) resnorm = SUNLinSolResNorm(arkls_mem->LS); if (arkls_mem->LS->ops->numiters) @@ -2222,7 +2505,7 @@ int arkLsSolve(void* arkode_mem, N_Vector b, realtype tnow, /* Log solver statistics to diagnostics file (if requested) */ if (ark_mem->report) fprintf(ark_mem->diagfp, "ARKLS kry %"RSYM" %"RSYM" %i %i\n", - bnorm, resnorm, nli_inc, (int) arkls_mem->nps - nps_inc); + bnorm, resnorm, nli_inc, (int) (arkls_mem->nps - nps_inc)); /* Interpret solver return value */ arkls_mem->last_flag = retval; @@ -2393,7 +2676,7 @@ int arkLsMassSetup(void *arkode_mem, N_Vector vtemp1, { ARKodeMem ark_mem; ARKLsMassMem arkls_mem; - booleantype call_mtsetup, call_lssetup; + booleantype call_mtsetup, call_mvsetup, call_lssetup; int retval; /* access ARKLsMassMem structure */ @@ -2419,12 +2702,13 @@ int arkLsMassSetup(void *arkode_mem, N_Vector vtemp1, } } - /* Perform user-facing setup based on whether this is matrix-free */ if (arkls_mem->M == NULL) { /*** matrix-free -- only call LS setup if preconditioner setup exists ***/ call_lssetup = (arkls_mem->pset != NULL); + /*** matrix-free -- dont call matvec setup ***/ + call_mvsetup = SUNFALSE; } else { @@ -2437,17 +2721,19 @@ int arkLsMassSetup(void *arkode_mem, N_Vector vtemp1, return(arkls_mem->last_flag); } - /* Update mass matrix */ - retval = SUNMatZero(arkls_mem->M); - if (retval) { - arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", - "arkLsMassSetup", MSG_LS_SUNMAT_FAILED); - arkls_mem->last_flag = ARKLS_SUNMAT_FAIL; - return(arkls_mem->last_flag); + /* Clear the mass matrix if necessary */ + if (SUNLinSolGetType(arkls_mem->LS) == SUNLINEARSOLVER_DIRECT) { + retval = SUNMatZero(arkls_mem->M); + if (retval) { + arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", + "arkLsMassSetup", MSG_LS_SUNMAT_FAILED); + arkls_mem->last_flag = ARKLS_SUNMAT_FAIL; + return(arkls_mem->last_flag); + } } retval = arkls_mem->mass(ark_mem->tcur, arkls_mem->M, - ark_mem->user_data, + arkls_mem->M_data, vtemp1, vtemp2, vtemp3); if (retval < 0) { arkProcessError(ark_mem, ARKLS_MASSFUNC_UNRECVR, "ARKLS", @@ -2469,17 +2755,37 @@ int arkLsMassSetup(void *arkode_mem, N_Vector vtemp1, return(arkls_mem->last_flag); } + /* signal call to matvec setup routine only if the user didn't provide + * mtimes and the SUNMatrix implements the matvecsetup routine */ + if ((!arkls_mem->mtimes) && (arkls_mem->M->ops->matvecsetup)) + call_mvsetup = SUNTRUE; + else + call_mvsetup = SUNFALSE; + /* signal call to LS setup routine */ call_lssetup = SUNTRUE; } + /* Call matvec setup routine if applicable */ + if (call_mvsetup) { + retval = SUNMatMatvecSetup(arkls_mem->M); + arkls_mem->nmvsetup++; + if (retval) { + arkProcessError(ark_mem, ARKLS_SUNMAT_FAIL, "ARKLS", + "arkLsMassSetup", MSG_LS_SUNMAT_FAILED); + arkls_mem->last_flag = ARKLS_SUNMAT_FAIL; + return(arkls_mem->last_flag); + } + } + /* Call LS setup routine if applicable, and return */ if (call_lssetup) { arkls_mem->last_flag = SUNLinSolSetup(arkls_mem->LS, arkls_mem->M_lu); arkls_mem->nmsetups++; } + return(arkls_mem->last_flag); } @@ -2495,19 +2801,16 @@ int arkLsMassSolve(void *arkode_mem, N_Vector b, realtype nlscoef) realtype resnorm, delta, rwt_mean; ARKodeMem ark_mem; ARKLsMassMem arkls_mem; - int nli_inc, nps_inc, retval, LSType; + long int nps_inc; + int nli_inc, retval; /* access ARKLsMassMem structure */ retval = arkLs_AccessMassMem(arkode_mem, "arkLsMassSolve", &ark_mem, &arkls_mem); if (retval != ARK_SUCCESS) return(retval); - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(arkls_mem->LS); - /* Set input tolerance for iterative solvers */ - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (arkls_mem->iterative) { delta = arkls_mem->eplifac * nlscoef * arkls_mem->sqrtN; } else { delta = ZERO; @@ -2541,16 +2844,18 @@ int arkLsMassSolve(void *arkode_mem, N_Vector b, realtype nlscoef) <=> rwt_mean^2 \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 <=> \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 / rwt_mean^2 <=> || b - A x ||_2 < tol / rwt_mean - So we compute rwt_mean = ||rwt||_RMS = ||rwt||_2 / sqrt(n), and scale - the desired tolerance accordingly. */ - } else if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + So we compute rwt_mean = ||rwt||_RMS and scale the desired tolerance accordingly. */ + } else if (arkls_mem->iterative) { - rwt_mean = SUNRsqrt( N_VDotProd(ark_mem->rwt, ark_mem->rwt) ) / arkls_mem->sqrtN; + N_VConst(ONE, arkls_mem->x); + rwt_mean = N_VWrmsNorm(ark_mem->rwt, arkls_mem->x); delta /= rwt_mean; } + /* Set initial guess x = 0 for LS */ + N_VConst(ZERO, arkls_mem->x); + /* Store previous nps value in nps_inc */ nps_inc = arkls_mem->nps; @@ -2563,8 +2868,7 @@ int arkLsMassSolve(void *arkode_mem, N_Vector b, realtype nlscoef) /* Retrieve statistics from iterative linear solvers */ resnorm = ZERO; nli_inc = 0; - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (arkls_mem->iterative) { if (arkls_mem->LS->ops->resnorm) resnorm = SUNLinSolResNorm(arkls_mem->LS); if (arkls_mem->LS->ops->numiters) @@ -2578,7 +2882,7 @@ int arkLsMassSolve(void *arkode_mem, N_Vector b, realtype nlscoef) /* Log solver statistics to diagnostics file (if requested) */ if (ark_mem->report) fprintf(ark_mem->diagfp, "ARKLS mass %"RSYM" %i %i\n", - resnorm, nli_inc, (int) arkls_mem->nps - nps_inc); + resnorm, nli_inc, (int) (arkls_mem->nps - nps_inc)); /* Interpret solver return value */ arkls_mem->last_flag = retval; @@ -2705,6 +3009,7 @@ int arkLsInitializeMassCounters(ARKLsMassMem arkls_mem) arkls_mem->nmsolves = 0; arkls_mem->nmtsetup = 0; arkls_mem->nmtimes = 0; + arkls_mem->nmvsetup = 0; arkls_mem->npe = 0; arkls_mem->nli = 0; arkls_mem->nps = 0; diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_ls_impl.h b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_ls_impl.h index 568f6f1a7..e5d11df2c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_ls_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_ls_impl.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -45,12 +45,19 @@ extern "C" { ---------------------------------------------------------------*/ typedef struct ARKLsMemRec { + /* Linear solver type information */ + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ + /* Jacobian construction & storage */ booleantype jacDQ; /* SUNTRUE if using internal DQ Jacobian approx. */ ARKLsJacFn jac; /* Jacobian routine to be called */ void *J_data; /* user data is passed to jac */ booleantype jbad; /* heuristic suggestion for pset */ + /* Matrix-based solver, scale solution to account for change in gamma */ + booleantype scalesol; + /* Iterative solver tolerance */ realtype sqrtN; /* sqrt(N) */ realtype eplifac; /* nonlinear -> linear tol scaling factor */ @@ -102,7 +109,18 @@ typedef struct ARKLsMemRec { ARKLsJacTimesVecFn jtimes; void *Jt_data; - long int last_flag; /* last error flag returned by any function */ + /* Linear system setup function + * (a) user-provided linsys function: + * - user_linsys = SUNTRUE + * - A_data = user_data + * (b) internal linsys function: + * - user_linsys = SUNFALSE + * - A_data = cvode_mem */ + booleantype user_linsys; + ARKLsLinSysFn linsys; + void* A_data; + + int last_flag; /* last error flag returned by any function */ } *ARKLsMem; @@ -114,30 +132,36 @@ typedef struct ARKLsMemRec { ---------------------------------------------------------------*/ typedef struct ARKLsMassMemRec { + /* Linear solver type information */ + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ + /* Mass matrix construction & storage */ - ARKLsMassFn mass; /* user-provided mass matrix routine to call */ - SUNMatrix M; /* mass matrix structure */ - SUNMatrix M_lu; /* mass matrix structure for LU decomposition */ + ARKLsMassFn mass; /* user-provided mass matrix routine to call */ + SUNMatrix M; /* mass matrix structure */ + SUNMatrix M_lu; /* mass matrix structure for LU decomposition */ + void* M_data; /* user data pointer */ /* Iterative solver tolerance */ - realtype sqrtN; /* sqrt(N) */ - realtype eplifac; /* nonlinear -> linear tol scaling factor */ + realtype sqrtN; /* sqrt(N) */ + realtype eplifac; /* nonlinear -> linear tol scaling factor */ /* Statistics and associated parameters */ - booleantype time_dependent; /* flag whether M depends on t */ - long int nmsetups; /* total number of mass matrix-solver setups */ - long int nmsolves; /* total number of mass matrix-solver solves */ - long int nmtsetup; /* total number of calls to mtsetup */ - long int nmtimes; /* total number of calls to mtimes */ - long int npe; /* total number of pset calls */ - long int nli; /* total number of linear iterations */ - long int nps; /* total number of psolve calls */ - long int ncfl; /* total number of convergence failures */ + booleantype time_dependent; /* flag whether M depends on t */ + long int nmsetups; /* total number of mass matrix-solver setups */ + long int nmsolves; /* total number of mass matrix-solver solves */ + long int nmtsetup; /* total number of calls to mtsetup */ + long int nmtimes; /* total number of calls to mtimes */ + long int nmvsetup; /* total number of calls to SUNMatMatvec setup */ + long int npe; /* total number of pset calls */ + long int nli; /* total number of linear iterations */ + long int nps; /* total number of psolve calls */ + long int ncfl; /* total number of convergence failures */ /* Linear solver, matrix and vector objects/pointers */ - SUNLinearSolver LS; /* generic linear solver object */ - N_Vector x; /* solution vector used by SUNLinearSolver */ - N_Vector ycur; /* ptr to ARKode current y vector */ + SUNLinearSolver LS; /* generic linear solver object */ + N_Vector x; /* solution vector used by SUNLinearSolver */ + N_Vector ycur; /* ptr to ARKode current y vector */ /* Preconditioner computation (a) user-provided: @@ -145,7 +169,7 @@ typedef struct ARKLsMassMemRec { - pfree == NULL (the user dealocates memory for user_data) (b) internal preconditioner module - P_data == arkode_mem - - pfree == set by the prec. module and called in ARKodeFree */ + - pfree == set by the prec. module and called in ARKodeFree */ ARKLsMassPrecSetupFn pset; ARKLsMassPrecSolveFn psolve; int (*pfree)(ARKodeMem ark_mem); @@ -156,7 +180,7 @@ typedef struct ARKLsMassMemRec { ARKLsMassTimesVecFn mtimes; void *mt_data; - long int last_flag; /* last error flag returned by any function */ + int last_flag; /* last error flag returned by any function */ } *ARKLsMassMem; @@ -240,6 +264,7 @@ int arkLSSetMassFn(void* arkode_mem, ARKLsMassFn mass); int arkLSSetEpsLin(void* arkode_mem, realtype eplifac); int arkLSSetMassEpsLin(void* arkode_mem, realtype eplifac); int arkLSSetMaxStepsBetweenJac(void* arkode_mem, long int msbj); +int arkLSSetLinearSolutionScaling(void* arkode_mem, booleantype onoff); int arkLSSetPreconditioner(void* arkode_mem, ARKLsPrecSetupFn psetup, ARKLsPrecSolveFn psolve); int arkLSSetMassPreconditioner(void* arkode_mem, ARKLsMassPrecSetupFn psetup, @@ -248,6 +273,10 @@ int arkLSSetJacTimes(void* arkode_mem, ARKLsJacTimesSetupFn jtsetup, ARKLsJacTimesVecFn jtimes); int arkLSSetMassTimes(void* arkode_mem, ARKLsMassTimesSetupFn msetup, ARKLsMassTimesVecFn mtimes, void* mtimes_data); +int arkLSSetLinSysFn(void* arkode_mem, ARKLsLinSysFn linsys); + +int arkLSSetUserData(void *arkode_mem, void* user_data); +int arkLSSetMassUserData(void *arkode_mem, void* user_data); int arkLSGetWorkSpace(void* arkode_mem, long int* lenrwLS, long int* leniwLS); int arkLSGetNumJacEvals(void* arkode_mem, long int* njevals); @@ -264,6 +293,7 @@ int arkLSGetMassWorkSpace(void* arkode_mem, long int* lenrwMLS, long int* leniwMLS); int arkLSGetNumMassSetups(void* arkode_mem, long int* nmsetups); int arkLSGetNumMassMult(void* arkode_mem, long int* nmvevals); +int arkLSGetNumMassMatvecSetups(void *arkode_mem, long int *nmvsetups); int arkLSGetNumMassSolves(void* arkode_mem, long int* nmsolves); int arkLSGetNumMassPrecEvals(void* arkode_mem, long int* nmpevals); int arkLSGetNumMassPrecSolves(void* arkode_mem, long int* nmpsolves); diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_mristep.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_mristep.c index a66838dfa..ae568f9a4 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_mristep.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_mristep.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -21,6 +21,7 @@ #include "arkode_impl.h" #include "arkode_mristep_impl.h" +#include "arkode_interp_impl.h" #include #if defined(SUNDIALS_EXTENDED_PRECISION) @@ -45,118 +46,37 @@ MRIStep Exported functions -- Required ===============================================================*/ -void* MRIStepCreate(ARKRhsFn fs, ARKRhsFn ff, realtype t0, N_Vector y0) +/*--------------------------------------------------------------- + Create MRIStep integrator memory struct + ---------------------------------------------------------------*/ +void* MRIStepCreate(ARKRhsFn fs, realtype t0, N_Vector y0, + MRISTEP_ID inner_step_id, void* inner_mem) { - ARKodeMem ark_mem; - void *inner_arkode_mem; - ARKodeMRIStepMem step_mem; - booleantype nvectorOK; - int retval; - - /* Check that fs and ff are supplied */ - if (fs == NULL || ff == NULL) { - arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::MRIStep", - "MRIStepCreate", MSG_ARK_NULL_F); - return(NULL); - } - - /* Check for legal input parameters */ - if (y0 == NULL) { - arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::MRIStep", - "MRIStepCreate", MSG_ARK_NULL_Y0); - return(NULL); - } - - /* Test if all required vector operations are implemented */ - nvectorOK = mriStep_CheckNVector(y0); - if (!nvectorOK) { - arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::MRIStep", - "MRIStepCreate", MSG_ARK_BAD_NVECTOR); - return(NULL); - } - - /* Create ark_mem structure and set default values */ - ark_mem = arkCreate(); - if (ark_mem == NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepCreate", MSG_ARK_NO_MEM); - return(NULL); - } - - /* Allocate ARKodeMRIStepMem structure, and initialize to zero */ - step_mem = NULL; - step_mem = (ARKodeMRIStepMem) malloc(sizeof(struct ARKodeMRIStepMemRec)); - if (step_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::MRIStep", - "MRIStepCreate", MSG_ARK_ARKMEM_FAIL); - return(NULL); - } - memset(step_mem, 0, sizeof(struct ARKodeMRIStepMemRec)); - - /* Attach step_mem structure and function pointers to ark_mem */ - ark_mem->step_init = mriStep_Init; - ark_mem->step_fullrhs = mriStep_FullRHS; - ark_mem->step = mriStep_TakeStep; - ark_mem->step_mem = (void*) step_mem; - - /* Allocate the general MRI stepper vectors using y0 as a template */ - /* NOTE: F, cvals and Xvecs will be allocated later on - (based on the number of MRI stages) */ - - /* Clone input vector to create inner RHS forcing vector */ - if (!arkAllocVec(ark_mem, y0, &(step_mem->forcing))) - return(NULL); - - /* Copy the input parameters into ARKode state */ - step_mem->fs = fs; - step_mem->ff = ff; - - /* Update the ARKode workspace requirements */ - ark_mem->liw += 11; /* fcn/data ptr, int, long int, sunindextype, booleantype */ - ark_mem->lrw += 1; + void *arkode_mem; /* ARKode MRIStep memory */ + int retval; /* return value */ - /* Initialize all the counters */ - step_mem->nfs = 0; - step_mem->nff = 0; + /* Create the ARKode MRIStep memory */ + arkode_mem = mriStep_Create(fs, t0, y0); + if (arkode_mem == NULL) return(NULL); - /* Initialize main ARKode infrastructure (allocates vectors) */ - retval = arkInit(ark_mem, t0, y0); - if (retval != ARK_SUCCESS) { - arkProcessError(ark_mem, retval, "ARKode::MRIStep", "MRIStepCreate", - "Unable to initialize main ARKode infrastructure"); - return(NULL); - } - - /* create and attach the inner ARK stepper (assume explicit) */ - inner_arkode_mem = ARKStepCreate(mriStep_InnerRhsFn, NULL, t0, y0); - if (inner_arkode_mem == NULL) { - arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::MRIStep", "MRIStepCreate", - "Allocation of the inner step memory failed"); - return(NULL); - } - step_mem->inner_arkode_mem = inner_arkode_mem; - - /* initialize the saved return value for the inner stepper */ - step_mem->inner_retval = ARK_SUCCESS; - - /* Set default values for MRIStep optional inputs (inner and outer) */ - retval = MRIStepSetDefaults((void *) ark_mem); - if (retval != ARK_SUCCESS) { - arkProcessError(ark_mem, retval, "ARKode::MRIStep", - "MRIStepCreate", - "Error setting default solver options"); + /* Set the inner integrator */ + switch (inner_step_id) { + case MRISTEP_ARKSTEP: + retval = mriStep_AttachARK(arkode_mem, inner_mem); + break; + default: + arkProcessError((ARKodeMem) arkode_mem, ARK_ILL_INPUT, + "ARKode::MRIStep", "MRIStepCreate", + "Invalid inner integrator option"); + MRIStepFree(&arkode_mem); return(NULL); } - /* attach outer stepper mem to inner stepper as user data */ - retval = ARKStepSetUserData(inner_arkode_mem, (void *)ark_mem); - if (retval != ARK_SUCCESS) { - arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::MRIStep", "MRIStepCreate", - "Attaching data to inner stepper failed"); - return(NULL); - } + /* check if inner integrator was attached successfully */ + if (retval != ARK_SUCCESS) return(NULL); - return((void *)ark_mem); + /* return ARKode memory */ + return(arkode_mem); } @@ -197,29 +117,22 @@ int MRIStepResize(void *arkode_mem, N_Vector y0, realtype t0, return(flag); } - /* Resize the forcing vector */ - if (step_mem->forcing != NULL) { - retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, - liw_diff, y0, &step_mem->forcing); - if (retval != ARK_SUCCESS) return(retval); + /* Resize the inner forcing vector */ + if (step_mem->inner_forcing != NULL) { + for (i = 0; i < step_mem->inner_num_forcing; i++) { + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &(step_mem->inner_forcing[i])); + if (retval != ARK_SUCCESS) return(retval); + } } /* Resize the RHS vectors */ for (i=0; istages; i++) { retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, - liw_diff, y0, &step_mem->F[i]); + liw_diff, y0, &step_mem->F[i]); if (retval != ARK_SUCCESS) return(retval); } - /* Resize the inner stepper (use hscale = 1.0) */ - retval = ARKStepResize(step_mem->inner_arkode_mem, - y0, RCONST(1.0), t0, resize, resize_data); - if (retval != ARK_SUCCESS) { - arkProcessError(ark_mem, retval, "ARKode::MRIStep", "MRIStepResize", - "Unable to resize inner ARKode infrastructure"); - return(retval); - } - return(ARK_SUCCESS); } @@ -229,9 +142,11 @@ int MRIStepResize(void *arkode_mem, N_Vector y0, realtype t0, This routine re-initializes the MRIStep module to solve a new problem of the same size as was previously solved. + + NOTE: the inner stepper needs to be reinitialized before + calling this function. ---------------------------------------------------------------*/ -int MRIStepReInit(void* arkode_mem, ARKRhsFn fs, ARKRhsFn ff, - realtype t0, N_Vector y0) +int MRIStepReInit(void* arkode_mem, ARKRhsFn fs, realtype t0, N_Vector y0) { ARKodeMem ark_mem; ARKodeMRIStepMem step_mem; @@ -242,14 +157,14 @@ int MRIStepReInit(void* arkode_mem, ARKRhsFn fs, ARKRhsFn ff, &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - /* Check that fs and ff are supplied */ - if (fs == NULL || ff == NULL) { + /* Check that fs is supplied */ + if (fs == NULL) { arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", "MRIStepReInit", MSG_ARK_NULL_F); return(ARK_ILL_INPUT); } - /* Check for legal input parameters */ + /* Check that y0 is supplied */ if (y0 == NULL) { arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", "MRIStepReInit", MSG_ARK_NULL_Y0); @@ -266,23 +181,24 @@ int MRIStepReInit(void* arkode_mem, ARKRhsFn fs, ARKRhsFn ff, /* Copy the input parameters into ARKode state */ step_mem->fs = fs; - step_mem->ff = ff; /* Initialize all the counters */ step_mem->nfs = 0; - step_mem->nff = 0; - /* Reinitialize the inner stepper (assume explicit) */ - retval = ARKStepReInit(step_mem->inner_arkode_mem, - mriStep_InnerRhsFn, NULL, t0, y0); - if (retval != ARK_SUCCESS) { - arkProcessError(ark_mem, retval, "ARKode::MRIStep", "MRIStepReInit", - "Unable to reinitialize inner ARKode infrastructure"); - return(retval); + /* Reattach the inner integrator */ + switch (step_mem->inner_stepper_id) { + case MRISTEP_ARKSTEP: + retval = mriStep_AttachARK(arkode_mem, step_mem->inner_mem); + break; + default: + arkProcessError(ark_mem, ARK_ILL_INPUT, + "ARKode::MRIStep", "MRIStepReInit", + "Invalid inner integrator option"); + return(ARK_ILL_INPUT); } - /* Initialize the saved return value for the inner stepper */ - step_mem->inner_retval = ARK_SUCCESS; + /* check if inner integrator was attached successfully */ + if (retval != ARK_SUCCESS) return(ARK_INNERSTEP_ATTACH_ERR); return(ARK_SUCCESS); } @@ -379,10 +295,13 @@ void MRIStepFree(void **arkode_mem) ark_mem->lrw -= Blrw; } - /* free the forcing vector */ - if (step_mem->forcing != NULL) { - arkFreeVec(ark_mem, &step_mem->forcing); - step_mem->forcing = NULL; + /* free the inner forcing vector */ + if (step_mem->inner_forcing != NULL) { + for (j = 0; j < step_mem->inner_num_forcing; j++) { + arkFreeVec(ark_mem, &(step_mem->inner_forcing[j])); + step_mem->inner_forcing[j] = NULL; + } + free(step_mem->inner_forcing); } /* free the RHS vectors */ @@ -406,12 +325,6 @@ void MRIStepFree(void **arkode_mem) ark_mem->liw -= (step_mem->stages + 1); } - /* free the inner stepper */ - if (step_mem->inner_arkode_mem != NULL) { - ARKStepFree(&(step_mem->inner_arkode_mem)); - step_mem->inner_arkode_mem = NULL; - } - /* free the time stepper module itself */ free(ark_mem->step_mem); ark_mem->step_mem = NULL; @@ -451,7 +364,6 @@ void MRIStepPrintMem(void* arkode_mem, FILE* outfile) /* output long integer quantities */ fprintf(outfile,"MRIStep: nfs = %li\n", step_mem->nfs); - fprintf(outfile,"MRIStep: nff = %li\n", step_mem->nff); /* output realtype quantities */ fprintf(outfile,"MRIStep: Butcher table:\n"); @@ -465,9 +377,7 @@ void MRIStepPrintMem(void* arkode_mem, FILE* outfile) } #endif - /* Print inner stepper memory */ - fprintf(outfile,"MRIStep Fast Stepper Mem:\n"); - ARKStepPrintMem(step_mem->inner_arkode_mem, outfile); + return; } @@ -476,6 +386,136 @@ void MRIStepPrintMem(void* arkode_mem, FILE* outfile) MRIStep Private functions ===============================================================*/ +/*--------------------------------------------------------------- + Create outer memory structure + ---------------------------------------------------------------*/ + +void* mriStep_Create(ARKRhsFn fs, realtype t0, N_Vector y0) +{ + ARKodeMem ark_mem; /* outer ARKode memory */ + ARKodeMRIStepMem step_mem; /* outer stepper memory */ + booleantype nvectorOK; + int retval; + + /* Check that fs is supplied */ + if (fs == NULL) { + arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::MRIStep", + "MRIStepCreate", MSG_ARK_NULL_F); + return(NULL); + } + + /* Check that y0 is supplied */ + if (y0 == NULL) { + arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::MRIStep", + "MRIStepCreate", MSG_ARK_NULL_Y0); + return(NULL); + } + + /* Test if all required vector operations are implemented */ + nvectorOK = mriStep_CheckNVector(y0); + if (!nvectorOK) { + arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::MRIStep", + "MRIStepCreate", MSG_ARK_BAD_NVECTOR); + return(NULL); + } + + /* Create ark_mem structure and set default values */ + ark_mem = arkCreate(); + if (ark_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", + "MRIStepCreate", MSG_ARK_NO_MEM); + return(NULL); + } + + /* Allocate ARKodeMRIStepMem structure, and initialize to zero */ + step_mem = NULL; + step_mem = (ARKodeMRIStepMem) malloc(sizeof(struct ARKodeMRIStepMemRec)); + if (step_mem == NULL) { + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::MRIStep", + "MRIStepCreate", MSG_ARK_ARKMEM_FAIL); + return(NULL); + } + memset(step_mem, 0, sizeof(struct ARKodeMRIStepMemRec)); + + /* Attach step_mem structure and function pointers to ark_mem */ + ark_mem->step_init = mriStep_Init; + ark_mem->step_fullrhs = mriStep_FullRHS; + ark_mem->step = mriStep_TakeStep; + ark_mem->step_mem = (void*) step_mem; + + /* Set default values for MRIStep optional inputs */ + retval = MRIStepSetDefaults((void *) ark_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode::MRIStep", + "MRIStepCreate", + "Error setting default solver options"); + return(NULL); + } + + /* Allocate the general MRI stepper vectors using y0 as a template */ + /* NOTE: F, inner_forcing, cvals and Xvecs will be allocated later on + (based on the MRI method) */ + + /* Copy the slow RHS function into stepper memory */ + step_mem->fs = fs; + + /* Update the ARKode workspace requirements */ + ark_mem->liw += 11; /* fcn/data ptr, int, long int, sunindextype, booleantype */ + ark_mem->lrw += 1; + + /* Initialize all the counters */ + step_mem->nfs = 0; + + /* Initialize pre and post inner evolve functions */ + step_mem->pre_inner_evolve = NULL; + step_mem->post_inner_evolve = NULL; + + /* Initialize main ARKode infrastructure (allocates vectors) */ + retval = arkInit(ark_mem, t0, y0); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode::MRIStep", "MRIStepCreate", + "Unable to initialize main ARKode infrastructure"); + return(NULL); + } + + return((void *)ark_mem); +} + + +/*--------------------------------------------------------------- + Attach ARKStep inner integrator + ---------------------------------------------------------------*/ + +int mriStep_AttachARK(void* arkode_mem, void* inner_mem) +{ + ARKodeMem ark_mem; /* outer ARKode memory */ + ARKodeMRIStepMem step_mem; /* outer stepper memory */ + ARKodeMem inner_ark_mem; /* inner ARKode memory */ + ARKodeARKStepMem inner_step_mem; /* inner stepper memory */ + int retval; /* return value */ + + /* Access MRIStep memory */ + retval = mriStep_AccessStepMem(arkode_mem, "mriStep_AttachARK", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) { MRIStepFree(&arkode_mem); return(-1); } + + /* Access ARKStep memory */ + retval = arkStep_AccessStepMem(inner_mem, "mriStep_AttachARK", + &inner_ark_mem, &inner_step_mem); + if (retval != ARK_SUCCESS) { MRIStepFree(&arkode_mem); return(-1); } + + /* attach the inner stepper and initialize the inner stepper return flag */ + step_mem->inner_mem = inner_mem; + step_mem->inner_stepper_id = MRISTEP_ARKSTEP; + step_mem->inner_retval = ARK_SUCCESS; + step_mem->inner_setforcing = arkStep_SetInnerForcing; + step_mem->inner_evolve = mriStep_EvolveInnerARK; + step_mem->inner_fullrhs = arkStep_FullRHS; + + return(ARK_SUCCESS); +} + + /*--------------------------------------------------------------- Interface routines supplied to ARKode ---------------------------------------------------------------*/ @@ -502,21 +542,29 @@ int mriStep_Init(void* arkode_mem, int init_type) sunindextype Blrw, Bliw; int retval, j; - /* immediately return if init_type == 1 */ - if (init_type == 1) return(ARK_SUCCESS); - /* access ARKodeMRIStepMem structure */ retval = mriStep_AccessStepMem(arkode_mem, "mriStep_Init", &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - /* assume fixed stepping */ + /* immediately return if init_type == 1 */ + if (init_type == 1) { + ark_mem->call_fullrhs = SUNTRUE; + return(ARK_SUCCESS); + } + + /* assume fixed outer step size */ if (!ark_mem->fixedstep) { arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", "mriStep_Init", - "Adaptive time stepping is not currently supported"); + "Adaptive outer time stepping is not currently supported"); return(ARK_ILL_INPUT); } + /* enforce use of arkEwtSmallReal since using a fixed step size */ + ark_mem->user_efun = SUNFALSE; + ark_mem->efun = arkEwtSetSmallReal; + ark_mem->e_data = ark_mem; + /* Create Butcher table (if not already set) */ retval = mriStep_SetButcherTable(ark_mem); if (retval != ARK_SUCCESS) { @@ -548,6 +596,17 @@ int mriStep_Init(void* arkode_mem, int init_type) } ark_mem->liw += step_mem->stages; /* pointers */ + /* Allocate MRI forcing vectors if needed */ + step_mem->inner_num_forcing = 1; /* only support 1 forcing vector at this time */ + if (step_mem->inner_forcing == NULL) { + step_mem->inner_forcing = (N_Vector *) calloc(step_mem->inner_num_forcing, + sizeof(N_Vector)); + for (j = 0; j < step_mem->inner_num_forcing; j++) { + if (!arkAllocVec(ark_mem, ark_mem->ewt, &(step_mem->inner_forcing[j]))) + return(ARK_MEM_FAIL); + } + } + /* Allocate reusable arrays for fused vector interface */ if (step_mem->cvals == NULL) { step_mem->cvals = (realtype *) calloc(step_mem->stages+1, sizeof(realtype)); @@ -560,6 +619,20 @@ int mriStep_Init(void* arkode_mem, int init_type) ark_mem->liw += (step_mem->stages + 1); /* pointers */ } + /* Limit interpolant degree based on method order (use negative + argument to specify update instead of overwrite) */ + if (ark_mem->interp != NULL) { + retval = arkInterpSetDegree(ark_mem, ark_mem->interp, -(step_mem->q-1)); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", "mriStep_Init", + "Unable to update interpolation polynomial degree"); + return(ARK_ILL_INPUT); + } + } + + /* Signal to shared arkode module that fullrhs is required after each step */ + ark_mem->call_fullrhs = SUNTRUE; + return(ARK_SUCCESS); } @@ -598,6 +671,11 @@ int mriStep_FullRHS(void* arkode_mem, realtype t, &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); + /* disable inner forcing */ + step_mem->inner_retval = + step_mem->inner_setforcing(step_mem->inner_mem, ZERO, ONE, NULL, 0); + if (step_mem->inner_retval != 0) return(ARK_INNERSTEP_FAIL); + /* perform RHS functions contingent on 'mode' argument */ switch(mode) { @@ -615,10 +693,10 @@ int mriStep_FullRHS(void* arkode_mem, realtype t, return(ARK_RHSFUNC_FAIL); } - /* call ff */ - retval = step_mem->ff(t, y, f, ark_mem->user_data); - step_mem->nff++; - if (retval != 0) { + /* call ff (force new RHS computation) */ + step_mem->inner_retval = + step_mem->inner_fullrhs(step_mem->inner_mem, t, y, f, 2); + if (step_mem->inner_retval != 0) { arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::MRIStep", "mriStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); return(ARK_RHSFUNC_FAIL); @@ -644,10 +722,10 @@ int mriStep_FullRHS(void* arkode_mem, realtype t, return(ARK_RHSFUNC_FAIL); } - /* call ff */ - retval = step_mem->ff(t, y, f, ark_mem->user_data); - step_mem->nff++; - if (retval != 0) { + /* call ff (force new RHS computation) */ + step_mem->inner_retval = + step_mem->inner_fullrhs(step_mem->inner_mem, t, y, f, 2); + if (step_mem->inner_retval != 0) { arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::MRIStep", "mriStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); return(ARK_RHSFUNC_FAIL); @@ -672,10 +750,10 @@ int mriStep_FullRHS(void* arkode_mem, realtype t, return(ARK_RHSFUNC_FAIL); } - /* call ff */ - retval = step_mem->ff(t, y, f, ark_mem->user_data); - step_mem->nff++; - if (retval != 0) { + /* call ff (force new RHS computation) */ + step_mem->inner_retval = + step_mem->inner_fullrhs(arkode_mem, t, y, f, 2); + if (step_mem->inner_retval != 0) { arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::MRIStep", "mriStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); return(ARK_RHSFUNC_FAIL); @@ -695,187 +773,174 @@ int mriStep_FullRHS(void* arkode_mem, realtype t, mriStep_TakeStep: This routine serves the primary purpose of the MRIStep module: - it performs a single successful MRI step (if possible). - Multiple attempts may be taken in this process -- once a step - completes with successful (non)linear solves at each stage and - passes the error estimate, the routine returns successfully. - If it cannot do so, it returns with an appropriate error flag. + it performs a single MRI step (with embedding, if possible). + + The output variable dsmPtr should contain estimate of the + weighted local error if an embedding is present; otherwise it + should be 0. + + The input/output variable nflagPtr is used to gauge convergence + of any algebraic solvers within the step. As this routine + currently involves no algebraic solve, it is set to 0 (success). + + The return value from this routine is: + 0 => step completed successfully + >0 => step encountered recoverable failure; + reduce step and retry (if possible) + <0 => step encountered unrecoverable failure ---------------------------------------------------------------*/ -int mriStep_TakeStep(void* arkode_mem) +int mriStep_TakeStep(void* arkode_mem, realtype *dsmPtr, int *nflagPtr) { - realtype dsm, tspan, hi, rcdiff, tret; - int retval, is, eflag, js, nvec, nstep; - realtype* cvals; - N_Vector* Xvecs; - ARKodeMem ark_mem; - ARKodeMRIStepMem step_mem; + ARKodeMem ark_mem; /* outer ARKode memory */ + ARKodeMRIStepMem step_mem; /* outer stepper memory */ - /* access ARKodeMRIStepMem structure */ + realtype cdiff, t0; + int retval, is; + + /* initialize algebraic solver convergence flag to success; + error estimate to zero */ + *nflagPtr = ARK_SUCCESS; + *dsmPtr = ZERO; + + /* access the MRIStep mem structure */ retval = mriStep_AccessStepMem(arkode_mem, "mriStep_TakeStep", &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - /* local shortcuts for fused vector operations */ - cvals = step_mem->cvals; - Xvecs = step_mem->Xvecs; - - dsm = ZERO; - eflag = ARK_SUCCESS; - - /* Looping point for attempts to take a step */ - for(;;) { - #ifdef DEBUG_OUTPUT printf("stage 0 RHS:\n"); N_VPrint_Serial(step_mem->F[0]); #endif - /* Loop over internal stages to the step; since the method is explicit - the first stage RHS is just the slow RHS from the start of the step */ - for (is=1; isstages; is++) { + /* Loop over internal stages to the step; since the method is explicit + the first stage RHS is just the slow RHS from the start of the step */ + for (is = 1; is < step_mem->stages; is++) { - /* Set current stage time */ - ark_mem->tcur = ark_mem->tn + step_mem->B->c[is]*ark_mem->h; + /* Set current stage time */ + ark_mem->tcur = ark_mem->tn + step_mem->B->c[is]*ark_mem->h; #ifdef DEBUG_OUTPUT - printf("step %li, stage %i, h = %"RSYM", t_n = %"RSYM"\n", - ark_mem->nst, is, ark_mem->h, ark_mem->tcur); + printf("step %li, stage %i, h = %"RSYM", t_n = %"RSYM"\n", + ark_mem->nst, is, ark_mem->h, ark_mem->tcur); #endif - /* Solver diagnostics reporting */ - if (ark_mem->report) - fprintf(ark_mem->diagfp, "MRIStep step %li %"RSYM" %i %"RSYM"\n", - ark_mem->nst, ark_mem->h, is, ark_mem->tcur); - - /* compute forcing vector of inner steps (assumes c[is] != c[is-1]) */ - rcdiff = ONE / (step_mem->B->c[is] - step_mem->B->c[is-1]); - nvec = 0; - for (js=0; jsB->A[is][js] - step_mem->B->A[is-1][js]); - Xvecs[js] = step_mem->F[js]; - nvec++; - } - - retval = N_VLinearCombination(nvec, cvals, Xvecs, step_mem->forcing); - if (retval != 0) return(ARK_VECTOROP_ERR); - - /* compute inner step size (assumes fixed step) */ - tspan = (step_mem->B->c[is] - step_mem->B->c[is-1]) * ark_mem->h; - nstep = ceil(tspan / step_mem->hf); - hi = tspan / nstep; - - /* set inner time step size */ - step_mem->inner_retval = ARKStepSetFixedStep(step_mem->inner_arkode_mem, - hi); - if (step_mem->inner_retval != 0) return(ARK_INNERSTEP_FAIL); - - /* set stop time */ - step_mem->inner_retval = ARKStepSetStopTime(step_mem->inner_arkode_mem, - ark_mem->tcur); - if (step_mem->inner_retval != 0) return(ARK_INNERSTEP_FAIL); - - /* adjust max steps if needed */ - if (nstep > MXSTEP_DEFAULT) { - step_mem->inner_retval = ARKStepSetMaxNumSteps(step_mem->inner_arkode_mem, - 2*nstep); - if (step_mem->inner_retval != 0) return(ARK_INNERSTEP_FAIL); - } - - /* advance inner method in time */ - step_mem->inner_retval = ARKStepEvolve(step_mem->inner_arkode_mem, - ark_mem->tcur, - ark_mem->ycur, &tret, - ARK_NORMAL); - if (step_mem->inner_retval < 0) return(ARK_INNERSTEP_FAIL); + /* Solver diagnostics reporting */ + if (ark_mem->report) + fprintf(ark_mem->diagfp, "MRIStep step %li %"RSYM" %i %"RSYM"\n", + ark_mem->nst, ark_mem->h, is, ark_mem->tcur); - /* compute updated slow RHS */ - retval = step_mem->fs(ark_mem->tcur, ark_mem->ycur, - step_mem->F[is], ark_mem->user_data); - step_mem->nfs++; - if (retval < 0) return(ARK_RHSFUNC_FAIL); - if (retval > 0) return(ARK_UNREC_RHSFUNC_ERR); + /* compute the inner forcing */ + /* TO DO: Add if cdiff < tiny, then apply correction step */ + cdiff = step_mem->B->c[is] - step_mem->B->c[is-1]; -#ifdef DEBUG_OUTPUT - printf("RHS:\n"); - N_VPrint_Serial(step_mem->F[is]); -#endif + retval = mriStep_ComputeInnerForcing(step_mem, is, cdiff); + if (retval != 0) return(retval); - } /* loop over stages */ + /* initial time for inner integrator */ + t0 = ark_mem->tn + step_mem->B->c[is-1]*ark_mem->h; - /* Compute time step solution */ + /* set the forcing data in the inner stepper */ + step_mem->inner_retval = + step_mem->inner_setforcing(step_mem->inner_mem, t0, cdiff*ark_mem->h, + step_mem->inner_forcing, + step_mem->inner_num_forcing); + if (step_mem->inner_retval != 0) return(ARK_INNERSTEP_FAIL); - /* compute forcing vector of inner steps (assumes c[stages-1] != 1) */ - rcdiff = ONE / (ONE - step_mem->B->c[step_mem->stages-1]); - nvec = 0; - for (js=0; jsstages; js++) { - cvals[js] = rcdiff * (step_mem->B->b[js] - step_mem->B->A[step_mem->stages-1][js]); - Xvecs[js] = step_mem->F[js]; - nvec++; + /* pre inner evolve function */ + if (step_mem->pre_inner_evolve) { + retval = step_mem->pre_inner_evolve(t0, step_mem->inner_forcing, + step_mem->inner_num_forcing, + ark_mem->user_data); + if (retval != 0) return(ARK_OUTERTOINNER_FAIL); } - retval = N_VLinearCombination(nvec, cvals, Xvecs, step_mem->forcing); - if (retval != 0) return(ARK_VECTOROP_ERR); - - /* compute inner step size (assumes fixed step) */ - tspan = (ONE - step_mem->B->c[step_mem->stages-1]) * ark_mem->h; - nstep = ceil(tspan / step_mem->hf); - hi = tspan / nstep; - - /* set inner time step size */ - step_mem->inner_retval = ARKStepSetFixedStep(step_mem->inner_arkode_mem, - hi); - if (step_mem->inner_retval != 0) return(ARK_INNERSTEP_FAIL); + /* advance inner method in time */ + step_mem->inner_retval = + step_mem->inner_evolve(step_mem->inner_mem, t0, ark_mem->ycur, + ark_mem->tcur); + if (step_mem->inner_retval < 0) return(ARK_INNERSTEP_FAIL); - /* set stop time */ - step_mem->inner_retval = ARKStepSetStopTime(step_mem->inner_arkode_mem, - ark_mem->tn + ark_mem->h); - if (step_mem->inner_retval != 0) return(ARK_INNERSTEP_FAIL); + /* post inner evolve function */ + if (step_mem->post_inner_evolve) { + retval = step_mem->post_inner_evolve(ark_mem->tcur, ark_mem->ycur, + ark_mem->user_data); + if (retval != 0) return(ARK_INNERTOOUTER_FAIL); + } - /* adjust max steps if needed */ - if (nstep > MXSTEP_DEFAULT) { - step_mem->inner_retval = ARKStepSetMaxNumSteps(step_mem->inner_arkode_mem, - nstep); - if (step_mem->inner_retval != 0) return(ARK_INNERSTEP_FAIL); + /* apply user-supplied stage postprocessing function (if supplied) */ + if (ark_mem->ProcessStage != NULL) { + retval = ark_mem->ProcessStage(ark_mem->tcur, + ark_mem->ycur, + ark_mem->user_data); + if (retval != 0) return(ARK_POSTPROCESS_STAGE_FAIL); } - /* advance inner method in time */ - step_mem->inner_retval = ARKStepEvolve(step_mem->inner_arkode_mem, - ark_mem->tn + ark_mem->h, - ark_mem->ycur, &tret, - ARK_NORMAL); - if (step_mem->inner_retval < 0) return(ARK_INNERSTEP_FAIL); + /* compute updated slow RHS */ + retval = step_mem->fs(ark_mem->tcur, ark_mem->ycur, + step_mem->F[is], ark_mem->user_data); + step_mem->nfs++; + if (retval < 0) return(ARK_RHSFUNC_FAIL); + if (retval > 0) return(ARK_UNREC_RHSFUNC_ERR); #ifdef DEBUG_OUTPUT - printf("error estimate = %"RSYM"\n", dsm); - printf("updated solution:\n"); - N_VPrint_Serial(ark_mem->ycur); + printf("RHS:\n"); + N_VPrint_Serial(step_mem->F[is]); #endif - /* Solver diagnostics reporting */ - if (ark_mem->report) - fprintf(ark_mem->diagfp, "MRIStep etest %li %"RSYM" %"RSYM"\n", - ark_mem->nst, ark_mem->h, dsm); + } /* loop over stages */ -#ifdef DEBUG_OUTPUT - printf("error test flag = %i\n", eflag); -#endif + /* Compute time step solution */ - /* Restart step attempt (recompute all stages) if error test fails recoverably */ - if (eflag == TRY_AGAIN) continue; + /* set current time for solution */ + ark_mem->tcur = ark_mem->tn + ark_mem->h; - /* Return if error test failed and recovery not possible. */ - if (eflag != ARK_SUCCESS) return(eflag); + /* compute the inner forcing */ + cdiff = ONE - step_mem->B->c[step_mem->stages-1]; - /* Error test passed (eflag=ARK_SUCCESS), break from loop */ - break; + retval = mriStep_ComputeInnerForcing(step_mem, step_mem->stages, cdiff); + if (retval != 0) return(retval); - } /* loop over step attempts */ + /* initial time for inner integrator */ + t0 = ark_mem->tn + step_mem->B->c[step_mem->stages-1]*ark_mem->h; + + /* set the forcing data in the inner stepper */ + step_mem->inner_retval = + step_mem->inner_setforcing(step_mem->inner_mem, t0, cdiff*ark_mem->h, + step_mem->inner_forcing, + step_mem->inner_num_forcing); + if (step_mem->inner_retval != 0) return(ARK_INNERSTEP_FAIL); + + /* pre inner evolve function */ + if (step_mem->pre_inner_evolve) { + retval = step_mem->pre_inner_evolve(t0, step_mem->inner_forcing, + step_mem->inner_num_forcing, + ark_mem->user_data); + if (retval != 0) return(ARK_OUTERTOINNER_FAIL); + } + /* advance inner method in time */ + step_mem->inner_retval = + step_mem->inner_evolve(step_mem->inner_mem, t0, ark_mem->ycur, + ark_mem->tcur); + if (step_mem->inner_retval < 0) return(ARK_INNERSTEP_FAIL); + + /* post inner evolve function */ + if (step_mem->post_inner_evolve) { + retval = step_mem->post_inner_evolve(ark_mem->tcur, ark_mem->ycur, + ark_mem->user_data); + if (retval != 0) return(ARK_INNERTOOUTER_FAIL); + } + +#ifdef DEBUG_OUTPUT + printf("error estimate = %"RSYM"\n", dsm); + printf("updated solution:\n"); + N_VPrint_Serial(ark_mem->ycur); +#endif - /* The step has completed successfully, clean up and - consider change of step size */ - retval = mriStep_PrepareNextStep(ark_mem, dsm); - if (retval != ARK_SUCCESS) return(retval); + /* Solver diagnostics reporting */ + if (ark_mem->report) + fprintf(ark_mem->diagfp, "MRIStep etest %li %"RSYM" %"RSYM"\n", + ark_mem->nst, ark_mem->h, *dsmPtr); return(ARK_SUCCESS); } @@ -940,8 +1005,8 @@ booleantype mriStep_CheckNVector(N_Vector tmpl) ---------------------------------------------------------------*/ int mriStep_SetButcherTable(ARKodeMem ark_mem) { - int istable, iftable, retval; ARKodeMRIStepMem step_mem; + int itable; /* access ARKodeMRIStepMem structure */ if (ark_mem->step_mem==NULL) { @@ -952,29 +1017,26 @@ int mriStep_SetButcherTable(ARKodeMem ark_mem) step_mem = (ARKodeMRIStepMem) ark_mem->step_mem; /* if table has already been specified, just return */ - if (step_mem->B != NULL) - return(ARK_SUCCESS); + if (step_mem->B != NULL) return(ARK_SUCCESS); - /* initialize table number to illegal values */ - istable = -1; + /* initialize table number to an illegal value */ + itable = -1; /* select method based on order */ switch (step_mem->q) { case(3): - istable = DEFAULT_MRI_STABLE_3; - iftable = DEFAULT_MRI_FTABLE_3; + itable = DEFAULT_MRI_TABLE_3; break; default: /* no available method, set default */ arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", "mriStep_SetButcherTable", "No explicit MRI method at requested order, using q=3."); - istable = DEFAULT_MRI_STABLE_3; - iftable = DEFAULT_MRI_FTABLE_3; + itable = DEFAULT_MRI_TABLE_3; break; } - if (istable > -1) - step_mem->B = ARKodeButcherTable_LoadERK(istable); + /* load the Butcher table */ + if (itable > -1) step_mem->B = ARKodeButcherTable_LoadERK(itable); /* set [redundant] stored values for stage numbers and method orders */ if (step_mem->B != NULL) { @@ -983,11 +1045,6 @@ int mriStep_SetButcherTable(ARKodeMem ark_mem) step_mem->p = step_mem->B->p; } - /* set inner Butcher table (assume explicit) */ - retval = ARKStepSetTableNum(step_mem->inner_arkode_mem, -1, iftable); - if (retval != 0) return(ARK_ILL_INPUT); - - return(ARK_SUCCESS); } @@ -1089,56 +1146,103 @@ int mriStep_CheckButcherTable(ARKodeMem ark_mem) /*--------------------------------------------------------------- - mriStep_PrepareNextStep - - This routine handles MRI-specific updates following a successful - step: copying the MRI result to the current solution vector, - updating the error/step history arrays, and setting the - prospective step size, hprime, for the next step. Along with - hprime, it sets the ratio eta=hprime/h. It also updates other - state variables related to a change of step size. + mriStep_ComputeInnerForcing ---------------------------------------------------------------*/ -int mriStep_PrepareNextStep(ARKodeMem ark_mem, realtype dsm) + +int mriStep_ComputeInnerForcing(ARKodeMRIStepMem step_mem, int stage, + realtype cdiff) { - /* If fixed time-stepping requested, defer - step size changes until next step */ - if (ark_mem->fixedstep) { - ark_mem->hprime = ark_mem->h; - ark_mem->eta = ONE; - return(ARK_SUCCESS); + realtype rcdiff; + int j, nvec, retval; + realtype* cvals; + N_Vector* Xvecs; + + /* local shortcuts for fused vector operations */ + cvals = step_mem->cvals; + Xvecs = step_mem->Xvecs; + + /* compute constant inner forcing vector (assumes cdiff != 0) */ + rcdiff = ONE / cdiff; + nvec = 0; + + if (stage < step_mem->stages) { + for (j = 0; j < stage; j++) { + cvals[j] = rcdiff * (step_mem->B->A[stage][j] - + step_mem->B->A[stage - 1][j]); + Xvecs[j] = step_mem->F[j]; + nvec++; + } + } else { + for (j = 0; j < step_mem->stages; j++) { + cvals[j] = rcdiff * (step_mem->B->b[j] - + step_mem->B->A[step_mem->stages - 1][j]); + Xvecs[j] = step_mem->F[j]; + nvec++; + } } - /* Set hprime value for next step size */ - ark_mem->hprime = ark_mem->h * ark_mem->eta; + retval = N_VLinearCombination(nvec, cvals, Xvecs, + step_mem->inner_forcing[0]); + if (retval != 0) return(ARK_VECTOROP_ERR); - return(ARK_SUCCESS); + return(0); } /*--------------------------------------------------------------- - Routines for inner stepper + Inner stepper evolve functions ---------------------------------------------------------------*/ -int mriStep_InnerRhsFn(realtype t, N_Vector y, N_Vector ydot, - void *user_data) +int mriStep_EvolveInnerARK(void* inner_mem, realtype t0, + N_Vector y0, realtype tout) { - ARKodeMem ark_mem; - ARKodeMRIStepMem step_mem; - int retval; + ARKodeMem inner_ark_mem; /* inner ARKode memory */ + ARKodeARKStepMem inner_step_mem; /* inner stepper memory */ + realtype hf, hi; /* time step sizes */ + realtype tspan; /* integration time span */ + realtype tret; /* return time */ + int retval; /* return value */ + + /* initialize hf to avoid compiler warning */ + hf = ZERO; + + /* access the inner ARKStep mem structure */ + retval = arkStep_AccessStepMem(inner_mem, + "mriStep_EvolveInnerARK", + &inner_ark_mem, &inner_step_mem); + if (retval != ARK_SUCCESS) return(retval); - /* access outer integrator memory */ - ark_mem = (ARKodeMem) user_data; - step_mem = (ARKodeMRIStepMem) ark_mem->step_mem; + /* if fixed time stepping adjust the step size */ + /* >>>>>>> SHOULD BE ABLE TO REMOVE THIS IF TSTOP IS UPDATED <<<<<<< */ + if (inner_ark_mem->fixedstep) { - /* call user fast RHS function */ - retval = step_mem->ff(t, y, ydot, ark_mem->user_data); - if (retval != 0) return(retval); + /* save a copy of the inner step size */ + hf = inner_ark_mem->hin; - /* add contribution from the outer integrator */ - N_VLinearSum(ONE, step_mem->forcing, ONE, ydot, ydot); + /* compute inner step size */ + tspan = tout - t0; + hi = tspan / SUNRceil(tspan / hf); - /* successfully computed RHS */ - return(0); + /* set inner time step size */ + retval = ARKStepSetFixedStep(inner_mem, hi); + if (retval != ARK_SUCCESS) return(retval); + } + + /* set stop time */ + retval = ARKStepSetStopTime(inner_mem, tout); + if (retval != ARK_SUCCESS) return(retval); + + /* evolve inner ODE */ + retval = ARKStepEvolve(inner_mem, tout, y0, &tret, ARK_NORMAL); + if (retval < 0) return(retval); + + /* if fixed time stepping restore fast step size */ + if (inner_ark_mem->fixedstep) { + retval = ARKStepSetFixedStep(inner_mem, hf); + if (retval != ARK_SUCCESS) return(retval); + } + + return(ARK_SUCCESS); } /*=============================================================== diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_mristep_impl.h b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_mristep_impl.h index 5b405a126..38b53a9f9 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_mristep_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_mristep_impl.h @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -17,21 +17,34 @@ #ifndef _ARKODE_MRISTEP_IMPL_H #define _ARKODE_MRISTEP_IMPL_H -#include -#include "arkode_impl.h" +#include "arkode/arkode_mristep.h" #include "arkode/arkode_arkstep.h" +#include "arkode_impl.h" +#include "arkode_arkstep_impl.h" + #ifdef __cplusplus /* wrapper to enable C++ usage */ extern "C" { #endif + +/*=============================================================== + MRI function types + ===============================================================*/ + +typedef int (*MRIStepSetInnerForcingFn)(void* inner_arkode_mem, realtype tshift, + realtype tscale, N_Vector *f, + int nvecs); + +typedef int (*MRIStepInnerEvolveFn)(void* inner_arkode_mem, realtype t0, + N_Vector y0, realtype tout); + + /*=============================================================== MRI time step module data structure ===============================================================*/ /*--------------------------------------------------------------- - Types : struct ARKodeMRIStepMemRec, ARKodeMRIStepMem - --------------------------------------------------------------- The type ARKodeMRIStepMem is type pointer to struct ARKodeMRIStepMemRec. This structure contains fields to perform a MRI time step. @@ -39,8 +52,7 @@ extern "C" { typedef struct ARKodeMRIStepMemRec { /* MRI problem specification */ - ARKRhsFn fs; /* y' = fs(t,y) + ff(t,y) */ - ARKRhsFn ff; + ARKRhsFn fs; /* y' = fs(t,y) + ff(t,y) */ /* Outer RK method storage and parameters */ N_Vector *F; /* slow RHS at each stage */ @@ -50,14 +62,23 @@ typedef struct ARKodeMRIStepMemRec { ARKodeButcherTable B; /* MRI Butcher table */ /* Inner stepper data */ - void *inner_arkode_mem; /* inner stepper memory */ - N_Vector forcing; /* RHS forcing vector */ - realtype hf; /* inner step size */ - int inner_retval; /* last inner stepper return value */ + void *inner_mem; /* inner stepper memory */ + N_Vector *inner_forcing; /* RHS forcing vectors */ + int inner_num_forcing; /* number of RHS forcing vectors */ + int inner_retval; /* last inner stepper return value */ + MRISTEP_ID inner_stepper_id; /* inner stepper identifier */ + + /* Inner-stepper-supplied functions */ + MRIStepSetInnerForcingFn inner_setforcing; /* set inner forcing data */ + MRIStepInnerEvolveFn inner_evolve; /* inner evolve function */ + ARKTimestepFullRHSFn inner_fullrhs; /* inner full RHS function */ + + /* User-supplied pre and post inner evolve functions */ + MRIStepPreInnerFn pre_inner_evolve; + MRIStepPostInnerFn post_inner_evolve; /* Counters */ - long int nfs; /* num fe calls */ - long int nff; /* num fe calls */ + long int nfs; /* num fs calls */ /* Reusable arrays for fused vector operations */ realtype* cvals; @@ -66,16 +87,18 @@ typedef struct ARKodeMRIStepMemRec { } *ARKodeMRIStepMem; - /*=============================================================== MRI time step module private function prototypes ===============================================================*/ +/* Create MRIStep memory structure */ +void* mriStep_Create(ARKRhsFn fs, realtype t0, N_Vector y0); + /* Interface routines supplied to ARKode */ int mriStep_Init(void* arkode_mem, int init_type); int mriStep_FullRHS(void* arkode_mem, realtype t, N_Vector y, N_Vector f, int mode); -int mriStep_TakeStep(void* arkode_mem); +int mriStep_TakeStep(void* arkode_mem, realtype *dsmPtr, int *nflagPtr); /* Internal utility routines */ int mriStep_AccessStepMem(void* arkode_mem, const char *fname, @@ -84,13 +107,16 @@ booleantype mriStep_CheckNVector(N_Vector tmpl); int mriStep_SetButcherTable(ARKodeMem ark_mem); int mriStep_CheckButcherTable(ARKodeMem ark_mem); -int mriStep_ComputeErrorEst(ARKodeMem ark_mem, realtype *dsm); -int mriStep_DoErrorTest(ARKodeMem ark_mem, int *nefPtr, - realtype dsm); -int mriStep_PrepareNextStep(ARKodeMem ark_mem, realtype dsm); +/* Attach ARKStep inner stepper */ +int mriStep_AttachARK(void* arkode_mem, void* inner_arkode_mem); + +/* Compute forcing for inner stepper */ +int mriStep_ComputeInnerForcing(ARKodeMRIStepMem step_mem, int stage, + realtype cdiff); -/* Internal inner stepper routines */ -int mriStep_InnerRhsFn(realtype t, N_Vector y, N_Vector ydot, void *user_data); +/* Evolve ARKStep inner stepper */ +int mriStep_EvolveInnerARK(void* inner_arkode_mem, realtype t0, + N_Vector y0, realtype tout); /*=============================================================== Reusable MRIStep Error Messages diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_mristep_io.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_mristep_io.c index cced0b6d3..b1aa17251 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_mristep_io.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_mristep_io.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -31,394 +31,88 @@ /*=============================================================== MRIStep Optional input functions (wrappers for generic ARKode - utility routines) + utility routines). All are documented in arkode_io.c. ===============================================================*/ - -/*--------------------------------------------------------------- - MRIStepSetDenseOrder: Specifies the polynomial order for dense - output. Positive values are sent to the interpolation module; - negative values imply to use the default. - ---------------------------------------------------------------*/ -int MRIStepSetDenseOrder(void *arkode_mem, int dord) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepSetDenseOrder", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetDenseOrder(ark_mem, dord)); -} - -/*--------------------------------------------------------------- - MRIStepSetErrHandlerFn: Specifies the error handler function - ---------------------------------------------------------------*/ +int MRIStepSetDenseOrder(void *arkode_mem, int dord) { + return(MRIStepSetInterpolantDegree(arkode_mem, dord)); } +int MRIStepSetInterpolantDegree(void *arkode_mem, int degree) { + if (degree < 0) degree = ARK_INTERP_MAX_DEGREE; + return(arkSetInterpolantDegree(arkode_mem, degree)); } +int MRIStepSetInterpolantType(void *arkode_mem, int itype) { + return(arkSetInterpolantType(arkode_mem, itype)); } int MRIStepSetErrHandlerFn(void *arkode_mem, ARKErrHandlerFn ehfun, - void *eh_data) -{ - ARKodeMem ark_mem; - ARKodeMRIStepMem step_mem; - int retval; - - /* access ARKodeMRIStepMem structure */ - retval = mriStep_AccessStepMem(arkode_mem, "MRIStepSetErrHandlerFn", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* set outer stepper error handler function */ - retval = arkSetErrHandlerFn(ark_mem, ehfun, eh_data); - if (retval != ARK_SUCCESS) return(retval); - - /* set inner stepper error handler function */ - retval = ARKStepSetErrHandlerFn(step_mem->inner_arkode_mem, ehfun, eh_data); - if (retval != ARK_SUCCESS) return(retval); - - return(ARK_SUCCESS); -} - -/*--------------------------------------------------------------- - MRIStepSetErrFile: Specifies the FILE pointer for output (NULL - means no messages) - ---------------------------------------------------------------*/ -int MRIStepSetErrFile(void *arkode_mem, FILE *errfp) -{ - ARKodeMem ark_mem; - ARKodeMRIStepMem step_mem; - int retval; - - /* access ARKodeMRIStepMem structure */ - retval = mriStep_AccessStepMem(arkode_mem, "MRIStepSetErrFile", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* set outer stepper error file */ - retval = arkSetErrFile(ark_mem, errfp); - if (retval != ARK_SUCCESS) return(retval); - - /* set inner stepper error file */ - retval = ARKStepSetErrFile(step_mem->inner_arkode_mem, errfp); - if (retval != ARK_SUCCESS) return(retval); - - return(ARK_SUCCESS); -} - -/*--------------------------------------------------------------- - MRIStepSetUserData: Specifies the user data pointer for f - ---------------------------------------------------------------*/ -int MRIStepSetUserData(void *arkode_mem, void *user_data) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepSetUserData", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetUserData(ark_mem, user_data)); -} - -/*--------------------------------------------------------------- - MRIStepSetDiagnostics: Specifies to enable solver diagnostics, - and specifies the FILE pointer for output (diagfp==NULL - disables output) - ---------------------------------------------------------------*/ -int MRIStepSetDiagnostics(void *arkode_mem, FILE *diagfp) -{ - ARKodeMem ark_mem; - ARKodeMRIStepMem step_mem; - int retval; - - /* access ARKodeMRIStepMem structure */ - retval = mriStep_AccessStepMem(arkode_mem, "MRIStepSetDiagnostics", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* set outer stepper diagnostics file */ - retval = arkSetDiagnostics(ark_mem, diagfp); - if (retval != ARK_SUCCESS) return(retval); - - /* set inner stepper diagnostics file */ - retval = ARKStepSetDiagnostics(step_mem->inner_arkode_mem, diagfp); - if (retval != ARK_SUCCESS) return(retval); - - return(ARK_SUCCESS); -} - -/*--------------------------------------------------------------- - MRIStepSetMaxNumSteps: Specifies the maximum number of - integration steps - ---------------------------------------------------------------*/ -int MRIStepSetMaxNumSteps(void *arkode_mem, long int mxsteps) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepSetMaxNumSteps", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetMaxNumSteps(ark_mem, mxsteps)); -} - -/*--------------------------------------------------------------- - MRIStepSetMaxHnilWarns: Specifies the maximum number of warnings - for small h - ---------------------------------------------------------------*/ -int MRIStepSetMaxHnilWarns(void *arkode_mem, int mxhnil) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepSetMaxHnilWarns", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetMaxHnilWarns(ark_mem, mxhnil)); -} - -/*--------------------------------------------------------------- - MRIStepSetStopTime: Specifies the time beyond which the - integration is not to proceed. - ---------------------------------------------------------------*/ -int MRIStepSetStopTime(void *arkode_mem, realtype tstop) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepSetStopTime", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetStopTime(ark_mem, tstop)); -} - -/*--------------------------------------------------------------- - MRIStepSetFixedStep: Specifies the fixed time step sizes to use - with MRIStep. MRIStep will use this step size for all steps - (unless tstop is set, in which case it may need to modify that - last step approaching tstop. If any solver failure occurs in the - timestepping module, MRIStep will typically immediately return - with an error message indicating that the selected step size - cannot be used. - - Any nonzero argument will result in the use of that fixed step - size. - ---------------------------------------------------------------*/ -int MRIStepSetFixedStep(void *arkode_mem, realtype hsfixed, realtype hffixed) -{ - ARKodeMem ark_mem; - ARKodeMRIStepMem step_mem; - int retval; - - /* access ARKodeMRIStepMem structure */ - retval = mriStep_AccessStepMem(arkode_mem, "MRIStepSetFixedStep", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* check for valid step sizes */ - if (SUNRabs(hffixed) > SUNRabs(hsfixed)) return(ARK_ILL_INPUT); - - /* set outer step size */ - retval = arkSetFixedStep(ark_mem, hsfixed); - if (retval != ARK_SUCCESS) return(retval); - - /* set inner step size */ - step_mem->hf = hffixed; - retval = ARKStepSetFixedStep(step_mem->inner_arkode_mem, hffixed); - if (retval != ARK_SUCCESS) return(retval); - - return(ARK_SUCCESS); -} - -/*--------------------------------------------------------------- - MRIStepSetRootDirection: Specifies the direction of zero-crossings - to be monitored. The default is to monitor both crossings. - ---------------------------------------------------------------*/ -int MRIStepSetRootDirection(void *arkode_mem, int *rootdir) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepSetRootDirection", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetRootDirection(ark_mem, rootdir)); -} - -/*--------------------------------------------------------------- - MRIStepSetNoInactiveRootWarn: Disables issuing a warning if - some root function appears to be identically zero at the - beginning of the integration - ---------------------------------------------------------------*/ -int MRIStepSetNoInactiveRootWarn(void *arkode_mem) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepSetNoInactiveRootWarn", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetNoInactiveRootWarn(ark_mem)); -} - -/*--------------------------------------------------------------- - MRIStepSetPostprocessStepFn: Specifies a user-provided step - postprocessing function having type ARKPostProcessStepFn. A - NULL input function disables step postprocessing. - - IF THE SUPPLIED FUNCTION MODIFIES ANY OF THE ACTIVE STATE DATA, - THEN ALL THEORETICAL GUARANTEES OF SOLUTION ACCURACY AND - STABILITY ARE LOST. - ---------------------------------------------------------------*/ + void *eh_data) { + return(arkSetErrHandlerFn(arkode_mem, ehfun, eh_data)); } +int MRIStepSetErrFile(void *arkode_mem, FILE *errfp) { + return(arkSetErrFile(arkode_mem, errfp)); } +int MRIStepSetDiagnostics(void *arkode_mem, FILE *diagfp) { + return(arkSetDiagnostics(arkode_mem, diagfp)); } +int MRIStepSetMaxNumSteps(void *arkode_mem, long int mxsteps) { + return(arkSetMaxNumSteps(arkode_mem, mxsteps)); } +int MRIStepSetMaxHnilWarns(void *arkode_mem, int mxhnil) { + return(arkSetMaxHnilWarns(arkode_mem, mxhnil)); } +int MRIStepSetStopTime(void *arkode_mem, realtype tstop) { + return(arkSetStopTime(arkode_mem, tstop)); } +int MRIStepSetRootDirection(void *arkode_mem, int *rootdir) { + return(arkSetRootDirection(arkode_mem, rootdir)); } +int MRIStepSetNoInactiveRootWarn(void *arkode_mem) { + return(arkSetNoInactiveRootWarn(arkode_mem)); } int MRIStepSetPostprocessStepFn(void *arkode_mem, - ARKPostProcessStepFn ProcessStep) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepSetPostprocessStepFn", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkSetPostprocessStepFn(ark_mem, ProcessStep)); -} + ARKPostProcessFn ProcessStep) { + return(arkSetPostprocessStepFn(arkode_mem, ProcessStep)); } +int MRIStepSetPostprocessStageFn(void *arkode_mem, + ARKPostProcessFn ProcessStage) { + return(arkSetPostprocessStageFn(arkode_mem, ProcessStage)); } /*=============================================================== - MRIStep Optional output functions (wrappers for generic ARKode - utility routines) + MRIStep Optional input functions (customized wrappers for + generic ARKode utility routines). All are documented in + arkode_io.c and arkode_ls.c. ===============================================================*/ -/*--------------------------------------------------------------- - MRIStepGetNumSteps: Returns the current number of integration - steps - ---------------------------------------------------------------*/ -int MRIStepGetNumSteps(void *arkode_mem, long int *nssteps, long int *nfsteps) -{ - ARKodeMem ark_mem; - ARKodeMRIStepMem step_mem; - int retval; - - /* access ARKodeMRIStepMem structure */ - retval = mriStep_AccessStepMem(arkode_mem, "MRIStepGetNumSteps", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* set outer number of steps */ - retval = arkGetNumSteps(ark_mem, nssteps); - if (retval != ARK_SUCCESS) return(retval); - - /* set inner number of steps */ - retval = ARKStepGetNumSteps(step_mem->inner_arkode_mem, nfsteps); - if (retval != ARK_SUCCESS) return(retval); - - return(ARK_SUCCESS); -} - -/*--------------------------------------------------------------- - MRIStepGetLastStep: Returns the step size used on the last - successful step - ---------------------------------------------------------------*/ -int MRIStepGetLastStep(void *arkode_mem, realtype *hlast) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepGetLastStep", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetLastStep(ark_mem, hlast)); -} - -/*--------------------------------------------------------------- - MRIStepGetCurrentTime: Returns the current value of the - independent variable - ---------------------------------------------------------------*/ -int MRIStepGetCurrentTime(void *arkode_mem, realtype *tcur) +int MRIStepSetFixedStep(void *arkode_mem, realtype hsfixed) { ARKodeMem ark_mem; if (arkode_mem==NULL) { arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepGetCurrentTime", MSG_ARK_NO_MEM); + "MRIStepSetFixedStep", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } ark_mem = (ARKodeMem) arkode_mem; - return(arkGetCurrentTime(ark_mem, tcur)); -} - -/*--------------------------------------------------------------- - MRIStepGetWorkSpace: Returns integrator work space requirements - ---------------------------------------------------------------*/ -int MRIStepGetWorkSpace(void *arkode_mem, long int *lenrw, long int *leniw) -{ - ARKodeMem ark_mem; - ARKodeMRIStepMem step_mem; - int retval; - long int tmplenrw, tmpleniw; - - /* access ARKodeMRIStepMem structure */ - retval = mriStep_AccessStepMem(arkode_mem, "MRIStepGetWorkSpace", - &ark_mem, &step_mem); - if (retval != ARK_SUCCESS) return(retval); - - /* set outer workspace size */ - retval = arkGetWorkSpace(ark_mem, lenrw, leniw); - if (retval != ARK_SUCCESS) return(retval); - - /* set inner step size */ - retval = ARKStepGetWorkSpace(step_mem->inner_arkode_mem, &tmplenrw, &tmpleniw); - if (retval != ARK_SUCCESS) return(retval); - - /* total workspace size */ - *lenrw += tmplenrw; - *leniw += tmpleniw; - - return(ARK_SUCCESS); -} -/*--------------------------------------------------------------- - MRIStepGetNumGEvals: Returns the current number of calls to g - (for rootfinding) - ---------------------------------------------------------------*/ -int MRIStepGetNumGEvals(void *arkode_mem, long int *ngevals) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepGetNumGEvals", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); + if (hsfixed == ZERO) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", + "MRIStepSetFixedStep", + "MIRStep does not support adaptive steps at this time."); + return(ARK_ILL_INPUT); } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetNumGEvals(ark_mem, ngevals)); -} -/*--------------------------------------------------------------- - MRIStepGetRootInfo: Returns pointer to array rootsfound showing - roots found - ---------------------------------------------------------------*/ -int MRIStepGetRootInfo(void *arkode_mem, int *rootsfound) -{ - ARKodeMem ark_mem; - if (arkode_mem==NULL) { - arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepGetRootInfo", MSG_ARK_NO_MEM); - return(ARK_MEM_NULL); - } - ark_mem = (ARKodeMem) arkode_mem; - return(arkGetRootInfo(ark_mem, rootsfound)); + /* call generic routine for remaining work */ + return(arkSetFixedStep(ark_mem, hsfixed)); } -/*--------------------------------------------------------------- - MRIStepGetReturnFlagName: translates from return flags IDs to - names - ---------------------------------------------------------------*/ -char *MRIStepGetReturnFlagName(long int flag) -{ return(arkGetReturnFlagName(flag)); } +/*=============================================================== + MRIStep Optional output functions (wrappers for generic ARKode + utility routines). All are documented in arkode_io.c. + ===============================================================*/ +int MRIStepGetNumSteps(void *arkode_mem, long int *nssteps) { + return(arkGetNumSteps(arkode_mem, nssteps)); } +int MRIStepGetLastStep(void *arkode_mem, realtype *hlast) { + return(arkGetLastStep(arkode_mem, hlast)); } +int MRIStepGetCurrentTime(void *arkode_mem, realtype *tcur) { + return(arkGetCurrentTime(arkode_mem, tcur)); } +int MRIStepGetCurrentState(void *arkode_mem, N_Vector *ycur) { + return(arkGetCurrentState(arkode_mem, ycur)); } +int MRIStepGetWorkSpace(void *arkode_mem, long int *lenrw, long int *leniw) { + return(arkGetWorkSpace(arkode_mem, lenrw, leniw)); } +int MRIStepGetNumGEvals(void *arkode_mem, long int *ngevals) { + return(arkGetNumGEvals(arkode_mem, ngevals)); } +int MRIStepGetRootInfo(void *arkode_mem, int *rootsfound) { + return(arkGetRootInfo(arkode_mem, rootsfound)); } +char *MRIStepGetReturnFlagName(long int flag) { + return(arkGetReturnFlagName(flag)); } /*=============================================================== @@ -449,27 +143,33 @@ int MRIStepSetDefaults(void* arkode_mem) step_mem->stages = 0; /* no stages */ step_mem->B = NULL; /* no Butcher table */ - /* set inner method defaults */ - retval = ARKStepSetDefaults(step_mem->inner_arkode_mem); - if (retval != ARK_SUCCESS) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepSetDefaults", - "An error occuer when setting the inner stepper defaults"); - return(retval); - } - return(ARK_SUCCESS); } /*--------------------------------------------------------------- - MRIStepSetTables: + MRIStepSetUserData: Specifies the user data pointer + ---------------------------------------------------------------*/ +int MRIStepSetUserData(void *arkode_mem, void *user_data) +{ + ARKodeMem ark_mem; + if (arkode_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", + "MRIStepSetUserData", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkSetUserData(ark_mem, user_data)); +} + + +/*--------------------------------------------------------------- + MRIStepSetTable: Specifies to use a customized Butcher table for the explicit portion of the system. ---------------------------------------------------------------*/ -int MRIStepSetTables(void *arkode_mem, int q, - ARKodeButcherTable Bs, ARKodeButcherTable Bf) +int MRIStepSetTable(void *arkode_mem, int q, ARKodeButcherTable B) { int retval; ARKodeMem ark_mem; @@ -481,7 +181,7 @@ int MRIStepSetTables(void *arkode_mem, int q, if (retval != ARK_SUCCESS) return(retval); /* check for illegal inputs */ - if ((Bs == NULL) && (Bf == NULL)) { + if (B == NULL) { arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", "MRIStepSetTables", MSG_ARK_NO_MEM); return(ARK_ILL_INPUT); @@ -495,27 +195,18 @@ int MRIStepSetTables(void *arkode_mem, int q, step_mem->B = NULL; /* set the relevant parameters */ - step_mem->stages = Bs->stages; - step_mem->q = Bs->q; + step_mem->stages = B->stages; + step_mem->q = B->q; step_mem->p = 0; /* assume fixed stepping */ /* copy the table in step memory */ - step_mem->B = ARKodeButcherTable_Copy(Bs); + step_mem->B = ARKodeButcherTable_Copy(B); if (step_mem->B == NULL) { arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", "MRIStepSetTables", MSG_ARK_NO_MEM); return(ARK_MEM_NULL); } - /* set the inner Butcher table (assume explicit) */ - retval = ARKStepSetTables(step_mem->inner_arkode_mem, Bf->q, Bf->p, NULL, Bf); - if (retval != ARK_SUCCESS) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepSetTables", - "An error occuer when setting the inner table"); - return(retval); - } - return(ARK_SUCCESS); } @@ -527,7 +218,7 @@ int MRIStepSetTables(void *arkode_mem, int q, based on the integer flags passed to ARKodeButcherTable_LoadERK() within the file arkode_butcher_erk.c. ---------------------------------------------------------------*/ -int MRIStepSetTableNum(void *arkode_mem, int istable, int iftable) +int MRIStepSetTableNum(void *arkode_mem, int itable) { ARKodeMem ark_mem; ARKodeMRIStepMem step_mem; @@ -539,8 +230,7 @@ int MRIStepSetTableNum(void *arkode_mem, int istable, int iftable) if (retval != ARK_SUCCESS) return(retval); /* check that argument specifies an explicit table (assume explicit) */ - if (istable < MIN_ERK_NUM || istable > MAX_ERK_NUM || - iftable < MIN_ERK_NUM || iftable > MAX_ERK_NUM ) { + if (itable < MIN_ERK_NUM || itable > MAX_ERK_NUM ) { arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", "MRIStepSetTableNum", "Illegal MRI table number"); @@ -554,7 +244,7 @@ int MRIStepSetTableNum(void *arkode_mem, int istable, int iftable) ARKodeButcherTable_Free(step_mem->B); step_mem->B = NULL; /* fill in table based on argument */ - step_mem->B = ARKodeButcherTable_LoadERK(istable); + step_mem->B = ARKodeButcherTable_LoadERK(itable); if (step_mem->B == NULL) { arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", "MRIStepSetTableNum", @@ -565,14 +255,49 @@ int MRIStepSetTableNum(void *arkode_mem, int istable, int iftable) step_mem->q = step_mem->B->q; step_mem->p = step_mem->B->p; - /* fill inner table based on argument (assume expicit) */ - retval = ARKStepSetTableNum(step_mem->inner_arkode_mem, -1, iftable); - if (retval != ARK_SUCCESS) { - arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", - "MRIStepSetTableNum", - "Error setting table with that index"); - return(ARK_ILL_INPUT); - } + return(ARK_SUCCESS); +} + +/*--------------------------------------------------------------- + MRIStepSetPreInnerFn: + + Sets the user-supplied function called BEFORE the inner evolve + ---------------------------------------------------------------*/ +int MRIStepSetPreInnerFn(void *arkode_mem, MRIStepPreInnerFn prefn) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + int retval; + + /* access ARKodeMRIStepMem structure */ + retval = mriStep_AccessStepMem(arkode_mem, "MRIStepSetDefaults", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Set pre inner evolve function */ + step_mem->pre_inner_evolve = prefn; + + return(ARK_SUCCESS); +} + +/*--------------------------------------------------------------- + MRIStepSetPostInnerFn: + + Sets the user-supplied function called AFTER the inner evolve + ---------------------------------------------------------------*/ +int MRIStepSetPostInnerFn(void *arkode_mem, MRIStepPostInnerFn postfn) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + int retval; + + /* access ARKodeMRIStepMem structure */ + retval = mriStep_AccessStepMem(arkode_mem, "MRIStepSetDefaults", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Set pre inner evolve function */ + step_mem->post_inner_evolve = postfn; return(ARK_SUCCESS); } @@ -610,13 +335,11 @@ int MRIStepGetLastInnerStepFlag(void *arkode_mem, int *flag) Returns the current number of calls to fs and ff ---------------------------------------------------------------*/ -int MRIStepGetNumRhsEvals(void *arkode_mem, long int *nfs_evals, - long int *nff_evals) +int MRIStepGetNumRhsEvals(void *arkode_mem, long int *nfs_evals) { ARKodeMem ark_mem; ARKodeMRIStepMem step_mem; int retval; - long int tmp; /* access ARKodeMRIStepMem structure */ retval = mriStep_AccessStepMem(arkode_mem, "MRIStepGetNumRhsEvals", @@ -626,13 +349,6 @@ int MRIStepGetNumRhsEvals(void *arkode_mem, long int *nfs_evals, /* get number of fs evals from step_mem */ *nfs_evals = step_mem->nfs; - /* get number of ff evals from inner stepper (assume explicit) */ - retval = ARKStepGetNumRhsEvals(step_mem->inner_arkode_mem, nff_evals, &tmp); - if (retval != ARK_SUCCESS) return(retval); - - /* add ff evals from outer stepper */ - *nff_evals += step_mem->nff; - return(ARK_SUCCESS); } @@ -643,27 +359,19 @@ int MRIStepGetNumRhsEvals(void *arkode_mem, long int *nfs_evals, Sets pointers to the slow and fast Butcher tables currently in use. ---------------------------------------------------------------*/ -int MRIStepGetCurrentButcherTables(void *arkode_mem, - ARKodeButcherTable *Bs, - ARKodeButcherTable *Bf) +int MRIStepGetCurrentButcherTables(void *arkode_mem, ARKodeButcherTable *B) { ARKodeMem ark_mem; ARKodeMRIStepMem step_mem; int retval; - ARKodeButcherTable tmp; /* access ARKodeMRIStepMem structure */ retval = mriStep_AccessStepMem(arkode_mem, "MRIStepGetCurrentButcherTable", &ark_mem, &step_mem); if (retval != ARK_SUCCESS) return(retval); - /* get tables from step_mem */ - *Bs = step_mem->B; - - /* get inner table (assume explicit) */ - retval = ARKStepGetCurrentButcherTables(step_mem->inner_arkode_mem, - &tmp, Bf); - if (retval != ARK_SUCCESS) return(retval); + /* get table from step_mem */ + *B = step_mem->B; return(ARK_SUCCESS); } @@ -698,15 +406,6 @@ int MRIStepWriteParameters(void *arkode_mem, FILE *fp) return(retval); } - /* print integrator parameters to file */ - fprintf(fp, "MRIStep time step module parameters:\n"); - fprintf(fp, " Method order %i\n",step_mem->q); - fprintf(fp, "\n"); - - /* write inner stepper parameters */ - retval = ARKStepWriteParameters(step_mem->inner_arkode_mem, fp); - if (retval != ARK_SUCCESS) return(retval); - return(ARK_SUCCESS); } @@ -720,7 +419,6 @@ int MRIStepWriteButcher(void *arkode_mem, FILE *fp) { ARKodeMem ark_mem; ARKodeMRIStepMem step_mem; - ARKodeButcherTable Bfi, Bfe; int retval; /* access ARKodeMRIStepMem structure */ @@ -743,22 +441,6 @@ int MRIStepWriteButcher(void *arkode_mem, FILE *fp) } fprintf(fp, "\n"); - /* initialize the inner Butcher tables to NULL */ - Bfi = NULL; - Bfe = NULL; - - /* get the inner Butcher tables */ - retval = ARKStepGetCurrentButcherTables(step_mem->inner_arkode_mem, - &Bfi, &Bfe); - if (retval != ARK_SUCCESS) return(retval); - - /* write inner butcher tables (assume explicit only) */ - if (Bfe != NULL) { - fprintf(fp, " Fast Butcher table (stages = %i):\n", Bfe->stages); - ARKodeButcherTable_Write(Bfe, fp); - } - fprintf(fp, "\n"); - return(ARK_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_root.c b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_root.c index 8131c14e3..3044f2761 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_root.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_root.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -61,15 +61,16 @@ int arkRootInit(ARKodeMem ark_mem, int nrtfn, ARKRootFn g) MSG_ARK_ARKMEM_FAIL); return(ARK_MEM_FAIL); } - ark_mem->root_mem->glo = NULL; - ark_mem->root_mem->ghi = NULL; - ark_mem->root_mem->grout = NULL; - ark_mem->root_mem->iroots = NULL; - ark_mem->root_mem->rootdir = NULL; - ark_mem->root_mem->gfun = NULL; - ark_mem->root_mem->nrtfn = 0; - ark_mem->root_mem->gactive = NULL; - ark_mem->root_mem->mxgnull = 1; + ark_mem->root_mem->glo = NULL; + ark_mem->root_mem->ghi = NULL; + ark_mem->root_mem->grout = NULL; + ark_mem->root_mem->iroots = NULL; + ark_mem->root_mem->rootdir = NULL; + ark_mem->root_mem->gfun = NULL; + ark_mem->root_mem->nrtfn = 0; + ark_mem->root_mem->gactive = NULL; + ark_mem->root_mem->mxgnull = 1; + ark_mem->root_mem->root_data = ark_mem->user_data; ark_mem->lrw += ARK_ROOT_LRW; ark_mem->liw += ARK_ROOT_LIW; @@ -328,7 +329,7 @@ int arkRootCheck1(void* arkode_mem) /* Evaluate g at initial t and check for zero values. */ retval = rootmem->gfun(rootmem->tlo, ark_mem->yn, - rootmem->glo, ark_mem->user_data); + rootmem->glo, rootmem->root_data); rootmem->nge = 1; if (retval != 0) return(ARK_RTFUNC_FAIL); @@ -345,10 +346,9 @@ int arkRootCheck1(void* arkode_mem) hratio = SUNMAX(rootmem->ttol/SUNRabs(ark_mem->h), TENTH); smallh = hratio*ark_mem->h; tplus = rootmem->tlo + smallh; - N_VLinearSum(ONE, ark_mem->yn, smallh, - ark_mem->interp->fold, ark_mem->ycur); + N_VLinearSum(ONE, ark_mem->yn, smallh, ark_mem->fn, ark_mem->ycur); retval = rootmem->gfun(tplus, ark_mem->ycur, rootmem->ghi, - ark_mem->user_data); + rootmem->root_data); rootmem->nge++; if (retval != 0) return(ARK_RTFUNC_FAIL); @@ -407,7 +407,7 @@ int arkRootCheck2(void* arkode_mem) /* Evaluate root-finding function: glo = g(tlo, y(tlo)) */ retval = rootmem->gfun(rootmem->tlo, ark_mem->ycur, - rootmem->glo, ark_mem->user_data); + rootmem->glo, rootmem->root_data); rootmem->nge++; if (retval != 0) return(ARK_RTFUNC_FAIL); @@ -436,15 +436,14 @@ int arkRootCheck2(void* arkode_mem) /* update ark_ycur with small explicit Euler step (if tplus is past tn) */ if ( (tplus - ark_mem->tcur)*ark_mem->h >= ZERO ) { /* hratio = smallh/ark_mem->h; */ - N_VLinearSum(ONE, ark_mem->ycur, smallh, - ark_mem->interp->fold, ark_mem->ycur); + N_VLinearSum(ONE, ark_mem->ycur, smallh, ark_mem->fn, ark_mem->ycur); } else { /* set ark_ycur = y(tplus) via interpolation */ (void) arkGetDky(ark_mem, tplus, 0, ark_mem->ycur); } /* set ghi = g(tplus,y(tplus)) */ retval = rootmem->gfun(tplus, ark_mem->ycur, rootmem->ghi, - ark_mem->user_data); + rootmem->root_data); rootmem->nge++; if (retval != 0) return(ARK_RTFUNC_FAIL); @@ -509,7 +508,7 @@ int arkRootCheck3(void* arkode_mem) /* Set rootmem->ghi = g(thi) and call arkRootfind to search (tlo,thi) for roots. */ retval = rootmem->gfun(rootmem->thi, ark_mem->ycur, - rootmem->ghi, ark_mem->user_data); + rootmem->ghi, rootmem->root_data); rootmem->nge++; if (retval != 0) return(ARK_RTFUNC_FAIL); @@ -709,7 +708,7 @@ int arkRootfind(void* arkode_mem) (void) arkGetDky(ark_mem, tmid, 0, ark_mem->ycur); retval = rootmem->gfun(tmid, ark_mem->ycur, rootmem->grout, - ark_mem->user_data); + rootmem->root_data); rootmem->nge++; if (retval != 0) return(ARK_RTFUNC_FAIL); diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_root_impl.h b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_root_impl.h index 69b61701b..14f999d9c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_root_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/arkode_root_impl.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -11,7 +11,7 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End *--------------------------------------------------------------- - * Implementation header file for ARKode's root-finding (in time) + * Implementation header file for ARKode's root-finding (in time) * utility. *--------------------------------------------------------------*/ @@ -32,7 +32,11 @@ extern "C" { #define ARK_ROOT_LRW 5 #define ARK_ROOT_LIW 12 /* int, ptr, etc */ - + +/* Numeric constants */ +#define HUND RCONST(100.0) /* real 100.0 */ + + /*=============================================================== ARKode Root-finding Data Structure ===============================================================*/ @@ -40,8 +44,8 @@ extern "C" { /*--------------------------------------------------------------- Types : struct ARKodeRootMemRec, ARKodeRootMem ----------------------------------------------------------------- - The type ARKodeRootMem is type pointer to struct - ARKodeRootMemRec. This structure contains data pertaining to + The type ARKodeRootMem is type pointer to struct + ARKodeRootMemRec. This structure contains data pertaining to the use of root-finding capabilities in ARKode. ---------------------------------------------------------------*/ typedef struct ARKodeRootMemRec { @@ -63,6 +67,7 @@ typedef struct ARKodeRootMemRec { long int nge; /* counter for g evaluations */ booleantype *gactive; /* array with active/inactive event functions */ int mxgnull; /* num. warning messages about possible g==0 */ + void *root_data; /* pointer to user_data */ } *ARKodeRootMem; @@ -78,7 +83,7 @@ int arkRootCheck2(void* arkode_mem); int arkRootCheck3(void* arkode_mem); int arkRootfind(void* arkode_mem); - + #ifdef __cplusplus } #endif diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/CMakeLists.txt index 12b6b542c..774452ace 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,9 +12,10 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the FARKODE library +# --------------------------------------------------------------- # Add variable farkode_SOURCES with the sources for the FARKODE library -SET(farkode_SOURCES +set(farkode_SOURCES farkadapt.c farkband.c farkbandmass.c @@ -39,13 +40,13 @@ SET(farkode_SOURCES # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the ARKODE library -SET(shared_SOURCES +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/nvector/serial/fnvector_serial.c ) # Add variable sunmatrix_SOURCES with the common SUNMatrix sources which will # also be included in the ARKODE library -SET(sunmatrix_SOURCES +set(sunmatrix_SOURCES ${sundials_SOURCE_DIR}/src/sunmatrix/band/fsunmatrix_band.c ${sundials_SOURCE_DIR}/src/sunmatrix/dense/fsunmatrix_dense.c ${sundials_SOURCE_DIR}/src/sunmatrix/sparse/fsunmatrix_sparse.c @@ -53,7 +54,7 @@ SET(sunmatrix_SOURCES # Add variable sunlinsol_SOURCES with the common SUNLinearSolver sources which will # also be included in the ARKODE library -SET(sunlinsol_SOURCES +set(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/band/fsunlinsol_band.c ${sundials_SOURCE_DIR}/src/sunlinsol/dense/fsunlinsol_dense.c ${sundials_SOURCE_DIR}/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c @@ -63,28 +64,9 @@ SET(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/pcg/fsunlinsol_pcg.c ) -IF(KLU_FOUND) - LIST(APPEND sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/klu/fsunlinsol_klu.c - ) -ENDIF() - -IF(SUPERLUMT_FOUND) - LIST(APPEND sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/superlumt/fsunlinsol_superlumt.c - ) -ENDIF() - -IF(LAPACK_FOUND) - LIST(APPEND sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/lapackband/fsunlinsol_lapackband.c - ${sundials_SOURCE_DIR}/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.c - ) -ENDIF() - # Add variable sunnonlinsol_SOURCES with the common SUNNonlinearSolver sources # which will also be included in the ARKODE library -SET(sunnonlinsol_SOURCES +set(sunnonlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunnonlinsol_newton/fsunnonlinsol_newton.c ${sundials_SOURCE_DIR}/src/sunnonlinsol_fixedpoint/fsunnonlinsol_fixedpoint.c ) @@ -92,26 +74,26 @@ SET(sunnonlinsol_SOURCES # Add source directories to include directories for access to # implementation only header files (both for farkode and arkode) -INCLUDE_DIRECTORIES(.) -INCLUDE_DIRECTORIES(..) +include_directories(.) +include_directories(..) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) # Only build STATIC libraries (we cannot build shared libraries # for the FCMIX interfaces due to unresolved symbol errors # coming from inexistent user-provided functions) # Add the build target for the FARKODE library -ADD_LIBRARY(sundials_farkode_static STATIC +add_library(sundials_farkode_static STATIC ${farkode_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES}) # Set the library name and make sure it is not deleted -SET_TARGET_PROPERTIES(sundials_farkode_static +set_target_properties(sundials_farkode_static PROPERTIES OUTPUT_NAME sundials_farkode CLEAN_DIRECT_OUTPUT 1) # Install the FARKODE library -INSTALL(TARGETS sundials_farkode_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(TARGETS sundials_farkode_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) # -MESSAGE(STATUS "Added ARKODE FCMIX module") +message(STATUS "Added ARKODE FCMIX module") diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkadapt.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkadapt.c index 09a83003d..b970800bd 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkadapt.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkadapt.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkband.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkband.c index 0247b735e..ad2d541e8 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkband.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkband.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbandmass.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbandmass.c index 38bdd50e4..1ba4d84d7 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbandmass.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbandmass.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbbd.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbbd.c index 9bf7c0d9c..84f7e50da 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbbd.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbbd.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -55,8 +55,13 @@ void FARK_BBDINIT(long int *Nloc, long int *mudq, { /* Notes: FARKgloc is a pointer to the ARKLocalFn function, and FARKcfn is a pointer to the ARKCommFn function */ - *ier = ARKBBDPrecInit(ARK_arkodemem, *Nloc, *mudq, *mldq, - *mu, *ml, *dqrely, + *ier = ARKBBDPrecInit(ARK_arkodemem, + (sunindextype)(*Nloc), + (sunindextype)(*mudq), + (sunindextype)(*mldq), + (sunindextype)(*mu), + (sunindextype)(*ml), + *dqrely, (ARKLocalFn) FARKgloc, (ARKCommFn) FARKcfn); return; @@ -69,7 +74,10 @@ void FARK_BBDINIT(long int *Nloc, long int *mudq, void FARK_BBDREINIT(long int *mudq, long int *mldq, realtype* dqrely, int *ier) { - *ier = ARKBBDPrecReInit(ARK_arkodemem, *mudq, *mldq, *dqrely); + *ier = ARKBBDPrecReInit(ARK_arkodemem, + (sunindextype)(*mudq), + (sunindextype)(*mldq), + *dqrely); return; } diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbbd.h b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbbd.h index 65dd52298..2d86b41e5 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbbd.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbbd.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbp.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbp.c index fbb7aac82..432659023 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbp.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbp.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -30,7 +30,10 @@ void FARK_BPINIT(long int *N, long int *mu, long int *ml, int *ier) { - *ier = ARKBandPrecInit(ARK_arkodemem, *N, *mu, *ml); + *ier = ARKBandPrecInit(ARK_arkodemem, + (sunindextype)(*N), + (sunindextype)(*mu), + (sunindextype)(*ml)); return; } diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbp.h b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbp.h index 2781725ca..f0677a636 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbp.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkbp.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkdense.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkdense.c index d55189541..2d771c55c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkdense.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkdense.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkdensemass.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkdensemass.c index 7aea9b691..410f5046a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkdensemass.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkdensemass.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkewt.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkewt.c index 4dc039593..deb43dd2d 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkewt.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkewt.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkexpstab.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkexpstab.c index e7fa37e46..0ad6fa685 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkexpstab.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkexpstab.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkjtimes.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkjtimes.c index a4b07d500..e23617af7 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkjtimes.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkjtimes.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkmasspreco.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkmasspreco.c index 3f78949c0..611b8e0a7 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkmasspreco.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkmasspreco.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkmtimes.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkmtimes.c index 2a2a8a223..628da3ded 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkmtimes.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkmtimes.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farknulllinsol.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farknulllinsol.c index e7b9d9841..68e550dc6 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farknulllinsol.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farknulllinsol.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farknullmatrix.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farknullmatrix.c index 36fc016e2..9c54bebb1 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farknullmatrix.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farknullmatrix.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farknullnonlinsol.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farknullnonlinsol.c index 1097f91cc..c316ca9f8 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farknullnonlinsol.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farknullnonlinsol.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkode.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkode.c index be0f6f9a2..834223be3 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkode.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkode.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -44,6 +44,7 @@ realtype *ARK_rout; int ARK_nrtfn; int ARK_ls; int ARK_mass_ls; +int ARK_constr; /*=============================================================*/ @@ -105,6 +106,7 @@ void FARK_MALLOC(realtype *t0, realtype *y0, int *imex, ARK_nrtfn = 0; ARK_ls = SUNFALSE; ARK_mass_ls = SUNFALSE; + ARK_constr = SUNFALSE; /* Set data in F2C_ARKODE_vec to y0 */ N_VSetArrayPointer(y0, F2C_ARKODE_vec); @@ -166,7 +168,6 @@ void FARK_MALLOC(realtype *t0, realtype *y0, int *imex, return; } N_VSetArrayPointer(atol, Vatol); - if (N_VMin(Vatol) <= ZERO) N_VConst(abstol, Vatol); *ier = ARKStepSVtolerances(ARK_arkodemem, reltol, Vatol); N_VDestroy(Vatol); break; @@ -250,7 +251,6 @@ void FARK_REINIT(realtype *t0, realtype *y0, int *imex, int *iatol, return; } N_VSetArrayPointer(atol, Vatol); - if (N_VMin(Vatol) <= ZERO) N_VConst(abstol, Vatol); *ier = ARKStepSVtolerances(ARK_arkodemem, reltol, Vatol); N_VDestroy(Vatol); break; @@ -360,6 +360,8 @@ void FARK_SETIIN(char key_name[], long int *ival, int *ier) { *ier = ARKStepSetSmallNumEFails(ARK_arkodemem, (int) *ival); else if (!strncmp(key_name, "LSETUP_MSBP", 11)) *ier = ARKStepSetMaxStepsBetweenLSet(ARK_arkodemem, (int) *ival); + else if (!strncmp(key_name, "MAX_CONSTR_FAIL", 15)) + *ier = ARKStepSetMaxNumConstrFails(ARK_arkodemem, (int) *ival); else { *ier = -99; fprintf(stderr, "FARKSETIIN: Unrecognized key.\n\n"); @@ -415,6 +417,32 @@ void FARK_SETRIN(char key_name[], realtype *rval, int *ier) { /*=============================================================*/ +void FARK_SETVIN(char key_name[], realtype *vval, int *ier) +{ + N_Vector Vec; + + *ier = 0; + + if (!strncmp(key_name,"CONSTR_VEC",10)) { + Vec = NULL; + Vec = N_VCloneEmpty(F2C_ARKODE_vec); + if (Vec == NULL) { + *ier = -1; + return; + } + N_VSetArrayPointer(vval, Vec); + *ier = ARKStepSetConstraints(ARK_arkodemem, Vec); + ARK_constr = SUNTRUE; + N_VDestroy(Vec); + } + else { + *ier = -99; + fprintf(stderr, "FARKSETVIN: Unrecognized key. \n\n"); + } + +} +/*=============================================================*/ + /* Fortran interface to C routine ARKStepSetAdaptivityMethod; see farkode.h for further details */ void FARK_SETADAPTMETHOD(int *imethod, int *idefault, int *ipq, @@ -624,7 +652,7 @@ void FARK_LSMASSINIT(int *time_dep, int *ier) { } *ier = ARKStepSetMassLinearSolver(ARK_arkodemem, F2C_ARKODE_mass_sol, - F2C_ARKODE_mass_matrix, + F2C_ARKODE_mass_matrix, *time_dep); ARK_mass_ls = SUNTRUE; return; @@ -698,7 +726,7 @@ void FARK_ARKODE(realtype *tout, realtype *t, realtype *y, ARKStepGetNumLinIters(ARK_arkodemem, &ARK_iout[22]); /* NLI */ ARKStepGetNumLinConvFails(ARK_arkodemem, &ARK_iout[23]); /* NCFL */ } - + /* Attach mass matrix linear solver outputs */ if(ARK_mass_ls) { ARKStepGetMassWorkSpace(ARK_arkodemem, &ARK_iout[24], &ARK_iout[25]); /* LENRWMS, LENIWMS */ @@ -712,6 +740,11 @@ void FARK_ARKODE(realtype *tout, realtype *t, realtype *y, ARKStepGetNumMassIters(ARK_arkodemem, &ARK_iout[33]); /* NMLI */ ARKStepGetNumMassConvFails(ARK_arkodemem, &ARK_iout[34]); /* NMCFL */ } + + /* Attach constraints output */ + if(ARK_constr) { + ARKStepGetNumConstrFails(ARK_arkodemem, &ARK_iout[35]); + } return; } @@ -828,6 +861,8 @@ void FARK_FREE() { SUNLinSolFree(F2C_ARKODE_linsol); if (F2C_ARKODE_mass_sol) SUNLinSolFree(F2C_ARKODE_mass_sol); + if (F2C_ARKODE_nonlinsol) + SUNNonlinSolFree(F2C_ARKODE_nonlinsol); return; } diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkode.h b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkode.h index 02eb14f2f..d7cd35119 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkode.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkode.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -19,17 +19,17 @@ FARKODE Interface Package The FARKODE Interface Package is a package of C functions which - support the use of the ARKODE solver in a mixed Fortran/C - setting. While ARKODE is written in C, it is assumed here that - the user's calling program and user-supplied problem-defining - routines are written in Fortran. This package provides the - necessary interface to ARKODE for any acceptable NVECTOR + support the use of the ARKODE solver in a mixed Fortran/C + setting. While ARKODE is written in C, it is assumed here that + the user's calling program and user-supplied problem-defining + routines are written in Fortran. This package provides the + necessary interface to ARKODE for any acceptable NVECTOR implementation. - - While previous versions of this file included relatively - exhaustive documentation of the FARKODE interface, such + + While previous versions of this file included relatively + exhaustive documentation of the FARKODE interface, such information is also included in the main ARKode documentation - (PDF and HTML formats), so to ease the maintenance burden the + (PDF and HTML formats), so to ease the maintenance burden the FARKODE documentation has been removed from this file. ===============================================================*/ @@ -61,6 +61,7 @@ extern "C" { #define FARK_SETDEFAULTS SUNDIALS_F77_FUNC(farksetdefaults, FARKSETDEFAULTS) #define FARK_SETIIN SUNDIALS_F77_FUNC(farksetiin, FARKSETIIN) #define FARK_SETRIN SUNDIALS_F77_FUNC(farksetrin, FARKSETRIN) +#define FARK_SETVIN SUNDIALS_F77_FUNC(farksetvin, FARKSETVIN) #define FARK_SETADAPTMETHOD SUNDIALS_F77_FUNC(farksetadaptivitymethod, FARKSETADAPTIVITYMETHOD) #define FARK_SETERKTABLE SUNDIALS_F77_FUNC(farkseterktable, FARKSETERKTABLE) #define FARK_SETIRKTABLE SUNDIALS_F77_FUNC(farksetirktable, FARKSETIRKTABLE) @@ -136,7 +137,7 @@ extern "C" { #define FARK_SPILSSETMASS SUNDIALS_F77_FUNC(farkspilssetmass, FARKSPILSSETMASS) #define FARK_SPILSSETMASSPREC SUNDIALS_F77_FUNC(farkspilssetmassprec, FARKSPILSSETMASSPREC) /*----------------*/ - + #else #define FARK_IMP_FUN farkifun_ @@ -147,6 +148,7 @@ extern "C" { #define FARK_SETDEFAULTS farksetdefaults_ #define FARK_SETIIN farksetiin_ #define FARK_SETRIN farksetrin_ +#define FARK_SETVIN farksetvin_ #define FARK_SETADAPTMETHOD farksetadaptivitymethod_ #define FARK_SETERKTABLE farkseterktable_ #define FARK_SETIRKTABLE farksetirktable_ @@ -222,7 +224,7 @@ extern "C" { #define FARK_SPILSSETMASS farkspilssetmass_ #define FARK_SPILSSETMASSPREC farkspilssetmassprec_ /*----------------*/ - + #endif /* Type for user data */ @@ -232,9 +234,9 @@ extern "C" { } *FARKUserData; /* Prototypes of exported functions */ - void FARK_MALLOC(realtype *t0, realtype *y0, int *imex, - int *iatol, realtype *rtol, realtype *atol, - long int *iout, realtype *rout, + void FARK_MALLOC(realtype *t0, realtype *y0, int *imex, + int *iatol, realtype *rtol, realtype *atol, + long int *iout, realtype *rout, long int *ipar, realtype *rpar, int *ier); void FARK_REINIT(realtype *t0, realtype *y0, int *imex, @@ -247,17 +249,18 @@ extern "C" { void FARK_SETDEFAULTS(int *ier); void FARK_SETIIN(char key_name[], long int *ival, int *ier); void FARK_SETRIN(char key_name[], realtype *rval, int *ier); + void FARK_SETVIN(char key_name[], realtype *vval, int *ier); - void FARK_SETADAPTMETHOD(int *imethod, int *idefault, int *ipq, + void FARK_SETADAPTMETHOD(int *imethod, int *idefault, int *ipq, realtype *params, int *ier); - void FARK_SETERKTABLE(int *s, int *q, int *p, realtype *c, realtype *A, + void FARK_SETERKTABLE(int *s, int *q, int *p, realtype *c, realtype *A, realtype *b, realtype *b2, int *ier); void FARK_SETIRKTABLE(int *s, int *q, int *p, realtype *c, realtype *A, realtype *b, realtype *b2, int *ier); - void FARK_SETARKTABLES(int *s, int *q, int *p, realtype *ci, - realtype *ce, realtype *Ai, realtype *Ae, - realtype *bi, realtype *be, realtype *b2i, + void FARK_SETARKTABLES(int *s, int *q, int *p, realtype *ci, + realtype *ce, realtype *Ai, realtype *Ae, + realtype *bi, realtype *be, realtype *b2i, realtype *b2e, int *ier); void FARK_SETRESTOLERANCE(int *itol, realtype *atol, int *ier); @@ -265,13 +268,13 @@ extern "C" { void FARK_STOPDIAGNOSTICS(int *ier); void FARK_NLSINIT(int *ier); - + void FARK_LSINIT(int *ier); void FARK_LSSETEPSLIN(realtype *eplifac, int *ier); void FARK_LSMASSINIT(int *time_dep, int *ier); void FARK_LSSETMASSEPSLIN(realtype *eplifac, int *ier); - - void FARK_ARKODE(realtype *tout, realtype *t, realtype *y, + + void FARK_ARKODE(realtype *tout, realtype *t, realtype *y, int *itask, int *ier); void FARK_DKY(realtype *t, int *k, realtype *dky, int *ier); @@ -313,54 +316,54 @@ extern "C" { void FARK_SPILSSETMASSPREC(int *flag, int *ier); /*----------------*/ - + /* Prototypes: Functions Called by the ARKODE Solver */ int FARKfe(realtype t, N_Vector y, N_Vector ydot, void *user_data); int FARKfi(realtype t, N_Vector y, N_Vector ydot, void *user_data); - - int FARKDenseJac(realtype t, N_Vector y, N_Vector fy, + + int FARKDenseJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix J, void *user_data, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); - + int FARKBandJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix J, void *user_data, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); - - int FARKSparseJac(realtype t, N_Vector y, N_Vector fy, - SUNMatrix J, void *user_data, N_Vector vtemp1, + + int FARKSparseJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix J, void *user_data, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); - - int FARKDenseMass(realtype t, SUNMatrix M, void *user_data, + + int FARKDenseMass(realtype t, SUNMatrix M, void *user_data, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); - - int FARKBandMass(realtype t, SUNMatrix M, void *user_data, + + int FARKBandMass(realtype t, SUNMatrix M, void *user_data, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); - - int FARKSparseMass(realtype t, SUNMatrix M, void *user_data, + + int FARKSparseMass(realtype t, SUNMatrix M, void *user_data, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); - + int FARKPSet(realtype tn, N_Vector y, N_Vector fy, booleantype jok, booleantype *jcurPtr, realtype gamma, void *user_data); - + int FARKMassPSet(realtype tn, void *user_data); - - int FARKPSol(realtype tn, N_Vector y, N_Vector fy, N_Vector r, - N_Vector z, realtype gamma, realtype delta, int lr, + + int FARKPSol(realtype tn, N_Vector y, N_Vector fy, N_Vector r, + N_Vector z, realtype gamma, realtype delta, int lr, void *user_data); - - int FARKMassPSol(realtype tn, N_Vector r, N_Vector z, realtype delta, + + int FARKMassPSol(realtype tn, N_Vector r, N_Vector z, realtype delta, int lr, void *user_data); - + int FARKJTSetup(realtype t, N_Vector y, N_Vector fy, void *user_data); - - int FARKJtimes(N_Vector v, N_Vector Jv, realtype t, N_Vector y, + + int FARKJtimes(N_Vector v, N_Vector Jv, realtype t, N_Vector y, N_Vector fy, void *user_data, N_Vector work); - + int FARKMTSetup(realtype t, void *user_data); - + int FARKMtimes(N_Vector v, N_Vector Mv, realtype t, void *user_data); int FARKEwt(N_Vector y, N_Vector ewt, void *user_data); @@ -374,8 +377,8 @@ extern "C" { void FARKNullMatrix(); void FARKNullLinsol(); void FARKNullNonlinsol(); - - /* Declarations for global variables shared amongst various routines; + + /* Declarations for global variables shared amongst various routines; each of these is defined in the implementation routines for the Fortran interface for their vector/matrix/linear solver/nonlinear solver modules */ extern N_Vector F2C_ARKODE_vec; diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkpreco.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkpreco.c index 32da99557..3e87fe8ee 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkpreco.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkpreco.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkroot.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkroot.c index b44235a32..9b4f62a6b 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkroot.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkroot.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkroot.h b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkroot.h index a6f1f91e0..c36e56d79 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkroot.h +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farkroot.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farksparse.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farksparse.c index 8be212480..914f4e9bf 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farksparse.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farksparse.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farksparsemass.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farksparsemass.c index 6075c52a4..838b3308d 100644 --- a/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farksparsemass.c +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fcmix/farksparsemass.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/CMakeLists.txt new file mode 100644 index 000000000..db05b9270 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/CMakeLists.txt @@ -0,0 +1,108 @@ +# --------------------------------------------------------------- +# Programmer(s): Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the F2003 ARKODE object library +# --------------------------------------------------------------- + +set(arkode_SOURCES + farkode_mod.f90 + farkode_mod.c + farkode_arkstep_mod.f90 + farkode_arkstep_mod.c + farkode_erkstep_mod.f90 + farkode_erkstep_mod.c + farkode_mristep_mod.f90 + farkode_mristep_mod.c) + +if(BUILD_STATIC_LIBS) + sundials_add_f2003_interface_library(sundials_farkode_mod_static STATIC + ${arkode_SOURCES} + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + + # include the directoy where the .mod files reside + target_include_directories(sundials_farkode_mod_static + PUBLIC + $ + $ + ) + + # Set the library name and make sure it is not deleted + set_target_properties(sundials_farkode_mod_static + PROPERTIES OUTPUT_NAME sundials_farkode_mod CLEAN_DIRECT_OUTPUT 1) + + # install the library + install(TARGETS sundials_farkode_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # install the arkode mod file from here since it won't go into the + # top level fortran mod file directory + install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_STATIC/farkode_mod.mod + DESTINATION ${Fortran_INSTALL_MODDIR}) +endif() + +if(BUILD_SHARED_LIBS) + sundials_add_f2003_interface_library(sundials_farkode_mod_shared SHARED + ${arkode_SOURCES} + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + + # include the directoy where the .mod files reside + target_include_directories(sundials_farkode_mod_shared + PUBLIC + $ + $ + ) + + # Set the library name and make sure it is not deleted + set_target_properties(sundials_farkode_mod_shared PROPERTIES + OUTPUT_NAME sundials_farkode_mod + CLEAN_DIRECT_OUTPUT 1 + VERSION ${arkodelib_VERSION} + SOVERSION ${arkodelib_SOVERSION}) + + # install the library + install(TARGETS sundials_farkode_mod_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # install the arkode mod file from here since it won't go into the + # top level fortran mod file directory + install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_SHARED/farkode_mod.mod + DESTINATION ${Fortran_INSTALL_MODDIR}) +endif() + +message(STATUS "Added ARKODE F2003 interface") diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_arkstep_mod.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_arkstep_mod.c new file mode 100644 index 000000000..4141aade3 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_arkstep_mod.c @@ -0,0 +1,2162 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "arkode/arkode_arkstep.h" + + +#include +#ifdef _MSC_VER +# ifndef strtoull +# define strtoull _strtoui64 +# endif +# ifndef strtoll +# define strtoll _strtoi64 +# endif +#endif + + +typedef struct { + void* data; + size_t size; +} SwigArrayWrapper; + + +SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() { + SwigArrayWrapper result; + result.data = NULL; + result.size = 0; + return result; +} + + +#include + +SWIGEXPORT void * _wrap_FARKStepCreate(ARKRhsFn farg1, ARKRhsFn farg2, double const *farg3, N_Vector farg4) { + void * fresult ; + ARKRhsFn arg1 = (ARKRhsFn) 0 ; + ARKRhsFn arg2 = (ARKRhsFn) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + void *result = 0 ; + + arg1 = (ARKRhsFn)(farg1); + arg2 = (ARKRhsFn)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + result = (void *)ARKStepCreate(arg1,arg2,arg3,arg4); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepResize(void *farg1, N_Vector farg2, double const *farg3, double const *farg4, ARKVecResizeFn farg5, void *farg6) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype arg3 ; + realtype arg4 ; + ARKVecResizeFn arg5 = (ARKVecResizeFn) 0 ; + void *arg6 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (realtype)(*farg4); + arg5 = (ARKVecResizeFn)(farg5); + arg6 = (void *)(farg6); + result = (int)ARKStepResize(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepReInit(void *farg1, ARKRhsFn farg2, ARKRhsFn farg3, double const *farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKRhsFn arg2 = (ARKRhsFn) 0 ; + ARKRhsFn arg3 = (ARKRhsFn) 0 ; + realtype arg4 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKRhsFn)(farg2); + arg3 = (ARKRhsFn)(farg3); + arg4 = (realtype)(*farg4); + arg5 = (N_Vector)(farg5); + result = (int)ARKStepReInit(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSStolerances(void *farg1, double const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)ARKStepSStolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSVtolerances(void *farg1, double const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)ARKStepSVtolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepWFtolerances(void *farg1, ARKEwtFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKEwtFn arg2 = (ARKEwtFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKEwtFn)(farg2); + result = (int)ARKStepWFtolerances(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepResStolerance(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepResStolerance(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepResVtolerance(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)ARKStepResVtolerance(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepResFtolerance(void *farg1, ARKRwtFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKRwtFn arg2 = (ARKRwtFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKRwtFn)(farg2); + result = (int)ARKStepResFtolerance(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetLinearSolver(void *farg1, SUNLinearSolver farg2, SUNMatrix farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNLinearSolver arg2 = (SUNLinearSolver) 0 ; + SUNMatrix arg3 = (SUNMatrix) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNLinearSolver)(farg2); + arg3 = (SUNMatrix)(farg3); + result = (int)ARKStepSetLinearSolver(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMassLinearSolver(void *farg1, SUNLinearSolver farg2, SUNMatrix farg3, int const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNLinearSolver arg2 = (SUNLinearSolver) 0 ; + SUNMatrix arg3 = (SUNMatrix) 0 ; + int arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNLinearSolver)(farg2); + arg3 = (SUNMatrix)(farg3); + arg4 = (int)(*farg4); + result = (int)ARKStepSetMassLinearSolver(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepRootInit(void *farg1, int const *farg2, ARKRootFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + ARKRootFn arg3 = (ARKRootFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (ARKRootFn)(farg3); + result = (int)ARKStepRootInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetDefaults(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)ARKStepSetDefaults(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetOptimalParams(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)ARKStepSetOptimalParams(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetOrder(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetInterpolantType(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetInterpolantType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetInterpolantDegree(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetInterpolantDegree(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetDenseOrder(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetDenseOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetNonlinearSolver(void *farg1, SUNNonlinearSolver farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNNonlinearSolver arg2 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNNonlinearSolver)(farg2); + result = (int)ARKStepSetNonlinearSolver(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetLinear(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetLinear(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetNonlinear(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)ARKStepSetNonlinear(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetExplicit(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)ARKStepSetExplicit(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetImplicit(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)ARKStepSetImplicit(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetImEx(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)ARKStepSetImEx(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetTables(void *farg1, int const *farg2, int const *farg3, void *farg4, void *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + ARKodeButcherTable arg4 = (ARKodeButcherTable) 0 ; + ARKodeButcherTable arg5 = (ARKodeButcherTable) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + arg4 = (ARKodeButcherTable)(farg4); + arg5 = (ARKodeButcherTable)(farg5); + result = (int)ARKStepSetTables(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetTableNum(void *farg1, int const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (int)ARKStepSetTableNum(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetCFLFraction(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetCFLFraction(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetSafetyFactor(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetSafetyFactor(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetErrorBias(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetErrorBias(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxGrowth(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetMaxGrowth(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetFixedStepBounds(void *farg1, double const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)ARKStepSetFixedStepBounds(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetAdaptivityMethod(void *farg1, int const *farg2, int const *farg3, int const *farg4, double *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + int arg4 ; + realtype *arg5 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + arg4 = (int)(*farg4); + arg5 = (double *)(farg5); + result = (int)ARKStepSetAdaptivityMethod(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetAdaptivityFn(void *farg1, ARKAdaptFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKAdaptFn arg2 = (ARKAdaptFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKAdaptFn)(farg2); + arg3 = (void *)(farg3); + result = (int)ARKStepSetAdaptivityFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxFirstGrowth(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetMaxFirstGrowth(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxEFailGrowth(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetMaxEFailGrowth(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetSmallNumEFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetSmallNumEFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxCFailGrowth(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetMaxCFailGrowth(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetNonlinCRDown(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetNonlinCRDown(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetNonlinRDiv(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetNonlinRDiv(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetDeltaGammaMax(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetDeltaGammaMax(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxStepsBetweenLSet(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetMaxStepsBetweenLSet(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetPredictorMethod(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetPredictorMethod(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetStabilityFn(void *farg1, ARKExpStabFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKExpStabFn arg2 = (ARKExpStabFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKExpStabFn)(farg2); + arg3 = (void *)(farg3); + result = (int)ARKStepSetStabilityFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxErrTestFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetMaxErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxNonlinIters(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetMaxNonlinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxConvFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetMaxConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetNonlinConvCoef(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetNonlinConvCoef(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetConstraints(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)ARKStepSetConstraints(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxNumSteps(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)ARKStepSetMaxNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxHnilWarns(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetMaxHnilWarns(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetInitStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetInitStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMinStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetMinStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetMaxStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetStopTime(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetStopTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetFixedStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetFixedStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxNumConstrFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetMaxNumConstrFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetRootDirection(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)ARKStepSetRootDirection(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetNoInactiveRootWarn(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)ARKStepSetNoInactiveRootWarn(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetErrHandlerFn(void *farg1, ARKErrHandlerFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKErrHandlerFn arg2 = (ARKErrHandlerFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKErrHandlerFn)(farg2); + arg3 = (void *)(farg3); + result = (int)ARKStepSetErrHandlerFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetErrFile(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)ARKStepSetErrFile(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetUserData(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + void *arg2 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (void *)(farg2); + result = (int)ARKStepSetUserData(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetDiagnostics(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)ARKStepSetDiagnostics(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetPostprocessStepFn(void *farg1, ARKPostProcessFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKPostProcessFn arg2 = (ARKPostProcessFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKPostProcessFn)(farg2); + result = (int)ARKStepSetPostprocessStepFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetPostprocessStageFn(void *farg1, ARKPostProcessFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKPostProcessFn arg2 = (ARKPostProcessFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKPostProcessFn)(farg2); + result = (int)ARKStepSetPostprocessStageFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetStagePredictFn(void *farg1, ARKStepStagePredictFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKStepStagePredictFn arg2 = (ARKStepStagePredictFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKStepStagePredictFn)(farg2); + result = (int)ARKStepSetStagePredictFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetJacFn(void *farg1, ARKLsJacFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKLsJacFn arg2 = (ARKLsJacFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKLsJacFn)(farg2); + result = (int)ARKStepSetJacFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMassFn(void *farg1, ARKLsMassFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKLsMassFn arg2 = (ARKLsMassFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKLsMassFn)(farg2); + result = (int)ARKStepSetMassFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMaxStepsBetweenJac(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)ARKStepSetMaxStepsBetweenJac(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetLinearSolutionScaling(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ARKStepSetLinearSolutionScaling(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetEpsLin(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetEpsLin(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMassEpsLin(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ARKStepSetMassEpsLin(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetPreconditioner(void *farg1, ARKLsPrecSetupFn farg2, ARKLsPrecSolveFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKLsPrecSetupFn arg2 = (ARKLsPrecSetupFn) 0 ; + ARKLsPrecSolveFn arg3 = (ARKLsPrecSolveFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKLsPrecSetupFn)(farg2); + arg3 = (ARKLsPrecSolveFn)(farg3); + result = (int)ARKStepSetPreconditioner(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMassPreconditioner(void *farg1, ARKLsMassPrecSetupFn farg2, ARKLsMassPrecSolveFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKLsMassPrecSetupFn arg2 = (ARKLsMassPrecSetupFn) 0 ; + ARKLsMassPrecSolveFn arg3 = (ARKLsMassPrecSolveFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKLsMassPrecSetupFn)(farg2); + arg3 = (ARKLsMassPrecSolveFn)(farg3); + result = (int)ARKStepSetMassPreconditioner(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetJacTimes(void *farg1, ARKLsJacTimesSetupFn farg2, ARKLsJacTimesVecFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKLsJacTimesSetupFn arg2 = (ARKLsJacTimesSetupFn) 0 ; + ARKLsJacTimesVecFn arg3 = (ARKLsJacTimesVecFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKLsJacTimesSetupFn)(farg2); + arg3 = (ARKLsJacTimesVecFn)(farg3); + result = (int)ARKStepSetJacTimes(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetMassTimes(void *farg1, ARKLsMassTimesSetupFn farg2, ARKLsMassTimesVecFn farg3, void *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKLsMassTimesSetupFn arg2 = (ARKLsMassTimesSetupFn) 0 ; + ARKLsMassTimesVecFn arg3 = (ARKLsMassTimesVecFn) 0 ; + void *arg4 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKLsMassTimesSetupFn)(farg2); + arg3 = (ARKLsMassTimesVecFn)(farg3); + arg4 = (void *)(farg4); + result = (int)ARKStepSetMassTimes(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepSetLinSysFn(void *farg1, ARKLsLinSysFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKLsLinSysFn arg2 = (ARKLsLinSysFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKLsLinSysFn)(farg2); + result = (int)ARKStepSetLinSysFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepEvolve(void *farg1, double const *farg2, N_Vector farg3, double *farg4, int const *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype *arg4 = (realtype *) 0 ; + int arg5 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + arg4 = (realtype *)(farg4); + arg5 = (int)(*farg5); + result = (int)ARKStepEvolve(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetDky(void *farg1, double const *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)ARKStepGetDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumExpSteps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumExpSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumAccSteps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumAccSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumStepAttempts(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumStepAttempts(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumRhsEvals(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)ARKStepGetNumRhsEvals(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumLinSolvSetups(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumLinSolvSetups(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumErrTestFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetCurrentButcherTables(void *farg1, void *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKodeButcherTable *arg2 = (ARKodeButcherTable *) 0 ; + ARKodeButcherTable *arg3 = (ARKodeButcherTable *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKodeButcherTable *)(farg2); + arg3 = (ARKodeButcherTable *)(farg3); + result = (int)ARKStepGetCurrentButcherTables(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetEstLocalErrors(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)ARKStepGetEstLocalErrors(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)ARKStepGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumSteps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetActualInitStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)ARKStepGetActualInitStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetLastStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)ARKStepGetLastStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetCurrentStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)ARKStepGetCurrentStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetCurrentTime(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)ARKStepGetCurrentTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetCurrentState(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)ARKStepGetCurrentState(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetCurrentGamma(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)ARKStepGetCurrentGamma(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetTolScaleFactor(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)ARKStepGetTolScaleFactor(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetErrWeights(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)ARKStepGetErrWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetResWeights(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)ARKStepGetResWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumGEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumGEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetRootInfo(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)ARKStepGetRootInfo(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumConstrFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumConstrFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FARKStepGetReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)ARKStepGetReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepWriteParameters(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)ARKStepWriteParameters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepWriteButcher(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)ARKStepWriteButcher(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetTimestepperStats(void *farg1, long *farg2, long *farg3, long *farg4, long *farg5, long *farg6, long *farg7, long *farg8) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + long *arg4 = (long *) 0 ; + long *arg5 = (long *) 0 ; + long *arg6 = (long *) 0 ; + long *arg7 = (long *) 0 ; + long *arg8 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + arg4 = (long *)(farg4); + arg5 = (long *)(farg5); + arg6 = (long *)(farg6); + arg7 = (long *)(farg7); + arg8 = (long *)(farg8); + result = (int)ARKStepGetTimestepperStats(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetStepStats(void *farg1, long *farg2, double *farg3, double *farg4, double *farg5, double *farg6) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + realtype *arg3 = (realtype *) 0 ; + realtype *arg4 = (realtype *) 0 ; + realtype *arg5 = (realtype *) 0 ; + realtype *arg6 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (realtype *)(farg3); + arg4 = (realtype *)(farg4); + arg5 = (realtype *)(farg5); + arg6 = (realtype *)(farg6); + result = (int)ARKStepGetStepStats(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumNonlinSolvIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumNonlinSolvIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumNonlinSolvConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumNonlinSolvConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNonlinSolvStats(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)ARKStepGetNonlinSolvStats(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetLinWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)ARKStepGetLinWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumJacEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumJacEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumPrecEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumPrecEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumPrecSolves(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumPrecSolves(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumLinIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumLinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumLinConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumLinConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumJTSetupEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumJTSetupEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumJtimesEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumJtimesEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumLinRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumLinRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetLastLinFlag(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetLastLinFlag(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetMassWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)ARKStepGetMassWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumMassSetups(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumMassSetups(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumMassMultSetups(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumMassMultSetups(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumMassMult(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumMassMult(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumMassSolves(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumMassSolves(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumMassPrecEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumMassPrecEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumMassPrecSolves(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumMassPrecSolves(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumMassIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumMassIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumMassConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumMassConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetNumMTSetups(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetNumMTSetups(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKStepGetLastMassFlag(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKStepGetLastMassFlag(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FARKStepGetLinReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)ARKStepGetLinReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FARKStepFree(void *farg1) { + void **arg1 = (void **) 0 ; + + arg1 = (void **)(farg1); + ARKStepFree(arg1); +} + + +SWIGEXPORT void _wrap_FARKStepPrintMem(void *farg1, void *farg2) { + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + ARKStepPrintMem(arg1,arg2); +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_arkstep_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_arkstep_mod.f90 new file mode 100644 index 000000000..1316adae4 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_arkstep_mod.f90 @@ -0,0 +1,3680 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module farkode_arkstep_mod + use, intrinsic :: ISO_C_BINDING + use farkode_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_linearsolver_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_nonlinearsolver_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: DEFAULT_ERK_2 = 0_C_INT + integer(C_INT), parameter, public :: DEFAULT_ERK_3 = 1_C_INT + integer(C_INT), parameter, public :: DEFAULT_ERK_4 = 3_C_INT + integer(C_INT), parameter, public :: DEFAULT_ERK_5 = 6_C_INT + integer(C_INT), parameter, public :: DEFAULT_ERK_6 = 10_C_INT + integer(C_INT), parameter, public :: DEFAULT_ERK_8 = 11_C_INT + integer(C_INT), parameter, public :: DEFAULT_DIRK_2 = 100_C_INT + integer(C_INT), parameter, public :: DEFAULT_DIRK_3 = 104_C_INT + integer(C_INT), parameter, public :: DEFAULT_DIRK_4 = 107_C_INT + integer(C_INT), parameter, public :: DEFAULT_DIRK_5 = 111_C_INT + integer(C_INT), parameter, public :: DEFAULT_ARK_ETABLE_3 = 2_C_INT + integer(C_INT), parameter, public :: DEFAULT_ARK_ETABLE_4 = 4_C_INT + integer(C_INT), parameter, public :: DEFAULT_ARK_ETABLE_5 = 9_C_INT + integer(C_INT), parameter, public :: DEFAULT_ARK_ITABLE_3 = 104_C_INT + integer(C_INT), parameter, public :: DEFAULT_ARK_ITABLE_4 = 109_C_INT + integer(C_INT), parameter, public :: DEFAULT_ARK_ITABLE_5 = 111_C_INT + public :: FARKStepCreate + public :: FARKStepResize + public :: FARKStepReInit + public :: FARKStepSStolerances + public :: FARKStepSVtolerances + public :: FARKStepWFtolerances + public :: FARKStepResStolerance + public :: FARKStepResVtolerance + public :: FARKStepResFtolerance + public :: FARKStepSetLinearSolver + public :: FARKStepSetMassLinearSolver + public :: FARKStepRootInit + public :: FARKStepSetDefaults + public :: FARKStepSetOptimalParams + public :: FARKStepSetOrder + public :: FARKStepSetInterpolantType + public :: FARKStepSetInterpolantDegree + public :: FARKStepSetDenseOrder + public :: FARKStepSetNonlinearSolver + public :: FARKStepSetLinear + public :: FARKStepSetNonlinear + public :: FARKStepSetExplicit + public :: FARKStepSetImplicit + public :: FARKStepSetImEx + public :: FARKStepSetTables + public :: FARKStepSetTableNum + public :: FARKStepSetCFLFraction + public :: FARKStepSetSafetyFactor + public :: FARKStepSetErrorBias + public :: FARKStepSetMaxGrowth + public :: FARKStepSetFixedStepBounds + public :: FARKStepSetAdaptivityMethod + public :: FARKStepSetAdaptivityFn + public :: FARKStepSetMaxFirstGrowth + public :: FARKStepSetMaxEFailGrowth + public :: FARKStepSetSmallNumEFails + public :: FARKStepSetMaxCFailGrowth + public :: FARKStepSetNonlinCRDown + public :: FARKStepSetNonlinRDiv + public :: FARKStepSetDeltaGammaMax + public :: FARKStepSetMaxStepsBetweenLSet + public :: FARKStepSetPredictorMethod + public :: FARKStepSetStabilityFn + public :: FARKStepSetMaxErrTestFails + public :: FARKStepSetMaxNonlinIters + public :: FARKStepSetMaxConvFails + public :: FARKStepSetNonlinConvCoef + public :: FARKStepSetConstraints + public :: FARKStepSetMaxNumSteps + public :: FARKStepSetMaxHnilWarns + public :: FARKStepSetInitStep + public :: FARKStepSetMinStep + public :: FARKStepSetMaxStep + public :: FARKStepSetStopTime + public :: FARKStepSetFixedStep + public :: FARKStepSetMaxNumConstrFails + public :: FARKStepSetRootDirection + public :: FARKStepSetNoInactiveRootWarn + public :: FARKStepSetErrHandlerFn + public :: FARKStepSetErrFile + public :: FARKStepSetUserData + public :: FARKStepSetDiagnostics + public :: FARKStepSetPostprocessStepFn + public :: FARKStepSetPostprocessStageFn + public :: FARKStepSetStagePredictFn + public :: FARKStepSetJacFn + public :: FARKStepSetMassFn + public :: FARKStepSetMaxStepsBetweenJac + public :: FARKStepSetLinearSolutionScaling + public :: FARKStepSetEpsLin + public :: FARKStepSetMassEpsLin + public :: FARKStepSetPreconditioner + public :: FARKStepSetMassPreconditioner + public :: FARKStepSetJacTimes + public :: FARKStepSetMassTimes + public :: FARKStepSetLinSysFn + public :: FARKStepEvolve + public :: FARKStepGetDky + public :: FARKStepGetNumExpSteps + public :: FARKStepGetNumAccSteps + public :: FARKStepGetNumStepAttempts + public :: FARKStepGetNumRhsEvals + public :: FARKStepGetNumLinSolvSetups + public :: FARKStepGetNumErrTestFails + public :: FARKStepGetCurrentButcherTables + public :: FARKStepGetEstLocalErrors + public :: FARKStepGetWorkSpace + public :: FARKStepGetNumSteps + public :: FARKStepGetActualInitStep + public :: FARKStepGetLastStep + public :: FARKStepGetCurrentStep + public :: FARKStepGetCurrentTime + public :: FARKStepGetCurrentState + public :: FARKStepGetCurrentGamma + public :: FARKStepGetTolScaleFactor + public :: FARKStepGetErrWeights + public :: FARKStepGetResWeights + public :: FARKStepGetNumGEvals + public :: FARKStepGetRootInfo + public :: FARKStepGetNumConstrFails + type, bind(C) :: SwigArrayWrapper + type(C_PTR), public :: data = C_NULL_PTR + integer(C_SIZE_T), public :: size = 0 + end type + public :: FARKStepGetReturnFlagName + public :: FARKStepWriteParameters + public :: FARKStepWriteButcher + public :: FARKStepGetTimestepperStats + public :: FARKStepGetStepStats + public :: FARKStepGetNumNonlinSolvIters + public :: FARKStepGetNumNonlinSolvConvFails + public :: FARKStepGetNonlinSolvStats + public :: FARKStepGetLinWorkSpace + public :: FARKStepGetNumJacEvals + public :: FARKStepGetNumPrecEvals + public :: FARKStepGetNumPrecSolves + public :: FARKStepGetNumLinIters + public :: FARKStepGetNumLinConvFails + public :: FARKStepGetNumJTSetupEvals + public :: FARKStepGetNumJtimesEvals + public :: FARKStepGetNumLinRhsEvals + public :: FARKStepGetLastLinFlag + public :: FARKStepGetMassWorkSpace + public :: FARKStepGetNumMassSetups + public :: FARKStepGetNumMassMultSetups + public :: FARKStepGetNumMassMult + public :: FARKStepGetNumMassSolves + public :: FARKStepGetNumMassPrecEvals + public :: FARKStepGetNumMassPrecSolves + public :: FARKStepGetNumMassIters + public :: FARKStepGetNumMassConvFails + public :: FARKStepGetNumMTSetups + public :: FARKStepGetLastMassFlag + public :: FARKStepGetLinReturnFlagName + public :: FARKStepFree + public :: FARKStepPrintMem + +! WRAPPER DECLARATIONS +interface +function swigc_FARKStepCreate(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FARKStepCreate") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_FUNPTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR) :: fresult +end function + +function swigc_FARKStepResize(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FARKStepResize") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_FUNPTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepReInit(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FARKStepReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSStolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepSStolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSVtolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepSVtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepWFtolerances(farg1, farg2) & +bind(C, name="_wrap_FARKStepWFtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepResStolerance(farg1, farg2) & +bind(C, name="_wrap_FARKStepResStolerance") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepResVtolerance(farg1, farg2) & +bind(C, name="_wrap_FARKStepResVtolerance") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepResFtolerance(farg1, farg2) & +bind(C, name="_wrap_FARKStepResFtolerance") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetLinearSolver(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepSetLinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMassLinearSolver(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FARKStepSetMassLinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepRootInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepRootInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetDefaults(farg1) & +bind(C, name="_wrap_FARKStepSetDefaults") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetOptimalParams(farg1) & +bind(C, name="_wrap_FARKStepSetOptimalParams") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetOrder(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetInterpolantType(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetInterpolantType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetInterpolantDegree(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetInterpolantDegree") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetDenseOrder(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetDenseOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetNonlinearSolver(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetNonlinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetLinear(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetLinear") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetNonlinear(farg1) & +bind(C, name="_wrap_FARKStepSetNonlinear") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetExplicit(farg1) & +bind(C, name="_wrap_FARKStepSetExplicit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetImplicit(farg1) & +bind(C, name="_wrap_FARKStepSetImplicit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetImEx(farg1) & +bind(C, name="_wrap_FARKStepSetImEx") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetTables(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FARKStepSetTables") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetTableNum(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepSetTableNum") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetCFLFraction(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetCFLFraction") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetSafetyFactor(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetSafetyFactor") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetErrorBias(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetErrorBias") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxGrowth(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxGrowth") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetFixedStepBounds(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepSetFixedStepBounds") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetAdaptivityMethod(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FARKStepSetAdaptivityMethod") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT), intent(in) :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetAdaptivityFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepSetAdaptivityFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxFirstGrowth(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxFirstGrowth") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxEFailGrowth(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxEFailGrowth") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetSmallNumEFails(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetSmallNumEFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxCFailGrowth(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxCFailGrowth") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetNonlinCRDown(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetNonlinCRDown") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetNonlinRDiv(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetNonlinRDiv") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetDeltaGammaMax(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetDeltaGammaMax") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxStepsBetweenLSet(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxStepsBetweenLSet") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetPredictorMethod(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetPredictorMethod") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetStabilityFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepSetStabilityFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxNonlinIters(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxNonlinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxConvFails(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetNonlinConvCoef(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetNonlinConvCoef") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetConstraints(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetConstraints") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxNumSteps(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxHnilWarns(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxHnilWarns") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetInitStep(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetInitStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMinStep(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMinStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxStep(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetStopTime(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetStopTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetFixedStep(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetFixedStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxNumConstrFails(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxNumConstrFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetRootDirection(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetRootDirection") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetNoInactiveRootWarn(farg1) & +bind(C, name="_wrap_FARKStepSetNoInactiveRootWarn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetErrHandlerFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepSetErrHandlerFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetErrFile(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetErrFile") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetUserData(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetUserData") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetDiagnostics(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetDiagnostics") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetPostprocessStepFn(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetPostprocessStepFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetPostprocessStageFn(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetPostprocessStageFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetStagePredictFn(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetStagePredictFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetJacFn(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetJacFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMassFn(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMassFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMaxStepsBetweenJac(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMaxStepsBetweenJac") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetLinearSolutionScaling(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetLinearSolutionScaling") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetEpsLin(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetEpsLin") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMassEpsLin(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetMassEpsLin") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetPreconditioner(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepSetPreconditioner") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMassPreconditioner(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepSetMassPreconditioner") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetJacTimes(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepSetJacTimes") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetMassTimes(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FARKStepSetMassTimes") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepSetLinSysFn(farg1, farg2) & +bind(C, name="_wrap_FARKStepSetLinSysFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepEvolve(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FARKStepEvolve") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FARKStepGetDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumExpSteps(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumExpSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumAccSteps(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumAccSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumStepAttempts(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumStepAttempts") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumRhsEvals(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepGetNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumLinSolvSetups(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumLinSolvSetups") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetCurrentButcherTables(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepGetCurrentButcherTables") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetEstLocalErrors(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetEstLocalErrors") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumSteps(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetActualInitStep(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetActualInitStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetLastStep(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetLastStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetCurrentStep(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetCurrentStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetCurrentTime(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetCurrentTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetCurrentState(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetCurrentState") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetCurrentGamma(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetCurrentGamma") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetTolScaleFactor(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetTolScaleFactor") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetErrWeights(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetErrWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetResWeights(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetResWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumGEvals(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumGEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetRootInfo(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetRootInfo") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumConstrFails(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumConstrFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + + subroutine SWIG_free(cptr) & + bind(C, name="free") + use, intrinsic :: ISO_C_BINDING + type(C_PTR), value :: cptr +end subroutine +function swigc_FARKStepGetReturnFlagName(farg1) & +bind(C, name="_wrap_FARKStepGetReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +function swigc_FARKStepWriteParameters(farg1, farg2) & +bind(C, name="_wrap_FARKStepWriteParameters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepWriteButcher(farg1, farg2) & +bind(C, name="_wrap_FARKStepWriteButcher") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetTimestepperStats(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8) & +bind(C, name="_wrap_FARKStepGetTimestepperStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +type(C_PTR), value :: farg7 +type(C_PTR), value :: farg8 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetStepStats(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FARKStepGetStepStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumNonlinSolvIters(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumNonlinSolvIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumNonlinSolvConvFails(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumNonlinSolvConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNonlinSolvStats(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepGetNonlinSolvStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetLinWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepGetLinWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumJacEvals(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumJacEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumPrecEvals(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumPrecEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumPrecSolves(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumPrecSolves") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumLinIters(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumLinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumLinConvFails(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumLinConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumJTSetupEvals(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumJTSetupEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumJtimesEvals(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumJtimesEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumLinRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumLinRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetLastLinFlag(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetLastLinFlag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetMassWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKStepGetMassWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumMassSetups(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumMassSetups") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumMassMultSetups(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumMassMultSetups") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumMassMult(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumMassMult") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumMassSolves(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumMassSolves") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumMassPrecEvals(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumMassPrecEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumMassPrecSolves(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumMassPrecSolves") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumMassIters(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumMassIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumMassConvFails(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumMassConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetNumMTSetups(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetNumMTSetups") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetLastMassFlag(farg1, farg2) & +bind(C, name="_wrap_FARKStepGetLastMassFlag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKStepGetLinReturnFlagName(farg1) & +bind(C, name="_wrap_FARKStepGetLinReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +subroutine swigc_FARKStepFree(farg1) & +bind(C, name="_wrap_FARKStepFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FARKStepPrintMem(farg1, farg2) & +bind(C, name="_wrap_FARKStepPrintMem") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FARKStepCreate(fe, fi, t0, y0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +type(C_FUNPTR), intent(in), value :: fe +type(C_FUNPTR), intent(in), value :: fi +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: y0 +type(C_PTR) :: fresult +type(C_FUNPTR) :: farg1 +type(C_FUNPTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 + +farg1 = fe +farg2 = fi +farg3 = t0 +farg4 = c_loc(y0) +fresult = swigc_FARKStepCreate(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FARKStepResize(arkode_mem, ynew, hscale, t0, resize, resize_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(N_Vector), target, intent(inout) :: ynew +real(C_DOUBLE), intent(in) :: hscale +real(C_DOUBLE), intent(in) :: t0 +type(C_FUNPTR), intent(in), value :: resize +type(C_PTR) :: resize_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +real(C_DOUBLE) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_FUNPTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = arkode_mem +farg2 = c_loc(ynew) +farg3 = hscale +farg4 = t0 +farg5 = resize +farg6 = resize_data +fresult = swigc_FARKStepResize(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FARKStepReInit(arkode_mem, fe, fi, t0, y0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: fe +type(C_FUNPTR), intent(in), value :: fi +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: y0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_PTR) :: farg5 + +farg1 = arkode_mem +farg2 = fe +farg3 = fi +farg4 = t0 +farg5 = c_loc(y0) +fresult = swigc_FARKStepReInit(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FARKStepSStolerances(arkode_mem, reltol, abstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: reltol +real(C_DOUBLE), intent(in) :: abstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = arkode_mem +farg2 = reltol +farg3 = abstol +fresult = swigc_FARKStepSStolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepSVtolerances(arkode_mem, reltol, abstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: reltol +type(N_Vector), target, intent(inout) :: abstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = reltol +farg3 = c_loc(abstol) +fresult = swigc_FARKStepSVtolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepWFtolerances(arkode_mem, efun) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: efun +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = efun +fresult = swigc_FARKStepWFtolerances(farg1, farg2) +swig_result = fresult +end function + +function FARKStepResStolerance(arkode_mem, rabstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: rabstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = rabstol +fresult = swigc_FARKStepResStolerance(farg1, farg2) +swig_result = fresult +end function + +function FARKStepResVtolerance(arkode_mem, rabstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(N_Vector), target, intent(inout) :: rabstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(rabstol) +fresult = swigc_FARKStepResVtolerance(farg1, farg2) +swig_result = fresult +end function + +function FARKStepResFtolerance(arkode_mem, rfun) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: rfun +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = rfun +fresult = swigc_FARKStepResFtolerance(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetLinearSolver(arkode_mem, ls, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(SUNLinearSolver), target, intent(inout) :: ls +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = c_loc(ls) +farg3 = c_loc(a) +fresult = swigc_FARKStepSetLinearSolver(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepSetMassLinearSolver(arkode_mem, ls, m, time_dep) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(SUNLinearSolver), target, intent(inout) :: ls +type(SUNMatrix), target, intent(inout) :: m +integer(C_INT), intent(in) :: time_dep +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +integer(C_INT) :: farg4 + +farg1 = arkode_mem +farg2 = c_loc(ls) +farg3 = c_loc(m) +farg4 = time_dep +fresult = swigc_FARKStepSetMassLinearSolver(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FARKStepRootInit(arkode_mem, nrtfn, g) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: nrtfn +type(C_FUNPTR), intent(in), value :: g +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = arkode_mem +farg2 = nrtfn +farg3 = g +fresult = swigc_FARKStepRootInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepSetDefaults(arkode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = arkode_mem +fresult = swigc_FARKStepSetDefaults(farg1) +swig_result = fresult +end function + +function FARKStepSetOptimalParams(arkode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = arkode_mem +fresult = swigc_FARKStepSetOptimalParams(farg1) +swig_result = fresult +end function + +function FARKStepSetOrder(arkode_mem, maxord) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: maxord +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = maxord +fresult = swigc_FARKStepSetOrder(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetInterpolantType(arkode_mem, itype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: itype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = itype +fresult = swigc_FARKStepSetInterpolantType(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetInterpolantDegree(arkode_mem, degree) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: degree +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = degree +fresult = swigc_FARKStepSetInterpolantDegree(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetDenseOrder(arkode_mem, dord) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: dord +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = dord +fresult = swigc_FARKStepSetDenseOrder(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetNonlinearSolver(arkode_mem, nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nls) +fresult = swigc_FARKStepSetNonlinearSolver(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetLinear(arkode_mem, timedepend) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: timedepend +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = timedepend +fresult = swigc_FARKStepSetLinear(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetNonlinear(arkode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = arkode_mem +fresult = swigc_FARKStepSetNonlinear(farg1) +swig_result = fresult +end function + +function FARKStepSetExplicit(arkode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = arkode_mem +fresult = swigc_FARKStepSetExplicit(farg1) +swig_result = fresult +end function + +function FARKStepSetImplicit(arkode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = arkode_mem +fresult = swigc_FARKStepSetImplicit(farg1) +swig_result = fresult +end function + +function FARKStepSetImEx(arkode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = arkode_mem +fresult = swigc_FARKStepSetImEx(farg1) +swig_result = fresult +end function + +function FARKStepSetTables(arkode_mem, q, p, bi, be) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: q +integer(C_INT), intent(in) :: p +type(C_PTR) :: bi +type(C_PTR) :: be +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = arkode_mem +farg2 = q +farg3 = p +farg4 = bi +farg5 = be +fresult = swigc_FARKStepSetTables(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FARKStepSetTableNum(arkode_mem, itable, etable) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: itable +integer(C_INT), intent(in) :: etable +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = arkode_mem +farg2 = itable +farg3 = etable +fresult = swigc_FARKStepSetTableNum(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepSetCFLFraction(arkode_mem, cfl_frac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: cfl_frac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = cfl_frac +fresult = swigc_FARKStepSetCFLFraction(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetSafetyFactor(arkode_mem, safety) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: safety +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = safety +fresult = swigc_FARKStepSetSafetyFactor(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetErrorBias(arkode_mem, bias) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: bias +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = bias +fresult = swigc_FARKStepSetErrorBias(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMaxGrowth(arkode_mem, mx_growth) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: mx_growth +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = mx_growth +fresult = swigc_FARKStepSetMaxGrowth(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetFixedStepBounds(arkode_mem, lb, ub) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: lb +real(C_DOUBLE), intent(in) :: ub +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = arkode_mem +farg2 = lb +farg3 = ub +fresult = swigc_FARKStepSetFixedStepBounds(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepSetAdaptivityMethod(arkode_mem, imethod, idefault, pq, adapt_params) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: imethod +integer(C_INT), intent(in) :: idefault +integer(C_INT), intent(in) :: pq +real(C_DOUBLE), dimension(3), target, intent(inout) :: adapt_params +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 +integer(C_INT) :: farg4 +type(C_PTR) :: farg5 + +farg1 = arkode_mem +farg2 = imethod +farg3 = idefault +farg4 = pq +farg5 = c_loc(adapt_params(1)) +fresult = swigc_FARKStepSetAdaptivityMethod(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FARKStepSetAdaptivityFn(arkode_mem, hfun, h_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: hfun +type(C_PTR) :: h_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = hfun +farg3 = h_data +fresult = swigc_FARKStepSetAdaptivityFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepSetMaxFirstGrowth(arkode_mem, etamx1) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: etamx1 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = etamx1 +fresult = swigc_FARKStepSetMaxFirstGrowth(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMaxEFailGrowth(arkode_mem, etamxf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: etamxf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = etamxf +fresult = swigc_FARKStepSetMaxEFailGrowth(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetSmallNumEFails(arkode_mem, small_nef) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: small_nef +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = small_nef +fresult = swigc_FARKStepSetSmallNumEFails(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMaxCFailGrowth(arkode_mem, etacf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: etacf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = etacf +fresult = swigc_FARKStepSetMaxCFailGrowth(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetNonlinCRDown(arkode_mem, crdown) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: crdown +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = crdown +fresult = swigc_FARKStepSetNonlinCRDown(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetNonlinRDiv(arkode_mem, rdiv) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: rdiv +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = rdiv +fresult = swigc_FARKStepSetNonlinRDiv(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetDeltaGammaMax(arkode_mem, dgmax) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: dgmax +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = dgmax +fresult = swigc_FARKStepSetDeltaGammaMax(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMaxStepsBetweenLSet(arkode_mem, msbp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: msbp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = msbp +fresult = swigc_FARKStepSetMaxStepsBetweenLSet(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetPredictorMethod(arkode_mem, method) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: method +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = method +fresult = swigc_FARKStepSetPredictorMethod(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetStabilityFn(arkode_mem, estab, estab_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: estab +type(C_PTR) :: estab_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = estab +farg3 = estab_data +fresult = swigc_FARKStepSetStabilityFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepSetMaxErrTestFails(arkode_mem, maxnef) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: maxnef +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = maxnef +fresult = swigc_FARKStepSetMaxErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMaxNonlinIters(arkode_mem, maxcor) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: maxcor +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = maxcor +fresult = swigc_FARKStepSetMaxNonlinIters(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMaxConvFails(arkode_mem, maxncf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: maxncf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = maxncf +fresult = swigc_FARKStepSetMaxConvFails(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetNonlinConvCoef(arkode_mem, nlscoef) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: nlscoef +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = nlscoef +fresult = swigc_FARKStepSetNonlinConvCoef(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetConstraints(arkode_mem, constraints) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(N_Vector), target, intent(inout) :: constraints +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(constraints) +fresult = swigc_FARKStepSetConstraints(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMaxNumSteps(arkode_mem, mxsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), intent(in) :: mxsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = arkode_mem +farg2 = mxsteps +fresult = swigc_FARKStepSetMaxNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMaxHnilWarns(arkode_mem, mxhnil) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: mxhnil +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = mxhnil +fresult = swigc_FARKStepSetMaxHnilWarns(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetInitStep(arkode_mem, hin) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: hin +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = hin +fresult = swigc_FARKStepSetInitStep(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMinStep(arkode_mem, hmin) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: hmin +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = hmin +fresult = swigc_FARKStepSetMinStep(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMaxStep(arkode_mem, hmax) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: hmax +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = hmax +fresult = swigc_FARKStepSetMaxStep(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetStopTime(arkode_mem, tstop) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: tstop +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = tstop +fresult = swigc_FARKStepSetStopTime(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetFixedStep(arkode_mem, hfixed) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: hfixed +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = hfixed +fresult = swigc_FARKStepSetFixedStep(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMaxNumConstrFails(arkode_mem, maxfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: maxfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = maxfails +fresult = swigc_FARKStepSetMaxNumConstrFails(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetRootDirection(arkode_mem, rootdir) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootdir +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(rootdir(1)) +fresult = swigc_FARKStepSetRootDirection(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetNoInactiveRootWarn(arkode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = arkode_mem +fresult = swigc_FARKStepSetNoInactiveRootWarn(farg1) +swig_result = fresult +end function + +function FARKStepSetErrHandlerFn(arkode_mem, ehfun, eh_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: ehfun +type(C_PTR) :: eh_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = ehfun +farg3 = eh_data +fresult = swigc_FARKStepSetErrHandlerFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepSetErrFile(arkode_mem, errfp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: errfp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = errfp +fresult = swigc_FARKStepSetErrFile(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetUserData(arkode_mem, user_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: user_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = user_data +fresult = swigc_FARKStepSetUserData(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetDiagnostics(arkode_mem, diagfp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: diagfp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = diagfp +fresult = swigc_FARKStepSetDiagnostics(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetPostprocessStepFn(arkode_mem, processstep) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: processstep +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = processstep +fresult = swigc_FARKStepSetPostprocessStepFn(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetPostprocessStageFn(arkode_mem, processstage) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: processstage +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = processstage +fresult = swigc_FARKStepSetPostprocessStageFn(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetStagePredictFn(arkode_mem, predictstage) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: predictstage +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = predictstage +fresult = swigc_FARKStepSetStagePredictFn(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetJacFn(arkode_mem, jac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: jac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = jac +fresult = swigc_FARKStepSetJacFn(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMassFn(arkode_mem, mass) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: mass +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = mass +fresult = swigc_FARKStepSetMassFn(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMaxStepsBetweenJac(arkode_mem, msbj) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), intent(in) :: msbj +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = arkode_mem +farg2 = msbj +fresult = swigc_FARKStepSetMaxStepsBetweenJac(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetLinearSolutionScaling(arkode_mem, onoff) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: onoff +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = onoff +fresult = swigc_FARKStepSetLinearSolutionScaling(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetEpsLin(arkode_mem, eplifac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: eplifac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = eplifac +fresult = swigc_FARKStepSetEpsLin(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetMassEpsLin(arkode_mem, eplifac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: eplifac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = eplifac +fresult = swigc_FARKStepSetMassEpsLin(farg1, farg2) +swig_result = fresult +end function + +function FARKStepSetPreconditioner(arkode_mem, psetup, psolve) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: psetup +type(C_FUNPTR), intent(in), value :: psolve +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = arkode_mem +farg2 = psetup +farg3 = psolve +fresult = swigc_FARKStepSetPreconditioner(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepSetMassPreconditioner(arkode_mem, psetup, psolve) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: psetup +type(C_FUNPTR), intent(in), value :: psolve +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = arkode_mem +farg2 = psetup +farg3 = psolve +fresult = swigc_FARKStepSetMassPreconditioner(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepSetJacTimes(arkode_mem, jtsetup, jtimes) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: jtsetup +type(C_FUNPTR), intent(in), value :: jtimes +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = arkode_mem +farg2 = jtsetup +farg3 = jtimes +fresult = swigc_FARKStepSetJacTimes(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepSetMassTimes(arkode_mem, msetup, mtimes, mtimes_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: msetup +type(C_FUNPTR), intent(in), value :: mtimes +type(C_PTR) :: mtimes_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = arkode_mem +farg2 = msetup +farg3 = mtimes +farg4 = mtimes_data +fresult = swigc_FARKStepSetMassTimes(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FARKStepSetLinSysFn(arkode_mem, linsys) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: linsys +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = linsys +fresult = swigc_FARKStepSetLinSysFn(farg1, farg2) +swig_result = fresult +end function + +function FARKStepEvolve(arkode_mem, tout, yout, tret, itask) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: tout +type(N_Vector), target, intent(inout) :: yout +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +integer(C_INT), intent(in) :: itask +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +integer(C_INT) :: farg5 + +farg1 = arkode_mem +farg2 = tout +farg3 = c_loc(yout) +farg4 = c_loc(tret(1)) +farg5 = itask +fresult = swigc_FARKStepEvolve(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FARKStepGetDky(arkode_mem, t, k, dky) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(N_Vector), target, intent(inout) :: dky +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = arkode_mem +farg2 = t +farg3 = k +farg4 = c_loc(dky) +fresult = swigc_FARKStepGetDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FARKStepGetNumExpSteps(arkode_mem, expsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: expsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(expsteps(1)) +fresult = swigc_FARKStepGetNumExpSteps(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumAccSteps(arkode_mem, accsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: accsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(accsteps(1)) +fresult = swigc_FARKStepGetNumAccSteps(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumStepAttempts(arkode_mem, step_attempts) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: step_attempts +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(step_attempts(1)) +fresult = swigc_FARKStepGetNumStepAttempts(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumRhsEvals(arkode_mem, nfe_evals, nfi_evals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfe_evals +integer(C_LONG), dimension(*), target, intent(inout) :: nfi_evals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = c_loc(nfe_evals(1)) +farg3 = c_loc(nfi_evals(1)) +fresult = swigc_FARKStepGetNumRhsEvals(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepGetNumLinSolvSetups(arkode_mem, nlinsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nlinsetups(1)) +fresult = swigc_FARKStepGetNumLinSolvSetups(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumErrTestFails(arkode_mem, netfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: netfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(netfails(1)) +fresult = swigc_FARKStepGetNumErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetCurrentButcherTables(arkode_mem, bi, be) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR), target, intent(inout) :: bi +type(C_PTR), target, intent(inout) :: be +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = c_loc(bi) +farg3 = c_loc(be) +fresult = swigc_FARKStepGetCurrentButcherTables(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepGetEstLocalErrors(arkode_mem, ele) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(N_Vector), target, intent(inout) :: ele +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(ele) +fresult = swigc_FARKStepGetEstLocalErrors(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetWorkSpace(arkode_mem, lenrw, leniw) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrw +integer(C_LONG), dimension(*), target, intent(inout) :: leniw +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = c_loc(lenrw(1)) +farg3 = c_loc(leniw(1)) +fresult = swigc_FARKStepGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepGetNumSteps(arkode_mem, nsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nsteps(1)) +fresult = swigc_FARKStepGetNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetActualInitStep(arkode_mem, hinused) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hinused +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(hinused(1)) +fresult = swigc_FARKStepGetActualInitStep(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetLastStep(arkode_mem, hlast) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(hlast(1)) +fresult = swigc_FARKStepGetLastStep(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetCurrentStep(arkode_mem, hcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(hcur(1)) +fresult = swigc_FARKStepGetCurrentStep(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetCurrentTime(arkode_mem, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(tcur(1)) +fresult = swigc_FARKStepGetCurrentTime(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetCurrentState(arkode_mem, ycur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: ycur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = ycur +fresult = swigc_FARKStepGetCurrentState(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetCurrentGamma(arkode_mem, gamma) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: gamma +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(gamma(1)) +fresult = swigc_FARKStepGetCurrentGamma(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetTolScaleFactor(arkode_mem, tolsfac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tolsfac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(tolsfac(1)) +fresult = swigc_FARKStepGetTolScaleFactor(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetErrWeights(arkode_mem, eweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(N_Vector), target, intent(inout) :: eweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(eweight) +fresult = swigc_FARKStepGetErrWeights(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetResWeights(arkode_mem, rweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(N_Vector), target, intent(inout) :: rweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(rweight) +fresult = swigc_FARKStepGetResWeights(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumGEvals(arkode_mem, ngevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(ngevals(1)) +fresult = swigc_FARKStepGetNumGEvals(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetRootInfo(arkode_mem, rootsfound) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootsfound +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(rootsfound(1)) +fresult = swigc_FARKStepGetRootInfo(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumConstrFails(arkode_mem, nconstrfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nconstrfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nconstrfails(1)) +fresult = swigc_FARKStepGetNumConstrFails(farg1, farg2) +swig_result = fresult +end function + + +subroutine SWIG_chararray_to_string(wrap, string) + use, intrinsic :: ISO_C_BINDING + type(SwigArrayWrapper), intent(IN) :: wrap + character(kind=C_CHAR, len=:), allocatable, intent(OUT) :: string + character(kind=C_CHAR), dimension(:), pointer :: chars + integer(kind=C_SIZE_T) :: i + call c_f_pointer(wrap%data, chars, [wrap%size]) + allocate(character(kind=C_CHAR, len=wrap%size) :: string) + do i=1, wrap%size + string(i:i) = chars(i) + end do +end subroutine + +function FARKStepGetReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FARKStepGetReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +function FARKStepWriteParameters(arkode_mem, fp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: fp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = fp +fresult = swigc_FARKStepWriteParameters(farg1, farg2) +swig_result = fresult +end function + +function FARKStepWriteButcher(arkode_mem, fp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: fp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = fp +fresult = swigc_FARKStepWriteButcher(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetTimestepperStats(arkode_mem, expsteps, accsteps, step_attempts, nfe_evals, nfi_evals, nlinsetups, & + netfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: expsteps +integer(C_LONG), dimension(*), target, intent(inout) :: accsteps +integer(C_LONG), dimension(*), target, intent(inout) :: step_attempts +integer(C_LONG), dimension(*), target, intent(inout) :: nfe_evals +integer(C_LONG), dimension(*), target, intent(inout) :: nfi_evals +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetups +integer(C_LONG), dimension(*), target, intent(inout) :: netfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 +type(C_PTR) :: farg7 +type(C_PTR) :: farg8 + +farg1 = arkode_mem +farg2 = c_loc(expsteps(1)) +farg3 = c_loc(accsteps(1)) +farg4 = c_loc(step_attempts(1)) +farg5 = c_loc(nfe_evals(1)) +farg6 = c_loc(nfi_evals(1)) +farg7 = c_loc(nlinsetups(1)) +farg8 = c_loc(netfails(1)) +fresult = swigc_FARKStepGetTimestepperStats(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8) +swig_result = fresult +end function + +function FARKStepGetStepStats(arkode_mem, nsteps, hinused, hlast, hcur, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsteps +real(C_DOUBLE), dimension(*), target, intent(inout) :: hinused +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +real(C_DOUBLE), dimension(*), target, intent(inout) :: hcur +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = arkode_mem +farg2 = c_loc(nsteps(1)) +farg3 = c_loc(hinused(1)) +farg4 = c_loc(hlast(1)) +farg5 = c_loc(hcur(1)) +farg6 = c_loc(tcur(1)) +fresult = swigc_FARKStepGetStepStats(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FARKStepGetNumNonlinSolvIters(arkode_mem, nniters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nniters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nniters(1)) +fresult = swigc_FARKStepGetNumNonlinSolvIters(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumNonlinSolvConvFails(arkode_mem, nncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nncfails(1)) +fresult = swigc_FARKStepGetNumNonlinSolvConvFails(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNonlinSolvStats(arkode_mem, nniters, nncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nniters +integer(C_LONG), dimension(*), target, intent(inout) :: nncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = c_loc(nniters(1)) +farg3 = c_loc(nncfails(1)) +fresult = swigc_FARKStepGetNonlinSolvStats(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepGetLinWorkSpace(arkode_mem, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FARKStepGetLinWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepGetNumJacEvals(arkode_mem, njevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(njevals(1)) +fresult = swigc_FARKStepGetNumJacEvals(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumPrecEvals(arkode_mem, npevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: npevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(npevals(1)) +fresult = swigc_FARKStepGetNumPrecEvals(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumPrecSolves(arkode_mem, npsolves) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: npsolves +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(npsolves(1)) +fresult = swigc_FARKStepGetNumPrecSolves(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumLinIters(arkode_mem, nliters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nliters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nliters(1)) +fresult = swigc_FARKStepGetNumLinIters(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumLinConvFails(arkode_mem, nlcfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nlcfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nlcfails(1)) +fresult = swigc_FARKStepGetNumLinConvFails(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumJTSetupEvals(arkode_mem, njtsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njtsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(njtsetups(1)) +fresult = swigc_FARKStepGetNumJTSetupEvals(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumJtimesEvals(arkode_mem, njvevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njvevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(njvevals(1)) +fresult = swigc_FARKStepGetNumJtimesEvals(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumLinRhsEvals(arkode_mem, nfevalsls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevalsls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nfevalsls(1)) +fresult = swigc_FARKStepGetNumLinRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetLastLinFlag(arkode_mem, flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: flag +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(flag(1)) +fresult = swigc_FARKStepGetLastLinFlag(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetMassWorkSpace(arkode_mem, lenrwmls, leniwmls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwmls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwmls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = c_loc(lenrwmls(1)) +farg3 = c_loc(leniwmls(1)) +fresult = swigc_FARKStepGetMassWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKStepGetNumMassSetups(arkode_mem, nmsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nmsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nmsetups(1)) +fresult = swigc_FARKStepGetNumMassSetups(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumMassMultSetups(arkode_mem, nmvsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nmvsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nmvsetups(1)) +fresult = swigc_FARKStepGetNumMassMultSetups(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumMassMult(arkode_mem, nmvevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nmvevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nmvevals(1)) +fresult = swigc_FARKStepGetNumMassMult(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumMassSolves(arkode_mem, nmsolves) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nmsolves +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nmsolves(1)) +fresult = swigc_FARKStepGetNumMassSolves(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumMassPrecEvals(arkode_mem, nmpevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nmpevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nmpevals(1)) +fresult = swigc_FARKStepGetNumMassPrecEvals(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumMassPrecSolves(arkode_mem, nmpsolves) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nmpsolves +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nmpsolves(1)) +fresult = swigc_FARKStepGetNumMassPrecSolves(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumMassIters(arkode_mem, nmiters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nmiters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nmiters(1)) +fresult = swigc_FARKStepGetNumMassIters(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumMassConvFails(arkode_mem, nmcfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nmcfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nmcfails(1)) +fresult = swigc_FARKStepGetNumMassConvFails(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetNumMTSetups(arkode_mem, nmtsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nmtsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nmtsetups(1)) +fresult = swigc_FARKStepGetNumMTSetups(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetLastMassFlag(arkode_mem, flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: flag +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(flag(1)) +fresult = swigc_FARKStepGetLastMassFlag(farg1, farg2) +swig_result = fresult +end function + +function FARKStepGetLinReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FARKStepGetLinReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +subroutine FARKStepFree(arkode_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), target, intent(inout) :: arkode_mem +type(C_PTR) :: farg1 + +farg1 = c_loc(arkode_mem) +call swigc_FARKStepFree(farg1) +end subroutine + +subroutine FARKStepPrintMem(arkode_mem, outfile) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: arkode_mem +type(C_PTR) :: outfile +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = outfile +call swigc_FARKStepPrintMem(farg1, farg2) +end subroutine + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_erkstep_mod.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_erkstep_mod.c new file mode 100644 index 000000000..a9b073685 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_erkstep_mod.c @@ -0,0 +1,1263 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "arkode/arkode_erkstep.h" + + +#include +#ifdef _MSC_VER +# ifndef strtoull +# define strtoull _strtoui64 +# endif +# ifndef strtoll +# define strtoll _strtoi64 +# endif +#endif + + +typedef struct { + void* data; + size_t size; +} SwigArrayWrapper; + + +SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() { + SwigArrayWrapper result; + result.data = NULL; + result.size = 0; + return result; +} + + +#include + +SWIGEXPORT void * _wrap_FERKStepCreate(ARKRhsFn farg1, double const *farg2, N_Vector farg3) { + void * fresult ; + ARKRhsFn arg1 = (ARKRhsFn) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + void *result = 0 ; + + arg1 = (ARKRhsFn)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + result = (void *)ERKStepCreate(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepResize(void *farg1, N_Vector farg2, double const *farg3, double const *farg4, ARKVecResizeFn farg5, void *farg6) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype arg3 ; + realtype arg4 ; + ARKVecResizeFn arg5 = (ARKVecResizeFn) 0 ; + void *arg6 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (realtype)(*farg4); + arg5 = (ARKVecResizeFn)(farg5); + arg6 = (void *)(farg6); + result = (int)ERKStepResize(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepReInit(void *farg1, ARKRhsFn farg2, double const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKRhsFn arg2 = (ARKRhsFn) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKRhsFn)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)ERKStepReInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSStolerances(void *farg1, double const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)ERKStepSStolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSVtolerances(void *farg1, double const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)ERKStepSVtolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepWFtolerances(void *farg1, ARKEwtFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKEwtFn arg2 = (ARKEwtFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKEwtFn)(farg2); + result = (int)ERKStepWFtolerances(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepRootInit(void *farg1, int const *farg2, ARKRootFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + ARKRootFn arg3 = (ARKRootFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (ARKRootFn)(farg3); + result = (int)ERKStepRootInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetDefaults(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)ERKStepSetDefaults(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetOrder(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ERKStepSetOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetInterpolantType(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ERKStepSetInterpolantType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetInterpolantDegree(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ERKStepSetInterpolantDegree(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetDenseOrder(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ERKStepSetDenseOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetTable(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKodeButcherTable arg2 = (ARKodeButcherTable) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKodeButcherTable)(farg2); + result = (int)ERKStepSetTable(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetTableNum(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ERKStepSetTableNum(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetCFLFraction(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ERKStepSetCFLFraction(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetSafetyFactor(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ERKStepSetSafetyFactor(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetErrorBias(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ERKStepSetErrorBias(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetMaxGrowth(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ERKStepSetMaxGrowth(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetFixedStepBounds(void *farg1, double const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)ERKStepSetFixedStepBounds(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetAdaptivityMethod(void *farg1, int const *farg2, int const *farg3, int const *farg4, double *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + int arg4 ; + realtype *arg5 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + arg4 = (int)(*farg4); + arg5 = (double *)(farg5); + result = (int)ERKStepSetAdaptivityMethod(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetAdaptivityFn(void *farg1, ARKAdaptFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKAdaptFn arg2 = (ARKAdaptFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKAdaptFn)(farg2); + arg3 = (void *)(farg3); + result = (int)ERKStepSetAdaptivityFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetMaxFirstGrowth(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ERKStepSetMaxFirstGrowth(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetMaxEFailGrowth(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ERKStepSetMaxEFailGrowth(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetSmallNumEFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ERKStepSetSmallNumEFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetStabilityFn(void *farg1, ARKExpStabFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKExpStabFn arg2 = (ARKExpStabFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKExpStabFn)(farg2); + arg3 = (void *)(farg3); + result = (int)ERKStepSetStabilityFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetMaxErrTestFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ERKStepSetMaxErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetConstraints(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)ERKStepSetConstraints(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetMaxNumSteps(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)ERKStepSetMaxNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetMaxHnilWarns(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ERKStepSetMaxHnilWarns(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetInitStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ERKStepSetInitStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetMinStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ERKStepSetMinStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetMaxStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ERKStepSetMaxStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetStopTime(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ERKStepSetStopTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetFixedStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)ERKStepSetFixedStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetMaxNumConstrFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)ERKStepSetMaxNumConstrFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetRootDirection(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)ERKStepSetRootDirection(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetNoInactiveRootWarn(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)ERKStepSetNoInactiveRootWarn(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetErrHandlerFn(void *farg1, ARKErrHandlerFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKErrHandlerFn arg2 = (ARKErrHandlerFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKErrHandlerFn)(farg2); + arg3 = (void *)(farg3); + result = (int)ERKStepSetErrHandlerFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetErrFile(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)ERKStepSetErrFile(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetUserData(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + void *arg2 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (void *)(farg2); + result = (int)ERKStepSetUserData(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetDiagnostics(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)ERKStepSetDiagnostics(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetPostprocessStepFn(void *farg1, ARKPostProcessFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKPostProcessFn arg2 = (ARKPostProcessFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKPostProcessFn)(farg2); + result = (int)ERKStepSetPostprocessStepFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepSetPostprocessStageFn(void *farg1, ARKPostProcessFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKPostProcessFn arg2 = (ARKPostProcessFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKPostProcessFn)(farg2); + result = (int)ERKStepSetPostprocessStageFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepEvolve(void *farg1, double const *farg2, N_Vector farg3, double *farg4, int const *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype *arg4 = (realtype *) 0 ; + int arg5 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + arg4 = (realtype *)(farg4); + arg5 = (int)(*farg5); + result = (int)ERKStepEvolve(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetDky(void *farg1, double const *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)ERKStepGetDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetNumExpSteps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ERKStepGetNumExpSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetNumAccSteps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ERKStepGetNumAccSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetNumStepAttempts(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ERKStepGetNumStepAttempts(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ERKStepGetNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetNumErrTestFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ERKStepGetNumErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetCurrentButcherTable(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKodeButcherTable *arg2 = (ARKodeButcherTable *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKodeButcherTable *)(farg2); + result = (int)ERKStepGetCurrentButcherTable(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetEstLocalErrors(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)ERKStepGetEstLocalErrors(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)ERKStepGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetNumSteps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ERKStepGetNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetActualInitStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)ERKStepGetActualInitStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetLastStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)ERKStepGetLastStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetCurrentStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)ERKStepGetCurrentStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetCurrentTime(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)ERKStepGetCurrentTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetTolScaleFactor(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)ERKStepGetTolScaleFactor(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetErrWeights(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)ERKStepGetErrWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetNumGEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ERKStepGetNumGEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetRootInfo(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)ERKStepGetRootInfo(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetNumConstrFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ERKStepGetNumConstrFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FERKStepGetReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)ERKStepGetReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepWriteParameters(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)ERKStepWriteParameters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepWriteButcher(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)ERKStepWriteButcher(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetTimestepperStats(void *farg1, long *farg2, long *farg3, long *farg4, long *farg5, long *farg6) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + long *arg4 = (long *) 0 ; + long *arg5 = (long *) 0 ; + long *arg6 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + arg4 = (long *)(farg4); + arg5 = (long *)(farg5); + arg6 = (long *)(farg6); + result = (int)ERKStepGetTimestepperStats(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FERKStepGetStepStats(void *farg1, long *farg2, double *farg3, double *farg4, double *farg5, double *farg6) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + realtype *arg3 = (realtype *) 0 ; + realtype *arg4 = (realtype *) 0 ; + realtype *arg5 = (realtype *) 0 ; + realtype *arg6 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (realtype *)(farg3); + arg4 = (realtype *)(farg4); + arg5 = (realtype *)(farg5); + arg6 = (realtype *)(farg6); + result = (int)ERKStepGetStepStats(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FERKStepFree(void *farg1) { + void **arg1 = (void **) 0 ; + + arg1 = (void **)(farg1); + ERKStepFree(arg1); +} + + +SWIGEXPORT void _wrap_FERKStepPrintMem(void *farg1, void *farg2) { + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + ERKStepPrintMem(arg1,arg2); +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_erkstep_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_erkstep_mod.f90 new file mode 100644 index 000000000..a48ad53b3 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_erkstep_mod.f90 @@ -0,0 +1,1995 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module farkode_erkstep_mod + use, intrinsic :: ISO_C_BINDING + use farkode_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_linearsolver_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_nonlinearsolver_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: DEFAULT_ERK_2 = 0_C_INT + integer(C_INT), parameter, public :: DEFAULT_ERK_3 = 1_C_INT + integer(C_INT), parameter, public :: DEFAULT_ERK_4 = 3_C_INT + integer(C_INT), parameter, public :: DEFAULT_ERK_5 = 6_C_INT + integer(C_INT), parameter, public :: DEFAULT_ERK_6 = 10_C_INT + integer(C_INT), parameter, public :: DEFAULT_ERK_8 = 11_C_INT + public :: FERKStepCreate + public :: FERKStepResize + public :: FERKStepReInit + public :: FERKStepSStolerances + public :: FERKStepSVtolerances + public :: FERKStepWFtolerances + public :: FERKStepRootInit + public :: FERKStepSetDefaults + public :: FERKStepSetOrder + public :: FERKStepSetInterpolantType + public :: FERKStepSetInterpolantDegree + public :: FERKStepSetDenseOrder + public :: FERKStepSetTable + public :: FERKStepSetTableNum + public :: FERKStepSetCFLFraction + public :: FERKStepSetSafetyFactor + public :: FERKStepSetErrorBias + public :: FERKStepSetMaxGrowth + public :: FERKStepSetFixedStepBounds + public :: FERKStepSetAdaptivityMethod + public :: FERKStepSetAdaptivityFn + public :: FERKStepSetMaxFirstGrowth + public :: FERKStepSetMaxEFailGrowth + public :: FERKStepSetSmallNumEFails + public :: FERKStepSetStabilityFn + public :: FERKStepSetMaxErrTestFails + public :: FERKStepSetConstraints + public :: FERKStepSetMaxNumSteps + public :: FERKStepSetMaxHnilWarns + public :: FERKStepSetInitStep + public :: FERKStepSetMinStep + public :: FERKStepSetMaxStep + public :: FERKStepSetStopTime + public :: FERKStepSetFixedStep + public :: FERKStepSetMaxNumConstrFails + public :: FERKStepSetRootDirection + public :: FERKStepSetNoInactiveRootWarn + public :: FERKStepSetErrHandlerFn + public :: FERKStepSetErrFile + public :: FERKStepSetUserData + public :: FERKStepSetDiagnostics + public :: FERKStepSetPostprocessStepFn + public :: FERKStepSetPostprocessStageFn + public :: FERKStepEvolve + public :: FERKStepGetDky + public :: FERKStepGetNumExpSteps + public :: FERKStepGetNumAccSteps + public :: FERKStepGetNumStepAttempts + public :: FERKStepGetNumRhsEvals + public :: FERKStepGetNumErrTestFails + public :: FERKStepGetCurrentButcherTable + public :: FERKStepGetEstLocalErrors + public :: FERKStepGetWorkSpace + public :: FERKStepGetNumSteps + public :: FERKStepGetActualInitStep + public :: FERKStepGetLastStep + public :: FERKStepGetCurrentStep + public :: FERKStepGetCurrentTime + public :: FERKStepGetTolScaleFactor + public :: FERKStepGetErrWeights + public :: FERKStepGetNumGEvals + public :: FERKStepGetRootInfo + public :: FERKStepGetNumConstrFails + type, bind(C) :: SwigArrayWrapper + type(C_PTR), public :: data = C_NULL_PTR + integer(C_SIZE_T), public :: size = 0 + end type + public :: FERKStepGetReturnFlagName + public :: FERKStepWriteParameters + public :: FERKStepWriteButcher + public :: FERKStepGetTimestepperStats + public :: FERKStepGetStepStats + public :: FERKStepFree + public :: FERKStepPrintMem + +! WRAPPER DECLARATIONS +interface +function swigc_FERKStepCreate(farg1, farg2, farg3) & +bind(C, name="_wrap_FERKStepCreate") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_FUNPTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FERKStepResize(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FERKStepResize") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_FUNPTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepReInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FERKStepReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSStolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FERKStepSStolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSVtolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FERKStepSVtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepWFtolerances(farg1, farg2) & +bind(C, name="_wrap_FERKStepWFtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepRootInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FERKStepRootInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetDefaults(farg1) & +bind(C, name="_wrap_FERKStepSetDefaults") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetOrder(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetInterpolantType(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetInterpolantType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetInterpolantDegree(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetInterpolantDegree") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetDenseOrder(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetDenseOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetTable(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetTable") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetTableNum(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetTableNum") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetCFLFraction(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetCFLFraction") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetSafetyFactor(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetSafetyFactor") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetErrorBias(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetErrorBias") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetMaxGrowth(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetMaxGrowth") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetFixedStepBounds(farg1, farg2, farg3) & +bind(C, name="_wrap_FERKStepSetFixedStepBounds") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetAdaptivityMethod(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FERKStepSetAdaptivityMethod") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT), intent(in) :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetAdaptivityFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FERKStepSetAdaptivityFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetMaxFirstGrowth(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetMaxFirstGrowth") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetMaxEFailGrowth(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetMaxEFailGrowth") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetSmallNumEFails(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetSmallNumEFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetStabilityFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FERKStepSetStabilityFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetMaxErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetMaxErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetConstraints(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetConstraints") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetMaxNumSteps(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetMaxNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetMaxHnilWarns(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetMaxHnilWarns") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetInitStep(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetInitStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetMinStep(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetMinStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetMaxStep(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetMaxStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetStopTime(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetStopTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetFixedStep(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetFixedStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetMaxNumConstrFails(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetMaxNumConstrFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetRootDirection(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetRootDirection") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetNoInactiveRootWarn(farg1) & +bind(C, name="_wrap_FERKStepSetNoInactiveRootWarn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetErrHandlerFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FERKStepSetErrHandlerFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetErrFile(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetErrFile") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetUserData(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetUserData") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetDiagnostics(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetDiagnostics") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetPostprocessStepFn(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetPostprocessStepFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepSetPostprocessStageFn(farg1, farg2) & +bind(C, name="_wrap_FERKStepSetPostprocessStageFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepEvolve(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FERKStepEvolve") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FERKStepGetDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetNumExpSteps(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetNumExpSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetNumAccSteps(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetNumAccSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetNumStepAttempts(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetNumStepAttempts") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetNumErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetNumErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetCurrentButcherTable(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetCurrentButcherTable") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetEstLocalErrors(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetEstLocalErrors") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FERKStepGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetNumSteps(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetActualInitStep(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetActualInitStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetLastStep(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetLastStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetCurrentStep(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetCurrentStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetCurrentTime(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetCurrentTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetTolScaleFactor(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetTolScaleFactor") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetErrWeights(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetErrWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetNumGEvals(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetNumGEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetRootInfo(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetRootInfo") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetNumConstrFails(farg1, farg2) & +bind(C, name="_wrap_FERKStepGetNumConstrFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + + subroutine SWIG_free(cptr) & + bind(C, name="free") + use, intrinsic :: ISO_C_BINDING + type(C_PTR), value :: cptr +end subroutine +function swigc_FERKStepGetReturnFlagName(farg1) & +bind(C, name="_wrap_FERKStepGetReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +function swigc_FERKStepWriteParameters(farg1, farg2) & +bind(C, name="_wrap_FERKStepWriteParameters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepWriteButcher(farg1, farg2) & +bind(C, name="_wrap_FERKStepWriteButcher") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetTimestepperStats(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FERKStepGetTimestepperStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FERKStepGetStepStats(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FERKStepGetStepStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +subroutine swigc_FERKStepFree(farg1) & +bind(C, name="_wrap_FERKStepFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FERKStepPrintMem(farg1, farg2) & +bind(C, name="_wrap_FERKStepPrintMem") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FERKStepCreate(f, t0, y0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +type(C_FUNPTR), intent(in), value :: f +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: y0 +type(C_PTR) :: fresult +type(C_FUNPTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = f +farg2 = t0 +farg3 = c_loc(y0) +fresult = swigc_FERKStepCreate(farg1, farg2, farg3) +swig_result = fresult +end function + +function FERKStepResize(arkode_mem, ynew, hscale, t0, resize, resize_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(N_Vector), target, intent(inout) :: ynew +real(C_DOUBLE), intent(in) :: hscale +real(C_DOUBLE), intent(in) :: t0 +type(C_FUNPTR), intent(in), value :: resize +type(C_PTR) :: resize_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +real(C_DOUBLE) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_FUNPTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = arkode_mem +farg2 = c_loc(ynew) +farg3 = hscale +farg4 = t0 +farg5 = resize +farg6 = resize_data +fresult = swigc_FERKStepResize(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FERKStepReInit(arkode_mem, f, t0, y0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: f +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: y0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 + +farg1 = arkode_mem +farg2 = f +farg3 = t0 +farg4 = c_loc(y0) +fresult = swigc_FERKStepReInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FERKStepSStolerances(arkode_mem, reltol, abstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: reltol +real(C_DOUBLE), intent(in) :: abstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = arkode_mem +farg2 = reltol +farg3 = abstol +fresult = swigc_FERKStepSStolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FERKStepSVtolerances(arkode_mem, reltol, abstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: reltol +type(N_Vector), target, intent(inout) :: abstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = reltol +farg3 = c_loc(abstol) +fresult = swigc_FERKStepSVtolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FERKStepWFtolerances(arkode_mem, efun) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: efun +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = efun +fresult = swigc_FERKStepWFtolerances(farg1, farg2) +swig_result = fresult +end function + +function FERKStepRootInit(arkode_mem, nrtfn, g) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: nrtfn +type(C_FUNPTR), intent(in), value :: g +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = arkode_mem +farg2 = nrtfn +farg3 = g +fresult = swigc_FERKStepRootInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FERKStepSetDefaults(arkode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = arkode_mem +fresult = swigc_FERKStepSetDefaults(farg1) +swig_result = fresult +end function + +function FERKStepSetOrder(arkode_mem, maxord) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: maxord +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = maxord +fresult = swigc_FERKStepSetOrder(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetInterpolantType(arkode_mem, itype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: itype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = itype +fresult = swigc_FERKStepSetInterpolantType(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetInterpolantDegree(arkode_mem, degree) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: degree +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = degree +fresult = swigc_FERKStepSetInterpolantDegree(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetDenseOrder(arkode_mem, dord) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: dord +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = dord +fresult = swigc_FERKStepSetDenseOrder(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetTable(arkode_mem, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: b +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = b +fresult = swigc_FERKStepSetTable(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetTableNum(arkode_mem, itable) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: itable +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = itable +fresult = swigc_FERKStepSetTableNum(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetCFLFraction(arkode_mem, cfl_frac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: cfl_frac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = cfl_frac +fresult = swigc_FERKStepSetCFLFraction(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetSafetyFactor(arkode_mem, safety) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: safety +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = safety +fresult = swigc_FERKStepSetSafetyFactor(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetErrorBias(arkode_mem, bias) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: bias +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = bias +fresult = swigc_FERKStepSetErrorBias(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetMaxGrowth(arkode_mem, mx_growth) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: mx_growth +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = mx_growth +fresult = swigc_FERKStepSetMaxGrowth(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetFixedStepBounds(arkode_mem, lb, ub) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: lb +real(C_DOUBLE), intent(in) :: ub +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = arkode_mem +farg2 = lb +farg3 = ub +fresult = swigc_FERKStepSetFixedStepBounds(farg1, farg2, farg3) +swig_result = fresult +end function + +function FERKStepSetAdaptivityMethod(arkode_mem, imethod, idefault, pq, adapt_params) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: imethod +integer(C_INT), intent(in) :: idefault +integer(C_INT), intent(in) :: pq +real(C_DOUBLE), dimension(3), target, intent(inout) :: adapt_params +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 +integer(C_INT) :: farg4 +type(C_PTR) :: farg5 + +farg1 = arkode_mem +farg2 = imethod +farg3 = idefault +farg4 = pq +farg5 = c_loc(adapt_params(1)) +fresult = swigc_FERKStepSetAdaptivityMethod(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FERKStepSetAdaptivityFn(arkode_mem, hfun, h_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: hfun +type(C_PTR) :: h_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = hfun +farg3 = h_data +fresult = swigc_FERKStepSetAdaptivityFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FERKStepSetMaxFirstGrowth(arkode_mem, etamx1) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: etamx1 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = etamx1 +fresult = swigc_FERKStepSetMaxFirstGrowth(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetMaxEFailGrowth(arkode_mem, etamxf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: etamxf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = etamxf +fresult = swigc_FERKStepSetMaxEFailGrowth(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetSmallNumEFails(arkode_mem, small_nef) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: small_nef +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = small_nef +fresult = swigc_FERKStepSetSmallNumEFails(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetStabilityFn(arkode_mem, estab, estab_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: estab +type(C_PTR) :: estab_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = estab +farg3 = estab_data +fresult = swigc_FERKStepSetStabilityFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FERKStepSetMaxErrTestFails(arkode_mem, maxnef) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: maxnef +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = maxnef +fresult = swigc_FERKStepSetMaxErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetConstraints(arkode_mem, constraints) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(N_Vector), target, intent(inout) :: constraints +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(constraints) +fresult = swigc_FERKStepSetConstraints(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetMaxNumSteps(arkode_mem, mxsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), intent(in) :: mxsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = arkode_mem +farg2 = mxsteps +fresult = swigc_FERKStepSetMaxNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetMaxHnilWarns(arkode_mem, mxhnil) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: mxhnil +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = mxhnil +fresult = swigc_FERKStepSetMaxHnilWarns(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetInitStep(arkode_mem, hin) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: hin +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = hin +fresult = swigc_FERKStepSetInitStep(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetMinStep(arkode_mem, hmin) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: hmin +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = hmin +fresult = swigc_FERKStepSetMinStep(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetMaxStep(arkode_mem, hmax) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: hmax +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = hmax +fresult = swigc_FERKStepSetMaxStep(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetStopTime(arkode_mem, tstop) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: tstop +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = tstop +fresult = swigc_FERKStepSetStopTime(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetFixedStep(arkode_mem, hfixed) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: hfixed +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = hfixed +fresult = swigc_FERKStepSetFixedStep(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetMaxNumConstrFails(arkode_mem, maxfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: maxfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = maxfails +fresult = swigc_FERKStepSetMaxNumConstrFails(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetRootDirection(arkode_mem, rootdir) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootdir +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(rootdir(1)) +fresult = swigc_FERKStepSetRootDirection(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetNoInactiveRootWarn(arkode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = arkode_mem +fresult = swigc_FERKStepSetNoInactiveRootWarn(farg1) +swig_result = fresult +end function + +function FERKStepSetErrHandlerFn(arkode_mem, ehfun, eh_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: ehfun +type(C_PTR) :: eh_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = ehfun +farg3 = eh_data +fresult = swigc_FERKStepSetErrHandlerFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FERKStepSetErrFile(arkode_mem, errfp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: errfp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = errfp +fresult = swigc_FERKStepSetErrFile(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetUserData(arkode_mem, user_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: user_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = user_data +fresult = swigc_FERKStepSetUserData(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetDiagnostics(arkode_mem, diagfp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: diagfp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = diagfp +fresult = swigc_FERKStepSetDiagnostics(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetPostprocessStepFn(arkode_mem, processstep) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: processstep +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = processstep +fresult = swigc_FERKStepSetPostprocessStepFn(farg1, farg2) +swig_result = fresult +end function + +function FERKStepSetPostprocessStageFn(arkode_mem, processstage) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: processstage +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = processstage +fresult = swigc_FERKStepSetPostprocessStageFn(farg1, farg2) +swig_result = fresult +end function + +function FERKStepEvolve(arkode_mem, tout, yout, tret, itask) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: tout +type(N_Vector), target, intent(inout) :: yout +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +integer(C_INT), intent(in) :: itask +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +integer(C_INT) :: farg5 + +farg1 = arkode_mem +farg2 = tout +farg3 = c_loc(yout) +farg4 = c_loc(tret(1)) +farg5 = itask +fresult = swigc_FERKStepEvolve(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FERKStepGetDky(arkode_mem, t, k, dky) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(N_Vector), target, intent(inout) :: dky +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = arkode_mem +farg2 = t +farg3 = k +farg4 = c_loc(dky) +fresult = swigc_FERKStepGetDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FERKStepGetNumExpSteps(arkode_mem, expsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: expsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(expsteps(1)) +fresult = swigc_FERKStepGetNumExpSteps(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetNumAccSteps(arkode_mem, accsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: accsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(accsteps(1)) +fresult = swigc_FERKStepGetNumAccSteps(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetNumStepAttempts(arkode_mem, step_attempts) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: step_attempts +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(step_attempts(1)) +fresult = swigc_FERKStepGetNumStepAttempts(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetNumRhsEvals(arkode_mem, nfevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nfevals(1)) +fresult = swigc_FERKStepGetNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetNumErrTestFails(arkode_mem, netfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: netfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(netfails(1)) +fresult = swigc_FERKStepGetNumErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetCurrentButcherTable(arkode_mem, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR), target, intent(inout) :: b +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(b) +fresult = swigc_FERKStepGetCurrentButcherTable(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetEstLocalErrors(arkode_mem, ele) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(N_Vector), target, intent(inout) :: ele +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(ele) +fresult = swigc_FERKStepGetEstLocalErrors(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetWorkSpace(arkode_mem, lenrw, leniw) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrw +integer(C_LONG), dimension(*), target, intent(inout) :: leniw +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = c_loc(lenrw(1)) +farg3 = c_loc(leniw(1)) +fresult = swigc_FERKStepGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FERKStepGetNumSteps(arkode_mem, nsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nsteps(1)) +fresult = swigc_FERKStepGetNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetActualInitStep(arkode_mem, hinused) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hinused +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(hinused(1)) +fresult = swigc_FERKStepGetActualInitStep(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetLastStep(arkode_mem, hlast) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(hlast(1)) +fresult = swigc_FERKStepGetLastStep(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetCurrentStep(arkode_mem, hcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(hcur(1)) +fresult = swigc_FERKStepGetCurrentStep(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetCurrentTime(arkode_mem, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(tcur(1)) +fresult = swigc_FERKStepGetCurrentTime(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetTolScaleFactor(arkode_mem, tolsfac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tolsfac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(tolsfac(1)) +fresult = swigc_FERKStepGetTolScaleFactor(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetErrWeights(arkode_mem, eweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(N_Vector), target, intent(inout) :: eweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(eweight) +fresult = swigc_FERKStepGetErrWeights(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetNumGEvals(arkode_mem, ngevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(ngevals(1)) +fresult = swigc_FERKStepGetNumGEvals(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetRootInfo(arkode_mem, rootsfound) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootsfound +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(rootsfound(1)) +fresult = swigc_FERKStepGetRootInfo(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetNumConstrFails(arkode_mem, nconstrfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nconstrfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nconstrfails(1)) +fresult = swigc_FERKStepGetNumConstrFails(farg1, farg2) +swig_result = fresult +end function + + +subroutine SWIG_chararray_to_string(wrap, string) + use, intrinsic :: ISO_C_BINDING + type(SwigArrayWrapper), intent(IN) :: wrap + character(kind=C_CHAR, len=:), allocatable, intent(OUT) :: string + character(kind=C_CHAR), dimension(:), pointer :: chars + integer(kind=C_SIZE_T) :: i + call c_f_pointer(wrap%data, chars, [wrap%size]) + allocate(character(kind=C_CHAR, len=wrap%size) :: string) + do i=1, wrap%size + string(i:i) = chars(i) + end do +end subroutine + +function FERKStepGetReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FERKStepGetReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +function FERKStepWriteParameters(arkode_mem, fp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: fp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = fp +fresult = swigc_FERKStepWriteParameters(farg1, farg2) +swig_result = fresult +end function + +function FERKStepWriteButcher(arkode_mem, fp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: fp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = fp +fresult = swigc_FERKStepWriteButcher(farg1, farg2) +swig_result = fresult +end function + +function FERKStepGetTimestepperStats(arkode_mem, expsteps, accsteps, step_attempts, nfevals, netfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: expsteps +integer(C_LONG), dimension(*), target, intent(inout) :: accsteps +integer(C_LONG), dimension(*), target, intent(inout) :: step_attempts +integer(C_LONG), dimension(*), target, intent(inout) :: nfevals +integer(C_LONG), dimension(*), target, intent(inout) :: netfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = arkode_mem +farg2 = c_loc(expsteps(1)) +farg3 = c_loc(accsteps(1)) +farg4 = c_loc(step_attempts(1)) +farg5 = c_loc(nfevals(1)) +farg6 = c_loc(netfails(1)) +fresult = swigc_FERKStepGetTimestepperStats(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FERKStepGetStepStats(arkode_mem, nsteps, hinused, hlast, hcur, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsteps +real(C_DOUBLE), dimension(*), target, intent(inout) :: hinused +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +real(C_DOUBLE), dimension(*), target, intent(inout) :: hcur +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = arkode_mem +farg2 = c_loc(nsteps(1)) +farg3 = c_loc(hinused(1)) +farg4 = c_loc(hlast(1)) +farg5 = c_loc(hcur(1)) +farg6 = c_loc(tcur(1)) +fresult = swigc_FERKStepGetStepStats(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +subroutine FERKStepFree(arkode_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), target, intent(inout) :: arkode_mem +type(C_PTR) :: farg1 + +farg1 = c_loc(arkode_mem) +call swigc_FERKStepFree(farg1) +end subroutine + +subroutine FERKStepPrintMem(arkode_mem, outfile) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: arkode_mem +type(C_PTR) :: outfile +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = outfile +call swigc_FERKStepPrintMem(farg1, farg2) +end subroutine + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_mod.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_mod.c new file mode 100644 index 000000000..72b9acd79 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_mod.c @@ -0,0 +1,768 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +enum { + SWIG_MEM_OWN = 0x01, + SWIG_MEM_RVALUE = 0x02, + SWIG_MEM_CONST = 0x04 +}; + + +#define SWIG_check_mutable(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL) \ + if ((SWIG_CLASS_WRAPPER).cmemflags & SWIG_MEM_CONST) { \ + SWIG_exception_impl(FUNCNAME, SWIG_TypeError, \ + "Cannot pass const " TYPENAME " (class " FNAME ") " \ + "as a mutable reference", \ + RETURNNULL); \ + } + + +#define SWIG_check_nonnull(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL) \ + if (!(SWIG_CLASS_WRAPPER).cptr) { \ + SWIG_exception_impl(FUNCNAME, SWIG_TypeError, \ + "Cannot pass null " TYPENAME " (class " FNAME ") " \ + "as a reference", RETURNNULL); \ + } + + +#define SWIG_check_mutable_nonnull(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL) \ + SWIG_check_nonnull(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL); \ + SWIG_check_mutable(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL); + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "arkode/arkode.h" +#include "arkode/arkode_bandpre.h" +#include "arkode/arkode_bbdpre.h" +#include "arkode/arkode_butcher.h" +#include "arkode/arkode_butcher_dirk.h" +#include "arkode/arkode_butcher_erk.h" +#include "arkode/arkode_ls.h" + + +typedef struct { + void* cptr; + int cmemflags; +} SwigClassWrapper; + + +SWIGINTERN SwigClassWrapper SwigClassWrapper_uninitialized() { + SwigClassWrapper result; + result.cptr = NULL; + result.cmemflags = 0; + return result; +} + + +#include +#ifdef _MSC_VER +# ifndef strtoull +# define strtoull _strtoui64 +# endif +# ifndef strtoll +# define strtoll _strtoi64 +# endif +#endif + + +#include + + +SWIGINTERN void SWIG_assign(SwigClassWrapper* self, SwigClassWrapper other) { + if (self->cptr == NULL) { + /* LHS is unassigned */ + if (other.cmemflags & SWIG_MEM_RVALUE) { + /* Capture pointer from RHS, clear 'moving' flag */ + self->cptr = other.cptr; + self->cmemflags = other.cmemflags & (~SWIG_MEM_RVALUE); + } else { + /* Become a reference to the other object */ + self->cptr = other.cptr; + self->cmemflags = other.cmemflags & (~SWIG_MEM_OWN); + } + } else if (other.cptr == NULL) { + /* Replace LHS with a null pointer */ + free(self->cptr); + *self = SwigClassWrapper_uninitialized(); + } else { + if (self->cmemflags & SWIG_MEM_OWN) { + free(self->cptr); + } + self->cptr = other.cptr; + if (other.cmemflags & SWIG_MEM_RVALUE) { + /* Capture RHS */ + self->cmemflags = other.cmemflags & ~SWIG_MEM_RVALUE; + } else { + /* Point to RHS */ + self->cmemflags = other.cmemflags & ~SWIG_MEM_OWN; + } + } +} + +SWIGEXPORT int _wrap_FARKBandPrecInit(void *farg1, int64_t const *farg2, int64_t const *farg3, int64_t const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + result = (int)ARKBandPrecInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKBandPrecGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)ARKBandPrecGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKBandPrecGetNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKBandPrecGetNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKBBDPrecInit(void *farg1, int64_t const *farg2, int64_t const *farg3, int64_t const *farg4, int64_t const *farg5, int64_t const *farg6, double const *farg7, ARKLocalFn farg8, ARKCommFn farg9) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + sunindextype arg5 ; + sunindextype arg6 ; + realtype arg7 ; + ARKLocalFn arg8 = (ARKLocalFn) 0 ; + ARKCommFn arg9 = (ARKCommFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + arg5 = (sunindextype)(*farg5); + arg6 = (sunindextype)(*farg6); + arg7 = (realtype)(*farg7); + arg8 = (ARKLocalFn)(farg8); + arg9 = (ARKCommFn)(farg9); + result = (int)ARKBBDPrecInit(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKBBDPrecReInit(void *farg1, int64_t const *farg2, int64_t const *farg3, double const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + realtype arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (realtype)(*farg4); + result = (int)ARKBBDPrecReInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKBBDPrecGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)ARKBBDPrecGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKBBDPrecGetNumGfnEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)ARKBBDPrecGetNumGfnEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_ARKodeButcherTableMem_q_set(SwigClassWrapper const *farg1, int const *farg2) { + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + int arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::q", return ); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + arg2 = (int)(*farg2); + if (arg1) (arg1)->q = arg2; +} + + +SWIGEXPORT int _wrap_ARKodeButcherTableMem_q_get(SwigClassWrapper const *farg1) { + int fresult ; + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + int result; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::q", return 0); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + result = (int) ((arg1)->q); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_ARKodeButcherTableMem_p_set(SwigClassWrapper const *farg1, int const *farg2) { + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + int arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::p", return ); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + arg2 = (int)(*farg2); + if (arg1) (arg1)->p = arg2; +} + + +SWIGEXPORT int _wrap_ARKodeButcherTableMem_p_get(SwigClassWrapper const *farg1) { + int fresult ; + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + int result; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::p", return 0); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + result = (int) ((arg1)->p); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_ARKodeButcherTableMem_stages_set(SwigClassWrapper const *farg1, int const *farg2) { + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + int arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::stages", return ); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + arg2 = (int)(*farg2); + if (arg1) (arg1)->stages = arg2; +} + + +SWIGEXPORT int _wrap_ARKodeButcherTableMem_stages_get(SwigClassWrapper const *farg1) { + int fresult ; + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + int result; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::stages", return 0); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + result = (int) ((arg1)->stages); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_ARKodeButcherTableMem_A_set(SwigClassWrapper const *farg1, void *farg2) { + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + realtype **arg2 = (realtype **) 0 ; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::A", return ); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + arg2 = (realtype **)(farg2); + if (arg1) (arg1)->A = arg2; +} + + +SWIGEXPORT void * _wrap_ARKodeButcherTableMem_A_get(SwigClassWrapper const *farg1) { + void * fresult ; + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + realtype **result = 0 ; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::A", return 0); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + result = (realtype **) ((arg1)->A); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_ARKodeButcherTableMem_c_set(SwigClassWrapper const *farg1, double *farg2) { + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + realtype *arg2 = (realtype *) 0 ; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::c", return ); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + arg2 = (realtype *)(farg2); + if (arg1) (arg1)->c = arg2; +} + + +SWIGEXPORT double * _wrap_ARKodeButcherTableMem_c_get(SwigClassWrapper const *farg1) { + double * fresult ; + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + realtype *result = 0 ; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::c", return 0); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + result = (realtype *) ((arg1)->c); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_ARKodeButcherTableMem_b_set(SwigClassWrapper const *farg1, double *farg2) { + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + realtype *arg2 = (realtype *) 0 ; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::b", return ); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + arg2 = (realtype *)(farg2); + if (arg1) (arg1)->b = arg2; +} + + +SWIGEXPORT double * _wrap_ARKodeButcherTableMem_b_get(SwigClassWrapper const *farg1) { + double * fresult ; + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + realtype *result = 0 ; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::b", return 0); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + result = (realtype *) ((arg1)->b); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_ARKodeButcherTableMem_d_set(SwigClassWrapper const *farg1, double *farg2) { + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + realtype *arg2 = (realtype *) 0 ; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::d", return ); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + arg2 = (realtype *)(farg2); + if (arg1) (arg1)->d = arg2; +} + + +SWIGEXPORT double * _wrap_ARKodeButcherTableMem_d_get(SwigClassWrapper const *farg1) { + double * fresult ; + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + realtype *result = 0 ; + + SWIG_check_mutable_nonnull(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::d", return 0); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + result = (realtype *) ((arg1)->d); + fresult = result; + return fresult; +} + + +SWIGEXPORT SwigClassWrapper _wrap_new_ARKodeButcherTableMem() { + SwigClassWrapper fresult ; + struct ARKodeButcherTableMem *result = 0 ; + + result = (struct ARKodeButcherTableMem *)calloc(1, sizeof(struct ARKodeButcherTableMem)); + fresult.cptr = result; + fresult.cmemflags = SWIG_MEM_RVALUE | (1 ? SWIG_MEM_OWN : 0); + return fresult; +} + + +SWIGEXPORT void _wrap_delete_ARKodeButcherTableMem(SwigClassWrapper *farg1) { + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + + SWIG_check_mutable(*farg1, "struct ARKodeButcherTableMem *", "ARKodeButcherTableMem", "ARKodeButcherTableMem::~ARKodeButcherTableMem()", return ); + arg1 = (struct ARKodeButcherTableMem *)(farg1->cptr); + free((char *) arg1); +} + + +SWIGEXPORT void _wrap_ARKodeButcherTableMem_op_assign__(SwigClassWrapper *farg1, SwigClassWrapper const *farg2) { + struct ARKodeButcherTableMem *arg1 = (struct ARKodeButcherTableMem *) 0 ; + struct ARKodeButcherTableMem *arg2 = 0 ; + + (void)sizeof(arg1); + (void)sizeof(arg2); + SWIG_assign(farg1, *farg2); + +} + + +SWIGEXPORT void * _wrap_FARKodeButcherTable_Alloc(int const *farg1, int const *farg2) { + void * fresult ; + int arg1 ; + int arg2 ; + ARKodeButcherTable result; + + arg1 = (int)(*farg1); + arg2 = (int)(*farg2); + result = (ARKodeButcherTable)ARKodeButcherTable_Alloc(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FARKodeButcherTable_Create(int const *farg1, int const *farg2, int const *farg3, double *farg4, double *farg5, double *farg6, double *farg7) { + void * fresult ; + int arg1 ; + int arg2 ; + int arg3 ; + realtype *arg4 = (realtype *) 0 ; + realtype *arg5 = (realtype *) 0 ; + realtype *arg6 = (realtype *) 0 ; + realtype *arg7 = (realtype *) 0 ; + ARKodeButcherTable result; + + arg1 = (int)(*farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + arg4 = (realtype *)(farg4); + arg5 = (realtype *)(farg5); + arg6 = (realtype *)(farg6); + arg7 = (realtype *)(farg7); + result = (ARKodeButcherTable)ARKodeButcherTable_Create(arg1,arg2,arg3,arg4,arg5,arg6,arg7); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FARKodeButcherTable_Copy(void *farg1) { + void * fresult ; + ARKodeButcherTable arg1 = (ARKodeButcherTable) 0 ; + ARKodeButcherTable result; + + arg1 = (ARKodeButcherTable)(farg1); + result = (ARKodeButcherTable)ARKodeButcherTable_Copy(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FARKodeButcherTable_Space(void *farg1, int64_t *farg2, int64_t *farg3) { + ARKodeButcherTable arg1 = (ARKodeButcherTable) 0 ; + sunindextype *arg2 = (sunindextype *) 0 ; + sunindextype *arg3 = (sunindextype *) 0 ; + + arg1 = (ARKodeButcherTable)(farg1); + arg2 = (sunindextype *)(farg2); + arg3 = (sunindextype *)(farg3); + ARKodeButcherTable_Space(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FARKodeButcherTable_Free(void *farg1) { + ARKodeButcherTable arg1 = (ARKodeButcherTable) 0 ; + + arg1 = (ARKodeButcherTable)(farg1); + ARKodeButcherTable_Free(arg1); +} + + +SWIGEXPORT void _wrap_FARKodeButcherTable_Write(void *farg1, void *farg2) { + ARKodeButcherTable arg1 = (ARKodeButcherTable) 0 ; + FILE *arg2 = (FILE *) 0 ; + + arg1 = (ARKodeButcherTable)(farg1); + arg2 = (FILE *)(farg2); + ARKodeButcherTable_Write(arg1,arg2); +} + + +SWIGEXPORT int _wrap_FARKodeButcherTable_CheckOrder(void *farg1, int *farg2, int *farg3, void *farg4) { + int fresult ; + ARKodeButcherTable arg1 = (ARKodeButcherTable) 0 ; + int *arg2 = (int *) 0 ; + int *arg3 = (int *) 0 ; + FILE *arg4 = (FILE *) 0 ; + int result; + + arg1 = (ARKodeButcherTable)(farg1); + arg2 = (int *)(farg2); + arg3 = (int *)(farg3); + arg4 = (FILE *)(farg4); + result = (int)ARKodeButcherTable_CheckOrder(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FARKodeButcherTable_CheckARKOrder(void *farg1, void *farg2, int *farg3, int *farg4, void *farg5) { + int fresult ; + ARKodeButcherTable arg1 = (ARKodeButcherTable) 0 ; + ARKodeButcherTable arg2 = (ARKodeButcherTable) 0 ; + int *arg3 = (int *) 0 ; + int *arg4 = (int *) 0 ; + FILE *arg5 = (FILE *) 0 ; + int result; + + arg1 = (ARKodeButcherTable)(farg1); + arg2 = (ARKodeButcherTable)(farg2); + arg3 = (int *)(farg3); + arg4 = (int *)(farg4); + arg5 = (FILE *)(farg5); + result = (int)ARKodeButcherTable_CheckARKOrder(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void * _wrap_FARKodeButcherTable_LoadDIRK(int const *farg1) { + void * fresult ; + int arg1 ; + ARKodeButcherTable result; + + arg1 = (int)(*farg1); + result = (ARKodeButcherTable)ARKodeButcherTable_LoadDIRK(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FARKodeButcherTable_LoadERK(int const *farg1) { + void * fresult ; + int arg1 ; + ARKodeButcherTable result; + + arg1 = (int)(*farg1); + result = (ARKodeButcherTable)ARKodeButcherTable_LoadERK(arg1); + fresult = result; + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_mod.f90 new file mode 100644 index 000000000..d78550783 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_mod.f90 @@ -0,0 +1,1035 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module farkode_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_linearsolver_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_nonlinearsolver_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: ARK_NORMAL = 1_C_INT + integer(C_INT), parameter, public :: ARK_ONE_STEP = 2_C_INT + integer(C_INT), parameter, public :: ARK_INTERP_MAX_DEGREE = 5_C_INT + integer(C_INT), parameter, public :: ARK_INTERP_HERMITE = 0_C_INT + integer(C_INT), parameter, public :: ARK_INTERP_LAGRANGE = 1_C_INT + integer(C_INT), parameter, public :: ARK_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: ARK_TSTOP_RETURN = 1_C_INT + integer(C_INT), parameter, public :: ARK_ROOT_RETURN = 2_C_INT + integer(C_INT), parameter, public :: ARK_WARNING = 99_C_INT + integer(C_INT), parameter, public :: ARK_TOO_MUCH_WORK = -1_C_INT + integer(C_INT), parameter, public :: ARK_TOO_MUCH_ACC = -2_C_INT + integer(C_INT), parameter, public :: ARK_ERR_FAILURE = -3_C_INT + integer(C_INT), parameter, public :: ARK_CONV_FAILURE = -4_C_INT + integer(C_INT), parameter, public :: ARK_LINIT_FAIL = -5_C_INT + integer(C_INT), parameter, public :: ARK_LSETUP_FAIL = -6_C_INT + integer(C_INT), parameter, public :: ARK_LSOLVE_FAIL = -7_C_INT + integer(C_INT), parameter, public :: ARK_RHSFUNC_FAIL = -8_C_INT + integer(C_INT), parameter, public :: ARK_FIRST_RHSFUNC_ERR = -9_C_INT + integer(C_INT), parameter, public :: ARK_REPTD_RHSFUNC_ERR = -10_C_INT + integer(C_INT), parameter, public :: ARK_UNREC_RHSFUNC_ERR = -11_C_INT + integer(C_INT), parameter, public :: ARK_RTFUNC_FAIL = -12_C_INT + integer(C_INT), parameter, public :: ARK_LFREE_FAIL = -13_C_INT + integer(C_INT), parameter, public :: ARK_MASSINIT_FAIL = -14_C_INT + integer(C_INT), parameter, public :: ARK_MASSSETUP_FAIL = -15_C_INT + integer(C_INT), parameter, public :: ARK_MASSSOLVE_FAIL = -16_C_INT + integer(C_INT), parameter, public :: ARK_MASSFREE_FAIL = -17_C_INT + integer(C_INT), parameter, public :: ARK_MASSMULT_FAIL = -18_C_INT + integer(C_INT), parameter, public :: ARK_CONSTR_FAIL = -19_C_INT + integer(C_INT), parameter, public :: ARK_MEM_FAIL = -20_C_INT + integer(C_INT), parameter, public :: ARK_MEM_NULL = -21_C_INT + integer(C_INT), parameter, public :: ARK_ILL_INPUT = -22_C_INT + integer(C_INT), parameter, public :: ARK_NO_MALLOC = -23_C_INT + integer(C_INT), parameter, public :: ARK_BAD_K = -24_C_INT + integer(C_INT), parameter, public :: ARK_BAD_T = -25_C_INT + integer(C_INT), parameter, public :: ARK_BAD_DKY = -26_C_INT + integer(C_INT), parameter, public :: ARK_TOO_CLOSE = -27_C_INT + integer(C_INT), parameter, public :: ARK_VECTOROP_ERR = -28_C_INT + integer(C_INT), parameter, public :: ARK_NLS_INIT_FAIL = -29_C_INT + integer(C_INT), parameter, public :: ARK_NLS_SETUP_FAIL = -30_C_INT + integer(C_INT), parameter, public :: ARK_NLS_SETUP_RECVR = -31_C_INT + integer(C_INT), parameter, public :: ARK_NLS_OP_ERR = -32_C_INT + integer(C_INT), parameter, public :: ARK_INNERSTEP_ATTACH_ERR = -33_C_INT + integer(C_INT), parameter, public :: ARK_INNERSTEP_FAIL = -34_C_INT + integer(C_INT), parameter, public :: ARK_OUTERTOINNER_FAIL = -35_C_INT + integer(C_INT), parameter, public :: ARK_INNERTOOUTER_FAIL = -36_C_INT + integer(C_INT), parameter, public :: ARK_POSTPROCESS_FAIL = -37_C_INT + integer(C_INT), parameter, public :: ARK_POSTPROCESS_STEP_FAIL = -37_C_INT + integer(C_INT), parameter, public :: ARK_POSTPROCESS_STAGE_FAIL = -38_C_INT + integer(C_INT), parameter, public :: ARK_USER_PREDICT_FAIL = -39_C_INT + integer(C_INT), parameter, public :: ARK_INTERP_FAIL = -40_C_INT + integer(C_INT), parameter, public :: ARK_UNRECOGNIZED_ERROR = -99_C_INT + public :: FARKBandPrecInit + public :: FARKBandPrecGetWorkSpace + public :: FARKBandPrecGetNumRhsEvals + public :: FARKBBDPrecInit + public :: FARKBBDPrecReInit + public :: FARKBBDPrecGetWorkSpace + public :: FARKBBDPrecGetNumGfnEvals + + integer, parameter :: swig_cmem_own_bit = 0 + integer, parameter :: swig_cmem_rvalue_bit = 1 + integer, parameter :: swig_cmem_const_bit = 2 + type, bind(C) :: SwigClassWrapper + type(C_PTR), public :: cptr = C_NULL_PTR + integer(C_INT), public :: cmemflags = 0 + end type + ! struct struct ARKodeButcherTableMem + type, public :: ARKodeButcherTableMem + type(SwigClassWrapper), public :: swigdata + contains + procedure :: set_q => swigf_ARKodeButcherTableMem_q_set + procedure :: get_q => swigf_ARKodeButcherTableMem_q_get + procedure :: set_p => swigf_ARKodeButcherTableMem_p_set + procedure :: get_p => swigf_ARKodeButcherTableMem_p_get + procedure :: set_stages => swigf_ARKodeButcherTableMem_stages_set + procedure :: get_stages => swigf_ARKodeButcherTableMem_stages_get + procedure :: set_A => swigf_ARKodeButcherTableMem_A_set + procedure :: get_A => swigf_ARKodeButcherTableMem_A_get + procedure :: set_c => swigf_ARKodeButcherTableMem_c_set + procedure :: get_c => swigf_ARKodeButcherTableMem_c_get + procedure :: set_b => swigf_ARKodeButcherTableMem_b_set + procedure :: get_b => swigf_ARKodeButcherTableMem_b_get + procedure :: set_d => swigf_ARKodeButcherTableMem_d_set + procedure :: get_d => swigf_ARKodeButcherTableMem_d_get + procedure :: release => swigf_release_ARKodeButcherTableMem + procedure, private :: swigf_ARKodeButcherTableMem_op_assign__ + generic :: assignment(=) => swigf_ARKodeButcherTableMem_op_assign__ + end type ARKodeButcherTableMem + interface ARKodeButcherTableMem + module procedure swigf_create_ARKodeButcherTableMem + end interface + public :: FARKodeButcherTable_Alloc + public :: FARKodeButcherTable_Create + public :: FARKodeButcherTable_Copy + public :: FARKodeButcherTable_Space + public :: FARKodeButcherTable_Free + public :: FARKodeButcherTable_Write + public :: FARKodeButcherTable_CheckOrder + public :: FARKodeButcherTable_CheckARKOrder + integer(C_INT), parameter, public :: SDIRK_2_1_2 = 100_C_INT + integer(C_INT), parameter, public :: BILLINGTON_3_3_2 = 101_C_INT + integer(C_INT), parameter, public :: TRBDF2_3_3_2 = 102_C_INT + integer(C_INT), parameter, public :: KVAERNO_4_2_3 = 103_C_INT + integer(C_INT), parameter, public :: ARK324L2SA_DIRK_4_2_3 = 104_C_INT + integer(C_INT), parameter, public :: CASH_5_2_4 = 105_C_INT + integer(C_INT), parameter, public :: CASH_5_3_4 = 106_C_INT + integer(C_INT), parameter, public :: SDIRK_5_3_4 = 107_C_INT + integer(C_INT), parameter, public :: KVAERNO_5_3_4 = 108_C_INT + integer(C_INT), parameter, public :: ARK436L2SA_DIRK_6_3_4 = 109_C_INT + integer(C_INT), parameter, public :: KVAERNO_7_4_5 = 110_C_INT + integer(C_INT), parameter, public :: ARK548L2SA_DIRK_8_4_5 = 111_C_INT + integer(C_INT), parameter, public :: ARK437L2SA_DIRK_7_3_4 = 112_C_INT + integer(C_INT), parameter, public :: ARK548L2SAb_DIRK_8_4_5 = 113_C_INT + integer(C_INT), parameter, public :: MIN_DIRK_NUM = 100_C_INT + integer(C_INT), parameter, public :: MAX_DIRK_NUM = 113_C_INT + public :: FARKodeButcherTable_LoadDIRK + integer(C_INT), parameter, public :: HEUN_EULER_2_1_2 = 0_C_INT + integer(C_INT), parameter, public :: BOGACKI_SHAMPINE_4_2_3 = 1_C_INT + integer(C_INT), parameter, public :: ARK324L2SA_ERK_4_2_3 = 2_C_INT + integer(C_INT), parameter, public :: ZONNEVELD_5_3_4 = 3_C_INT + integer(C_INT), parameter, public :: ARK436L2SA_ERK_6_3_4 = 4_C_INT + integer(C_INT), parameter, public :: SAYFY_ABURUB_6_3_4 = 5_C_INT + integer(C_INT), parameter, public :: CASH_KARP_6_4_5 = 6_C_INT + integer(C_INT), parameter, public :: FEHLBERG_6_4_5 = 7_C_INT + integer(C_INT), parameter, public :: DORMAND_PRINCE_7_4_5 = 8_C_INT + integer(C_INT), parameter, public :: ARK548L2SA_ERK_8_4_5 = 9_C_INT + integer(C_INT), parameter, public :: VERNER_8_5_6 = 10_C_INT + integer(C_INT), parameter, public :: FEHLBERG_13_7_8 = 11_C_INT + integer(C_INT), parameter, public :: KNOTH_WOLKE_3_3 = 12_C_INT + integer(C_INT), parameter, public :: ARK437L2SA_ERK_7_3_4 = 13_C_INT + integer(C_INT), parameter, public :: ARK548L2SAb_ERK_8_4_5 = 14_C_INT + integer(C_INT), parameter, public :: MIN_ERK_NUM = 0_C_INT + integer(C_INT), parameter, public :: MAX_ERK_NUM = 14_C_INT + public :: FARKodeButcherTable_LoadERK + integer(C_INT), parameter, public :: ARKLS_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: ARKLS_MEM_NULL = -1_C_INT + integer(C_INT), parameter, public :: ARKLS_LMEM_NULL = -2_C_INT + integer(C_INT), parameter, public :: ARKLS_ILL_INPUT = -3_C_INT + integer(C_INT), parameter, public :: ARKLS_MEM_FAIL = -4_C_INT + integer(C_INT), parameter, public :: ARKLS_PMEM_NULL = -5_C_INT + integer(C_INT), parameter, public :: ARKLS_MASSMEM_NULL = -6_C_INT + integer(C_INT), parameter, public :: ARKLS_JACFUNC_UNRECVR = -7_C_INT + integer(C_INT), parameter, public :: ARKLS_JACFUNC_RECVR = -8_C_INT + integer(C_INT), parameter, public :: ARKLS_MASSFUNC_UNRECVR = -9_C_INT + integer(C_INT), parameter, public :: ARKLS_MASSFUNC_RECVR = -10_C_INT + integer(C_INT), parameter, public :: ARKLS_SUNMAT_FAIL = -11_C_INT + integer(C_INT), parameter, public :: ARKLS_SUNLS_FAIL = -12_C_INT + +! WRAPPER DECLARATIONS +interface +function swigc_FARKBandPrecInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FARKBandPrecInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FARKBandPrecGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKBandPrecGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKBandPrecGetNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FARKBandPrecGetNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FARKBBDPrecInit(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) & +bind(C, name="_wrap_FARKBBDPrecInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +integer(C_INT64_T), intent(in) :: farg5 +integer(C_INT64_T), intent(in) :: farg6 +real(C_DOUBLE), intent(in) :: farg7 +type(C_FUNPTR), value :: farg8 +type(C_FUNPTR), value :: farg9 +integer(C_INT) :: fresult +end function + +function swigc_FARKBBDPrecReInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FARKBBDPrecReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FARKBBDPrecGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKBBDPrecGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FARKBBDPrecGetNumGfnEvals(farg1, farg2) & +bind(C, name="_wrap_FARKBBDPrecGetNumGfnEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +subroutine swigc_ARKodeButcherTableMem_q_set(farg1, farg2) & +bind(C, name="_wrap_ARKodeButcherTableMem_q_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_INT), intent(in) :: farg2 +end subroutine + +function swigc_ARKodeButcherTableMem_q_get(farg1) & +bind(C, name="_wrap_ARKodeButcherTableMem_q_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_INT) :: fresult +end function + +subroutine swigc_ARKodeButcherTableMem_p_set(farg1, farg2) & +bind(C, name="_wrap_ARKodeButcherTableMem_p_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_INT), intent(in) :: farg2 +end subroutine + +function swigc_ARKodeButcherTableMem_p_get(farg1) & +bind(C, name="_wrap_ARKodeButcherTableMem_p_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_INT) :: fresult +end function + +subroutine swigc_ARKodeButcherTableMem_stages_set(farg1, farg2) & +bind(C, name="_wrap_ARKodeButcherTableMem_stages_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_INT), intent(in) :: farg2 +end subroutine + +function swigc_ARKodeButcherTableMem_stages_get(farg1) & +bind(C, name="_wrap_ARKodeButcherTableMem_stages_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_INT) :: fresult +end function + +subroutine swigc_ARKodeButcherTableMem_A_set(farg1, farg2) & +bind(C, name="_wrap_ARKodeButcherTableMem_A_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_ARKodeButcherTableMem_A_get(farg1) & +bind(C, name="_wrap_ARKodeButcherTableMem_A_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_ARKodeButcherTableMem_c_set(farg1, farg2) & +bind(C, name="_wrap_ARKodeButcherTableMem_c_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_ARKodeButcherTableMem_c_get(farg1) & +bind(C, name="_wrap_ARKodeButcherTableMem_c_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_ARKodeButcherTableMem_b_set(farg1, farg2) & +bind(C, name="_wrap_ARKodeButcherTableMem_b_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_ARKodeButcherTableMem_b_get(farg1) & +bind(C, name="_wrap_ARKodeButcherTableMem_b_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_ARKodeButcherTableMem_d_set(farg1, farg2) & +bind(C, name="_wrap_ARKodeButcherTableMem_d_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_ARKodeButcherTableMem_d_get(farg1) & +bind(C, name="_wrap_ARKodeButcherTableMem_d_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_new_ARKodeButcherTableMem() & +bind(C, name="_wrap_new_ARKodeButcherTableMem") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: fresult +end function + +subroutine swigc_delete_ARKodeButcherTableMem(farg1) & +bind(C, name="_wrap_delete_ARKodeButcherTableMem") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper), intent(inout) :: farg1 +end subroutine + +subroutine swigc_ARKodeButcherTableMem_op_assign__(farg1, farg2) & +bind(C, name="_wrap_ARKodeButcherTableMem_op_assign__") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper), intent(inout) :: farg1 +type(SwigClassWrapper) :: farg2 +end subroutine + +function swigc_FARKodeButcherTable_Alloc(farg1, farg2) & +bind(C, name="_wrap_FARKodeButcherTable_Alloc") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FARKodeButcherTable_Create(farg1, farg2, farg3, farg4, farg5, farg6, farg7) & +bind(C, name="_wrap_FARKodeButcherTable_Create") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), 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 +type(C_PTR), value :: farg6 +type(C_PTR), value :: farg7 +type(C_PTR) :: fresult +end function + +function swigc_FARKodeButcherTable_Copy(farg1) & +bind(C, name="_wrap_FARKodeButcherTable_Copy") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FARKodeButcherTable_Space(farg1, farg2, farg3) & +bind(C, name="_wrap_FARKodeButcherTable_Space") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FARKodeButcherTable_Free(farg1) & +bind(C, name="_wrap_FARKodeButcherTable_Free") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FARKodeButcherTable_Write(farg1, farg2) & +bind(C, name="_wrap_FARKodeButcherTable_Write") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_FARKodeButcherTable_CheckOrder(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FARKodeButcherTable_CheckOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FARKodeButcherTable_CheckARKOrder(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FARKodeButcherTable_CheckARKOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FARKodeButcherTable_LoadDIRK(farg1) & +bind(C, name="_wrap_FARKodeButcherTable_LoadDIRK") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FARKodeButcherTable_LoadERK(farg1) & +bind(C, name="_wrap_FARKodeButcherTable_LoadERK") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FARKBandPrecInit(arkode_mem, n, mu, ml) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT64_T), intent(in) :: n +integer(C_INT64_T), intent(in) :: mu +integer(C_INT64_T), intent(in) :: ml +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 + +farg1 = arkode_mem +farg2 = n +farg3 = mu +farg4 = ml +fresult = swigc_FARKBandPrecInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FARKBandPrecGetWorkSpace(arkode_mem, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FARKBandPrecGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKBandPrecGetNumRhsEvals(arkode_mem, nfevalsbp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevalsbp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nfevalsbp(1)) +fresult = swigc_FARKBandPrecGetNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FARKBBDPrecInit(arkode_mem, nlocal, mudq, mldq, mukeep, mlkeep, dqrely, gloc, cfn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT64_T), intent(in) :: nlocal +integer(C_INT64_T), intent(in) :: mudq +integer(C_INT64_T), intent(in) :: mldq +integer(C_INT64_T), intent(in) :: mukeep +integer(C_INT64_T), intent(in) :: mlkeep +real(C_DOUBLE), intent(in) :: dqrely +type(C_FUNPTR), intent(in), value :: gloc +type(C_FUNPTR), intent(in), value :: cfn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 +integer(C_INT64_T) :: farg5 +integer(C_INT64_T) :: farg6 +real(C_DOUBLE) :: farg7 +type(C_FUNPTR) :: farg8 +type(C_FUNPTR) :: farg9 + +farg1 = arkode_mem +farg2 = nlocal +farg3 = mudq +farg4 = mldq +farg5 = mukeep +farg6 = mlkeep +farg7 = dqrely +farg8 = gloc +farg9 = cfn +fresult = swigc_FARKBBDPrecInit(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) +swig_result = fresult +end function + +function FARKBBDPrecReInit(arkode_mem, mudq, mldq, dqrely) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT64_T), intent(in) :: mudq +integer(C_INT64_T), intent(in) :: mldq +real(C_DOUBLE), intent(in) :: dqrely +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +real(C_DOUBLE) :: farg4 + +farg1 = arkode_mem +farg2 = mudq +farg3 = mldq +farg4 = dqrely +fresult = swigc_FARKBBDPrecReInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FARKBBDPrecGetWorkSpace(arkode_mem, lenrwbbdp, leniwbbdp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwbbdp +integer(C_LONG), dimension(*), target, intent(inout) :: leniwbbdp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = c_loc(lenrwbbdp(1)) +farg3 = c_loc(leniwbbdp(1)) +fresult = swigc_FARKBBDPrecGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FARKBBDPrecGetNumGfnEvals(arkode_mem, ngevalsbbdp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevalsbbdp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(ngevalsbbdp(1)) +fresult = swigc_FARKBBDPrecGetNumGfnEvals(farg1, farg2) +swig_result = fresult +end function + +subroutine swigf_ARKodeButcherTableMem_q_set(self, q) +use, intrinsic :: ISO_C_BINDING +class(ARKodeButcherTableMem), intent(in) :: self +integer(C_INT), intent(in) :: q +type(SwigClassWrapper) :: farg1 +integer(C_INT) :: farg2 + +farg1 = self%swigdata +farg2 = q +call swigc_ARKodeButcherTableMem_q_set(farg1, farg2) +end subroutine + +function swigf_ARKodeButcherTableMem_q_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +class(ARKodeButcherTableMem), intent(in) :: self +integer(C_INT) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_ARKodeButcherTableMem_q_get(farg1) +swig_result = fresult +end function + +subroutine swigf_ARKodeButcherTableMem_p_set(self, p) +use, intrinsic :: ISO_C_BINDING +class(ARKodeButcherTableMem), intent(in) :: self +integer(C_INT), intent(in) :: p +type(SwigClassWrapper) :: farg1 +integer(C_INT) :: farg2 + +farg1 = self%swigdata +farg2 = p +call swigc_ARKodeButcherTableMem_p_set(farg1, farg2) +end subroutine + +function swigf_ARKodeButcherTableMem_p_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +class(ARKodeButcherTableMem), intent(in) :: self +integer(C_INT) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_ARKodeButcherTableMem_p_get(farg1) +swig_result = fresult +end function + +subroutine swigf_ARKodeButcherTableMem_stages_set(self, stages) +use, intrinsic :: ISO_C_BINDING +class(ARKodeButcherTableMem), intent(in) :: self +integer(C_INT), intent(in) :: stages +type(SwigClassWrapper) :: farg1 +integer(C_INT) :: farg2 + +farg1 = self%swigdata +farg2 = stages +call swigc_ARKodeButcherTableMem_stages_set(farg1, farg2) +end subroutine + +function swigf_ARKodeButcherTableMem_stages_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +class(ARKodeButcherTableMem), intent(in) :: self +integer(C_INT) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_ARKodeButcherTableMem_stages_get(farg1) +swig_result = fresult +end function + +subroutine swigf_ARKodeButcherTableMem_A_set(self, a) +use, intrinsic :: ISO_C_BINDING +class(ARKodeButcherTableMem), intent(in) :: self +type(C_PTR), target, intent(inout) :: a +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: farg2 + +farg1 = self%swigdata +farg2 = c_loc(a) +call swigc_ARKodeButcherTableMem_A_set(farg1, farg2) +end subroutine + +function swigf_ARKodeButcherTableMem_A_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), pointer :: swig_result +class(ARKodeButcherTableMem), intent(in) :: self +type(C_PTR) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_ARKodeButcherTableMem_A_get(farg1) +call c_f_pointer(fresult, swig_result) +end function + +subroutine swigf_ARKodeButcherTableMem_c_set(self, c) +use, intrinsic :: ISO_C_BINDING +class(ARKodeButcherTableMem), intent(in) :: self +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: farg2 + +farg1 = self%swigdata +farg2 = c_loc(c(1)) +call swigc_ARKodeButcherTableMem_c_set(farg1, farg2) +end subroutine + +function swigf_ARKodeButcherTableMem_c_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +class(ARKodeButcherTableMem), intent(in) :: self +type(C_PTR) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_ARKodeButcherTableMem_c_get(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +subroutine swigf_ARKodeButcherTableMem_b_set(self, b) +use, intrinsic :: ISO_C_BINDING +class(ARKodeButcherTableMem), intent(in) :: self +real(C_DOUBLE), dimension(*), target, intent(inout) :: b +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: farg2 + +farg1 = self%swigdata +farg2 = c_loc(b(1)) +call swigc_ARKodeButcherTableMem_b_set(farg1, farg2) +end subroutine + +function swigf_ARKodeButcherTableMem_b_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +class(ARKodeButcherTableMem), intent(in) :: self +type(C_PTR) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_ARKodeButcherTableMem_b_get(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +subroutine swigf_ARKodeButcherTableMem_d_set(self, d) +use, intrinsic :: ISO_C_BINDING +class(ARKodeButcherTableMem), intent(in) :: self +real(C_DOUBLE), dimension(*), target, intent(inout) :: d +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: farg2 + +farg1 = self%swigdata +farg2 = c_loc(d(1)) +call swigc_ARKodeButcherTableMem_d_set(farg1, farg2) +end subroutine + +function swigf_ARKodeButcherTableMem_d_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +class(ARKodeButcherTableMem), intent(in) :: self +type(C_PTR) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_ARKodeButcherTableMem_d_get(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +function swigf_create_ARKodeButcherTableMem() & +result(self) +use, intrinsic :: ISO_C_BINDING +type(ARKodeButcherTableMem) :: self +type(SwigClassWrapper) :: fresult + +fresult = swigc_new_ARKodeButcherTableMem() +self%swigdata = fresult +end function + +subroutine swigf_release_ARKodeButcherTableMem(self) +use, intrinsic :: ISO_C_BINDING +class(ARKodeButcherTableMem), intent(inout) :: self +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +if (btest(farg1%cmemflags, swig_cmem_own_bit)) then +call swigc_delete_ARKodeButcherTableMem(farg1) +endif +farg1%cptr = C_NULL_PTR +farg1%cmemflags = 0 +self%swigdata = farg1 +end subroutine + +subroutine swigf_ARKodeButcherTableMem_op_assign__(self, other) +use, intrinsic :: ISO_C_BINDING +class(ARKodeButcherTableMem), intent(inout) :: self +type(ARKodeButcherTableMem), intent(in) :: other +type(SwigClassWrapper) :: farg1 +type(SwigClassWrapper) :: farg2 + +farg1 = self%swigdata +farg2 = other%swigdata +call swigc_ARKodeButcherTableMem_op_assign__(farg1, farg2) +self%swigdata = farg1 +end subroutine + +function FARKodeButcherTable_Alloc(stages, embedded) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: stages +integer(C_INT), intent(in) :: embedded +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +integer(C_INT) :: farg2 + +farg1 = stages +farg2 = embedded +fresult = swigc_FARKodeButcherTable_Alloc(farg1, farg2) +swig_result = fresult +end function + +function FARKodeButcherTable_Create(s, q, p, c, a, b, d) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: s +integer(C_INT), intent(in) :: q +integer(C_INT), intent(in) :: p +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +real(C_DOUBLE), dimension(*), target, intent(inout) :: a +real(C_DOUBLE), dimension(*), target, intent(inout) :: b +real(C_DOUBLE), dimension(*), target, intent(inout) :: d +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 +type(C_PTR) :: farg7 + +farg1 = s +farg2 = q +farg3 = p +farg4 = c_loc(c(1)) +farg5 = c_loc(a(1)) +farg6 = c_loc(b(1)) +farg7 = c_loc(d(1)) +fresult = swigc_FARKodeButcherTable_Create(farg1, farg2, farg3, farg4, farg5, farg6, farg7) +swig_result = fresult +end function + +function FARKodeButcherTable_Copy(b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +type(C_PTR) :: b +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = b +fresult = swigc_FARKodeButcherTable_Copy(farg1) +swig_result = fresult +end function + +subroutine FARKodeButcherTable_Space(b, liw, lrw) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: b +integer(C_INT64_T), dimension(*), target, intent(inout) :: liw +integer(C_INT64_T), dimension(*), target, intent(inout) :: lrw +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = b +farg2 = c_loc(liw(1)) +farg3 = c_loc(lrw(1)) +call swigc_FARKodeButcherTable_Space(farg1, farg2, farg3) +end subroutine + +subroutine FARKodeButcherTable_Free(b) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: b +type(C_PTR) :: farg1 + +farg1 = b +call swigc_FARKodeButcherTable_Free(farg1) +end subroutine + +subroutine FARKodeButcherTable_Write(b, outfile) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: b +type(C_PTR) :: outfile +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = b +farg2 = outfile +call swigc_FARKodeButcherTable_Write(farg1, farg2) +end subroutine + +function FARKodeButcherTable_CheckOrder(b, q, p, outfile) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: b +integer(C_INT), dimension(*), target, intent(inout) :: q +integer(C_INT), dimension(*), target, intent(inout) :: p +type(C_PTR) :: outfile +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = b +farg2 = c_loc(q(1)) +farg3 = c_loc(p(1)) +farg4 = outfile +fresult = swigc_FARKodeButcherTable_CheckOrder(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FARKodeButcherTable_CheckARKOrder(b1, b2, q, p, outfile) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: b1 +type(C_PTR) :: b2 +integer(C_INT), dimension(*), target, intent(inout) :: q +integer(C_INT), dimension(*), target, intent(inout) :: p +type(C_PTR) :: outfile +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = b1 +farg2 = b2 +farg3 = c_loc(q(1)) +farg4 = c_loc(p(1)) +farg5 = outfile +fresult = swigc_FARKodeButcherTable_CheckARKOrder(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FARKodeButcherTable_LoadDIRK(imethod) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: imethod +type(C_PTR) :: fresult +integer(C_INT) :: farg1 + +farg1 = imethod +fresult = swigc_FARKodeButcherTable_LoadDIRK(farg1) +swig_result = fresult +end function + +function FARKodeButcherTable_LoadERK(imethod) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: imethod +type(C_PTR) :: fresult +integer(C_INT) :: farg1 + +farg1 = imethod +fresult = swigc_FARKodeButcherTable_LoadERK(farg1) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_mristep_mod.c b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_mristep_mod.c new file mode 100644 index 000000000..997a4ff6f --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_mristep_mod.c @@ -0,0 +1,829 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "arkode/arkode_mristep.h" + + +#include +#ifdef _MSC_VER +# ifndef strtoull +# define strtoull _strtoui64 +# endif +# ifndef strtoll +# define strtoll _strtoi64 +# endif +#endif + + +typedef struct { + void* data; + size_t size; +} SwigArrayWrapper; + + +SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() { + SwigArrayWrapper result; + result.data = NULL; + result.size = 0; + return result; +} + + +#include + +SWIGEXPORT void * _wrap_FMRIStepCreate(ARKRhsFn farg1, double const *farg2, N_Vector farg3, int const *farg4, void *farg5) { + void * fresult ; + ARKRhsFn arg1 = (ARKRhsFn) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + MRISTEP_ID arg4 ; + void *arg5 = (void *) 0 ; + void *result = 0 ; + + arg1 = (ARKRhsFn)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + arg4 = (MRISTEP_ID)(*farg4); + arg5 = (void *)(farg5); + result = (void *)MRIStepCreate(arg1,arg2,arg3,arg4,arg5); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepResize(void *farg1, N_Vector farg2, double const *farg3, ARKVecResizeFn farg4, void *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype arg3 ; + ARKVecResizeFn arg4 = (ARKVecResizeFn) 0 ; + void *arg5 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (ARKVecResizeFn)(farg4); + arg5 = (void *)(farg5); + result = (int)MRIStepResize(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepReInit(void *farg1, ARKRhsFn farg2, double const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKRhsFn arg2 = (ARKRhsFn) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKRhsFn)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)MRIStepReInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepRootInit(void *farg1, int const *farg2, ARKRootFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + ARKRootFn arg3 = (ARKRootFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (ARKRootFn)(farg3); + result = (int)MRIStepRootInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetDefaults(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)MRIStepSetDefaults(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetInterpolantType(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)MRIStepSetInterpolantType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetInterpolantDegree(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)MRIStepSetInterpolantDegree(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetDenseOrder(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)MRIStepSetDenseOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetTable(void *farg1, int const *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + ARKodeButcherTable arg3 = (ARKodeButcherTable) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (ARKodeButcherTable)(farg3); + result = (int)MRIStepSetTable(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetTableNum(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)MRIStepSetTableNum(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetMaxNumSteps(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)MRIStepSetMaxNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetMaxHnilWarns(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)MRIStepSetMaxHnilWarns(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetStopTime(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)MRIStepSetStopTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetFixedStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)MRIStepSetFixedStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetRootDirection(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)MRIStepSetRootDirection(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetNoInactiveRootWarn(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)MRIStepSetNoInactiveRootWarn(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetErrHandlerFn(void *farg1, ARKErrHandlerFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKErrHandlerFn arg2 = (ARKErrHandlerFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKErrHandlerFn)(farg2); + arg3 = (void *)(farg3); + result = (int)MRIStepSetErrHandlerFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetErrFile(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)MRIStepSetErrFile(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetUserData(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + void *arg2 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (void *)(farg2); + result = (int)MRIStepSetUserData(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetDiagnostics(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)MRIStepSetDiagnostics(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetPostprocessStepFn(void *farg1, ARKPostProcessFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKPostProcessFn arg2 = (ARKPostProcessFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKPostProcessFn)(farg2); + result = (int)MRIStepSetPostprocessStepFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetPostprocessStageFn(void *farg1, ARKPostProcessFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKPostProcessFn arg2 = (ARKPostProcessFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKPostProcessFn)(farg2); + result = (int)MRIStepSetPostprocessStageFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetPreInnerFn(void *farg1, MRIStepPreInnerFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + MRIStepPreInnerFn arg2 = (MRIStepPreInnerFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (MRIStepPreInnerFn)(farg2); + result = (int)MRIStepSetPreInnerFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepSetPostInnerFn(void *farg1, MRIStepPostInnerFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + MRIStepPostInnerFn arg2 = (MRIStepPostInnerFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (MRIStepPostInnerFn)(farg2); + result = (int)MRIStepSetPostInnerFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepEvolve(void *farg1, double const *farg2, N_Vector farg3, double *farg4, int const *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype *arg4 = (realtype *) 0 ; + int arg5 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + arg4 = (realtype *)(farg4); + arg5 = (int)(*farg5); + result = (int)MRIStepEvolve(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepGetDky(void *farg1, double const *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)MRIStepGetDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepGetNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)MRIStepGetNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepGetCurrentButcherTables(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + ARKodeButcherTable *arg2 = (ARKodeButcherTable *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (ARKodeButcherTable *)(farg2); + result = (int)MRIStepGetCurrentButcherTables(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)MRIStepGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepGetNumSteps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)MRIStepGetNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepGetLastStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)MRIStepGetLastStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepGetCurrentTime(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)MRIStepGetCurrentTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepGetCurrentState(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)MRIStepGetCurrentState(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepGetNumGEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)MRIStepGetNumGEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepGetRootInfo(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)MRIStepGetRootInfo(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepGetLastInnerStepFlag(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)MRIStepGetLastInnerStepFlag(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FMRIStepGetReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)MRIStepGetReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepWriteParameters(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)MRIStepWriteParameters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FMRIStepWriteButcher(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)MRIStepWriteButcher(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FMRIStepFree(void *farg1) { + void **arg1 = (void **) 0 ; + + arg1 = (void **)(farg1); + MRIStepFree(arg1); +} + + +SWIGEXPORT void _wrap_FMRIStepPrintMem(void *farg1, void *farg2) { + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + MRIStepPrintMem(arg1,arg2); +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_mristep_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_mristep_mod.f90 new file mode 100644 index 000000000..dabd341ad --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/arkode/fmod/farkode_mristep_mod.f90 @@ -0,0 +1,1186 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module farkode_mristep_mod + use, intrinsic :: ISO_C_BINDING + use farkode_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_linearsolver_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_nonlinearsolver_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + ! typedef enum MRISTEP_ID + enum, bind(c) + enumerator :: MRISTEP_ARKSTEP + end enum + integer, parameter, public :: MRISTEP_ID = kind(MRISTEP_ARKSTEP) + public :: MRISTEP_ARKSTEP + integer(C_INT), parameter, public :: DEFAULT_MRI_TABLE_3 = 12_C_INT + public :: FMRIStepCreate + public :: FMRIStepResize + public :: FMRIStepReInit + public :: FMRIStepRootInit + public :: FMRIStepSetDefaults + public :: FMRIStepSetInterpolantType + public :: FMRIStepSetInterpolantDegree + public :: FMRIStepSetDenseOrder + public :: FMRIStepSetTable + public :: FMRIStepSetTableNum + public :: FMRIStepSetMaxNumSteps + public :: FMRIStepSetMaxHnilWarns + public :: FMRIStepSetStopTime + public :: FMRIStepSetFixedStep + public :: FMRIStepSetRootDirection + public :: FMRIStepSetNoInactiveRootWarn + public :: FMRIStepSetErrHandlerFn + public :: FMRIStepSetErrFile + public :: FMRIStepSetUserData + public :: FMRIStepSetDiagnostics + public :: FMRIStepSetPostprocessStepFn + public :: FMRIStepSetPostprocessStageFn + public :: FMRIStepSetPreInnerFn + public :: FMRIStepSetPostInnerFn + public :: FMRIStepEvolve + public :: FMRIStepGetDky + public :: FMRIStepGetNumRhsEvals + public :: FMRIStepGetCurrentButcherTables + public :: FMRIStepGetWorkSpace + public :: FMRIStepGetNumSteps + public :: FMRIStepGetLastStep + public :: FMRIStepGetCurrentTime + public :: FMRIStepGetCurrentState + public :: FMRIStepGetNumGEvals + public :: FMRIStepGetRootInfo + public :: FMRIStepGetLastInnerStepFlag + type, bind(C) :: SwigArrayWrapper + type(C_PTR), public :: data = C_NULL_PTR + integer(C_SIZE_T), public :: size = 0 + end type + public :: FMRIStepGetReturnFlagName + public :: FMRIStepWriteParameters + public :: FMRIStepWriteButcher + public :: FMRIStepFree + public :: FMRIStepPrintMem + +! WRAPPER DECLARATIONS +interface +function swigc_FMRIStepCreate(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FMRIStepCreate") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_FUNPTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT), intent(in) :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR) :: fresult +end function + +function swigc_FMRIStepResize(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FMRIStepResize") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_FUNPTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepReInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FMRIStepReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepRootInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FMRIStepRootInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetDefaults(farg1) & +bind(C, name="_wrap_FMRIStepSetDefaults") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetInterpolantType(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetInterpolantType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetInterpolantDegree(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetInterpolantDegree") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetDenseOrder(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetDenseOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetTable(farg1, farg2, farg3) & +bind(C, name="_wrap_FMRIStepSetTable") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetTableNum(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetTableNum") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetMaxNumSteps(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetMaxNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetMaxHnilWarns(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetMaxHnilWarns") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetStopTime(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetStopTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetFixedStep(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetFixedStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetRootDirection(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetRootDirection") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetNoInactiveRootWarn(farg1) & +bind(C, name="_wrap_FMRIStepSetNoInactiveRootWarn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetErrHandlerFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FMRIStepSetErrHandlerFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetErrFile(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetErrFile") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetUserData(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetUserData") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetDiagnostics(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetDiagnostics") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetPostprocessStepFn(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetPostprocessStepFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetPostprocessStageFn(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetPostprocessStageFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetPreInnerFn(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetPreInnerFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepSetPostInnerFn(farg1, farg2) & +bind(C, name="_wrap_FMRIStepSetPostInnerFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepEvolve(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FMRIStepEvolve") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepGetDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FMRIStepGetDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepGetNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FMRIStepGetNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepGetCurrentButcherTables(farg1, farg2) & +bind(C, name="_wrap_FMRIStepGetCurrentButcherTables") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FMRIStepGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepGetNumSteps(farg1, farg2) & +bind(C, name="_wrap_FMRIStepGetNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepGetLastStep(farg1, farg2) & +bind(C, name="_wrap_FMRIStepGetLastStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepGetCurrentTime(farg1, farg2) & +bind(C, name="_wrap_FMRIStepGetCurrentTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepGetCurrentState(farg1, farg2) & +bind(C, name="_wrap_FMRIStepGetCurrentState") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepGetNumGEvals(farg1, farg2) & +bind(C, name="_wrap_FMRIStepGetNumGEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepGetRootInfo(farg1, farg2) & +bind(C, name="_wrap_FMRIStepGetRootInfo") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepGetLastInnerStepFlag(farg1, farg2) & +bind(C, name="_wrap_FMRIStepGetLastInnerStepFlag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + + subroutine SWIG_free(cptr) & + bind(C, name="free") + use, intrinsic :: ISO_C_BINDING + type(C_PTR), value :: cptr +end subroutine +function swigc_FMRIStepGetReturnFlagName(farg1) & +bind(C, name="_wrap_FMRIStepGetReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +function swigc_FMRIStepWriteParameters(farg1, farg2) & +bind(C, name="_wrap_FMRIStepWriteParameters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FMRIStepWriteButcher(farg1, farg2) & +bind(C, name="_wrap_FMRIStepWriteButcher") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +subroutine swigc_FMRIStepFree(farg1) & +bind(C, name="_wrap_FMRIStepFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FMRIStepPrintMem(farg1, farg2) & +bind(C, name="_wrap_FMRIStepPrintMem") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FMRIStepCreate(fs, t0, y0, inner_step_id, inner_step_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +type(C_FUNPTR), intent(in), value :: fs +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: y0 +integer(MRISTEP_ID), intent(in) :: inner_step_id +type(C_PTR) :: inner_step_mem +type(C_PTR) :: fresult +type(C_FUNPTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +integer(C_INT) :: farg4 +type(C_PTR) :: farg5 + +farg1 = fs +farg2 = t0 +farg3 = c_loc(y0) +farg4 = inner_step_id +farg5 = inner_step_mem +fresult = swigc_FMRIStepCreate(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FMRIStepResize(arkode_mem, ynew, t0, resize, resize_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(N_Vector), target, intent(inout) :: ynew +real(C_DOUBLE), intent(in) :: t0 +type(C_FUNPTR), intent(in), value :: resize +type(C_PTR) :: resize_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_FUNPTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = arkode_mem +farg2 = c_loc(ynew) +farg3 = t0 +farg4 = resize +farg5 = resize_data +fresult = swigc_FMRIStepResize(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FMRIStepReInit(arkode_mem, fs, t0, y0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: fs +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: y0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 + +farg1 = arkode_mem +farg2 = fs +farg3 = t0 +farg4 = c_loc(y0) +fresult = swigc_FMRIStepReInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FMRIStepRootInit(arkode_mem, nrtfn, g) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: nrtfn +type(C_FUNPTR), intent(in), value :: g +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = arkode_mem +farg2 = nrtfn +farg3 = g +fresult = swigc_FMRIStepRootInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FMRIStepSetDefaults(arkode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = arkode_mem +fresult = swigc_FMRIStepSetDefaults(farg1) +swig_result = fresult +end function + +function FMRIStepSetInterpolantType(arkode_mem, itype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: itype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = itype +fresult = swigc_FMRIStepSetInterpolantType(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetInterpolantDegree(arkode_mem, degree) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: degree +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = degree +fresult = swigc_FMRIStepSetInterpolantDegree(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetDenseOrder(arkode_mem, dord) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: dord +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = dord +fresult = swigc_FMRIStepSetDenseOrder(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetTable(arkode_mem, q, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: q +type(C_PTR) :: b +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = q +farg3 = b +fresult = swigc_FMRIStepSetTable(farg1, farg2, farg3) +swig_result = fresult +end function + +function FMRIStepSetTableNum(arkode_mem, itable) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: itable +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = itable +fresult = swigc_FMRIStepSetTableNum(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetMaxNumSteps(arkode_mem, mxsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), intent(in) :: mxsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = arkode_mem +farg2 = mxsteps +fresult = swigc_FMRIStepSetMaxNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetMaxHnilWarns(arkode_mem, mxhnil) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), intent(in) :: mxhnil +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = arkode_mem +farg2 = mxhnil +fresult = swigc_FMRIStepSetMaxHnilWarns(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetStopTime(arkode_mem, tstop) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: tstop +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = tstop +fresult = swigc_FMRIStepSetStopTime(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetFixedStep(arkode_mem, hsfixed) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: hsfixed +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = arkode_mem +farg2 = hsfixed +fresult = swigc_FMRIStepSetFixedStep(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetRootDirection(arkode_mem, rootdir) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootdir +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(rootdir(1)) +fresult = swigc_FMRIStepSetRootDirection(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetNoInactiveRootWarn(arkode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = arkode_mem +fresult = swigc_FMRIStepSetNoInactiveRootWarn(farg1) +swig_result = fresult +end function + +function FMRIStepSetErrHandlerFn(arkode_mem, ehfun, eh_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: ehfun +type(C_PTR) :: eh_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = ehfun +farg3 = eh_data +fresult = swigc_FMRIStepSetErrHandlerFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FMRIStepSetErrFile(arkode_mem, errfp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: errfp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = errfp +fresult = swigc_FMRIStepSetErrFile(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetUserData(arkode_mem, user_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: user_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = user_data +fresult = swigc_FMRIStepSetUserData(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetDiagnostics(arkode_mem, diagfp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: diagfp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = diagfp +fresult = swigc_FMRIStepSetDiagnostics(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetPostprocessStepFn(arkode_mem, processstep) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: processstep +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = processstep +fresult = swigc_FMRIStepSetPostprocessStepFn(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetPostprocessStageFn(arkode_mem, processstage) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: processstage +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = processstage +fresult = swigc_FMRIStepSetPostprocessStageFn(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetPreInnerFn(arkode_mem, prefn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: prefn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = prefn +fresult = swigc_FMRIStepSetPreInnerFn(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepSetPostInnerFn(arkode_mem, postfn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_FUNPTR), intent(in), value :: postfn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = arkode_mem +farg2 = postfn +fresult = swigc_FMRIStepSetPostInnerFn(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepEvolve(arkode_mem, tout, yout, tret, itask) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: tout +type(N_Vector), target, intent(inout) :: yout +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +integer(C_INT), intent(in) :: itask +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +integer(C_INT) :: farg5 + +farg1 = arkode_mem +farg2 = tout +farg3 = c_loc(yout) +farg4 = c_loc(tret(1)) +farg5 = itask +fresult = swigc_FMRIStepEvolve(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FMRIStepGetDky(arkode_mem, t, k, dky) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(N_Vector), target, intent(inout) :: dky +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = arkode_mem +farg2 = t +farg3 = k +farg4 = c_loc(dky) +fresult = swigc_FMRIStepGetDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FMRIStepGetNumRhsEvals(arkode_mem, nfs_evals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfs_evals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nfs_evals(1)) +fresult = swigc_FMRIStepGetNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepGetCurrentButcherTables(arkode_mem, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR), target, intent(inout) :: b +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(b) +fresult = swigc_FMRIStepGetCurrentButcherTables(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepGetWorkSpace(arkode_mem, lenrw, leniw) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrw +integer(C_LONG), dimension(*), target, intent(inout) :: leniw +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = arkode_mem +farg2 = c_loc(lenrw(1)) +farg3 = c_loc(leniw(1)) +fresult = swigc_FMRIStepGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FMRIStepGetNumSteps(arkode_mem, nssteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nssteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(nssteps(1)) +fresult = swigc_FMRIStepGetNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepGetLastStep(arkode_mem, hlast) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(hlast(1)) +fresult = swigc_FMRIStepGetLastStep(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepGetCurrentTime(arkode_mem, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(tcur(1)) +fresult = swigc_FMRIStepGetCurrentTime(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepGetCurrentState(arkode_mem, ycur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: ycur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = ycur +fresult = swigc_FMRIStepGetCurrentState(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepGetNumGEvals(arkode_mem, ngevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(ngevals(1)) +fresult = swigc_FMRIStepGetNumGEvals(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepGetRootInfo(arkode_mem, rootsfound) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootsfound +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(rootsfound(1)) +fresult = swigc_FMRIStepGetRootInfo(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepGetLastInnerStepFlag(arkode_mem, flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +integer(C_INT), dimension(*), target, intent(inout) :: flag +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = c_loc(flag(1)) +fresult = swigc_FMRIStepGetLastInnerStepFlag(farg1, farg2) +swig_result = fresult +end function + + +subroutine SWIG_chararray_to_string(wrap, string) + use, intrinsic :: ISO_C_BINDING + type(SwigArrayWrapper), intent(IN) :: wrap + character(kind=C_CHAR, len=:), allocatable, intent(OUT) :: string + character(kind=C_CHAR), dimension(:), pointer :: chars + integer(kind=C_SIZE_T) :: i + call c_f_pointer(wrap%data, chars, [wrap%size]) + allocate(character(kind=C_CHAR, len=wrap%size) :: string) + do i=1, wrap%size + string(i:i) = chars(i) + end do +end subroutine + +function FMRIStepGetReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FMRIStepGetReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +function FMRIStepWriteParameters(arkode_mem, fp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: fp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = fp +fresult = swigc_FMRIStepWriteParameters(farg1, farg2) +swig_result = fresult +end function + +function FMRIStepWriteButcher(arkode_mem, fp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: arkode_mem +type(C_PTR) :: fp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = fp +fresult = swigc_FMRIStepWriteButcher(farg1, farg2) +swig_result = fresult +end function + +subroutine FMRIStepFree(arkode_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), target, intent(inout) :: arkode_mem +type(C_PTR) :: farg1 + +farg1 = c_loc(arkode_mem) +call swigc_FMRIStepFree(farg1) +end subroutine + +subroutine FMRIStepPrintMem(arkode_mem, outfile) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: arkode_mem +type(C_PTR) :: outfile +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = arkode_mem +farg2 = outfile +call swigc_FMRIStepPrintMem(farg1, farg2) +end subroutine + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/cvode/CMakeLists.txt index a97073005..a591122c6 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/CMakeLists.txt @@ -1,9 +1,9 @@ # --------------------------------------------------------------- -# Programmer(s): Daniel R. Reynolds @ SMU -# Radu Serban @ LLNL +# Programmer(s): Daniel R. Reynolds @ SMU +# Radu Serban @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -13,16 +13,17 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the CVODE library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall CVODE\n\")") +install(CODE "MESSAGE(\"\nInstall CVODE\n\")") # Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF(F90_FOUND AND F2003_INTERFACE_ENABLE) +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) # Add variable cvode_SOURCES with the sources for the CVODE library -SET(cvode_SOURCES +set(cvode_SOURCES cvode.c cvode_bandpre.c cvode_bbdpre.c @@ -36,7 +37,7 @@ SET(cvode_SOURCES # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the CVODE library -SET(shared_SOURCES +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_matrix.c ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c @@ -48,12 +49,13 @@ SET(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c ${sundials_SOURCE_DIR}/src/sundials/sundials_version.c ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector_senswrapper.c + ${sundials_SOURCE_DIR}/src/sundials/sundials_futils.c ${sundials_SOURCE_DIR}/src/nvector/serial/nvector_serial.c ) # Add variable sunmatrix_SOURCES with the common SUNMatrix sources which will # also be included in the CVODE library -SET(sunmatrix_SOURCES +set(sunmatrix_SOURCES ${sundials_SOURCE_DIR}/src/sunmatrix/band/sunmatrix_band.c ${sundials_SOURCE_DIR}/src/sunmatrix/dense/sunmatrix_dense.c ${sundials_SOURCE_DIR}/src/sunmatrix/sparse/sunmatrix_sparse.c @@ -61,7 +63,7 @@ SET(sunmatrix_SOURCES # Add variable sunlinsol_SOURCES with the common SUNLinearSolver sources which will # also be included in the CVODE library -SET(sunlinsol_SOURCES +set(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/band/sunlinsol_band.c ${sundials_SOURCE_DIR}/src/sunlinsol/dense/sunlinsol_dense.c ${sundials_SOURCE_DIR}/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c @@ -73,13 +75,13 @@ SET(sunlinsol_SOURCES # Add variable sunnonlinsol_SOURCES with the common SUNNonlinearSolver sources # which will also be included in the CVODE library -SET(sunnonlinsol_SOURCES +set(sunnonlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunnonlinsol/newton/sunnonlinsol_newton.c ${sundials_SOURCE_DIR}/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c ) # Add variable cvode_HEADERS with the exported CVODE header files -SET(cvode_HEADERS +set(cvode_HEADERS cvode.h cvode_bandpre.h cvode_bbdpre.h @@ -90,58 +92,58 @@ SET(cvode_HEADERS ) # Add prefix with complete path to the CVODE header files -ADD_PREFIX(${sundials_SOURCE_DIR}/include/cvode/ cvode_HEADERS) +add_prefix(${sundials_SOURCE_DIR}/include/cvode/ cvode_HEADERS) # Add source directories to include directories for access to # implementation only header files. -INCLUDE_DIRECTORIES(.) -INCLUDE_DIRECTORIES(../sundials) +include_directories(.) +include_directories(../sundials) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) # Build the static library -IF(BUILD_STATIC_LIBS) +if(BUILD_STATIC_LIBS) # Add the build target for the static CVODE library - ADD_LIBRARY(sundials_cvode_static STATIC + add_library(sundials_cvode_static STATIC ${cvode_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ${sunnonlinsol_SOURCES} ) # Set the library name and make sure it is not deleted - SET_TARGET_PROPERTIES(sundials_cvode_static + set_target_properties(sundials_cvode_static PROPERTIES OUTPUT_NAME sundials_cvode CLEAN_DIRECT_OUTPUT 1) # Install the CVODE library - INSTALL(TARGETS sundials_cvode_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS sundials_cvode_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +endif(BUILD_STATIC_LIBS) # Build the shared library -IF(BUILD_SHARED_LIBS) +if(BUILD_SHARED_LIBS) # Add the build target for the shared CVODE library - ADD_LIBRARY(sundials_cvode_shared SHARED + add_library(sundials_cvode_shared SHARED ${cvode_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ${sunnonlinsol_SOURCES} ) - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_cvode_shared m) - ENDIF() + if(UNIX) + target_link_libraries(sundials_cvode_shared m) + endif() # Set the library name and make sure it is not deleted - SET_TARGET_PROPERTIES(sundials_cvode_shared + set_target_properties(sundials_cvode_shared PROPERTIES OUTPUT_NAME sundials_cvode CLEAN_DIRECT_OUTPUT 1) # Set VERSION and SOVERSION for shared libraries - SET_TARGET_PROPERTIES(sundials_cvode_shared + set_target_properties(sundials_cvode_shared PROPERTIES VERSION ${cvodelib_VERSION} SOVERSION ${cvodelib_SOVERSION}) # Install the CVODE library - INSTALL(TARGETS sundials_cvode_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS sundials_cvode_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) +endif(BUILD_SHARED_LIBS) # Install the CVODE header files -INSTALL(FILES ${cvode_HEADERS} DESTINATION include/cvode) +install(FILES ${cvode_HEADERS} DESTINATION include/cvode) # -MESSAGE(STATUS "Added CVODE module") +message(STATUS "Added CVODE module") diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/cvode/F90/CMakeLists.txt deleted file mode 100644 index 1c5ae2946..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/F90/CMakeLists.txt +++ /dev/null @@ -1,116 +0,0 @@ -# --------------------------------------------------------------- -# Programmer: Cody J. Balos @ LLNL -# --------------------------------------------------------------- -# SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security -# and Southern Methodist University. -# All rights reserved. -# -# See the top-level LICENSE and NOTICE files for details. -# -# SPDX-License-Identifier: BSD-3-Clause -# SUNDIALS Copyright End -# --------------------------------------------------------------- -# CMakeLists.txt file for the F2003 CVODE object library - -set(cvode_SOURCES fcvode.f90) - -# Add variable nvec_SOURCES with the common NVECTOR sources which will -# also be included in the CVODE library -set(nvec_SOURCES - ${sundials_SOURCE_DIR}/src/nvector/serial/F90/fnvector_serial.f90 -) - -# Add variable sunmatrix_SOURCES with the common SUNMatrix sources which will -# also be included in the CVODE library -set(sunmatrix_SOURCES - ${sundials_SOURCE_DIR}/src/sunmatrix/band/F90/fsunmatrix_band.f90 - ${sundials_SOURCE_DIR}/src/sunmatrix/dense/F90/fsunmatrix_dense.f90 - ${sundials_SOURCE_DIR}/src/sunmatrix/sparse/F90/fsunmatrix_sparse.f90 -) - -# Add variable sunlinsol_SOURCES with the common SUNLinearSolver sources which will -# also be included in the CVODE library -set(sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/band/F90/fsunlinsol_band.f90 - ${sundials_SOURCE_DIR}/src/sunlinsol/dense/F90/fsunlinsol_dense.f90 - ${sundials_SOURCE_DIR}/src/sunlinsol/spbcgs/F90/fsunlinsol_spbcgs.f90 - ${sundials_SOURCE_DIR}/src/sunlinsol/spfgmr/F90/fsunlinsol_spfgmr.f90 - ${sundials_SOURCE_DIR}/src/sunlinsol/spgmr/F90/fsunlinsol_spgmr.f90 - ${sundials_SOURCE_DIR}/src/sunlinsol/sptfqmr/F90/fsunlinsol_sptfqmr.f90 - ${sundials_SOURCE_DIR}/src/sunlinsol/pcg/F90/fsunlinsol_pcg.f90 -) - -# Add variable sunnonlinsol_SOURCES with the common SUNNonlinearSolver sources -# which will also be included in the CVODE library -set(sunnonlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunnonlinsol/newton/F90/fsunnonlinsol_newton.f90 - ${sundials_SOURCE_DIR}/src/sunnonlinsol/fixedpoint/F90/fsunnonlinsol_fixedpoint.f90 -) - -# Set the Fortran module directory to a temporary location. -# We do this to avoid naming collisions in parallel builds (make -j). -# The .mod files generated when building the fcvode_mod library are -# duplicates of the .mod files generated by the SUNDIALS modules themselves. -# As such, we do not need to keep them around. -set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/tmp) - -if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fcvode_mod_static STATIC - ${cvode_SOURCES} - ${nvec_SOURCES} - ${sunmatrix_SOURCES} - ${sunlinsol_SOURCES} - ${sunnonlinsol_SOURCES} - ) - - # include the directoy where the .mod files reside - target_include_directories(sundials_fcvode_mod_static - PUBLIC - $ - $ - ) - - # Set the library name and make sure it is not deleted - set_target_properties(sundials_fcvode_mod_static - PROPERTIES OUTPUT_NAME sundials_fcvode_mod CLEAN_DIRECT_OUTPUT 1) - - # install the library - install(TARGETS sundials_fcvode_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - - # install the cvode mod file from here since it won't go into the - # top level fortran mod file directory - install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_STATIC/fcvode_mod.mod - DESTINATION ${Fortran_INSTALL_MODDIR}) -endif() - -if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fcvode_mod_shared SHARED - ${cvode_SOURCES} - ${nvec_SOURCES} - ${sunmatrix_SOURCES} - ${sunlinsol_SOURCES} - ${sunnonlinsol_SOURCES} - ) - - # include the directoy where the .mod files reside - target_include_directories(sundials_fcvode_mod_shared - PUBLIC - $ - $ - ) - - # Set the library name and make sure it is not deleted - set_target_properties(sundials_fcvode_mod_shared - PROPERTIES OUTPUT_NAME sundials_fcvode_mod CLEAN_DIRECT_OUTPUT 1) - - # install the library - install(TARGETS sundials_fcvode_mod_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - - # install the cvode mod file from here since it won't go into the - # top level fortran mod file directory - install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_SHARED/fcvode_mod.mod - DESTINATION ${Fortran_INSTALL_MODDIR}) -endif() - -message(STATUS "Added CVODE F2003 interface") diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/F90/fcvode.f90 b/deps/AMICI/ThirdParty/sundials/src/cvode/F90/fcvode.f90 deleted file mode 100644 index 148235146..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/F90/fcvode.f90 +++ /dev/null @@ -1,887 +0,0 @@ -! ------------------------------------------------------------------ -! Programmer(s): David J. Gardner @ LLNL -! Daniel R. Reynolds @ SMU -! ------------------------------------------------------------------ -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ------------------------------------------------------------------ -! This file contains a Fortran module for interfacing directly with -! CVODE using the ISO_C_BINDING module. -! ------------------------------------------------------------------ - -module fcvode_mod - - use, intrinsic :: iso_c_binding, only : c_int - - ! ================================================================= - ! C V O D E C O N S T A N T S - ! ================================================================= - - ! ----------------------------------------------------------------- - ! Enumerations for inputs to CVodeCreate and CVode. - ! ----------------------------------------------------------------- - - ! lmm - integer(c_int), parameter :: CV_ADAMS = 1 - integer(c_int), parameter :: CV_BDF = 2 - - ! itask - integer(c_int), parameter :: CV_NORMAL = 1 - integer(c_int), parameter :: CV_ONE_STEP = 2 - - ! ----------------------------------------------------------------- - ! CVODE return flags - ! ----------------------------------------------------------------- - - integer(c_int), parameter :: CV_SUCCESS = 0 - integer(c_int), parameter :: CV_TSTOP_RETURN = 1 - integer(c_int), parameter :: CV_ROOT_RETURN = 2 - - integer(c_int), parameter :: CV_WARNING = 99 - - integer(c_int), parameter :: CV_TOO_MUCH_WORK = -1 - integer(c_int), parameter :: CV_TOO_MUCH_ACC = -2 - integer(c_int), parameter :: CV_ERR_FAILURE = -3 - integer(c_int), parameter :: CV_CONV_FAILURE = -4 - - integer(c_int), parameter :: CV_LINIT_FAIL = -5 - integer(c_int), parameter :: CV_LSETUP_FAIL = -6 - integer(c_int), parameter :: CV_LSOLVE_FAIL = -7 - integer(c_int), parameter :: CV_RHSFUNC_FAIL = -8 - integer(c_int), parameter :: CV_FIRST_RHSFUNC_ERR = -9 - integer(c_int), parameter :: CV_REPTD_RHSFUNC_ERR = -10 - integer(c_int), parameter :: CV_UNREC_RHSFUNC_ERR = -11 - integer(c_int), parameter :: CV_RTFUNC_FAIL = -12 - integer(c_int), parameter :: CV_NLS_INIT_FAIL = -13 - integer(c_int), parameter :: CV_NLS_SETUP_FAIL = -14 - integer(c_int), parameter :: CV_CONSTR_FAIL = -15 - - integer(c_int), parameter :: CV_MEM_FAIL = -20 - integer(c_int), parameter :: CV_MEM_NULL = -21 - integer(c_int), parameter :: CV_ILL_INPUT = -22 - integer(c_int), parameter :: CV_NO_MALLOC = -23 - integer(c_int), parameter :: CV_BAD_K = -24 - integer(c_int), parameter :: CV_BAD_T = -25 - integer(c_int), parameter :: CV_BAD_DKY = -26 - integer(c_int), parameter :: CV_TOO_CLOSE = -27 - integer(c_int), parameter :: CV_VECTOROP_ERR = -28 - - ! ----------------------------------------------------------------- - ! CVLS return values - ! ----------------------------------------------------------------- - - integer(c_int), parameter :: CVLS_SUCCESS = 0 - integer(c_int), parameter :: CVLS_MEM_NULL = -1 - integer(c_int), parameter :: CVLS_LMEM_NULL = -2 - integer(c_int), parameter :: CVLS_ILL_INPUT = -3 - integer(c_int), parameter :: CVLS_MEM_FAIL = -4 - integer(c_int), parameter :: CVLS_PMEM_NULL = -5 - integer(c_int), parameter :: CVLS_JACFUN_UNRECVR = -6 - integer(c_int), parameter :: CVLS_JACFUNC_RECVR = -7 - integer(c_int), parameter :: CVLS_SUNMAT_FAIL = -8 - integer(c_int), parameter :: CVLS_SUNLS_FAIL = -9 - - ! ----------------------------------------------------------------- - ! CVDIAG return values - ! ----------------------------------------------------------------- - - integer(c_int), parameter :: CVDIAG_SUCCESS = 0 - integer(c_int), parameter :: CVDIAG_MEM_NULL = -1 - integer(c_int), parameter :: CVDIAG_LMEM_NULL = -2 - integer(c_int), parameter :: CVDIAG_ILL_INPUT = -3 - integer(c_int), parameter :: CVDIAG_MEM_FAIL = -4 - - ! Additional last_flag values - integer(c_int), parameter :: CVDIAG_INV_FAIL = -5 - integer(c_int), parameter :: CVDIAG_RHSFUNC_UNRECVR = -6 - integer(c_int), parameter :: CVDIAG_RHSFUNC_RECVR = -7 - - ! ================================================================= - ! U S E R - C A L L A B L E R O U T I N E S - ! ================================================================= - - interface - - ! ================================================================= - ! Interfaces for cvode.h - ! ================================================================= - - ! ----------------------------------------------------------------- - ! CVodeCreate - ! ----------------------------------------------------------------- - - type(c_ptr) function FCVodeCreate(lmm) & - bind(C,name='CVodeCreate') - use, intrinsic :: iso_c_binding - implicit none - integer(c_int), value :: lmm - end function FCVodeCreate - - ! ----------------------------------------------------------------- - ! Integrator optional input specification functions - ! ----------------------------------------------------------------- - - integer(c_int) function FCVodeSetErrHandlerFn(cvode_mem, ehfun, eh_data) & - bind(C,name='CVodeSetErrHandlerFn') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - type(c_funptr), value :: ehfun - type(c_ptr), value :: eh_data - end function FCVodeSetErrHandlerFn - - ! ----------------------------------------------------------------- - ! NOT INTERFACED: CVodeSetErrFile - ! ----------------------------------------------------------------- - - integer(c_int) function FCVodeSetUserData(cvode_mem, user_data) & - bind(C,name='CVodeSetUserData') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - type(c_ptr), value :: user_data - end function FCVodeSetUserData - - integer(c_int) function FCVodeSetMaxOrd(cvode_mem, maxord) & - bind(C,name='CVodeSetMaxOrd') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_int), value :: maxord - end function FCVodeSetMaxOrd - - integer(c_int) function FCVodeSetMaxNumSteps(cvode_mem, mxsteps) & - bind(C,name='CVodeSetMaxNumSteps') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long), value :: mxsteps - end function FCVodeSetMaxNumSteps - - integer(c_int) function FCVodeSetMaxHnilWarns(cvode_mem, mxhnil) & - bind(C,name='CVodeSetMaxHnilWarns') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_int), value :: mxhnil - end function FCVodeSetMaxHnilWarns - - integer(c_int) function FCVodeSetStabLimDet(cvode_mem, stldet) & - bind(C,name='CVodeSetStabLimDet') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_int), value :: stldet - end function FCVodeSetStabLimDet - - integer(c_int) function FCVodeSetInitStep(cvode_mem, hin) & - bind(C,name='CVodeSetInitStep') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double), value :: hin - end function FCVodeSetInitStep - - integer(c_int) function FCVodeSetMinStep(cvode_mem, hmin) & - bind(C,name='CVodeSetMinStep') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double), value :: hmin - end function FCVodeSetMinStep - - integer(c_int) function FCVodeSetMaxStep(cvode_mem, hmax) & - bind(C,name='CVodeSetMaxStep') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double), value :: hmax - end function FCVodeSetMaxStep - - integer(c_int) function FCVodeSetStopTime(cvode_mem, tstop) & - bind(C,name='CVodeSetStopTime') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double), value :: tstop - end function FCVodeSetStopTime - - integer(c_int) function FCVodeSetMaxErrTestFails(cvode_mem, maxnef) & - bind(C,name='CVodeSetMaxErrTestFails') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_int), value :: maxnef - end function FCVodeSetMaxErrTestFails - - integer(c_int) function FCVodeSetMaxNonlinIters(cvode_mem, maxcor) & - bind(C,name='CVodeSetMaxNonlinIters') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_int), value :: maxcor - end function FCVodeSetMaxNonlinIters - - integer(c_int) function FCVodeSetMaxConvFails(cvode_mem, maxncf) & - bind(C,name='CVodeSetMaxConvFails') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_int), value :: maxncf - end function FCVodeSetMaxConvFails - - integer(c_int) function FCVodeSetNonlinConvCoef(cvode_mem, nlscoef) & - bind(C,name='CVodeSetNonlinConvCoef') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double), value :: nlscoef - end function FCVodeSetNonlinConvCoef - - integer(c_int) function FCVodeSetConstraints(cvode_mem, constraints) & - bind(C,name='CVodeSetConstraints') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - type(c_ptr), value :: constraints - end function FCVodeSetConstraints - - integer(c_int) function FCVodeSetIterType(cvode_mem, iter) & - bind(C,name='CVodeSetIterType') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double), value :: iter - end function FCVodeSetIterType - - integer(c_int) function FCVodeSetRootDirection(cvode_mem, rootdir) & - bind(C,name='CVodeSetRootDirection') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double) :: rootdir - end function FCVodeSetRootDirection - - integer(c_int) function FCVodeSetNoInactiveRootWarn(cvode_mem) & - bind(C,name='CVodeSetNoInactiveRootWarn') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - end function FCVodeSetNoInactiveRootWarn - - integer(c_int) function FCVodeSetNonlinearSolver(cvode_mem, NLS) & - bind(C,name='CVodeSetNonlinearSolver') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - type(c_ptr), value :: NLS - end function FCVodeSetNonlinearSolver - - ! ----------------------------------------------------------------- - ! CVodeInit - ! ----------------------------------------------------------------- - - integer(c_int) function FCVodeInit(cvode_mem, f, t0, y0) & - bind(C,name='CVodeInit') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - type(c_funptr), value :: f - real(c_double), value :: t0 - type(c_ptr), value :: y0 - end function FCVodeInit - - ! ----------------------------------------------------------------- - ! CVodeReInit - ! ----------------------------------------------------------------- - - integer(c_int) function FCVodeReInit(cvode_mem, t0, y0) & - bind(C,name='CVodeReInit') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double), value :: t0 - type(c_ptr), value :: y0 - end function FCVodeReInit - - ! ----------------------------------------------------------------- - ! CVodeSStolerances - ! CVodeSVtolerances - ! CVodeWFtolerances - ! ----------------------------------------------------------------- - - integer(c_int) function FCVodeSStolerances(cvode_mem, reltol, abstol) & - bind(C,name='CVodeSStolerances') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double), value :: reltol - real(c_double), value :: abstol - end function FCVodeSStolerances - - integer(c_int) function FCVodeSVtolerances(cvode_mem, reltol, abstol) & - bind(C,name='CVodeSVtolerances') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double), value :: reltol - type(c_ptr), value :: abstol - end function FCVodeSVtolerances - - integer(c_int) function FCVodeWFtolerances(cvode_mem, efun) & - bind(C,name='CVodeWFtolerances') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - type(c_funptr), value :: efun - end function FCVodeWFtolerances - - ! ----------------------------------------------------------------- - ! CVodeRootInit - ! ----------------------------------------------------------------- - - integer(c_int) function FCVodeRootInit(cvode_mem, nrtfn, g) & - bind(C,name='CVodeRootInit') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_int), value :: nrtfn - type(c_funptr), value :: g - end function FCVodeRootInit - - ! ----------------------------------------------------------------- - ! CVode - ! ----------------------------------------------------------------- - - integer(c_int) function FCVode(cvode_mem, tout, yout, tret, itask) & - bind(C,name='CVode') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double), value :: tout - type(c_ptr), value :: yout - real(c_double) :: tret - integer(c_int), value :: itask - end function FCVode - - ! ----------------------------------------------------------------- - ! CVodeGetDky - ! ----------------------------------------------------------------- - - integer(c_int) function FCVodeGetDky(cvode_mem, t, k, dky) & - bind(C,name='CVodeGetDky') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double), value :: t - integer(c_int), value :: k - type(c_ptr), value :: dky - end function FCVodeGetDky - - ! ----------------------------------------------------------------- - ! Integrator optional output extraction functions - ! ----------------------------------------------------------------- - - integer(c_int) function FCVodeGetWorkSpace(cvode_mem, lenrw, leniw) & - bind(C,name='CVodeGetWorkSpace') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: lenrw - integer(c_long) :: leniw - end function FCVodeGetWorkSpace - - integer(c_int) function FCVodeGetNumSteps(cvode_mem, nsteps) & - bind(C,name='CVodeGetNumSteps') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nsteps - end function FCVodeGetNumSteps - - integer(c_int) function FCVodeGetNumRhsEvals(cvode_mem, nfevals) & - bind(C,name='CVodeGetNumRhsEvals') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nfevals - end function FCVodeGetNumRhsEvals - - integer(c_int) function FCVodeGetNumLinSolvSetups(cvode_mem, nlinsetups) & - bind(C,name='CVodeGetNumLinSolvSetups') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nlinsetups - end function FCVodeGetNumLinSolvSetups - - integer(c_int) function FCVodeGetNumErrTestFails(cvode_mem, netfails) & - bind(C,name='CVodeGetNumErrTestFails') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: netfails - end function FCVodeGetNumErrTestFails - - integer(c_int) function FCVodeGetLastOrder(cvode_mem, qlast) & - bind(C,name='CVodeGetLastOrder') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_int) :: qlast - end function FCVodeGetLastOrder - - integer(c_int) function FCVodeGetCurrentOrder(cvode_mem, qcur) & - bind(C,name='CVodeGetCurrentOrder') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_int) :: qcur - end function FCVodeGetCurrentOrder - - integer(c_int) function FCVodeGetNumStabLimOrderReds(cvode_mem, nslred) & - bind(C,name='CVodeGetNumStabLimOrderReds') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nslred - end function FCVodeGetNumStabLimOrderReds - - integer(c_int) function FCVodeGetActualInitStep(cvode_mem, hinused) & - bind(C,name='CVodeGetActualInitStep') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double) :: hinused - end function FCVodeGetActualInitStep - - integer(c_int) function FCVodeGetLastStep(cvode_mem, hlast) & - bind(C,name='CVodeGetLastStep') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double) :: hlast - end function FCVodeGetLastStep - - integer(c_int) function FCVodeGetCurrentStep(cvode_mem, hcur) & - bind(C,name='CVodeGetCurrentStep') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double) :: hcur - end function FCVodeGetCurrentStep - - integer(c_int) function FCVodeGetCurrentTime(cvode_mem, tcur) & - bind(C,name='CVodeGetCurrentTime') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double) :: tcur - end function FCVodeGetCurrentTime - - integer(c_int) function FCVodeGetTolScaleFactor(cvode_mem, tolsfac) & - bind(C,name='CVodeGetTolScaleFactor') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double) :: tolsfac - end function FCVodeGetTolScaleFactor - - integer(c_int) function FCVodeGetErrWeights(cvode_mem, eweight) & - bind(C,name='CVodeGetEffWeights') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - type(c_ptr), value :: eweight - end function FCVodeGetErrWeights - - integer(c_int) function FCVodeGetEstLocalErrors(cvode_mem, ele) & - bind(C,name='CVodeGetEstLocalErrors') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - type(c_ptr), value :: ele - end function FCVodeGetEstLocalErrors - - integer(c_int) function FCVodeGetNumGEvals(cvode_mem, ngevals) & - bind(C,name='CVodeGetNumGEvals') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: ngevals - end function FCVodeGetNumGEvals - - integer(c_int) function FCVodeGetRootInfo(cvode_mem, rootsfound) & - bind(C,name='CVodeGetRootInfo') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_int) :: rootsfound - end function FCVodeGetRootInfo - - integer(c_int) function FCVodeGetIntegratorStats(cvode_mem, nsteps, nfevals, & - nlinsetups, netfails, qlast, qcur, hinused, hlast, hcur, tcur) & - bind(C,name='CVodeGetIntegratorStats') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nsteps - integer(c_long) :: nfevals - integer(c_long) :: nlinsetups - integer(c_long) :: netfails - integer(c_int) :: qlast - integer(c_int) :: qcur - real(c_double) :: hinused - real(c_double) :: hlast - real(c_double) :: hcur - real(c_double) :: tcur - end function FCVodeGetIntegratorStats - - ! ----------------------------------------------------------------- - ! Nonlinear solver optional output extraction functions - ! ----------------------------------------------------------------- - - integer(c_int) function FCVodeGetNumNonlinSolvIters(cvode_mem, nniters) & - bind(C,name='CVodeGetNumNonlinSolvIters') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nniters - end function FCVodeGetNumNonlinSolvIters - - integer(c_int) function FCVodeGetNumNonlinSolvConvFails(cvode_mem, nncfails) & - bind(C,name='CVodeGetNumNonlinSolvConvFails') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nncfails - end function FCVodeGetNumNonlinSolvConvFails - - integer(c_int) function FCVodeGetNonlinSolvStats(cvode_mem, nniters, nncfails) & - bind(C,name='CVodeGetNonlinSolvStats') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nniters - integer(c_long) :: nncfails - end function FCVodeGetNonlinSolvStats - - ! ----------------------------------------------------------------- - ! NOT INTERFACED: CVodeGetReturnFlagName - ! ----------------------------------------------------------------- - - ! ----------------------------------------------------------------- - ! CVodeFree - ! ----------------------------------------------------------------- - - subroutine FCVodeFree(cvode_mem) & - bind(C,name='CVodeFree') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr) :: cvode_mem ! DO NOT use value attribute input is void** - end subroutine FCVodeFree - - ! ================================================================= - ! Interfaces from cvode_ls.h - ! ================================================================= - - integer(c_int) function FCVodeSetLinearSolver(cvode_mem, LS, A) & - bind(C,name='CVodeSetLinearSolver') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - type(c_ptr), value :: LS - type(c_ptr), value :: A - end function FCVodeSetLinearSolver - - ! ----------------------------------------------------------------- - ! Optional inputs to the CVLS linear solver - ! ----------------------------------------------------------------- - - integer(c_int) function FCVodeSetJacFn(cvode_mem, jac) & - bind(C,name='CVodeSetJacFn') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - type(c_funptr), value :: jac - end function FCVodeSetJacFn - - integer(c_int) function FCVodeSetMaxStepsBetweenJac(cvode_mem, msbj) & - bind(C,name='CVodeSetMaxStepsBetweenJac') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long), value :: msbj - end function FCVodeSetMaxStepsBetweenJac - - integer(c_int) function FCVodeSetEpsLin(cvode_mem, eplifac) & - bind(C,name='CVodeSetEpsLin') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - real(c_double), value :: eplifac - end function FCVodeSetEpsLin - - integer(c_int) function FCVodeSetPreconditioner(cvode_mem, pset, psolve) & - bind(C,name='CVodeSetPreconditioner') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - type(c_funptr), value :: pset - type(c_funptr), value :: psolve - end function FCVodeSetPreconditioner - - integer(c_int) function FCVodeSetJacTimes(cvode_mem, jtsetup, jtimes) & - bind(C,name='CVodeSetJacTimes') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - type(c_funptr), value :: jtsetup - type(c_funptr), value :: jtimes - end function FCVodeSetJacTimes - - ! ----------------------------------------------------------------- - ! Optional outputs from the CVLS linear solver - ! ----------------------------------------------------------------- - - integer(c_int) function FCVodeGetLinWorkSpace(cvode_mem, lenrwLS, leniwLS) & - bind(C,name='CVodeGetLinWorkSpace') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: lenrwLS - integer(c_long) :: leniwLS - end function FCVodeGetLinWorkSpace - - integer(c_int) function FCVodeGetNumJacEvals(cvode_mem, njevals) & - bind(C,name='CVodeGetNumJacEvals') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: njevals - end function FCVodeGetNumJacEvals - - integer(c_int) function FCVodeGetNumPrecEvals(cvode_mem, npevals) & - bind(C,name='CVodeGetNumPrecEvals') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: npevals - end function FCVodeGetNumPrecEvals - - integer(c_int) function FCVodeGetNumPrecSolves(cvode_mem, npsolves) & - bind(C,name='CVodeGetNumPrecSolves') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: npsolves - end function FCVodeGetNumPrecSolves - - integer(c_int) function FCVodeGetNumLinIters(cvode_mem, nliters) & - bind(C,name='CVodeGetNumLinIters') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nliters - end function FCVodeGetNumLinIters - - integer(c_int) function FCVodeGetNumLinConvFails(cvode_mem, nlcfails) & - bind(C,name='CVodeGetNumLinConvFails') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nlcfails - end function FCVodeGetNumLinConvFails - - integer(c_int) function FCVodeGetNumJTSetupEvals(cvode_mem, njtsetups) & - bind(C,name='CVodeGetNumJTSetupEvals') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: njtsetups - end function FCVodeGetNumJTSetupEvals - - integer(c_int) function FCVodeGetNumJtimesEvals(cvode_mem, njvevals) & - bind(C,name='CVodeGetNumJtimesEvals') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: njvevals - end function FCVodeGetNumJtimesEvals - - integer(c_int) function FCVodeGetNumLinRhsEvals(cvode_mem, nfevalsLS) & - bind(C,name='CVodeGetNumLinRhsEvals') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nfevalsLS - end function FCVodeGetNumLinRhsEvals - - integer(c_int) function FCVodeGetLastLinFlag(cvode_mem, flag) & - bind(C,name='CVodeGetLastLinFlag') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: flag - end function FCVodeGetLastLinFlag - - ! ----------------------------------------------------------------- - ! NOT INTERFACED: CVodeGetLinReturnFlagName - ! ----------------------------------------------------------------- - - ! ================================================================= - ! Interfaces for cvode_diag.h - ! ================================================================= - - ! ----------------------------------------------------------------- - ! CVDiag - ! ----------------------------------------------------------------- - - integer(c_int) function FCVDiag(cvode_mem) & - bind(C,name='CVDiag') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - end function FCVDiag - - ! ----------------------------------------------------------------- - ! Optional outputs from the CVDIAG linear solver - ! ----------------------------------------------------------------- - - integer(c_int) function FCVDiagGetWorkSpace(cvode_mem, lenrwLS, leniwLS) & - bind(C,name='CVDiagGetWorkSpace') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: lenrwLS - integer(c_long) :: leniwLS - end function FCVDiagGetWorkSpace - - integer(c_int) function FCVDiagGetNumRhsEvals(cvode_mem, nfevalsLS) & - bind(C,name='CVDiagGetNumRhsEvals') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nfevalsLS - end function FCVDiagGetNumRhsEvals - - integer(c_int) function FCVDiagGetLastFlag(cvode_mem, flag) & - bind(C,name='CVDiagGetLastFlag') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: flag - end function FCVDiagGetLastFlag - - ! ----------------------------------------------------------------- - ! NOT INTERFACED: CVDiagGetReturnFlagName - ! ----------------------------------------------------------------- - - ! ================================================================= - ! Interfaces from cvode_bandpre.h - ! ================================================================= - - ! ----------------------------------------------------------------- - ! CVBandPrecInit - ! ----------------------------------------------------------------- - - integer(c_int) function FCVBandPrecInit(cvode_mem, N, mu, ml) & - bind(C,name='CVBandPrecInit') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long), value :: N - integer(c_long), value :: mu - integer(c_long), value :: ml - end function FCVBandPrecInit - - ! ----------------------------------------------------------------- - ! Optional output functions : CVBandPrecGet* - ! ----------------------------------------------------------------- - - integer(c_int) function FCVBandPrecGetWorkSpace(cvode_mem, lenrwLS, leniwLS) & - bind(C,name='CVBandPrecGetWorkSpace') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: lenrwLS - integer(c_long) :: leniwLS - end function FCVBandPrecGetWorkSpace - - integer(c_int) function FCVBandPrecGetNumRhsEvals(cvode_mem, nfevalsBP) & - bind(C,name='CVBandPrecGetNumRhsEvals') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: nfevalsBP - end function FCVBandPrecGetNumRhsEvals - - ! ================================================================= - ! Interfaces for cvode_bbdpre.h - ! ================================================================= - - ! ----------------------------------------------------------------- - ! CVBBDPrecInit - ! ----------------------------------------------------------------- - - integer(c_int) function FCVBBDPrecInit(cvode_mem, Nlocal, mudq, mldq, & - mukeep, mlkeep, dqrely, gloc, cfn) & - bind(C,name='CVBBDPrecInit') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long), value :: Nlocal - integer(c_long), value :: mudq - integer(c_long), value :: mldq - integer(c_long), value :: mukeep - integer(c_long), value :: mlkeep - real(c_double), value :: dqrely - type(c_funptr), value :: gloc - type(c_funptr), value :: cfn - end function FCVBBDPrecInit - - ! ----------------------------------------------------------------- - ! CVBBDPrecReInit - ! ----------------------------------------------------------------- - - integer(c_int) function FCVBBDPrecReInit(cvode_mem, mudq, mldq, dqrely) & - bind(C,name='CVBBNPrecReInit') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long), value :: mudq - integer(c_long), value :: mldq - real(c_double), value :: dqrely - end function FCVBBDPrecReInit - - ! ----------------------------------------------------------------- - ! BBDPRE optional output extraction routines - ! ----------------------------------------------------------------- - - integer(c_int) function FCVBBDPrecGetWorkSpace(cvode_mem, lenrwLS, leniwLS) & - bind(C,name='CVBBDPrecGetWorkSpace') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: lenrwLS - integer(c_long) :: leniwLS - end function FCVBBDPrecGetWorkSpace - - integer(c_int) function FCVBBDPrecGetNumGfnEvals(cvode_mem, ngevalsBBDP) & - bind(C,name='CVBBDPrecGetNumGfnEvals') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: cvode_mem - integer(c_long) :: ngevalsBBDP - end function FCVBBDPrecGetNumGfnEvals - - end interface - -end module fcvode_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/README b/deps/AMICI/ThirdParty/sundials/src/cvode/README deleted file mode 100644 index b6344ba13..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/README +++ /dev/null @@ -1,102 +0,0 @@ - CVODE - Release 4.1.0, Feb 2019 - Alan C. Hindmarsh and Radu Serban - Center for Applied Scientific Computing, LLNL - -CVODE is a solver for stiff and nonstiff ODE systems (initial value problem) -given in explicit form dy/dt = f(t,y). It is written in ANSI standard C. - -CVODE can be used both on serial and parallel computers. The main -difference is in the NVECTOR module of vector kernels. The desired -version is obtained when compiling the example files by linking the -appropriate library of NVECTOR kernels. In the parallel versions, -communication between processors is done with MPI, with OpenMP, or with Pthreads. - -When used with the serial NVECTOR module, CVODE provides both direct (dense -and band) and preconditioned Krylov (iterative) linear solvers. Three different -iterative solvers are available: scaled preconditioned GMRES (SPGMR), scaled -preconditioned BiCGStab (SPBCG), and scaled preconditioned TFQMR (SPTFQMR). -When CVODE is used with the parallel NVECTOR module, only the Krylov linear solvers -are available. (An approximate diagonal Jacobian option is available with both -versions.) For the serial version, there is a banded preconditioner module -called CVBANDPRE available for use with the Krylov solvers, while for the parallel -version there is a preconditioner module called CVBBDPRE which provides a -band-block-diagonal preconditioner. - -CVODE is part of a software family called SUNDIALS: SUite of Nonlinear -and DIfferential/ALgebraic equation Solvers. This suite consists of -CVODE, CVODES, ARKode, KINSOL, IDAS, and IDA, and variants of these. -The directory structure of the package supplied reflects this family -relationship. - -For use with Fortran applications, a set of Fortran/C interface routines, -called FCVODE, is also supplied. These are written in C, but assume that -the user calling program and all user-supplied routines are in Fortran. - -The notes below provide the location of documentation, directions for the -installation of the CVODE package, and relevant references. Following that -is a brief history of revisions to the package. - - -A. Documentation ----------------- - -/sundials/doc/cvode/ contains PDF files for the CVODE User Guide [1] (cv_guide.pdf) -and the CVODE Examples [2] (cv_examples.pdf) documents. - - -B. Installation ---------------- - -For basic installation instructions see the file /sundials/INSTALL_GUIDE.pdf. -For complete installation instructions see the "Installation Procedure" -chapter in the CVODE User Guide. - - -C. References -------------- - -[1] A. C. Hindmarsh and R. Serban, "User Documentation for CVODE v2.9.0," - LLNL technical report UCRL-SM-208108, March 2016. - -[2] A. C. Hindmarsh and R. Serban, "Example Programs for CVODE v2.9.0," - LLNL technical report UCRL-SM-208110, March 2016. - -[3] S.D. Cohen and A.C. Hindmarsh, "CVODE, a Stiff/nonstiff ODE Solver in C," - Computers in Physics, 10(2), pp. 138-143, 1996. - -[4] A. C. Hindmarsh, P. N. Brown, K. E. Grant, S. L. Lee, R. Serban, - D. E. Shumaker, and C. S. Woodward, "SUNDIALS, Suite of Nonlinear and - Differential/Algebraic Equation Solvers," ACM Trans. Math. Softw., - 31(3), pp. 363-396, 2005. - - -D. Releases ------------ - -v. 4.1.0 - Feb. 2019 -v. 4.0.2 - Jan. 2019 -v. 4.0.1 - Dec. 2018 -v. 4.0.0 - Dec. 2018 -v. 3.2.1 - Oct. 2018 -v. 3.2.0 - Sep. 2018 -v. 3.1.2 - Jul. 2018 -v. 3.1.1 - May 2018 -v. 3.1.0 - Nov. 2017 -v. 3.0.0 - Sep. 2017 -v. 2.9.0 - Sep. 2016 -v. 2.8.2 - Aug. 2015 -v. 2.8.1 - Mar. 2015 -v. 2.8.0 - Mar. 2015 -v. 2.7.0 - Mar. 2012 -v. 2.6.0 - May 2009 -v. 2.5.0 - Nov. 2006 -v. 2.4.0 - Mar. 2006 -v. 2.3.0 - Apr. 2005 -v. 2.2.2 - Mar. 2005 -v. 2.2.1 - Jan. 2005 -v. 2.2.0 - Dec. 2004 -v. 2.0 - Jul. 2002 (first SUNDIALS release) -v. 1.0 - Mar. 2002 (CVODE and PVODE combined) -v. 1.0 (PVODE) - Jul. 1997 (date written) -v. 1.0 (CVODE) - Sep. 1994 (date written) diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/README.md b/deps/AMICI/ThirdParty/sundials/src/cvode/README.md new file mode 100644 index 000000000..f6806bb7a --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/README.md @@ -0,0 +1,60 @@ +# CVODE +### Version 5.2.0 (Mar 2020) + +**Alan C. Hindmarsh and Radu Serban + Center for Applied Scientific Computing, LLNL** + +CVODE is a package for the solution of stiff and nonstiff ordinary differential +equation (ODE) systems (initial value problems) given in explicit form +``` +dy/dt = f(t,y), y(t0) = y0. +``` +CVODE provides a choice of two variable-order, variable-coefficient multistep +methods, Adams-Moulton methods for non-stiff problems or BDF (Backward +Differentiation Formula) methods in fixed-leading-coefficient form for stiff +problems. + +CVODE is part of the SUNDIALS Suite of Nonlinear and Differential/Algebraic +equation Solvers which consists of ARKode, CVODE, CVODES, IDA, IDAS and KINSOL. +It is written in ANSI standard C and can be used in a variety of computing +environments including serial, shared memory, distributed memory, and +accelerator-based (e.g., GPU) systems. This flexibility is obtained from a +modular design that leverages the shared vector, matrix, linear solver, and +nonlinear solver APIs used across SUNDIALS packages. + +For use with Fortran applications, a set of Fortran/C interface routines, called +FCVODE, is also supplied. These are written in C, but assume that the user +calling program and all user-supplied routines are in Fortran. + +## Documentation + +See the [CVODE User Guide](/doc/cvode/cv_guide.pdf) and +[CVODE Examples](/doc/cvode/cv_examples.pdf) document for more information +about CVODE usage and the provided example programs respectively. + +## Installation + +For installation instructions see the [INSTALL_GUIDE](/INSTALL_GUIDE.pdf) +or the "Installation Procedure" chapter in the CVODE User Guide. + +## Release History + +Information on recent changes to CVODE can be found in the "Introduction" +chapter of the CVODE User Guide and a complete release history is available in +the "SUNDIALS Release History" appendix of the CVODE User Guide. + +## References + +* A. C. Hindmarsh and R. Serban, "User Documentation for CVODE v5.2.0," + LLNL technical report UCRL-SM-208108, Mar 2020. + +* A. C. Hindmarsh and R. Serban, "Example Programs for CVODE v5.2.0," + LLNL technical report UCRL-SM-208110, Mar 2020. + +* S.D. Cohen and A.C. Hindmarsh, "CVODE, a Stiff/nonstiff ODE Solver in C," + Computers in Physics, 10(2), pp. 138-143, 1996. + +* A. C. Hindmarsh, P. N. Brown, K. E. Grant, S. L. Lee, R. Serban, + D. E. Shumaker, and C. S. Woodward, "SUNDIALS, Suite of Nonlinear and + Differential/Algebraic Equation Solvers," ACM Trans. Math. Softw., + 31(3), pp. 363-396, 2005. diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode.c b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode.c index 1bdc4aa13..c77d6b636 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode.c @@ -1,13 +1,9 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh, Radu Serban, * and Dan Shumaker @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -17,12 +13,10 @@ * SUNDIALS Copyright End * ----------------------------------------------------------------- * This is the implementation file for the main CVODE integrator. - * It is independent of the CVODE linear solver in use. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ /*=================================================================*/ -/* Import Header Files */ +/* Import Header Files */ /*=================================================================*/ #include @@ -33,10 +27,10 @@ #include "cvode_impl.h" #include #include -#include "sunnonlinsol/sunnonlinsol_newton.h" +#include /*=================================================================*/ -/* CVODE Private Constants */ +/* CVODE Private Constants */ /*=================================================================*/ #define ZERO RCONST(0.0) /* real 0.0 */ @@ -56,7 +50,7 @@ #define HUNDRED RCONST(100.0) /* real 100.0 */ /*=================================================================*/ -/* CVODE Routine-Specific Constants */ +/* CVODE Routine-Specific Constants */ /*=================================================================*/ /* @@ -101,32 +95,31 @@ #define PREDICT_AGAIN +3 #define TRY_AGAIN +5 - #define FIRST_CALL +6 #define PREV_CONV_FAIL +7 #define PREV_ERR_FAIL +8 -#define CONSTR_RECVR +10 +#define CONSTR_RECVR +10 /* * Control constants for lower-level rootfinding functions * ------------------------------------------------------- * * cvRcheck1 return values: - * CV_SUCCESS, - * CV_RTFUNC_FAIL, + * CV_SUCCESS + * CV_RTFUNC_FAIL * cvRcheck2 return values: * CV_SUCCESS - * CV_RTFUNC_FAIL, + * CV_RTFUNC_FAIL * CLOSERT * RTFOUND * cvRcheck3 return values: * CV_SUCCESS - * CV_RTFUNC_FAIL, + * CV_RTFUNC_FAIL * RTFOUND * cvRootfind return values: * CV_SUCCESS - * CV_RTFUNC_FAIL, + * CV_RTFUNC_FAIL * RTFOUND */ @@ -149,33 +142,33 @@ * * CVodeGetDky and cvStep * - * FUZZ_FACTOR + * FUZZ_FACTOR fuzz factor used to estimate infinitesimal time intervals * * cvHin * - * HLB_FACTOR - * HUB_FACTOR - * H_BIAS - * MAX_ITERS + * HLB_FACTOR factor for upper bound on initial step size + * HUB_FACTOR factor for lower bound on initial step size + * H_BIAS bias factor in selection of initial step size + * MAX_ITERS maximum attempts to compute the initial step size * * CVodeCreate * - * CORTES + * CORTES constant in nonlinear iteration convergence test * * cvStep * - * THRESH - * ETAMX1 - * ETAMX2 - * ETAMX3 - * ETAMXF - * ETAMIN - * ETACF - * ADDON - * BIAS1 - * BIAS2 - * BIAS3 - * ONEPSM + * THRESH if eta < THRESH reject a change in step size or order + * ETAMX1 -+ + * ETAMX2 | + * ETAMX3 |-> bounds for eta (step size change) + * ETAMXF | + * ETAMIN | + * ETACF -+ + * ADDON safety factor in computing eta + * BIAS1 -+ + * BIAS2 |-> bias factors in eta selection + * BIAS3 -+ + * ONEPSM (1+epsilon) used in testing if the step size is below its bound * * SMALL_NST nst > SMALL_NST => use ETAMX3 * MXNCF max no. of convergence failures during one step try @@ -188,7 +181,7 @@ * * cvNls * - * DGMAX iter == CV_NEWTON, |gamma/gammap-1| > DGMAX => call lsetup + * DGMAX |gamma/gammap-1| > DGMAX => call lsetup * MSBP max no. of steps between lsetup calls * */ @@ -227,26 +220,34 @@ #define MSBP 20 /*=================================================================*/ -/* Private Helper Functions Prototypes */ +/* Private Helper Functions Prototypes */ /*=================================================================*/ static booleantype cvCheckNvector(N_Vector tmpl); +/* Initial setup */ + static int cvInitialSetup(CVodeMem cv_mem); +/* Memory allocation/deallocation */ + static booleantype cvAllocVectors(CVodeMem cv_mem, N_Vector tmpl); static void cvFreeVectors(CVodeMem cv_mem); static int cvEwtSetSS(CVodeMem cv_mem, N_Vector ycur, N_Vector weight); static int cvEwtSetSV(CVodeMem cv_mem, N_Vector ycur, N_Vector weight); +/* Initial stepsize calculation */ + static int cvHin(CVodeMem cv_mem, realtype tout); static realtype cvUpperBoundH0(CVodeMem cv_mem, realtype tdist); static int cvYddNorm(CVodeMem cv_mem, realtype hg, realtype *yddnrm); +/* Main cvStep function */ + static int cvStep(CVodeMem cv_mem); -static int cvSLdet(CVodeMem cv_mem); +/* Function called at beginning of step */ static void cvAdjustParams(CVodeMem cv_mem); static void cvAdjustOrder(CVodeMem cv_mem, int deltaq); @@ -254,11 +255,8 @@ static void cvAdjustAdams(CVodeMem cv_mem, int deltaq); static void cvAdjustBDF(CVodeMem cv_mem, int deltaq); static void cvIncreaseBDF(CVodeMem cv_mem); static void cvDecreaseBDF(CVodeMem cv_mem); - static void cvRescale(CVodeMem cv_mem); - static void cvPredict(CVodeMem cv_mem); - static void cvSet(CVodeMem cv_mem); static void cvSetAdams(CVodeMem cv_mem); static realtype cvAdamsStart(CVodeMem cv_mem, realtype m[]); @@ -268,30 +266,42 @@ static void cvSetBDF(CVodeMem cv_mem); static void cvSetTqBDF(CVodeMem cv_mem, realtype hsum, realtype alpha0, realtype alpha0_hat, realtype xi_inv, realtype xistar_inv); +/* Nonlinear solver functions */ + static int cvNls(CVodeMem cv_mem, int nflag); static int cvCheckConstraints(CVodeMem cv_mem); - static int cvHandleNFlag(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, int *ncfPtr); static void cvRestore(CVodeMem cv_mem, realtype saved_t); +/* Error Test */ + static int cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, int *nefPtr, realtype *dsmPtr); -static void cvCompleteStep(CVodeMem cv_mem); +/* Function called after a successful step */ +static void cvCompleteStep(CVodeMem cv_mem); static void cvPrepareNextStep(CVodeMem cv_mem, realtype dsm); static void cvSetEta(CVodeMem cv_mem); static realtype cvComputeEtaqm1(CVodeMem cv_mem); static realtype cvComputeEtaqp1(CVodeMem cv_mem); static void cvChooseEta(CVodeMem cv_mem); -static void cvBDFStab(CVodeMem cv_mem); + +/* Function to handle failures */ static int cvHandleFailure(CVodeMem cv_mem,int flag); +/* Functions for BDF Stability Limit Detection */ + +static void cvBDFStab(CVodeMem cv_mem); +static int cvSLdet(CVodeMem cv_mem); + +/* Functions for rootfinding */ + static int cvRcheck1(CVodeMem cv_mem); static int cvRcheck2(CVodeMem cv_mem); static int cvRcheck3(CVodeMem cv_mem); @@ -299,10 +309,16 @@ static int cvRootfind(CVodeMem cv_mem); /* * ================================================================= - * EXPORTED FUNCTIONS IMPLEMENTATION + * Exported Functions Implementation * ================================================================= */ +/* + * ----------------------------------------------------------------- + * Creation, allocation and re-initialization functions + * ----------------------------------------------------------------- + */ + /* * CVodeCreate * @@ -345,27 +361,28 @@ void *CVodeCreate(int lmm) cv_mem->cv_uround = UNIT_ROUNDOFF; /* Set default values for integrator optional inputs */ - cv_mem->cv_f = NULL; - cv_mem->cv_user_data = NULL; - cv_mem->cv_itol = CV_NN; - cv_mem->cv_user_efun = SUNFALSE; - cv_mem->cv_efun = NULL; - cv_mem->cv_e_data = NULL; - cv_mem->cv_ehfun = cvErrHandler; - cv_mem->cv_eh_data = cv_mem; - cv_mem->cv_errfp = stderr; - cv_mem->cv_qmax = maxord; - cv_mem->cv_mxstep = MXSTEP_DEFAULT; - cv_mem->cv_mxhnil = MXHNIL_DEFAULT; - cv_mem->cv_sldeton = SUNFALSE; - cv_mem->cv_hin = ZERO; - cv_mem->cv_hmin = HMIN_DEFAULT; - cv_mem->cv_hmax_inv = HMAX_INV_DEFAULT; - cv_mem->cv_tstopset = SUNFALSE; - cv_mem->cv_maxnef = MXNEF; - cv_mem->cv_maxncf = MXNCF; - cv_mem->cv_nlscoef = CORTES; - cv_mem->convfail = CV_NO_FAILURES; + cv_mem->cv_f = NULL; + cv_mem->cv_user_data = NULL; + cv_mem->cv_itol = CV_NN; + cv_mem->cv_atolmin0 = SUNTRUE; + cv_mem->cv_user_efun = SUNFALSE; + cv_mem->cv_efun = NULL; + cv_mem->cv_e_data = NULL; + cv_mem->cv_ehfun = cvErrHandler; + cv_mem->cv_eh_data = cv_mem; + cv_mem->cv_errfp = stderr; + cv_mem->cv_qmax = maxord; + cv_mem->cv_mxstep = MXSTEP_DEFAULT; + cv_mem->cv_mxhnil = MXHNIL_DEFAULT; + cv_mem->cv_sldeton = SUNFALSE; + cv_mem->cv_hin = ZERO; + cv_mem->cv_hmin = HMIN_DEFAULT; + cv_mem->cv_hmax_inv = HMAX_INV_DEFAULT; + cv_mem->cv_tstopset = SUNFALSE; + cv_mem->cv_maxnef = MXNEF; + cv_mem->cv_maxncf = MXNCF; + cv_mem->cv_nlscoef = CORTES; + cv_mem->convfail = CV_NO_FAILURES; cv_mem->cv_constraints = NULL; cv_mem->cv_constraintsSet = SUNFALSE; @@ -381,7 +398,7 @@ void *CVodeCreate(int lmm) cv_mem->cv_gactive = NULL; cv_mem->cv_mxgnull = 1; - /* Set the saved value qmax_alloc */ + /* Set the saved value for qmax_alloc */ cv_mem->cv_qmax_alloc = maxord; @@ -448,7 +465,8 @@ int CVodeInit(void *cvode_mem, CVRhsFn f, realtype t0, N_Vector y0) nvectorOK = cvCheckNvector(y0); if(!nvectorOK) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeInit", MSGCV_BAD_NVECTOR); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeInit", + MSGCV_BAD_NVECTOR); return(CV_ILL_INPUT); } @@ -515,7 +533,7 @@ int CVodeInit(void *cvode_mem, CVRhsFn f, realtype t0, N_Vector y0) cv_mem->cv_tolsf = ONE; /* Set the linear solver addresses to NULL. - (We check != NULL later, in CVode, if using CV_NEWTON.) */ + (We check != NULL later, in CVode) */ cv_mem->cv_linit = NULL; cv_mem->cv_lsetup = NULL; @@ -595,14 +613,16 @@ int CVodeReInit(void *cvode_mem, realtype t0, N_Vector y0) /* Check if cvode_mem was allocated */ if (cv_mem->cv_MallocDone == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_MALLOC, "CVODE", "CVodeReInit", MSGCV_NO_MALLOC); + cvProcessError(cv_mem, CV_NO_MALLOC, "CVODE", "CVodeReInit", + MSGCV_NO_MALLOC); return(CV_NO_MALLOC); } /* Check for legal input parameters */ if (y0 == NULL) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeReInit", MSGCV_NULL_Y0); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeReInit", + MSGCV_NULL_Y0); return(CV_ILL_INPUT); } @@ -681,25 +701,29 @@ int CVodeSStolerances(void *cvode_mem, realtype reltol, realtype abstol) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSStolerances", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSStolerances", + MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_MallocDone == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_MALLOC, "CVODE", "CVodeSStolerances", MSGCV_NO_MALLOC); + cvProcessError(cv_mem, CV_NO_MALLOC, "CVODE", "CVodeSStolerances", + MSGCV_NO_MALLOC); return(CV_NO_MALLOC); } /* Check inputs */ if (reltol < ZERO) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSStolerances", MSGCV_BAD_RELTOL); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSStolerances", + MSGCV_BAD_RELTOL); return(CV_ILL_INPUT); } if (abstol < ZERO) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSStolerances", MSGCV_BAD_ABSTOL); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSStolerances", + MSGCV_BAD_ABSTOL); return(CV_ILL_INPUT); } @@ -707,6 +731,7 @@ int CVodeSStolerances(void *cvode_mem, realtype reltol, realtype abstol) cv_mem->cv_reltol = reltol; cv_mem->cv_Sabstol = abstol; + cv_mem->cv_atolmin0 = (abstol == ZERO); cv_mem->cv_itol = CV_SS; @@ -721,27 +746,38 @@ int CVodeSStolerances(void *cvode_mem, realtype reltol, realtype abstol) int CVodeSVtolerances(void *cvode_mem, realtype reltol, N_Vector abstol) { CVodeMem cv_mem; + realtype atolmin; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSVtolerances", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSVtolerances", + MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_MallocDone == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_MALLOC, "CVODE", "CVodeSVtolerances", MSGCV_NO_MALLOC); + cvProcessError(cv_mem, CV_NO_MALLOC, "CVODE", "CVodeSVtolerances", + MSGCV_NO_MALLOC); return(CV_NO_MALLOC); } /* Check inputs */ if (reltol < ZERO) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSVtolerances", MSGCV_BAD_RELTOL); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSVtolerances", + MSGCV_BAD_RELTOL); return(CV_ILL_INPUT); } - if (N_VMin(abstol) < ZERO) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSVtolerances", MSGCV_BAD_ABSTOL); + if (abstol->ops->nvmin == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSVtolerances", + "Missing N_VMin routine from N_Vector"); + return(CV_ILL_INPUT); + } + atolmin = N_VMin(abstol); + if (atolmin < ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSVtolerances", + MSGCV_BAD_ABSTOL); return(CV_ILL_INPUT); } @@ -756,6 +792,7 @@ int CVodeSVtolerances(void *cvode_mem, realtype reltol, N_Vector abstol) cv_mem->cv_reltol = reltol; N_VScale(ONE, abstol, cv_mem->cv_Vabstol); + cv_mem->cv_atolmin0 = (atolmin == ZERO); cv_mem->cv_itol = CV_SV; @@ -772,13 +809,15 @@ int CVodeWFtolerances(void *cvode_mem, CVEwtFn efun) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeWFtolerances", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeWFtolerances", + MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_MallocDone == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_MALLOC, "CVODE", "CVodeWFtolerances", MSGCV_NO_MALLOC); + cvProcessError(cv_mem, CV_NO_MALLOC, "CVODE", "CVodeWFtolerances", + MSGCV_NO_MALLOC); return(CV_NO_MALLOC); } @@ -858,7 +897,8 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) cv_mem->cv_lrw -= 3*nrt; cv_mem->cv_liw -= 3*nrt; - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeRootInit", MSGCV_NULL_G); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeRootInit", + MSGCV_NULL_G); return(CV_ILL_INPUT); } else { @@ -872,7 +912,8 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) /* Set variable values in CVode memory block */ cv_mem->cv_nrtfn = nrt; if (g == NULL) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeRootInit", MSGCV_NULL_G); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeRootInit", + MSGCV_NULL_G); return(CV_ILL_INPUT); } else cv_mem->cv_gfun = g; @@ -881,7 +922,8 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) cv_mem->cv_glo = NULL; cv_mem->cv_glo = (realtype *) malloc(nrt*sizeof(realtype)); if (cv_mem->cv_glo == NULL) { - cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeRootInit", MSGCV_MEM_FAIL); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeRootInit", + MSGCV_MEM_FAIL); return(CV_MEM_FAIL); } @@ -889,7 +931,8 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) cv_mem->cv_ghi = (realtype *) malloc(nrt*sizeof(realtype)); if (cv_mem->cv_ghi == NULL) { free(cv_mem->cv_glo); cv_mem->cv_glo = NULL; - cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeRootInit", MSGCV_MEM_FAIL); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeRootInit", + MSGCV_MEM_FAIL); return(CV_MEM_FAIL); } @@ -898,7 +941,8 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) if (cv_mem->cv_grout == NULL) { free(cv_mem->cv_glo); cv_mem->cv_glo = NULL; free(cv_mem->cv_ghi); cv_mem->cv_ghi = NULL; - cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeRootInit", MSGCV_MEM_FAIL); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeRootInit", + MSGCV_MEM_FAIL); return(CV_MEM_FAIL); } @@ -908,7 +952,8 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) free(cv_mem->cv_glo); cv_mem->cv_glo = NULL; free(cv_mem->cv_ghi); cv_mem->cv_ghi = NULL; free(cv_mem->cv_grout); cv_mem->cv_grout = NULL; - cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeRootInit", MSGCV_MEM_FAIL); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeRootInit", + MSGCV_MEM_FAIL); return(CV_MEM_FAIL); } @@ -919,7 +964,8 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) free(cv_mem->cv_ghi); cv_mem->cv_ghi = NULL; free(cv_mem->cv_grout); cv_mem->cv_grout = NULL; free(cv_mem->cv_iroots); cv_mem->cv_iroots = NULL; - cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeRootInit", MSGCV_MEM_FAIL); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeRootInit", + MSGCV_MEM_FAIL); return(CV_MEM_FAIL); } @@ -931,7 +977,8 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) free(cv_mem->cv_grout); cv_mem->cv_grout = NULL; free(cv_mem->cv_iroots); cv_mem->cv_iroots = NULL; free(cv_mem->cv_rootdir); cv_mem->cv_rootdir = NULL; - cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeRootInit", MSGCV_MEM_FAIL); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeRootInit", + MSGCV_MEM_FAIL); return(CV_MEM_FAIL); } @@ -947,8 +994,11 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) return(CV_SUCCESS); } - -/*-----------------------------------------------------------------*/ +/* + * ----------------------------------------------------------------- + * Main solver function + * ----------------------------------------------------------------- + */ /* * CVode @@ -1033,12 +1083,12 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + /* Check inputs for corectness */ + ier = cvInitialSetup(cv_mem); if (ier!= CV_SUCCESS) return(ier); - /* Call f at (t0,y0), set zn[1] = y'(t0), - set initial h (from H0 or cvHin), and scale zn[1] by h. - Also check for zeros of root function g at and near t0. */ + /* Call f at (t0,y0), set zn[1] = y'(t0). */ retval = cv_mem->cv_f(cv_mem->cv_tn, cv_mem->cv_zn[0], cv_mem->cv_zn[1], cv_mem->cv_user_data); @@ -1062,7 +1112,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, MSGCV_BAD_TSTOP, cv_mem->cv_tstop, cv_mem->cv_tn); return(CV_ILL_INPUT); } - } + } /* Set initial h (from H0 or cvHin). */ @@ -1073,7 +1123,8 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, } if (cv_mem->cv_h == ZERO) { tout_hin = tout; - if ( cv_mem->cv_tstopset && (tout-cv_mem->cv_tn)*(tout-cv_mem->cv_tstop) > ZERO ) + if ( cv_mem->cv_tstopset && + (tout-cv_mem->cv_tn)*(tout-cv_mem->cv_tstop) > ZERO ) tout_hin = cv_mem->cv_tstop; hflag = cvHin(cv_mem, tout_hin); if (hflag != CV_SUCCESS) { @@ -1134,7 +1185,8 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, /* Estimate an infinitesimal time interval to be used as a roundoff for time quantities (based on current time and step size) */ - troundoff = FUZZ_FACTOR*cv_mem->cv_uround*(SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_h)); + troundoff = FUZZ_FACTOR * cv_mem->cv_uround * + (SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_h)); /* First, check for a root in the last step taken, other than the last root found, if any. If itask = CV_ONE_STEP and y(tn) was not @@ -1208,7 +1260,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, /* Test for tn at tstop or near tstop */ if ( cv_mem->cv_tstopset ) { - if ( SUNRabs(cv_mem->cv_tn - cv_mem->cv_tstop) <= troundoff) { + if ( SUNRabs(cv_mem->cv_tn - cv_mem->cv_tstop) <= troundoff ) { ier = CVodeGetDky(cv_mem, cv_mem->cv_tstop, 0, yout); if (ier != CV_SUCCESS) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVode", @@ -1223,7 +1275,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, /* If next step would overtake tstop, adjust stepsize */ if ( (cv_mem->cv_tn + cv_mem->cv_hprime - cv_mem->cv_tstop)*cv_mem->cv_h > ZERO ) { cv_mem->cv_hprime = (cv_mem->cv_tstop - cv_mem->cv_tn)*(ONE-FOUR*cv_mem->cv_uround); - cv_mem->cv_eta = cv_mem->cv_hprime/cv_mem->cv_h; + cv_mem->cv_eta = cv_mem->cv_hprime / cv_mem->cv_h; } } @@ -1270,7 +1322,6 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; N_VScale(ONE, cv_mem->cv_zn[0], yout); break; - } } @@ -1303,8 +1354,8 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, if (cv_mem->cv_tn + cv_mem->cv_h == cv_mem->cv_tn) { cv_mem->cv_nhnil++; if (cv_mem->cv_nhnil <= cv_mem->cv_mxhnil) - cvProcessError(cv_mem, CV_WARNING, "CVODE", "CVode", - MSGCV_HNIL, cv_mem->cv_tn, cv_mem->cv_h); + cvProcessError(cv_mem, CV_WARNING, "CVODE", "CVode", MSGCV_HNIL, + cv_mem->cv_tn, cv_mem->cv_h); if (cv_mem->cv_nhnil == cv_mem->cv_mxhnil) cvProcessError(cv_mem, CV_WARNING, "CVODE", "CVode", MSGCV_HNIL_DONE); } @@ -1373,7 +1424,8 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, /* Check if tn is at tstop or near tstop */ if ( cv_mem->cv_tstopset ) { - troundoff = FUZZ_FACTOR*cv_mem->cv_uround*(SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_h)); + troundoff = FUZZ_FACTOR * cv_mem->cv_uround * + (SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_h)); if ( SUNRabs(cv_mem->cv_tn - cv_mem->cv_tstop) <= troundoff) { (void) CVodeGetDky(cv_mem, cv_mem->cv_tstop, 0, yout); cv_mem->cv_tretlast = *tret = cv_mem->cv_tstop; @@ -1384,7 +1436,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, if ( (cv_mem->cv_tn + cv_mem->cv_hprime - cv_mem->cv_tstop)*cv_mem->cv_h > ZERO ) { cv_mem->cv_hprime = (cv_mem->cv_tstop - cv_mem->cv_tn)*(ONE-FOUR*cv_mem->cv_uround); - cv_mem->cv_eta = cv_mem->cv_hprime/cv_mem->cv_h; + cv_mem->cv_eta = cv_mem->cv_hprime / cv_mem->cv_h; } } @@ -1404,7 +1456,11 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, return(istate); } -/*-----------------------------------------------------------------*/ +/* + * ----------------------------------------------------------------- + * Interpolated output and extraction functions + * ----------------------------------------------------------------- + */ /* * CVodeGetDky @@ -1448,7 +1504,8 @@ int CVodeGetDky(void *cvode_mem, realtype t, int k, N_Vector dky) } /* Allow for some slack */ - tfuzz = FUZZ_FACTOR * cv_mem->cv_uround * (SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_hu)); + tfuzz = FUZZ_FACTOR * cv_mem->cv_uround * + (SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_hu)); if (cv_mem->cv_hu < ZERO) tfuzz = -tfuzz; tp = cv_mem->cv_tn - cv_mem->cv_hu - tfuzz; tn1 = cv_mem->cv_tn + tfuzz; @@ -1475,7 +1532,7 @@ int CVodeGetDky(void *cvode_mem, realtype t, int k, N_Vector dky) if (ier != CV_SUCCESS) return (CV_VECTOROP_ERR); if (k == 0) return(CV_SUCCESS); - r = SUNRpowerI(cv_mem->cv_h,-k); + r = SUNRpowerI(cv_mem->cv_h, -k); N_VScale(r, dky, dky); return(CV_SUCCESS); } @@ -1546,13 +1603,18 @@ static booleantype cvCheckNvector(N_Vector tmpl) (tmpl->ops->nvinv == NULL) || (tmpl->ops->nvaddconst == NULL) || (tmpl->ops->nvmaxnorm == NULL) || - (tmpl->ops->nvwrmsnorm == NULL) || - (tmpl->ops->nvmin == NULL)) + (tmpl->ops->nvwrmsnorm == NULL)) return(SUNFALSE); else return(SUNTRUE); } +/* + * ----------------------------------------------------------------- + * Memory allocation/deallocation + * ----------------------------------------------------------------- + */ + /* * cvAllocVectors * @@ -1655,7 +1717,7 @@ static booleantype cvAllocVectors(CVodeMem cv_mem, N_Vector tmpl) /* * cvFreeVectors * - * This routine frees the CVODE vectors allocated in cvAllocVectors. + * This routine frees the vectors allocated in cvAllocVectors. */ static void cvFreeVectors(CVodeMem cv_mem) @@ -1689,6 +1751,14 @@ static void cvFreeVectors(CVodeMem cv_mem) } } + +/* + * ----------------------------------------------------------------- + * Initial setup + * ----------------------------------------------------------------- + */ + + /* * cvInitialSetup * @@ -1704,7 +1774,16 @@ static int cvInitialSetup(CVodeMem cv_mem) /* Did the user specify tolerances? */ if (cv_mem->cv_itol == CV_NN) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "cvInitialSetup", MSGCV_NO_TOLS); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "cvInitialSetup", + MSGCV_NO_TOL); + return(CV_ILL_INPUT); + } + + /* If using a built-in routine for error weights with abstol==0, + ensure that N_VMin is available */ + if ((!cv_mem->cv_user_efun) && (cv_mem->cv_atolmin0) && (!cv_mem->cv_tempv->ops->nvmin)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "cvInitialSetup", + "Missing N_VMin routine from N_Vector"); return(CV_ILL_INPUT); } @@ -1716,7 +1795,8 @@ static int cvInitialSetup(CVodeMem cv_mem) if (cv_mem->cv_constraintsSet) { conOK = N_VConstrMask(cv_mem->cv_constraints, cv_mem->cv_zn[0], cv_mem->cv_tempv); if (!conOK) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "cvInitialSetup", MSGCV_Y0_FAIL_CONSTR); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "cvInitialSetup", + MSGCV_Y0_FAIL_CONSTR); return(CV_ILL_INPUT); } } @@ -1725,35 +1805,40 @@ static int cvInitialSetup(CVodeMem cv_mem) ier = cv_mem->cv_efun(cv_mem->cv_zn[0], cv_mem->cv_ewt, cv_mem->cv_e_data); if (ier != 0) { if (cv_mem->cv_itol == CV_WF) - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "cvInitialSetup", MSGCV_EWT_FAIL); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "cvInitialSetup", + MSGCV_EWT_FAIL); else - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "cvInitialSetup", MSGCV_BAD_EWT); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "cvInitialSetup", + MSGCV_BAD_EWT); return(CV_ILL_INPUT); } - /* Check if lsolve function exists (if needed) and call linit function (if it exists) */ + /* Call linit function (if it exists) */ if (cv_mem->cv_linit != NULL) { ier = cv_mem->cv_linit(cv_mem); if (ier != 0) { - cvProcessError(cv_mem, CV_LINIT_FAIL, "CVODE", "cvInitialSetup", MSGCV_LINIT_FAIL); + cvProcessError(cv_mem, CV_LINIT_FAIL, "CVODE", "cvInitialSetup", + MSGCV_LINIT_FAIL); return(CV_LINIT_FAIL); } } - /* Initialize the nonlinear solver (must occur after linear solver is initialize) so - * that lsetup and lsolve pointer have been set */ + /* Initialize the nonlinear solver (must occur after linear solver is + initialized) so that lsetup and lsolve pointer have been set */ ier = cvNlsInit(cv_mem); if (ier != 0) { - cvProcessError(cv_mem, CV_NLS_INIT_FAIL, "CVODE", "cvInitialSetup", MSGCV_NLS_INIT_FAIL); + cvProcessError(cv_mem, CV_NLS_INIT_FAIL, "CVODE", "cvInitialSetup", + MSGCV_NLS_INIT_FAIL); return(CV_NLS_INIT_FAIL); } return(CV_SUCCESS); } + /* * ----------------------------------------------------------------- - * PRIVATE FUNCTIONS FOR CVODE + * Initial stepsize calculation * ----------------------------------------------------------------- */ @@ -1838,15 +1923,15 @@ static int cvHin(CVodeMem cv_mem, realtype tout) for (count2 = 1; count2 <= MAX_ITERS; count2++) { hgs = hg*sign; retval = cvYddNorm(cv_mem, hgs, &yddnrm); - /* If f() failed unrecoverably, give up */ + /* If the RHS function failed unrecoverably, give up */ if (retval < 0) return(CV_RHSFUNC_FAIL); /* If successful, we can use ydd */ if (retval == CV_SUCCESS) {hgOK = SUNTRUE; break;} - /* f() failed recoverably; cut step size and test it again */ + /* The RHS function failed recoverably; cut step size and test again */ hg *= POINT2; } - /* If f() failed recoverably MAX_ITERS times */ + /* If the RHS function failed recoverably MAX_ITERS times */ if (!hgOK) { /* Exit if this is the first or second pass. No recovery possible */ @@ -1862,10 +1947,10 @@ static int cvHin(CVodeMem cv_mem, realtype tout) /* Propose new step size */ hnew = (yddnrm*hub*hub > TWO) ? SUNRsqrt(TWO/yddnrm) : SUNRsqrt(hg*hub); - + /* If last pass, stop now with hnew */ if (count1 == MAX_ITERS) break; - + hrat = hnew/hg; /* Accept hnew if it does not differ from hg by more than a factor of 2 */ @@ -1963,6 +2048,13 @@ static int cvYddNorm(CVodeMem cv_mem, realtype hg, realtype *yddnrm) return(CV_SUCCESS); } + +/* + * ----------------------------------------------------------------- + * Main cvStep function + * ----------------------------------------------------------------- + */ + /* * cvStep * @@ -2004,7 +2096,7 @@ static int cvStep(CVodeMem cv_mem) nflag = cvNls(cv_mem, nflag); kflag = cvHandleNFlag(cv_mem, &nflag, saved_t, &ncf); - /* Go back in loop if we need to predict again (nflag=PREV_CONV_FAIL)*/ + /* Go back in loop if we need to predict again (nflag=PREV_CONV_FAIL) */ if (kflag == PREDICT_AGAIN) continue; /* Return if nonlinear solve failed and recovery not possible. */ @@ -2014,7 +2106,7 @@ static int cvStep(CVodeMem cv_mem) eflag = cvDoErrorTest(cv_mem, &nflag, saved_t, &nef, &dsm); /* Go back in loop if we need to predict again (nflag=PREV_ERR_FAIL) */ - if (eflag == TRY_AGAIN) continue; + if (eflag == TRY_AGAIN) continue; /* Return if error test failed and recovery not possible. */ if (eflag != CV_SUCCESS) return(eflag); @@ -2042,10 +2134,16 @@ static int cvStep(CVodeMem cv_mem) estimated local error vector. */ N_VScale(cv_mem->cv_tq[2], cv_mem->cv_acor, cv_mem->cv_acor); - return(CV_SUCCESS); + return(CV_SUCCESS); } +/* + * ----------------------------------------------------------------- + * Function called at beginning of step + * ----------------------------------------------------------------- + */ + /* * cvAdjustParams * @@ -2226,7 +2324,7 @@ static void cvDecreaseBDF(CVodeMem cv_mem) hsum = ZERO; for (j=1; j <= cv_mem->cv_q-2; j++) { hsum += cv_mem->cv_tau[j]; - xi = hsum /cv_mem->cv_hscale; + xi = hsum / cv_mem->cv_hscale; for (i=j+2; i >= 2; i--) cv_mem->cv_l[i] = cv_mem->cv_l[i]*xi + cv_mem->cv_l[i-1]; } @@ -2252,6 +2350,7 @@ static void cvRescale(CVodeMem cv_mem) { int j; + /* compute scaling factors */ cv_mem->cv_cvals[0] = cv_mem->cv_eta; for (j=1; j <= cv_mem->cv_q; j++) cv_mem->cv_cvals[j] = cv_mem->cv_eta * cv_mem->cv_cvals[j-1]; @@ -2284,6 +2383,7 @@ static void cvPredict(CVodeMem cv_mem) if ((cv_mem->cv_tn - cv_mem->cv_tstop)*cv_mem->cv_h > ZERO) cv_mem->cv_tn = cv_mem->cv_tstop; } + for (k = 1; k <= cv_mem->cv_q; k++) for (j = cv_mem->cv_q; j >= k; j--) N_VLinearSum(ONE, cv_mem->cv_zn[j-1], ONE, @@ -2533,6 +2633,12 @@ static void cvSetTqBDF(CVodeMem cv_mem, realtype hsum, realtype alpha0, cv_mem->cv_tq[4] = cv_mem->cv_nlscoef / cv_mem->cv_tq[2]; } +/* + * ----------------------------------------------------------------- + * Nonlinear solver functions + * ----------------------------------------------------------------- + */ + /* * cvNls * @@ -2561,28 +2667,35 @@ static int cvNls(CVodeMem cv_mem, int nflag) } /* initial guess for the correction to the predictor */ - N_VConst(ZERO, cv_mem->cv_tempv); + N_VConst(ZERO, cv_mem->cv_acor); /* call nonlinear solver setup if it exists */ if ((cv_mem->NLS)->ops->setup) { - flag = SUNNonlinSolSetup(cv_mem->NLS, cv_mem->cv_tempv, cv_mem); + flag = SUNNonlinSolSetup(cv_mem->NLS, cv_mem->cv_acor, cv_mem); if (flag < 0) return(CV_NLS_SETUP_FAIL); if (flag > 0) return(SUN_NLS_CONV_RECVR); } /* solve the nonlinear system */ - flag = SUNNonlinSolSolve(cv_mem->NLS, cv_mem->cv_tempv, cv_mem->cv_acor, + flag = SUNNonlinSolSolve(cv_mem->NLS, cv_mem->cv_zn[0], cv_mem->cv_acor, cv_mem->cv_ewt, cv_mem->cv_tq[4], callSetup, cv_mem); + /* if the solve failed return */ + if (flag != CV_SUCCESS) return(flag); + + /* solve successful */ + /* update the state based on the final correction from the nonlinear solver */ N_VLinearSum(ONE, cv_mem->cv_zn[0], ONE, cv_mem->cv_acor, cv_mem->cv_y); - /* if the solve failed return */ - if (flag != CV_SUCCESS) return(flag); + /* compute acnrm if is was not already done by the nonlinear solver */ + if (!cv_mem->cv_acnrmcur) + cv_mem->cv_acnrm = N_VWrmsNorm(cv_mem->cv_acor, cv_mem->cv_ewt); - /* solve successful, update Jacobian status and check constraints */ + /* update Jacobian status */ cv_mem->cv_jcur = SUNFALSE; + /* check inequality constraints */ if (cv_mem->cv_constraintsSet) flag = cvCheckConstraints(cv_mem); @@ -2597,53 +2710,56 @@ static int cvNls(CVodeMem cv_mem, int nflag) * * Possible return values are: * - * CV_SUCCESS ---> allows stepping forward + * CV_SUCCESS ---> allows stepping forward * - * CONSTR_RECVR ---> values failed to satisfy constraints + * CONSTR_RECVR ---> values failed to satisfy constraints + * + * CV_CONSTR_FAIL ---> values failed to satisfy constraints with hmin */ static int cvCheckConstraints(CVodeMem cv_mem) { booleantype constraintsPassed; realtype vnorm; - cv_mem->cv_mm = cv_mem->cv_ftemp; + N_Vector mm = cv_mem->cv_ftemp; + N_Vector tmp = cv_mem->cv_tempv; /* Get mask vector mm, set where constraints failed */ - - constraintsPassed = N_VConstrMask(cv_mem->cv_constraints, - cv_mem->cv_y, cv_mem->cv_mm); + constraintsPassed = N_VConstrMask(cv_mem->cv_constraints, cv_mem->cv_y, mm); if (constraintsPassed) return(CV_SUCCESS); - else { - N_VCompare(ONEPT5, cv_mem->cv_constraints, cv_mem->cv_tempv); - /* a, where a[i]=1 when |c[i]|=2; c the vector of constraints */ - N_VProd(cv_mem->cv_tempv, cv_mem->cv_constraints, - cv_mem->cv_tempv); /* a * c */ - N_VDiv(cv_mem->cv_tempv, cv_mem->cv_ewt, - cv_mem->cv_tempv); /* a * c * wt */ - N_VLinearSum(ONE, cv_mem->cv_y, -PT1, - cv_mem->cv_tempv, cv_mem->cv_tempv); /* y - 0.1 * a * c * wt */ - N_VProd(cv_mem->cv_tempv, cv_mem->cv_mm, - cv_mem->cv_tempv); /* v = mm*(y-0.1*a*c*wt) */ - - vnorm = N_VWrmsNorm(cv_mem->cv_tempv, cv_mem->cv_ewt); /* ||v|| */ - - /* If vector v of constraint corrections is small in - norm, correct and accept this step */ - if (vnorm <= cv_mem->cv_tq[4]) { - N_VLinearSum(ONE, cv_mem->cv_acor, -ONE, - cv_mem->cv_tempv, cv_mem->cv_acor); /* acor <- acor - v */ - return(CV_SUCCESS); - } - else { - /* Constraints not met - reduce h by computing eta = h'/h */ - N_VLinearSum(ONE, cv_mem->cv_zn[0], -ONE, cv_mem->cv_y, cv_mem->cv_tempv); - N_VProd(cv_mem->cv_mm, cv_mem->cv_tempv, cv_mem->cv_tempv); - cv_mem->cv_eta = PT9*N_VMinQuotient(cv_mem->cv_zn[0], cv_mem->cv_tempv); - cv_mem->cv_eta = SUNMAX(cv_mem->cv_eta, PT1); - return(CONSTR_RECVR); - } + + /* Constraints not met */ + + /* Compute correction to satisfy constraints */ + N_VCompare(ONEPT5, cv_mem->cv_constraints, tmp); /* a[i]=1 when |c[i]|=2 */ + N_VProd(tmp, cv_mem->cv_constraints, tmp); /* a * c */ + N_VDiv(tmp, cv_mem->cv_ewt, tmp); /* a * c * wt */ + N_VLinearSum(ONE, cv_mem->cv_y, -PT1, tmp, tmp); /* y - 0.1 * a * c * wt */ + N_VProd(tmp, mm, tmp); /* v = mm*(y-0.1*a*c*wt) */ + + vnorm = N_VWrmsNorm(tmp, cv_mem->cv_ewt); /* ||v|| */ + + /* If vector v of constraint corrections is small in norm, correct and + accept this step */ + if (vnorm <= cv_mem->cv_tq[4]) { + N_VLinearSum(ONE, cv_mem->cv_acor, + -ONE, tmp, cv_mem->cv_acor); /* acor <- acor - v */ + return(CV_SUCCESS); } - return(CV_SUCCESS); + + /* Return with error if |h| == hmin */ + if (SUNRabs(cv_mem->cv_h) <= cv_mem->cv_hmin*ONEPSM) return(CV_CONSTR_FAIL); + + /* Constraint correction is too large, reduce h by computing eta = h'/h */ + N_VLinearSum(ONE, cv_mem->cv_zn[0], -ONE, cv_mem->cv_y, tmp); + N_VProd(mm, tmp, tmp); + cv_mem->cv_eta = PT9*N_VMinQuotient(cv_mem->cv_zn[0], tmp); + cv_mem->cv_eta = SUNMAX(cv_mem->cv_eta, PT1); + cv_mem->cv_eta = SUNMAX(cv_mem->cv_eta, + cv_mem->cv_hmin / SUNRabs(cv_mem->cv_h)); + + /* Reattempt step with new step size */ + return(CONSTR_RECVR); } @@ -2670,12 +2786,13 @@ static int cvCheckConstraints(CVodeMem cv_mem) * If it failed due to an unrecoverable failure in rhs, then we return * the value CV_RHSFUNC_FAIL. * - * Otherwise, a recoverable failure occurred when solving the - * nonlinear system (cvNls returned nflag == CONV_FAIL or RHSFUNC_RECVR). - * In this case, if ncf is now equal to maxncf or |h| = hmin, - * we return the value CV_CONV_FAILURE (if nflag=CONV_FAIL) or - * CV_REPTD_RHSFUNC_ERR (if nflag=RHSFUNC_RECVR). - * If not, we set *nflagPtr = PREV_CONV_FAIL and return the value + * Otherwise, a recoverable failure occurred when solving the nonlinear system + * (cvNls returned SUN_NLS_CONV_RECVR or RHSFUNC_RECVR). + * + * If ncf is now equal to maxncf or |h| = hmin, we return the value + * CV_CONV_FAILURE (if SUN_NLS_CONV_RECVR) or + * CV_REPTD_RHSFUNC_ERR (if RHSFUNC_RECVR). + * Otherwise, we set *nflagPtr = PREV_CONV_FAIL and return the value * PREDICT_AGAIN, telling cvStep to reattempt the step. * */ @@ -2694,21 +2811,25 @@ static int cvHandleNFlag(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, cvRestore(cv_mem, saved_t); /* Return if failed unrecoverably */ - if (nflag < 0) return(nflag); + if (nflag < 0) { + if (nflag == CV_LSETUP_FAIL) return(CV_LSETUP_FAIL); + else if (nflag == CV_LSOLVE_FAIL) return(CV_LSOLVE_FAIL); + else if (nflag == CV_RHSFUNC_FAIL) return(CV_RHSFUNC_FAIL); + else return(CV_NLS_FAIL); + } - /* At this point, nflag = SUN_NLS_CONV_RECVR or RHSFUNC_RECVR; increment ncf */ + /* At this point, a recoverable error occured. */ (*ncfPtr)++; cv_mem->cv_etamax = ONE; - /* If we had maxncf failures or |h| = hmin, - return SUN_NLS_CONV_RECVR, CV_CONSTR_FAIL, or CV_REPTD_RHSFUNC_ERR. */ + /* If we had maxncf failures or |h| = hmin, return failure. */ if ((SUNRabs(cv_mem->cv_h) <= cv_mem->cv_hmin*ONEPSM) || (*ncfPtr == cv_mem->cv_maxncf)) { if (nflag == SUN_NLS_CONV_RECVR) return(CV_CONV_FAILURE); - if (nflag == RHSFUNC_RECVR) return(CV_REPTD_RHSFUNC_ERR); if (nflag == CONSTR_RECVR) return(CV_CONSTR_FAIL); + if (nflag == RHSFUNC_RECVR) return(CV_REPTD_RHSFUNC_ERR); } /* Reduce step size; return to reattempt the step @@ -2740,6 +2861,12 @@ static void cvRestore(CVodeMem cv_mem, realtype saved_t) cv_mem->cv_zn[j], cv_mem->cv_zn[j-1]); } +/* + * ----------------------------------------------------------------- + * Error Test + * ----------------------------------------------------------------- + */ + /* * cvDoErrorTest * @@ -2763,8 +2890,8 @@ static void cvRestore(CVodeMem cv_mem, realtype saved_t) * */ -static booleantype cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, - realtype saved_t, int *nefPtr, realtype *dsmPtr) +static int cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, + int *nefPtr, realtype *dsmPtr) { realtype dsm; int retval; @@ -2783,7 +2910,8 @@ static booleantype cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, /* At maxnef failures or |h| = hmin, return CV_ERR_FAILURE */ if ((SUNRabs(cv_mem->cv_h) <= cv_mem->cv_hmin*ONEPSM) || - (*nefPtr == cv_mem->cv_maxnef)) return(CV_ERR_FAILURE); + (*nefPtr == cv_mem->cv_maxnef)) + return(CV_ERR_FAILURE); /* Set etamax = 1 to prevent step size increase at end of this step */ cv_mem->cv_etamax = ONE; @@ -2821,8 +2949,8 @@ static booleantype cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, retval = cv_mem->cv_f(cv_mem->cv_tn, cv_mem->cv_zn[0], cv_mem->cv_tempv, cv_mem->cv_user_data); cv_mem->cv_nfe++; - if (retval < 0) return(CV_RHSFUNC_FAIL); - if (retval > 0) return(CV_UNREC_RHSFUNC_ERR); + if (retval < 0) return(CV_RHSFUNC_FAIL); + if (retval > 0) return(CV_UNREC_RHSFUNC_ERR); N_VScale(cv_mem->cv_h, cv_mem->cv_tempv, cv_mem->cv_zn[1]); @@ -2831,7 +2959,7 @@ static booleantype cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, /* * ----------------------------------------------------------------- - * Functions called after succesful step + * Functions called after a successful step * ----------------------------------------------------------------- */ @@ -2844,7 +2972,7 @@ static booleantype cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, * update the tau array, and apply the corrections to the zn array. * The tau[i] are the last q values of h, with tau[1] the most recent. * The counter qwait is decremented, and if qwait == 1 (and q < qmax) - * we save acor and cv_mem->cv_tq[5] for a possible order increase. + * we save acor and tq[5] for a possible order increase. */ static void cvCompleteStep(CVodeMem cv_mem) @@ -2930,7 +3058,8 @@ static void cvSetEta(CVodeMem cv_mem) } else { /* Limit eta by etamax and hmax, then set hprime */ cv_mem->cv_eta = SUNMIN(cv_mem->cv_eta, cv_mem->cv_etamax); - cv_mem->cv_eta /= SUNMAX(ONE, SUNRabs(cv_mem->cv_h)*cv_mem->cv_hmax_inv*cv_mem->cv_eta); + cv_mem->cv_eta /= SUNMAX(ONE, SUNRabs(cv_mem->cv_h) * + cv_mem->cv_hmax_inv*cv_mem->cv_eta); cv_mem->cv_hprime = cv_mem->cv_h * cv_mem->cv_eta; if (cv_mem->cv_qprime < cv_mem->cv_q) cv_mem->cv_nscon = 0; } @@ -3032,6 +3161,12 @@ static void cvChooseEta(CVodeMem cv_mem) } } +/* + * ----------------------------------------------------------------- + * Function to handle failures + * ----------------------------------------------------------------- + */ + /* * cvHandleFailure * @@ -3052,57 +3187,66 @@ static int cvHandleFailure(CVodeMem cv_mem, int flag) /* Depending on flag, print error message and return error flag */ switch (flag) { case CV_ERR_FAILURE: - cvProcessError(cv_mem, CV_ERR_FAILURE, "CVODE", "CVode", MSGCV_ERR_FAILS, - cv_mem->cv_tn, cv_mem->cv_h); + cvProcessError(cv_mem, CV_ERR_FAILURE, "CVODE", "CVode", + MSGCV_ERR_FAILS, cv_mem->cv_tn, cv_mem->cv_h); break; case CV_CONV_FAILURE: - cvProcessError(cv_mem, CV_CONV_FAILURE, "CVODE", "CVode", MSGCV_CONV_FAILS, - cv_mem->cv_tn, cv_mem->cv_h); + cvProcessError(cv_mem, CV_CONV_FAILURE, "CVODE", "CVode", + MSGCV_CONV_FAILS, cv_mem->cv_tn, cv_mem->cv_h); break; case CV_LSETUP_FAIL: - cvProcessError(cv_mem, CV_LSETUP_FAIL, "CVODE", "CVode", MSGCV_SETUP_FAILED, - cv_mem->cv_tn); + cvProcessError(cv_mem, CV_LSETUP_FAIL, "CVODE", "CVode", + MSGCV_SETUP_FAILED, cv_mem->cv_tn); break; case CV_LSOLVE_FAIL: - cvProcessError(cv_mem, CV_LSOLVE_FAIL, "CVODE", "CVode", MSGCV_SOLVE_FAILED, - cv_mem->cv_tn); + cvProcessError(cv_mem, CV_LSOLVE_FAIL, "CVODE", "CVode", + MSGCV_SOLVE_FAILED, cv_mem->cv_tn); break; case CV_RHSFUNC_FAIL: - cvProcessError(cv_mem, CV_RHSFUNC_FAIL, "CVODE", "CVode", MSGCV_RHSFUNC_FAILED, - cv_mem->cv_tn); + cvProcessError(cv_mem, CV_RHSFUNC_FAIL, "CVODE", "CVode", + MSGCV_RHSFUNC_FAILED, cv_mem->cv_tn); break; case CV_UNREC_RHSFUNC_ERR: - cvProcessError(cv_mem, CV_UNREC_RHSFUNC_ERR, "CVODE", "CVode", MSGCV_RHSFUNC_UNREC, - cv_mem->cv_tn); + cvProcessError(cv_mem, CV_UNREC_RHSFUNC_ERR, "CVODE", "CVode", + MSGCV_RHSFUNC_UNREC, cv_mem->cv_tn); break; case CV_REPTD_RHSFUNC_ERR: - cvProcessError(cv_mem, CV_REPTD_RHSFUNC_ERR, "CVODE", "CVode", MSGCV_RHSFUNC_REPTD, - cv_mem->cv_tn); + cvProcessError(cv_mem, CV_REPTD_RHSFUNC_ERR, "CVODE", "CVode", + MSGCV_RHSFUNC_REPTD, cv_mem->cv_tn); break; case CV_RTFUNC_FAIL: - cvProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODE", "CVode", MSGCV_RTFUNC_FAILED, - cv_mem->cv_tn); + cvProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODE", "CVode", + MSGCV_RTFUNC_FAILED, cv_mem->cv_tn); break; case CV_TOO_CLOSE: - cvProcessError(cv_mem, CV_TOO_CLOSE, "CVODE", "CVode", MSGCV_TOO_CLOSE); + cvProcessError(cv_mem, CV_TOO_CLOSE, "CVODE", "CVode", + MSGCV_TOO_CLOSE); break; case CV_MEM_NULL: - cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVode", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVode", + MSGCV_NO_MEM); break; case SUN_NLS_MEM_NULL: - cvProcessError(cv_mem, CV_MEM_NULL, "CVODE", "CVode", MSGCV_NLS_INPUT_NULL, - cv_mem->cv_tn); + cvProcessError(cv_mem, CV_MEM_NULL, "CVODE", "CVode", + MSGCV_NLS_INPUT_NULL, cv_mem->cv_tn); break; case CV_NLS_SETUP_FAIL: - cvProcessError(cv_mem, CV_NLS_SETUP_FAIL, "CVODE", "CVode", MSGCV_NLS_SETUP_FAILED, - cv_mem->cv_tn); + cvProcessError(cv_mem, CV_NLS_SETUP_FAIL, "CVODE", "CVode", + MSGCV_NLS_SETUP_FAILED, cv_mem->cv_tn); break; case CV_CONSTR_FAIL: - cvProcessError(cv_mem, CV_CONSTR_FAIL, "CVODE", "CVode", MSGCV_FAILED_CONSTR, - cv_mem->cv_tn); + cvProcessError(cv_mem, CV_CONSTR_FAIL, "CVODE", "CVode", + MSGCV_FAILED_CONSTR, cv_mem->cv_tn); + break; + case CV_NLS_FAIL: + cvProcessError(cv_mem, CV_NLS_FAIL, "CVODE", "CVode", + MSGCV_NLS_FAIL, cv_mem->cv_tn); break; default: - return(CV_SUCCESS); + /* This return should never happen */ + cvProcessError(cv_mem, CV_UNRECOGNIZED_ERR, "CVODE", "CVode", + "CVODE encountered an unrecognized error. Please report this to the Sundials developers at sundials-users@llnl.gov"); + return (CV_UNRECOGNIZED_ERR); } return(flag); @@ -3144,13 +3288,13 @@ static void cvBDFStab(CVodeMem cv_mem) cv_mem->cv_acnrm / SUNMAX(cv_mem->cv_tq[5],TINY); sqm1 = factorial * cv_mem->cv_q * N_VWrmsNorm(cv_mem->cv_zn[cv_mem->cv_q], cv_mem->cv_ewt); - sqm2 = factorial * N_VWrmsNorm(cv_mem->cv_zn[cv_mem->cv_q-1], cv_mem->cv_ewt); + sqm2 = factorial * + N_VWrmsNorm(cv_mem->cv_zn[cv_mem->cv_q-1], cv_mem->cv_ewt); cv_mem->cv_ssdat[1][1] = sqm2*sqm2; cv_mem->cv_ssdat[1][2] = sqm1*sqm1; cv_mem->cv_ssdat[1][3] = sq*sq; } - if (cv_mem->cv_qprime >= cv_mem->cv_q) { /* If order is 3 or greater, and enough ssdat has been saved, @@ -3167,7 +3311,7 @@ static void cvBDFStab(CVodeMem cv_mem) cv_mem->cv_eta = SUNMIN(cv_mem->cv_eta,cv_mem->cv_etamax); cv_mem->cv_eta = cv_mem->cv_eta / SUNMAX(ONE,SUNRabs(cv_mem->cv_h)*cv_mem->cv_hmax_inv*cv_mem->cv_eta); - cv_mem->cv_hprime = cv_mem->cv_h*cv_mem->cv_eta; + cv_mem->cv_hprime = cv_mem->cv_h * cv_mem->cv_eta; cv_mem->cv_nor = cv_mem->cv_nor + 1; } } @@ -3266,7 +3410,7 @@ static int cvSLdet(CVodeMem cv_mem) sumrat = ZERO; sumrsq = ZERO; for (i=1; i<=4; i++) { - rat[i][k] = cv_mem->cv_ssdat[i][k]/cv_mem->cv_ssdat[i+1][k]; + rat[i][k] = cv_mem->cv_ssdat[i][k] / cv_mem->cv_ssdat[i+1][k]; sumrat = sumrat + rat[i][k]; sumrsq = sumrsq + rat[i][k]*rat[i][k]; } @@ -3308,7 +3452,7 @@ static int cvSLdet(CVodeMem cv_mem) adrr = SUNRabs(rav[k] - rr); drrmax = SUNMAX(drrmax, adrr); } - if (drrmax > vrrt2) {kflag = -3; return(kflag);} + if (drrmax > vrrt2) { kflag = -3; return(kflag); } kflag = 1; @@ -3537,8 +3681,7 @@ static int cvRcheck1(CVodeMem cv_mem) hratio = SUNMAX(cv_mem->cv_ttol/SUNRabs(cv_mem->cv_h), PT1); smallh = hratio*cv_mem->cv_h; tplus = cv_mem->cv_tlo + smallh; - N_VLinearSum(ONE, cv_mem->cv_zn[0], hratio, - cv_mem->cv_zn[1], cv_mem->cv_y); + N_VLinearSum(ONE, cv_mem->cv_zn[0], hratio, cv_mem->cv_zn[1], cv_mem->cv_y); retval = cv_mem->cv_gfun(tplus, cv_mem->cv_y, cv_mem->cv_ghi, cv_mem->cv_user_data); cv_mem->cv_nge++; @@ -3879,7 +4022,8 @@ static int cvRootfind(CVodeMem cv_mem) } else { if ( (cv_mem->cv_glo[i]*cv_mem->cv_grout[i] < ZERO) && (cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) ) { - gfrac = SUNRabs(cv_mem->cv_grout[i]/(cv_mem->cv_grout[i] - cv_mem->cv_glo[i])); + gfrac = SUNRabs(cv_mem->cv_grout[i] / + (cv_mem->cv_grout[i] - cv_mem->cv_glo[i])); if (gfrac > maxfrac) { sgnchg = SUNTRUE; maxfrac = gfrac; @@ -3946,7 +4090,7 @@ static int cvRootfind(CVodeMem cv_mem) * This routine is responsible for setting the error weight vector ewt, * according to tol_type, as follows: * - * (1) ewt[i] = 1 / (reltol * SUNRabs(ycur[i]) + *abstol), i=0,...,neq-1 + * (1) ewt[i] = 1 / (reltol * SUNRabs(ycur[i]) + abstol), i=0,...,neq-1 * if tol_type = CV_SS * (2) ewt[i] = 1 / (reltol * SUNRabs(ycur[i]) + abstol[i]), i=0,...,neq-1 * if tol_type = CV_SV @@ -3983,9 +4127,10 @@ int cvEwtSet(N_Vector ycur, N_Vector weight, void *data) * cvEwtSetSS * * This routine sets ewt as decribed above in the case tol_type = CV_SS. - * It tests for non-positive components before inverting. cvEwtSetSS - * returns 0 if ewt is successfully set to a positive vector - * and -1 otherwise. In the latter case, ewt is considered undefined. + * If the absolute tolerance is zero, it tests for non-positive components + * before inverting. cvEwtSetSS returns 0 if ewt is successfully set to a + * positive vector and -1 otherwise. In the latter case, ewt is considered + * undefined. */ static int cvEwtSetSS(CVodeMem cv_mem, N_Vector ycur, N_Vector weight) @@ -3993,7 +4138,9 @@ static int cvEwtSetSS(CVodeMem cv_mem, N_Vector ycur, N_Vector weight) N_VAbs(ycur, cv_mem->cv_tempv); N_VScale(cv_mem->cv_reltol, cv_mem->cv_tempv, cv_mem->cv_tempv); N_VAddConst(cv_mem->cv_tempv, cv_mem->cv_Sabstol, cv_mem->cv_tempv); - if (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); + if (cv_mem->cv_atolmin0) { + if (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); + } N_VInv(cv_mem->cv_tempv, weight); return(0); } @@ -4002,9 +4149,10 @@ static int cvEwtSetSS(CVodeMem cv_mem, N_Vector ycur, N_Vector weight) * cvEwtSetSV * * This routine sets ewt as decribed above in the case tol_type = CV_SV. - * It tests for non-positive components before inverting. cvEwtSetSV - * returns 0 if ewt is successfully set to a positive vector - * and -1 otherwise. In the latter case, ewt is considered undefined. + * If any absolute tolerance is zero, it tests for non-positive components + * before inverting. cvEwtSetSV returns 0 if ewt is successfully set to a + * positive vector and -1 otherwise. In the latter case, ewt is considered + * undefined. */ static int cvEwtSetSV(CVodeMem cv_mem, N_Vector ycur, N_Vector weight) @@ -4012,7 +4160,9 @@ static int cvEwtSetSV(CVodeMem cv_mem, N_Vector ycur, N_Vector weight) N_VAbs(ycur, cv_mem->cv_tempv); N_VLinearSum(cv_mem->cv_reltol, cv_mem->cv_tempv, ONE, cv_mem->cv_Vabstol, cv_mem->cv_tempv); - if (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); + if (cv_mem->cv_atolmin0) { + if (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); + } N_VInv(cv_mem->cv_tempv, weight); return(0); } diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bandpre.c b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bandpre.c index 41194b0e4..61e6798bf 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bandpre.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bandpre.c @@ -5,7 +5,7 @@ * and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -34,11 +34,11 @@ #define TWO RCONST(2.0) /* Prototypes of CVBandPrecSetup and CVBandPrecSolve */ -static int CVBandPrecSetup(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, +static int CVBandPrecSetup(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, realtype gamma, void *bp_data); -static int CVBandPrecSolve(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, +static int CVBandPrecSolve(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, realtype delta, int lr, void *bp_data); @@ -46,16 +46,16 @@ static int CVBandPrecSolve(realtype t, N_Vector y, N_Vector fy, static int CVBandPrecFree(CVodeMem cv_mem); /* Prototype for difference quotient Jacobian calculation routine */ -static int CVBandPDQJac(CVBandPrecData pdata, realtype t, N_Vector y, +static int CVBandPDQJac(CVBandPrecData pdata, realtype t, N_Vector y, N_Vector fy, N_Vector ftemp, N_Vector ytemp); /*----------------------------------------------------------------- Initialization, Free, and Get Functions - NOTE: The band linear solver assumes a serial/OpenMP/Pthreads - implementation of the NVECTOR package. Therefore, - CVBandPrecInit will first test for a compatible N_Vector - internal representation by checking that the function + NOTE: The band linear solver assumes a serial/OpenMP/Pthreads + implementation of the NVECTOR package. Therefore, + CVBandPrecInit will first test for a compatible N_Vector + internal representation by checking that the function N_VGetArrayPointer exists. -----------------------------------------------------------------*/ int CVBandPrecInit(void *cvode_mem, sunindextype N, @@ -149,7 +149,7 @@ int CVBandPrecInit(void *cvode_mem, sunindextype N, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBANDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBANDPRE", "CVBandPrecInit", MSGBP_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -161,7 +161,7 @@ int CVBandPrecInit(void *cvode_mem, sunindextype N, SUNMatDestroy(pdata->savedJ); N_VDestroy(pdata->tmp1); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBANDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBANDPRE", "CVBandPrecInit", MSGBP_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -175,11 +175,11 @@ int CVBandPrecInit(void *cvode_mem, sunindextype N, N_VDestroy(pdata->tmp1); N_VDestroy(pdata->tmp2); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVBANDPRE", + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVBANDPRE", "CVBandPrecInit", MSGBP_SUNLS_FAIL); return(CVLS_SUNLS_FAIL); } - + /* make sure P_data is free from any previous allocations */ if (cvls_mem->pfree) cvls_mem->pfree(cv_mem); @@ -198,7 +198,7 @@ int CVBandPrecInit(void *cvode_mem, sunindextype N, } -int CVBandPrecGetWorkSpace(void *cvode_mem, long int *lenrwBP, +int CVBandPrecGetWorkSpace(void *cvode_mem, long int *lenrwBP, long int *leniwBP) { CVodeMem cv_mem; @@ -207,7 +207,7 @@ int CVBandPrecGetWorkSpace(void *cvode_mem, long int *lenrwBP, sunindextype lrw1, liw1; long int lrw, liw; int flag; - + if (cvode_mem == NULL) { cvProcessError(NULL, CVLS_MEM_NULL, "CVBANDPRE", "CVBandPrecGetWorkSpace", MSGBP_MEM_NULL); @@ -226,7 +226,7 @@ int CVBandPrecGetWorkSpace(void *cvode_mem, long int *lenrwBP, cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVBANDPRE", "CVBandPrecGetWorkSpace", MSGBP_PMEM_NULL); return(CVLS_PMEM_NULL); - } + } pdata = (CVBandPrecData) cvls_mem->P_data; /* sum space requirements for all objects in pdata */ @@ -284,7 +284,7 @@ int CVBandPrecGetNumRhsEvals(void *cvode_mem, long int *nfevalsBP) cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVBANDPRE", "CVBandPrecGetNumRhsEvals", MSGBP_PMEM_NULL); return(CVLS_PMEM_NULL); - } + } pdata = (CVBandPrecData) cvls_mem->P_data; *nfevalsBP = pdata->nfeBP; @@ -300,16 +300,16 @@ int CVBandPrecGetNumRhsEvals(void *cvode_mem, long int *nfevalsBP) difference quotient Jacobian to create a preconditioner. CVBandPrecSetup calculates a new J, if necessary, then calculates P = I - gamma*J, and does an LU factorization of P. - + The parameters of CVBandPrecSetup are as follows: - + t is the current value of the independent variable. - + y is the current value of the dependent variable vector, namely the predicted value of y(t). - + fy is the vector f(t,y). - + jok is an input flag indicating whether Jacobian-related data needs to be recomputed, as follows: jok == SUNFALSE means recompute Jacobian-related data @@ -319,29 +319,28 @@ int CVBandPrecGetNumRhsEvals(void *cvode_mem, long int *nfevalsBP) (with the current value of gamma). A CVBandPrecSetup call with jok == SUNTRUE should only occur after a call with jok == SUNFALSE. - + *jcurPtr is a pointer to an output integer flag which is set by CVBandPrecSetup as follows: *jcurPtr = SUNTRUE if Jacobian data was recomputed. *jcurPtr = SUNFALSE if Jacobian data was not recomputed, but saved data was reused. - + gamma is the scalar appearing in the Newton matrix. - + bp_data is a pointer to preconditoner data (set by CVBandPrecInit) - + The value to be returned by the CVBandPrecSetup function is 0 if successful, or 1 if the band factorization failed. -----------------------------------------------------------------*/ -static int CVBandPrecSetup(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, +static int CVBandPrecSetup(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, realtype gamma, void *bp_data) { CVBandPrecData pdata; CVodeMem cv_mem; int retval; - sunindextype ier; /* Assume matrix and lpivots have already been allocated. */ pdata = (CVBandPrecData) bp_data; @@ -353,7 +352,7 @@ static int CVBandPrecSetup(realtype t, N_Vector y, N_Vector fy, *jcurPtr = SUNFALSE; retval = SUNMatCopy(pdata->savedJ, pdata->savedP); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBANDPRE", + cvProcessError(cv_mem, -1, "CVBANDPRE", "CVBandPrecSetup", MSGBP_SUNMAT_FAIL); return(-1); } @@ -367,7 +366,7 @@ static int CVBandPrecSetup(realtype t, N_Vector y, N_Vector fy, *jcurPtr = SUNTRUE; retval = SUNMatZero(pdata->savedJ); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBANDPRE", + cvProcessError(cv_mem, -1, "CVBANDPRE", "CVBandPrecSetup", MSGBP_SUNMAT_FAIL); return(-1); } @@ -375,10 +374,10 @@ static int CVBandPrecSetup(realtype t, N_Vector y, N_Vector fy, return(1); } - retval = CVBandPDQJac(pdata, t, y, fy, + retval = CVBandPDQJac(pdata, t, y, fy, pdata->tmp1, pdata->tmp2); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBANDPRE", + cvProcessError(cv_mem, -1, "CVBANDPRE", "CVBandPrecSetup", MSGBP_RHSFUNC_FAILED); return(-1); } @@ -388,7 +387,7 @@ static int CVBandPrecSetup(realtype t, N_Vector y, N_Vector fy, retval = SUNMatCopy(pdata->savedJ, pdata->savedP); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBANDPRE", + cvProcessError(cv_mem, -1, "CVBANDPRE", "CVBandPrecSetup", MSGBP_SUNMAT_FAIL); return(-1); } @@ -397,18 +396,18 @@ static int CVBandPrecSetup(realtype t, N_Vector y, N_Vector fy, } } - + /* Scale and add identity to get savedP = I - gamma*J. */ retval = SUNMatScaleAddI(-gamma, pdata->savedP); if (retval) { - cvProcessError(cv_mem, -1, "CVBANDPRE", + cvProcessError(cv_mem, -1, "CVBANDPRE", "CVBandPrecSetup", MSGBP_SUNMAT_FAIL); return(-1); } /* Do LU factorization of matrix and return error flag */ - ier = SUNLinSolSetup_Band(pdata->LS, pdata->savedP); - return(ier); + retval = SUNLinSolSetup_Band(pdata->LS, pdata->savedP); + return(retval); } @@ -417,20 +416,20 @@ static int CVBandPrecSetup(realtype t, N_Vector y, N_Vector fy, ----------------------------------------------------------------- CVBandPrecSolve solves a linear system P z = r, where P is the matrix computed by CVBandPrecond. - + The parameters of CVBandPrecSolve used here are as follows: - + r is the right-hand side vector of the linear system. - + bp_data is a pointer to preconditoner data (set by CVBandPrecInit) - + z is the output vector computed by CVBandPrecSolve. - + The value returned by the CVBandPrecSolve function is always 0, indicating success. - -----------------------------------------------------------------*/ -static int CVBandPrecSolve(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, realtype gamma, + -----------------------------------------------------------------*/ +static int CVBandPrecSolve(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, realtype delta, int lr, void *bp_data) { CVBandPrecData pdata; @@ -452,7 +451,7 @@ static int CVBandPrecFree(CVodeMem cv_mem) if (cv_mem->cv_lmem == NULL) return(0); cvls_mem = (CVLsMem) cv_mem->cv_lmem; - + if (cvls_mem->P_data == NULL) return(0); pdata = (CVBandPrecData) cvls_mem->P_data; @@ -472,15 +471,15 @@ static int CVBandPrecFree(CVodeMem cv_mem) /*----------------------------------------------------------------- CVBandPDQJac ----------------------------------------------------------------- - This routine generates a banded difference quotient approximation - to the Jacobian of f(t,y). It assumes that a band SUNMatrix is - stored column-wise, and that elements within each column are + This routine generates a banded difference quotient approximation + to the Jacobian of f(t,y). It assumes that a band SUNMatrix is + stored column-wise, and that elements within each column are contiguous. This makes it possible to get the address of a column - of J via the accessor function SUNBandMatrix_Column() and to - write a simple for loop to set each of the elements of a column + of J via the accessor function SUNBandMatrix_Column() and to + write a simple for loop to set each of the elements of a column in succession. -----------------------------------------------------------------*/ -static int CVBandPDQJac(CVBandPrecData pdata, realtype t, N_Vector y, +static int CVBandPDQJac(CVBandPrecData pdata, realtype t, N_Vector y, N_Vector fy, N_Vector ftemp, N_Vector ytemp) { CVodeMem cv_mem; @@ -490,6 +489,9 @@ static int CVBandPDQJac(CVBandPrecData pdata, realtype t, N_Vector y, realtype *y_data, *ytemp_data, *cns_data; int retval; + /* initialize cns_data to avoid compiler warning */ + cns_data = NULL; + cv_mem = (CVodeMem) pdata->cvode_mem; /* Obtain pointers to the data for various vectors */ @@ -498,8 +500,8 @@ static int CVBandPDQJac(CVBandPrecData pdata, realtype t, N_Vector y, ftemp_data = N_VGetArrayPointer(ftemp); y_data = N_VGetArrayPointer(y); ytemp_data = N_VGetArrayPointer(ytemp); - if (cv_mem->cv_constraints != NULL) - cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); + if (cv_mem->cv_constraintsSet) + cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); /* Load ytemp with y = predicted y vector. */ N_VScale(ONE, y, ytemp); @@ -513,16 +515,16 @@ static int CVBandPDQJac(CVBandPrecData pdata, realtype t, N_Vector y, /* Set bandwidth and number of column groups for band differencing. */ width = pdata->ml + pdata->mu + 1; ngroups = SUNMIN(width, pdata->N); - + for (group = 1; group <= ngroups; group++) { - + /* Increment all y_j in group. */ for(j = group-1; j < pdata->N; j += width) { inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); yj = y_data[j]; /* Adjust sign(inc) again if yj has an inequality constraint. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} @@ -544,7 +546,7 @@ static int CVBandPDQJac(CVBandPrecData pdata, realtype t, N_Vector y, inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); /* Adjust sign(inc) as before. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bandpre_impl.h b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bandpre_impl.h index be463b1f5..39c1508d9 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bandpre_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bandpre_impl.h @@ -5,7 +5,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bbdpre.c b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bbdpre.c index 5ddd70129..bf21c0a5a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bbdpre.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bbdpre.c @@ -1,11 +1,11 @@ /* - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Programmer(s): Daniel R. Reynolds @ SMU - * Michael Wittman, Alan C. Hindmarsh, Radu Serban, and + * Michael Wittman, Alan C. Hindmarsh, Radu Serban, and * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -36,11 +36,11 @@ #define TWO RCONST(2.0) /* Prototypes of functions CVBBDPrecSetup and CVBBDPrecSolve */ -static int CVBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, +static int CVBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, realtype gamma, void *bbd_data); -static int CVBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, +static int CVBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, realtype delta, int lr, void *bbd_data); @@ -48,16 +48,16 @@ static int CVBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, static int CVBBDPrecFree(CVodeMem cv_mem); /* Prototype for difference quotient Jacobian calculation routine */ -static int CVBBDDQJac(CVBBDPrecData pdata, realtype t, - N_Vector y, N_Vector gy, +static int CVBBDDQJac(CVBBDPrecData pdata, realtype t, + N_Vector y, N_Vector gy, N_Vector ytemp, N_Vector gtemp); /*----------------------------------------------------------------- User-Callable Functions: initialization, reinit and free -----------------------------------------------------------------*/ -int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, +int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, sunindextype mudq, sunindextype mldq, - sunindextype mukeep, sunindextype mlkeep, + sunindextype mukeep, sunindextype mlkeep, realtype dqrely, CVLocalFn gloc, CVCommFn cfn) { CVodeMem cv_mem; @@ -91,7 +91,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, /* Allocate data memory */ pdata = NULL; - pdata = (CVBBDPrecData) malloc(sizeof *pdata); + pdata = (CVBBDPrecData) malloc(sizeof *pdata); if (pdata == NULL) { cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); @@ -111,11 +111,11 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, /* Allocate memory for saved Jacobian */ pdata->savedJ = SUNBandMatrixStorage(Nlocal, muk, mlk, muk); - if (pdata->savedJ == NULL) { - free(pdata); pdata = NULL; + if (pdata->savedJ == NULL) { + free(pdata); pdata = NULL; cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); - return(CVLS_MEM_FAIL); + return(CVLS_MEM_FAIL); } /* Allocate memory for preconditioner matrix */ @@ -137,7 +137,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -148,7 +148,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -160,7 +160,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -173,7 +173,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -187,7 +187,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -204,7 +204,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -221,7 +221,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedJ); SUNLinSolFree(pdata->LS); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVBBDPRE", + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVBBDPRE", "CVBBDPrecInit", MSGBBD_SUNLS_FAIL); return(CVLS_SUNLS_FAIL); } @@ -309,7 +309,7 @@ int CVBBDPrecReInit(void *cvode_mem, sunindextype mudq, cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVBBDPRE", "CVBBDPrecReInit", MSGBBD_PMEM_NULL); return(CVLS_PMEM_NULL); - } + } pdata = (CVBBDPrecData) cvls_mem->P_data; /* Load half-bandwidths */ @@ -354,7 +354,7 @@ int CVBBDPrecGetWorkSpace(void *cvode_mem, cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVBBDPRE", "CVBBDPrecGetWorkSpace", MSGBBD_PMEM_NULL); return(CVLS_PMEM_NULL); - } + } pdata = (CVBBDPrecData) cvls_mem->P_data; *lenrwBBDP = pdata->rpwsize; @@ -389,7 +389,7 @@ int CVBBDPrecGetNumGfnEvals(void *cvode_mem, cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVBBDPRE", "CVBBDPrecGetNumGfnEvals", MSGBBD_PMEM_NULL); return(CVLS_PMEM_NULL); - } + } pdata = (CVBBDPrecData) cvls_mem->P_data; *ngevalsBBDP = pdata->nge; @@ -399,25 +399,25 @@ int CVBBDPrecGetNumGfnEvals(void *cvode_mem, /*----------------------------------------------------------------- - Function : CVBBDPrecSetup + Function : CVBBDPrecSetup ----------------------------------------------------------------- CVBBDPrecSetup generates and factors a banded block of the preconditioner matrix on each processor, via calls to the user-supplied gloc and cfn functions. It uses difference quotient approximations to the Jacobian elements. - + CVBBDPrecSetup calculates a new J,if necessary, then calculates P = I - gamma*J, and does an LU factorization of P. - + The parameters of CVBBDPrecSetup used here are as follows: - + t is the current value of the independent variable. - + y is the current value of the dependent variable vector, namely the predicted value of y(t). - + fy is the vector f(t,y). - + jok is an input flag indicating whether Jacobian-related data needs to be recomputed, as follows: jok == SUNFALSE means recompute Jacobian-related data @@ -427,28 +427,27 @@ int CVBBDPrecGetNumGfnEvals(void *cvode_mem, (with the current value of gamma). A cvBBDPrecSetup call with jok == SUNTRUE should only occur after a call with jok == SUNFALSE. - + jcurPtr is a pointer to an output integer flag which is set by cvBBDPrecSetup as follows: *jcurPtr = SUNTRUE if Jacobian data was recomputed. *jcurPtr = SUNFALSE if Jacobian data was not recomputed, but saved data was reused. - + gamma is the scalar appearing in the Newton matrix. - + bbd_data is a pointer to the preconditioner data set by CVBBDPrecInit - + Return value: The value returned by this CVBBDPrecSetup function is the int 0 if successful, 1 for a recoverable error (step will be retried). -----------------------------------------------------------------*/ -static int CVBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, +static int CVBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, realtype gamma, void *bbd_data) { - sunindextype ier; CVBBDPrecData pdata; CVodeMem cv_mem; int retval; @@ -461,7 +460,7 @@ static int CVBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, *jcurPtr = SUNFALSE; retval = SUNMatCopy(pdata->savedJ, pdata->savedP); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBBDPRE", + cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); return(-1); } @@ -475,7 +474,7 @@ static int CVBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, *jcurPtr = SUNTRUE; retval = SUNMatZero(pdata->savedJ); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBBDPRE", + cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); return(-1); } @@ -483,10 +482,10 @@ static int CVBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, return(1); } - retval = CVBBDDQJac(pdata, t, y, pdata->tmp1, + retval = CVBBDDQJac(pdata, t, y, pdata->tmp1, pdata->tmp2, pdata->tmp3); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", + cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", MSGBBD_FUNC_FAILED); return(-1); } @@ -496,7 +495,7 @@ static int CVBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, retval = SUNMatCopy(pdata->savedJ, pdata->savedP); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBBDPRE", + cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); return(-1); } @@ -505,18 +504,18 @@ static int CVBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, } } - + /* Scale and add I to get P = I - gamma*J */ retval = SUNMatScaleAddI(-gamma, pdata->savedP); if (retval) { - cvProcessError(cv_mem, -1, "CVBBDPRE", + cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); return(-1); } - + /* Do LU factorization of matrix and return error flag */ - ier = SUNLinSolSetup_Band(pdata->LS, pdata->savedP); - return(ier); + retval = SUNLinSolSetup_Band(pdata->LS, pdata->savedP); + return(retval); } @@ -526,21 +525,21 @@ static int CVBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, CVBBDPrecSolve solves a linear system P z = r, with the band-block-diagonal preconditioner matrix P generated and factored by CVBBDPrecSetup. - + The parameters of CVBBDPrecSolve used here are as follows: - + r is the right-hand side vector of the linear system. - + bbd_data is a pointer to the preconditioner data set by CVBBDPrecInit. - + z is the output vector computed by CVBBDPrecSolve. - + The value returned by the CVBBDPrecSolve function is always 0, indicating success. -----------------------------------------------------------------*/ -static int CVBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, +static int CVBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, realtype delta, int lr, void *bbd_data) { @@ -552,9 +551,9 @@ static int CVBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, /* Attach local data arrays for r and z to rlocal and zlocal */ N_VSetArrayPointer(N_VGetArrayPointer(r), pdata->rlocal); N_VSetArrayPointer(N_VGetArrayPointer(z), pdata->zlocal); - + /* Call banded solver object to do the work */ - retval = SUNLinSolSolve(pdata->LS, pdata->savedP, pdata->zlocal, + retval = SUNLinSolSolve(pdata->LS, pdata->savedP, pdata->zlocal, pdata->rlocal, ZERO); /* Detach local data arrays from rlocal and zlocal */ @@ -569,10 +568,10 @@ static int CVBBDPrecFree(CVodeMem cv_mem) { CVLsMem cvls_mem; CVBBDPrecData pdata; - + if (cv_mem->cv_lmem == NULL) return(0); cvls_mem = (CVLsMem) cv_mem->cv_lmem; - + if (cvls_mem->P_data == NULL) return(0); pdata = (CVBBDPrecData) cvls_mem->P_data; @@ -597,8 +596,8 @@ static int CVBBDPrecFree(CVodeMem cv_mem) ----------------------------------------------------------------- This routine generates a banded difference quotient approximation to the local block of the Jacobian of g(t,y). It assumes that a - band SUNMatrix is stored columnwise, and that elements within each - column are contiguous. All matrix elements are generated as + band SUNMatrix is stored columnwise, and that elements within each + column are contiguous. All matrix elements are generated as difference quotients, by way of calls to the user routine gloc. By virtue of the band structure, the number of these calls is bandwidth + 1, where bandwidth = mldq + mudq + 1. @@ -606,7 +605,7 @@ static int CVBBDPrecFree(CVodeMem cv_mem) This routine also assumes that the local elements of a vector are stored contiguously. -----------------------------------------------------------------*/ -static int CVBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, +static int CVBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, N_Vector gy, N_Vector ytemp, N_Vector gtemp) { CVodeMem cv_mem; @@ -616,6 +615,9 @@ static int CVBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, realtype *ytemp_data, *col_j, *cns_data; int retval; + /* initialize cns_data to avoid compiler warning */ + cns_data = NULL; + cv_mem = (CVodeMem) pdata->cvode_mem; /* Load ytemp with y = predicted solution vector */ @@ -638,7 +640,7 @@ static int CVBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, ewt_data = N_VGetArrayPointer(cv_mem->cv_ewt); ytemp_data = N_VGetArrayPointer(ytemp); gtemp_data = N_VGetArrayPointer(gtemp); - if (cv_mem->cv_constraints != NULL) + if (cv_mem->cv_constraintsSet) cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); /* Set minimum increment based on uround and norm of g */ @@ -651,16 +653,16 @@ static int CVBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, width = pdata->mldq + pdata->mudq + 1; ngroups = SUNMIN(width, pdata->n_local); - /* Loop over groups */ + /* Loop over groups */ for (group=1; group <= ngroups; group++) { - + /* Increment all y_j in group */ for(j=group-1; j < pdata->n_local; j+=width) { inc = SUNMAX(pdata->dqrely * SUNRabs(y_data[j]), minInc/ewt_data[j]); yj = y_data[j]; /* Adjust sign(inc) again if yj has an inequality constraint. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} @@ -683,7 +685,7 @@ static int CVBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, inc = SUNMAX(pdata->dqrely * SUNRabs(y_data[j]), minInc/ewt_data[j]); /* Adjust sign(inc) as before. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bbdpre_impl.h b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bbdpre_impl.h index 4bb58d34a..26d864377 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bbdpre_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_bbdpre_impl.h @@ -4,7 +4,7 @@ * Michael Wittman, Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_diag.c b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_diag.c index 72b355500..fd1ff7d9e 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_diag.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_diag.c @@ -4,7 +4,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_diag_impl.h b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_diag_impl.h index 2d1333ada..7f2aaa2ca 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_diag_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_diag_impl.h @@ -4,7 +4,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_direct.c b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_direct.c index 44f694647..b597346b5 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_direct.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_direct.c @@ -1,8 +1,8 @@ -/*----------------------------------------------------------------- +/*----------------------------------------------------------------- * Programmer(s): Daniel R. Reynolds @ SMU *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -11,7 +11,7 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End *----------------------------------------------------------------- - * Implementation file for the deprecated direct linear solver interface in + * Implementation file for the deprecated direct linear solver interface in * CVODE; these routines now just wrap the updated CVODE generic * linear solver interface in cvode_ls.h. *-----------------------------------------------------------------*/ @@ -29,19 +29,19 @@ extern "C" { int CVDlsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, SUNMatrix A) { return(CVodeSetLinearSolver(cvode_mem, LS, A)); } - + int CVDlsSetJacFn(void *cvode_mem, CVDlsJacFn jac) { return(CVodeSetJacFn(cvode_mem, jac)); } int CVDlsGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS) { return(CVodeGetLinWorkSpace(cvode_mem, lenrwLS, leniwLS)); } - + int CVDlsGetNumJacEvals(void *cvode_mem, long int *njevals) { return(CVodeGetNumJacEvals(cvode_mem, njevals)); } - + int CVDlsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS) { return(CVodeGetNumLinRhsEvals(cvode_mem, nfevalsLS)); } - + int CVDlsGetLastFlag(void *cvode_mem, long int *flag) { return(CVodeGetLastLinFlag(cvode_mem, flag)); } @@ -52,4 +52,3 @@ char *CVDlsGetReturnFlagName(long int flag) #ifdef __cplusplus } #endif - diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_impl.h b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_impl.h index 42881de75..5aed37e64 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_impl.h @@ -5,7 +5,7 @@ * and Dan Shumaker @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -77,6 +77,7 @@ typedef struct CVodeMemRec { realtype cv_reltol; /* relative tolerance */ realtype cv_Sabstol; /* scalar absolute tolerance */ N_Vector cv_Vabstol; /* vector absolute tolerance */ + booleantype cv_atolmin0; /* flag indicating that min(abstol) = 0 */ booleantype cv_user_efun; /* SUNTRUE if user sets efun */ CVEwtFn cv_efun; /* function to set ewt */ void *cv_e_data; /* user pointer passed to efun */ @@ -110,8 +111,7 @@ typedef struct CVodeMemRec { N_Vector cv_vtemp2; /* temporary storage vector */ N_Vector cv_vtemp3; /* temporary storage vector */ - N_Vector cv_mm; /* mask vector in constraints tests */ - N_Vector cv_constraints; /* vector of inequality constraint options */ + N_Vector cv_constraints; /* vector of inequality constraint options */ /*----------------- Tstop information @@ -155,6 +155,7 @@ typedef struct CVodeMemRec { realtype cv_crate; /* estimated corrector convergence rate */ realtype cv_delp; /* norm of previous nonlinear solver update */ realtype cv_acnrm; /* | acor | wrms */ + booleantype cv_acnrmcur; /* is | acor | wrms current? */ realtype cv_nlscoef; /* coeficient in nonlinear convergence test */ /*------ @@ -246,7 +247,7 @@ typedef struct CVodeMemRec { int cv_indx_acor; /* index of the zn vector with saved acor */ booleantype cv_VabstolMallocDone; - booleantype cv_MallocDone; + booleantype cv_MallocDone; booleantype cv_constraintsMallocDone; /*------------------------------------------- @@ -516,7 +517,7 @@ int cvNlsInit(CVodeMem cv_mem); /* CVode Error Messages */ -#define MSGCV_NO_TOLS "No integration tolerances have been specified." +#define MSGCV_NO_TOL "No integration tolerances have been specified." #define MSGCV_LSOLVE_NULL "The linear solver's solve routine is NULL." #define MSGCV_YOUT_NULL "yout = NULL illegal." #define MSGCV_TRET_NULL "tret = NULL illegal." @@ -546,8 +547,9 @@ int cvNlsInit(CVodeMem cv_mem); #define MSGCV_CLOSE_ROOTS "Root found at and very near " MSG_TIME "." #define MSGCV_BAD_TSTOP "The value " MSG_TIME_TSTOP " is behind current " MSG_TIME " in the direction of integration." #define MSGCV_INACTIVE_ROOTS "At the end of the first step, there are still some root functions identically 0. This warning will not be issued again." -#define MSGCV_NLS_SETUP_FAILED "At " MSG_TIME "the nonlinear solver setup failed unrecoverably." -#define MSGCV_NLS_INPUT_NULL "At " MSG_TIME "the nonlinear solver was passed a NULL input." +#define MSGCV_NLS_SETUP_FAILED "At " MSG_TIME ", the nonlinear solver setup failed unrecoverably." +#define MSGCV_NLS_INPUT_NULL "At " MSG_TIME ", the nonlinear solver was passed a NULL input." +#define MSGCV_NLS_FAIL "At " MSG_TIME ", the nonlinear solver failed in an unrecoverable manner." #ifdef __cplusplus } diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_io.c b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_io.c index 48d4c027d..0ce639398 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_io.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_io.c @@ -6,7 +6,7 @@ * Programmer(s): Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -701,6 +701,29 @@ int CVodeGetCurrentOrder(void *cvode_mem, int *qcur) return(CV_SUCCESS); } +/* + * CVodeGetCurrentGamma + * + * Returns the value of gamma for the current step. + */ + +int CVodeGetCurrentGamma(void *cvode_mem, realtype *gamma) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetCurrentGamma", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *gamma = cv_mem->cv_gamma; + + return(CV_SUCCESS); +} + + /* * CVodeGetNumStabLimOrderReds * @@ -793,6 +816,28 @@ int CVodeGetCurrentStep(void *cvode_mem, realtype *hcur) return(CV_SUCCESS); } +/* + * CVodeGetCurrentState + * + * Returns the current state vector + */ + +int CVodeGetCurrentState(void *cvode_mem, N_Vector *y) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetCurrentState", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *y = cv_mem->cv_y; + + return(CV_SUCCESS); +} + /* * CVodeGetCurrentTime * @@ -1147,6 +1192,9 @@ char *CVodeGetReturnFlagName(long int flag) case CV_NLS_SETUP_FAIL: sprintf(name,"CV_NLS_SETUPT_FAIL"); break; + case CV_NLS_FAIL: + sprintf(name,"CV_NLS_FAIL"); + break; default: sprintf(name,"NONE"); } diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_ls.c b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_ls.c index cc716bec7..ebf0efeec 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_ls.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_ls.c @@ -3,7 +3,7 @@ * Alan C. Hindmarsh and Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -26,14 +26,22 @@ #include #include -/* constants */ +/* Private constants */ #define MIN_INC_MULT RCONST(1000.0) -#define MAX_DQITERS 3 /* max. # of attempts to recover in DQ J*v */ +#define MAX_DQITERS 3 /* max. number of attempts to recover in DQ J*v */ #define ZERO RCONST(0.0) #define PT25 RCONST(0.25) #define ONE RCONST(1.0) #define TWO RCONST(2.0) +/*================================================================= + PRIVATE FUNCTION PROTOTYPES + =================================================================*/ + +static int cvLsLinSys(realtype t, N_Vector y, N_Vector fy, SUNMatrix A, + booleantype jok, booleantype *jcur, realtype gamma, + void *user_data, N_Vector tmp1, N_Vector tmp2, + N_Vector tmp3); /*=============================================================== CVLS Exported functions -- Required @@ -45,9 +53,11 @@ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, SUNMatrix A) { - CVodeMem cv_mem; - CVLsMem cvls_mem; - int retval, LSType; + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval, LSType; + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ /* Return immediately if either cvode_mem or LS inputs are NULL */ if (cvode_mem == NULL) { @@ -58,48 +68,61 @@ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, if (LS == NULL) { cvProcessError(NULL, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", - "LS must be non-NULL"); + "LS must be non-NULL"); return(CVLS_ILL_INPUT); } cv_mem = (CVodeMem) cvode_mem; /* Test if solver is compatible with LS interface */ - if ( (LS->ops->gettype == NULL) || - (LS->ops->initialize == NULL) || - (LS->ops->setup == NULL) || - (LS->ops->solve == NULL) ) { + if ( (LS->ops->gettype == NULL) || (LS->ops->solve == NULL) ) { cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", "LS object is missing a required operation"); return(CVLS_ILL_INPUT); } + /* Retrieve the LS type */ + LSType = SUNLinSolGetType(LS); + + /* Set flags based on LS type */ + iterative = (LSType != SUNLINEARSOLVER_DIRECT); + matrixbased = (LSType != SUNLINEARSOLVER_ITERATIVE); + /* Test if vector is compatible with LS interface */ if ( (cv_mem->cv_tempv->ops->nvconst == NULL) || - (cv_mem->cv_tempv->ops->nvdotprod == NULL) ) { + (cv_mem->cv_tempv->ops->nvwrmsnorm == NULL) ) { cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", - "CVodeSetLinearSolver", MSG_LS_BAD_NVECTOR); + "CVodeSetLinearSolver", MSG_LS_BAD_NVECTOR); return(CVLS_ILL_INPUT); } - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(LS); - /* Check for compatible LS type, matrix and "atimes" support */ - if ((LSType == SUNLINEARSOLVER_ITERATIVE) && (LS->ops->setatimes == NULL)) { - cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", - "Incompatible inputs: iterative LS must support ATimes routine"); - return(CVLS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_DIRECT) && (A == NULL)) { - cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", - "Incompatible inputs: direct LS requires non-NULL matrix"); - return(CVLS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) && (A == NULL)) { + if (iterative) { + + if (cv_mem->cv_tempv->ops->nvgetlength == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", + "CVodeSetLinearSolver", MSG_LS_BAD_NVECTOR); + return(CVLS_ILL_INPUT); + } + + if (!matrixbased && LS->ops->setatimes == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", + "Incompatible inputs: iterative LS must support ATimes routine"); + return(CVLS_ILL_INPUT); + } + + if (matrixbased && A == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", + "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); + return(CVLS_ILL_INPUT); + } + + } else if (A == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", - "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); + "Incompatible inputs: direct LS requires non-NULL matrix"); return(CVLS_ILL_INPUT); + } /* free any existing system solver attached to CVode */ @@ -124,6 +147,10 @@ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, /* set SUNLinearSolver pointer */ cvls_mem->LS = LS; + /* Linear solver type information */ + cvls_mem->iterative = iterative; + cvls_mem->matrixbased = matrixbased; + /* Set defaults for Jacobian-related fields */ if (A != NULL) { cvls_mem->jacDQ = SUNTRUE; @@ -134,11 +161,16 @@ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, cvls_mem->jac = NULL; cvls_mem->J_data = NULL; } + cvls_mem->jtimesDQ = SUNTRUE; cvls_mem->jtsetup = NULL; cvls_mem->jtimes = cvLsDQJtimes; cvls_mem->jt_data = cv_mem; + cvls_mem->user_linsys = SUNFALSE; + cvls_mem->linsys = cvLsLinSys; + cvls_mem->A_data = cv_mem; + /* Set defaults for preconditioner-related fields */ cvls_mem->pset = NULL; cvls_mem->psolve = NULL; @@ -178,23 +210,17 @@ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, } } - /* When using a non-NULL SUNMatrix object, store pointer to A and create saved_J */ + /* When using a SUNMatrix object, store pointer to A and initialize savedJ */ if (A != NULL) { cvls_mem->A = A; - cvls_mem->savedJ = SUNMatClone(A); - if (cvls_mem->savedJ == NULL) { - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVLS", - "CVodeSetLinearSolver", MSG_LS_MEM_FAIL); - free(cvls_mem); cvls_mem = NULL; - return(CVLS_MEM_FAIL); - } + cvls_mem->savedJ = NULL; /* allocated in cvLsInitialize */ } + /* Allocate memory for ytemp and x */ cvls_mem->ytemp = N_VClone(cv_mem->cv_tempv); if (cvls_mem->ytemp == NULL) { cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVLS", "CVodeSetLinearSolver", MSG_LS_MEM_FAIL); - SUNMatDestroy(cvls_mem->savedJ); free(cvls_mem); cvls_mem = NULL; return(CVLS_MEM_FAIL); } @@ -203,19 +229,20 @@ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, if (cvls_mem->x == NULL) { cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVLS", "CVodeSetLinearSolver", MSG_LS_MEM_FAIL); - SUNMatDestroy(cvls_mem->savedJ); N_VDestroy(cvls_mem->ytemp); free(cvls_mem); cvls_mem = NULL; return(CVLS_MEM_FAIL); } - /* For iterative LS, compute sqrtN from a dot product */ - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { - N_VConst(ONE, cvls_mem->ytemp); - cvls_mem->sqrtN = SUNRsqrt( N_VDotProd(cvls_mem->ytemp, - cvls_mem->ytemp) ); - } + /* For iterative LS, compute sqrtN */ + if (iterative) + cvls_mem->sqrtN = SUNRsqrt( N_VGetLength(cvls_mem->ytemp) ); + + /* Check if soltuion scaling should be enabled */ + if (matrixbased && cv_mem->cv_lmm == CV_BDF) + cvls_mem->scalesol = SUNTRUE; + else + cvls_mem->scalesol = SUNFALSE; /* Attach linear solver memory to integrator memory */ cv_mem->cv_lmem = cvls_mem; @@ -248,7 +275,7 @@ int CVodeSetJacFn(void *cvode_mem, CVLsJacFn jac) return(CVLS_ILL_INPUT); } - /* set Jacobian routine pointer, and update relevant flags */ + /* set the Jacobian routine pointer, and update relevant flags */ if (jac != NULL) { cvls_mem->jacDQ = SUNFALSE; cvls_mem->jac = jac; @@ -259,6 +286,11 @@ int CVodeSetJacFn(void *cvode_mem, CVLsJacFn jac) cvls_mem->J_data = cv_mem; } + /* ensure the internal linear system function is used */ + cvls_mem->user_linsys = SUNFALSE; + cvls_mem->linsys = cvLsLinSys; + cvls_mem->A_data = cv_mem; + return(CVLS_SUCCESS); } @@ -307,6 +339,30 @@ int CVodeSetMaxStepsBetweenJac(void *cvode_mem, long int msbj) } +/* CVodeSetLinearSolutionScaling enables or disables scaling the + linear solver solution to account for changes in gamma. */ +int CVodeSetLinearSolutionScaling(void *cvode_mem, booleantype onoff) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; store input and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetLinearSolutionScaling", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* check for valid solver and method type */ + if (!(cvls_mem->matrixbased) || cv_mem->cv_lmm != CV_BDF) + return(CVLS_ILL_INPUT); + + /* set solution scaling flag */ + cvls_mem->scalesol = onoff; + + return(CVLS_SUCCESS); +} + + /* CVodeSetPreconditioner specifies the user-supplied preconditioner setup and solve routines */ int CVodeSetPreconditioner(void *cvode_mem, CVLsPrecSetupFn psetup, @@ -391,6 +447,40 @@ int CVodeSetJacTimes(void *cvode_mem, CVLsJacTimesSetupFn jtsetup, } +/* CVodeSetLinSysFn specifies the linear system setup function. */ +int CVodeSetLinSysFn(void *cvode_mem, CVLsLinSysFn linsys) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetLinSysFn", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* return with failure if linsys cannot be used */ + if ((linsys != NULL) && (cvls_mem->A == NULL)) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinSysFn", + "Linear system setup routine cannot be supplied for NULL SUNMatrix"); + return(CVLS_ILL_INPUT); + } + + /* set the linear system routine pointer, and update relevant flags */ + if (linsys != NULL) { + cvls_mem->user_linsys = SUNTRUE; + cvls_mem->linsys = linsys; + cvls_mem->A_data = cv_mem->cv_user_data; + } else { + cvls_mem->user_linsys = SUNFALSE; + cvls_mem->linsys = cvLsLinSys; + cvls_mem->A_data = cv_mem; + } + + return(CVLS_SUCCESS); +} + + /* CVodeGetLinWorkSpace returns the length of workspace allocated for the CVLS linear solver interface */ int CVodeGetLinWorkSpace(void *cvode_mem, long int *lenrwLS, @@ -822,6 +912,9 @@ int cvLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, CVLsMem cvls_mem; int retval = 0; + /* initialize cns_data to avoid compiler warning */ + cns_data = NULL; + /* access LsMem interface structure */ cvls_mem = (CVLsMem) cv_mem->cv_lmem; @@ -837,7 +930,7 @@ int cvLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, /* Obtain pointers to the data for ewt, y */ ewt_data = N_VGetArrayPointer(cv_mem->cv_ewt); y_data = N_VGetArrayPointer(y); - if (cv_mem->cv_constraints != NULL) + if (cv_mem->cv_constraintsSet) cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); /* Set minimum increment based on uround and norm of f */ @@ -855,7 +948,7 @@ int cvLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, inc = SUNMAX(srur*SUNRabs(yjsaved), minInc/ewt_data[j]); /* Adjust sign(inc) if y_j has an inequality constraint. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((yjsaved+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yjsaved+inc)*conj <= ZERO) inc = -inc;} @@ -905,6 +998,9 @@ int cvLsBandDQJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix Jac, CVLsMem cvls_mem; int retval = 0; + /* initialize cns_data to avoid compiler warning */ + cns_data = NULL; + /* access LsMem interface structure */ cvls_mem = (CVLsMem) cv_mem->cv_lmem; @@ -923,7 +1019,7 @@ int cvLsBandDQJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix Jac, ftemp_data = N_VGetArrayPointer(ftemp); y_data = N_VGetArrayPointer(y); ytemp_data = N_VGetArrayPointer(ytemp); - if (cv_mem->cv_constraints != NULL) + if (cv_mem->cv_constraintsSet) cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); /* Load ytemp with y = predicted y vector */ @@ -947,7 +1043,7 @@ int cvLsBandDQJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix Jac, inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); /* Adjust sign(inc) if yj has an inequality constraint. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((ytemp_data[j]+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((ytemp_data[j]+inc)*conj <= ZERO) inc = -inc;} @@ -968,7 +1064,7 @@ int cvLsBandDQJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix Jac, inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); /* Adjust sign(inc) as before. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((ytemp_data[j]+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((ytemp_data[j]+inc)*conj <= ZERO) inc = -inc;} @@ -1037,6 +1133,94 @@ int cvLsDQJtimes(N_Vector v, N_Vector Jv, realtype t, } +/*----------------------------------------------------------------- + cvLsLinSys + + Setup the linear system A = I - gamma J + -----------------------------------------------------------------*/ +static int cvLsLinSys(realtype t, N_Vector y, N_Vector fy, SUNMatrix A, + booleantype jok, booleantype *jcur, realtype gamma, + void *cvode_mem, N_Vector vtemp1, N_Vector vtemp2, + N_Vector vtemp3) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "cvLsLinSys", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Check if Jacobian needs to be updated */ + if (jok) { + + /* Use saved copy of J */ + *jcur = SUNFALSE; + + /* Overwrite linear system matrix with saved J */ + retval = SUNMatCopy(cvls_mem->savedJ, A); + if (retval) { + cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS", + "cvLsSetup", MSG_LS_SUNMAT_FAILED); + cvls_mem->last_flag = CVLS_SUNMAT_FAIL; + return(cvls_mem->last_flag); + } + + } else { + + /* Call jac() routine to update J */ + *jcur = SUNTRUE; + + /* Clear the linear system matrix if necessary */ + if (SUNLinSolGetType(cvls_mem->LS) == SUNLINEARSOLVER_DIRECT) { + retval = SUNMatZero(A); + if (retval) { + cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS", + "cvLsSetup", MSG_LS_SUNMAT_FAILED); + cvls_mem->last_flag = CVLS_SUNMAT_FAIL; + return(cvls_mem->last_flag); + } + } + + /* Compute new Jacobian matrix */ + retval = cvls_mem->jac(t, y, fy, A, cvls_mem->J_data, + vtemp1, vtemp2, vtemp3); + if (retval < 0) { + cvProcessError(cv_mem, CVLS_JACFUNC_UNRECVR, "CVLS", + "cvLsSetup", MSG_LS_JACFUNC_FAILED); + cvls_mem->last_flag = CVLS_JACFUNC_UNRECVR; + return(-1); + } + if (retval > 0) { + cvls_mem->last_flag = CVLS_JACFUNC_RECVR; + return(1); + } + + /* Update saved copy of the Jacobian matrix */ + retval = SUNMatCopy(A, cvls_mem->savedJ); + if (retval) { + cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS", + "cvLsSetup", MSG_LS_SUNMAT_FAILED); + cvls_mem->last_flag = CVLS_SUNMAT_FAIL; + return(cvls_mem->last_flag); + } + + } + + /* Perform linear combination A = I - gamma*J */ + retval = SUNMatScaleAddI(-gamma, A); + if (retval) { + cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS", + "cvLsSetup", MSG_LS_SUNMAT_FAILED); + cvls_mem->last_flag = CVLS_SUNMAT_FAIL; + return(cvls_mem->last_flag); + } + + return(CVLS_SUCCESS); +} + + /*----------------------------------------------------------------- cvLsInitialize @@ -1057,50 +1241,84 @@ int cvLsInitialize(CVodeMem cv_mem) cvls_mem = (CVLsMem) cv_mem->cv_lmem; /* Test for valid combinations of matrix & Jacobian routines: */ - if (cvls_mem->A == NULL) { + if (cvls_mem->A != NULL) { - /* If SUNMatrix A is NULL: ensure 'jac' function pointer is NULL */ - cvls_mem->jacDQ = SUNFALSE; - cvls_mem->jac = NULL; - cvls_mem->J_data = NULL; + /* Matrix-based case */ - } else if (cvls_mem->jacDQ) { + if (cvls_mem->user_linsys) { - /* If A is non-NULL, and 'jac' is not user-supplied: - - if A is dense or band, ensure that our DQ approx. is used - - otherwise => error */ - retval = 0; - if (cvls_mem->A->ops->getid) { + /* User-supplied linear system function, reset A_data (just in case) */ + cvls_mem->A_data = cv_mem->cv_user_data; + + } else { + + /* Internal linear system function, reset pointers (just in case) */ + cvls_mem->linsys = cvLsLinSys; + cvls_mem->A_data = cv_mem; + + /* Check if an internal or user-supplied Jacobian function is used */ + if (cvls_mem->jacDQ) { + + /* Internal difference quotient Jacobian. Check that A is dense or band, + otherwise return an error */ + retval = 0; + if (cvls_mem->A->ops->getid) { + + if ( (SUNMatGetID(cvls_mem->A) == SUNMATRIX_DENSE) || + (SUNMatGetID(cvls_mem->A) == SUNMATRIX_BAND) ) { + cvls_mem->jac = cvLsDQJac; + cvls_mem->J_data = cv_mem; + } else { + retval++; + } + + } else { + retval++; + } + if (retval) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "cvLsInitialize", + "No Jacobian constructor available for SUNMatrix type"); + cvls_mem->last_flag = CVLS_ILL_INPUT; + return(CVLS_ILL_INPUT); + } - if ( (SUNMatGetID(cvls_mem->A) == SUNMATRIX_DENSE) || - (SUNMatGetID(cvls_mem->A) == SUNMATRIX_BAND) ) { - cvls_mem->jac = cvLsDQJac; - cvls_mem->J_data = cv_mem; } else { - retval++; + + /* User-supplied Jacobian, reset J_data pointer (just in case) */ + cvls_mem->J_data = cv_mem->cv_user_data; + } - } else { - retval++; - } - if (retval) { - cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "cvLsInitialize", - "No Jacobian constructor available for SUNMatrix type"); - cvls_mem->last_flag = CVLS_ILL_INPUT; - return(CVLS_ILL_INPUT); - } + /* Allocate internally saved Jacobian if not already done */ + if (cvls_mem->savedJ == NULL) { + cvls_mem->savedJ = SUNMatClone(cvls_mem->A); + if (cvls_mem->savedJ == NULL) { + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVLS", "cvLsInitialize", + MSG_LS_MEM_FAIL); + cvls_mem->last_flag = CVLS_MEM_FAIL; + return(CVLS_MEM_FAIL); + } + } + + } /* end matrix-based case */ } else { - /* If A is non-NULL, and 'jac' is user-supplied, - reset J_data pointer (just in case) */ - cvls_mem->J_data = cv_mem->cv_user_data; + /* Matrix-free case: ensure 'jac' and `linsys` function pointers are NULL */ + cvls_mem->jacDQ = SUNFALSE; + cvls_mem->jac = NULL; + cvls_mem->J_data = NULL; + + cvls_mem->user_linsys = SUNFALSE; + cvls_mem->linsys = NULL; + cvls_mem->A_data = NULL; + } /* reset counters */ cvLsInitializeCounters(cvls_mem); - /* Set Jacobian-related fields, based on jtimesDQ */ + /* Set Jacobian-vector product related fields, based on jtimesDQ */ if (cvls_mem->jtimesDQ) { cvls_mem->jtsetup = NULL; cvls_mem->jtimes = cvLsDQJtimes; @@ -1161,70 +1379,41 @@ int cvLsSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, ((convfail == CV_FAIL_BAD_J) && (dgamma < CVLS_DGMAX)) || (convfail == CV_FAIL_OTHER); - /* If using a NULL SUNMatrix, set jcur to jbad; otherwise update J as appropriate */ - if (cvls_mem->A == NULL) { + /* Setup the linear system if necessary */ + if (cvls_mem->A != NULL) { - *jcurPtr = cvls_mem->jbad; - - } else { - - /* If jbad = SUNFALSE, use saved copy of J */ - if (!cvls_mem->jbad) { - - *jcurPtr = SUNFALSE; - retval = SUNMatCopy(cvls_mem->savedJ, cvls_mem->A); - if (retval) { - cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS", - "cvLsSetup", MSG_LS_SUNMAT_FAILED); - cvls_mem->last_flag = CVLS_SUNMAT_FAIL; - return(cvls_mem->last_flag); - } - - /* If jbad = SUNTRUE, call jac routine for new J value */ - } else { + /* Update J if appropriate and evaluate A = I - gamma J */ + retval = cvls_mem->linsys(cv_mem->cv_tn, ypred, fpred, cvls_mem->A, + !(cvls_mem->jbad), jcurPtr, cv_mem->cv_gamma, + cvls_mem->A_data, vtemp1, vtemp2, vtemp3); + /* Update J eval count and step when J was last updated */ + if (*jcurPtr) { cvls_mem->nje++; cvls_mem->nstlj = cv_mem->cv_nst; - *jcurPtr = SUNTRUE; - retval = SUNMatZero(cvls_mem->A); - if (retval) { - cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS", - "cvLsSetup", MSG_LS_SUNMAT_FAILED); - cvls_mem->last_flag = CVLS_SUNMAT_FAIL; - return(cvls_mem->last_flag); - } - - retval = cvls_mem->jac(cv_mem->cv_tn, ypred, fpred, cvls_mem->A, - cvls_mem->J_data, vtemp1, vtemp2, vtemp3); - if (retval < 0) { - cvProcessError(cv_mem, CVLS_JACFUNC_UNRECVR, "CVLS", - "cvLsSetup", MSG_LS_JACFUNC_FAILED); - cvls_mem->last_flag = CVLS_JACFUNC_UNRECVR; - return(-1); - } - if (retval > 0) { - cvls_mem->last_flag = CVLS_JACFUNC_RECVR; - return(1); - } + } - retval = SUNMatCopy(cvls_mem->A, cvls_mem->savedJ); - if (retval) { - cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS", - "cvLsSetup", MSG_LS_SUNMAT_FAILED); - cvls_mem->last_flag = CVLS_SUNMAT_FAIL; - return(cvls_mem->last_flag); + /* Check linsys() return value and return if necessary */ + if (retval != CVLS_SUCCESS) { + if (cvls_mem->user_linsys) { + if (retval < 0) { + cvProcessError(cv_mem, CVLS_JACFUNC_UNRECVR, "CVLS", + "cvLsSetup", MSG_LS_JACFUNC_FAILED); + cvls_mem->last_flag = CVLS_JACFUNC_UNRECVR; + return(-1); + } else { + cvls_mem->last_flag = CVLS_JACFUNC_RECVR; + return(1); + } + } else { + return(retval); } - } - /* Scale and add I to get A = I - gamma*J */ - retval = SUNMatScaleAddI(-cv_mem->cv_gamma, cvls_mem->A); - if (retval) { - cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS", - "cvLsSetup", MSG_LS_SUNMAT_FAILED); - cvls_mem->last_flag = CVLS_SUNMAT_FAIL; - return(cvls_mem->last_flag); - } + } else { + + /* Matrix-free case, set jcur to jbad */ + *jcurPtr = cvls_mem->jbad; } @@ -1232,7 +1421,7 @@ int cvLsSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, pass the heuristic suggestions above to the user code(s) */ cvls_mem->last_flag = SUNLinSolSetup(cvls_mem->LS, cvls_mem->A); - /* If the SUNMatrix was NULL, update heuristics flags */ + /* If Matrix-free, update heuristics flags */ if (cvls_mem->A == NULL) { /* If user set jcur to SUNTRUE, increment npe and save nst value */ @@ -1262,7 +1451,8 @@ int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, { CVLsMem cvls_mem; realtype bnorm, deltar, delta, w_mean; - int curiter, nli_inc, retval, LSType; + int curiter, nli_inc, retval; + /* access CVLsMem structure */ if (cv_mem->cv_lmem==NULL) { cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVLS", @@ -1271,17 +1461,13 @@ int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, } cvls_mem = (CVLsMem) cv_mem->cv_lmem; - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(cvls_mem->LS); - /* get current nonlinear solver iteration */ retval = SUNNonlinSolGetCurIter(cv_mem->NLS, &curiter); /* If the linear solver is iterative: test norm(b), if small, return x = 0 or x = b; set linear solver tolerance (in left/right scaled 2-norm) */ - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (cvls_mem->iterative) { deltar = cvls_mem->eplifac * cv_mem->cv_tq[4]; bnorm = N_VWrmsNorm(b, weight); if (bnorm <= deltar) { @@ -1299,9 +1485,6 @@ int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, cvls_mem->ycur = ynow; cvls_mem->fcur = fnow; - /* Set initial guess x = 0 to LS */ - N_VConst(ZERO, cvls_mem->x); - /* Set scaling vectors for LS to use (if applicable) */ if (cvls_mem->LS->ops->setscalingvectors) { retval = SUNLinSolSetScalingVectors(cvls_mem->LS, @@ -1327,16 +1510,18 @@ int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, <=> w_mean^2 \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 <=> \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 / w_mean^2 <=> || b - A x ||_2 < tol / w_mean - So we compute w_mean = ||w||_RMS = ||w||_2 / sqrt(n), and scale - the desired tolerance accordingly. */ - } else if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + So we compute w_mean = ||w||_RMS = ||w||_2 and scale the desired tolerance accordingly. */ + } else if (cvls_mem->iterative) { - w_mean = SUNRsqrt( N_VDotProd(weight, weight) ) / cvls_mem->sqrtN; + N_VConst(ONE, cvls_mem->x); + w_mean = N_VWrmsNorm(weight, cvls_mem->x); delta /= w_mean; } + /* Set initial guess x = 0 to LS */ + N_VConst(ZERO, cvls_mem->x); + /* If a user-provided jtsetup routine is supplied, call that here */ if (cvls_mem->jtsetup) { cvls_mem->last_flag = cvls_mem->jtsetup(cv_mem->cv_tn, ynow, fnow, @@ -1355,17 +1540,12 @@ int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, /* If using a direct or matrix-iterative solver, BDF method, and gamma has changed, scale the correction to account for change in gamma */ - if ( ((LSType == SUNLINEARSOLVER_DIRECT) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE)) && - (cv_mem->cv_lmm == CV_BDF) && - (cv_mem->cv_gamrat != ONE) ) + if (cvls_mem->scalesol && cv_mem->cv_gamrat != ONE) N_VScale(TWO/(ONE + cv_mem->cv_gamrat), b, b); /* Retrieve statistics from iterative linear solvers */ nli_inc = 0; - if ( ((LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE)) && - (cvls_mem->LS->ops->numiters) ) + if (cvls_mem->iterative && cvls_mem->LS->ops->numiters) nli_inc = SUNLinSolNumIters(cvls_mem->LS); /* Increment counters nli and ncfl */ diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_ls_impl.h b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_ls_impl.h index f20ac3fb6..808d110fd 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_ls_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_ls_impl.h @@ -3,7 +3,7 @@ * Alan C. Hindmarsh and Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -49,12 +49,19 @@ extern "C" { -----------------------------------------------------------------*/ typedef struct CVLsMemRec { + /* Linear solver type information */ + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ + /* Jacobian construction & storage */ booleantype jacDQ; /* SUNTRUE if using internal DQ Jac approx. */ CVLsJacFn jac; /* Jacobian routine to be called */ void *J_data; /* user data is passed to jac */ booleantype jbad; /* heuristic suggestion for pset */ + /* Matrix-based solver, scale solution to account for change in gamma */ + booleantype scalesol; + /* Iterative solver tolerance */ realtype sqrtN; /* sqrt(N) */ realtype eplifac; /* eplifac = user specified or EPLIN_DEFAULT */ @@ -64,7 +71,7 @@ typedef struct CVLsMemRec { SUNMatrix A; /* A = I - gamma * df/dy */ SUNMatrix savedJ; /* savedJ = old Jacobian */ N_Vector ytemp; /* temp vector passed to jtimes and psolve */ - N_Vector x; /* temp vector used by CVLsSolve */ + N_Vector x; /* temp vector used by CVLsSolve */ N_Vector ycur; /* CVODE current y vector in Newton Iteration */ N_Vector fcur; /* fcur = f(tn, ycur) */ @@ -105,7 +112,18 @@ typedef struct CVLsMemRec { CVLsJacTimesVecFn jtimes; void *jt_data; - long int last_flag; /* last error flag returned by any function */ + /* Linear system setup function + * (a) user-provided linsys function: + * - user_linsys = SUNTRUE + * - A_data = user_data + * (b) internal linsys function: + * - user_linsys = SUNFALSE + * - A_data = cvode_mem */ + booleantype user_linsys; + CVLsLinSysFn linsys; + void* A_data; + + int last_flag; /* last error flag returned by any function */ } *CVLsMem; diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_nls.c b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_nls.c index 9c28e50a8..117258429 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_nls.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_nls.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -34,9 +34,8 @@ static int cvNlsResidual(N_Vector ycor, N_Vector res, void* cvode_mem); static int cvNlsFPFunction(N_Vector ycor, N_Vector res, void* cvode_mem); -static int cvNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, - booleantype* jcur, void* cvode_mem); -static int cvNlsLSolve(N_Vector ycor, N_Vector delta, void* cvode_mem); +static int cvNlsLSetup(booleantype jbad, booleantype* jcur, void* cvode_mem); +static int cvNlsLSolve(N_Vector delta, void* cvode_mem); static int cvNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, realtype tol, N_Vector ewt, void* cvode_mem); @@ -65,9 +64,7 @@ int CVodeSetNonlinearSolver(void *cvode_mem, SUNNonlinearSolver NLS) /* check for required nonlinear solver functions */ if ( NLS->ops->gettype == NULL || - NLS->ops->initialize == NULL || NLS->ops->solve == NULL || - NLS->ops->free == NULL || NLS->ops->setsysfn == NULL ) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetNonlinearSolver", "NLS does not support required operations"); @@ -103,7 +100,7 @@ int CVodeSetNonlinearSolver(void *cvode_mem, SUNNonlinearSolver NLS) } /* set convergence test function */ - retval = SUNNonlinSolSetConvTestFn(cv_mem->NLS, cvNlsConvTest); + retval = SUNNonlinSolSetConvTestFn(cv_mem->NLS, cvNlsConvTest, cvode_mem); if (retval != CV_SUCCESS) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetNonlinearSolver", "Setting convergence test function failed"); @@ -118,6 +115,9 @@ int CVodeSetNonlinearSolver(void *cvode_mem, SUNNonlinearSolver NLS) return(CV_ILL_INPUT); } + /* Reset the acnrmcur flag to SUNFALSE */ + cv_mem->cv_acnrmcur = SUNFALSE; + return(CV_SUCCESS); } @@ -168,8 +168,7 @@ int cvNlsInit(CVodeMem cvode_mem) } -static int cvNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, - booleantype* jcur, void* cvode_mem) +static int cvNlsLSetup(booleantype jbad, booleantype* jcur, void* cvode_mem) { CVodeMem cv_mem; int retval; @@ -205,7 +204,7 @@ static int cvNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, } -static int cvNlsLSolve(N_Vector ycor, N_Vector delta, void* cvode_mem) +static int cvNlsLSolve(N_Vector delta, void* cvode_mem) { CVodeMem cv_mem; int retval; @@ -255,6 +254,7 @@ static int cvNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector delta, if (dcon <= ONE) { cv_mem->cv_acnrm = (m==0) ? del : N_VWrmsNorm(ycor, ewt); + cv_mem->cv_acnrmcur = SUNTRUE; return(CV_SUCCESS); /* Nonlinear system was solved successfully */ } diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_spils.c b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_spils.c index c4f9ffb2c..4d26892d0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_spils.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/cvode_spils.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -12,7 +12,7 @@ * SUNDIALS Copyright End * ----------------------------------------------------------------- * Implementation file for the deprecated Scaled, Preconditioned Iterative - * Linear Solver interface in CVODE; these routines now just wrap + * Linear Solver interface in CVODE; these routines now just wrap * the updated CVODE generic linear solver interface in cvode_ls.h. * -----------------------------------------------------------------*/ @@ -24,7 +24,7 @@ extern "C" { #endif /*================================================================= - CVSPILS Exported functions (wrappers for equivalent routines in + CVSPILS Exported functions (wrappers for equivalent routines in cvode_ls.h) =================================================================*/ @@ -33,45 +33,44 @@ int CVSpilsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS) int CVSpilsSetEpsLin(void *cvode_mem, realtype eplifac) { return(CVodeSetEpsLin(cvode_mem, eplifac)); } - + int CVSpilsSetPreconditioner(void *cvode_mem, CVSpilsPrecSetupFn pset, CVSpilsPrecSolveFn psolve) { return(CVodeSetPreconditioner(cvode_mem, pset, psolve)); } int CVSpilsSetJacTimes(void *cvode_mem, CVSpilsJacTimesSetupFn jtsetup, CVSpilsJacTimesVecFn jtimes) { return(CVodeSetJacTimes(cvode_mem, jtsetup, jtimes)); } - + int CVSpilsGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS) { return(CVodeGetLinWorkSpace(cvode_mem, lenrwLS, leniwLS)); } - + int CVSpilsGetNumPrecEvals(void *cvode_mem, long int *npevals) { return(CVodeGetNumPrecEvals(cvode_mem, npevals)); } - + int CVSpilsGetNumPrecSolves(void *cvode_mem, long int *npsolves) { return(CVodeGetNumPrecSolves(cvode_mem, npsolves)); } - + int CVSpilsGetNumLinIters(void *cvode_mem, long int *nliters) { return(CVodeGetNumLinIters(cvode_mem, nliters)); } - + int CVSpilsGetNumConvFails(void *cvode_mem, long int *nlcfails) { return(CVodeGetNumLinConvFails(cvode_mem, nlcfails)); } - + int CVSpilsGetNumJTSetupEvals(void *cvode_mem, long int *njtsetups) { return(CVodeGetNumJTSetupEvals(cvode_mem, njtsetups)); } - + int CVSpilsGetNumJtimesEvals(void *cvode_mem, long int *njvevals) { return(CVodeGetNumJtimesEvals(cvode_mem, njvevals)); } - + int CVSpilsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS) { return(CVodeGetNumLinRhsEvals(cvode_mem, nfevalsLS)); } - + int CVSpilsGetLastFlag(void *cvode_mem, long int *flag) { return(CVodeGetLastLinFlag(cvode_mem, flag)); } char *CVSpilsGetReturnFlagName(long int flag) { return(CVodeGetLinReturnFlagName(flag)); } - + #ifdef __cplusplus } #endif - diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/CMakeLists.txt index 482a31471..6cc99ed27 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/CMakeLists.txt @@ -1,7 +1,21 @@ +# ------------------------------------------------------------------------------ +# Programmer(s): +# ------------------------------------------------------------------------------ +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# ------------------------------------------------------------------------------ # CMakeLists.txt file for the FCVODE library +# ------------------------------------------------------------------------------ # Add variable fcvode_SOURCES with the sources for the FCVODE library -SET(fcvode_SOURCES +set(fcvode_SOURCES fcvband.c fcvbbd.c fcvbp.c @@ -19,13 +33,13 @@ SET(fcvode_SOURCES # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the CVODE library -SET(shared_SOURCES +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/nvector/serial/fnvector_serial.c ) # Add variable sunmatrix_SOURCES with the common SUNMatrix sources which will # also be included in the CVODE library -SET(sunmatrix_SOURCES +set(sunmatrix_SOURCES ${sundials_SOURCE_DIR}/src/sunmatrix/band/fsunmatrix_band.c ${sundials_SOURCE_DIR}/src/sunmatrix/dense/fsunmatrix_dense.c ${sundials_SOURCE_DIR}/src/sunmatrix/sparse/fsunmatrix_sparse.c @@ -33,7 +47,7 @@ SET(sunmatrix_SOURCES # Add variable sunlinsol_SOURCES with the common SUNLinearSolver sources which will # also be included in the CVODE library -SET(sunlinsol_SOURCES +set(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/band/fsunlinsol_band.c ${sundials_SOURCE_DIR}/src/sunlinsol/dense/fsunlinsol_dense.c ${sundials_SOURCE_DIR}/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c @@ -43,55 +57,36 @@ SET(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/pcg/fsunlinsol_pcg.c ) -IF(KLU_FOUND) - LIST(APPEND sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/klu/fsunlinsol_klu.c - ) -ENDIF() - -IF(SUPERLUMT_FOUND) - LIST(APPEND sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/superlumt/fsunlinsol_superlumt.c - ) -ENDIF() - -IF(LAPACK_FOUND) - LIST(APPEND sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/lapackband/fsunlinsol_lapackband.c - ${sundials_SOURCE_DIR}/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.c - ) -ENDIF() - # Add variable sunnonlinsol_SOURCES with the common SUNNonlinearSolver sources # which will also be included in the CVODE library -SET(sunnonlinsol_SOURCES +set(sunnonlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunnonlinsol/newton/fsunnonlinsol_newton.c ${sundials_SOURCE_DIR}/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.c ) # Add source directories to include directories for access to # implementation only header files (both for fcvode and cvode) -INCLUDE_DIRECTORIES(.) -INCLUDE_DIRECTORIES(..) +include_directories(.) +include_directories(..) -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY +add_definitions(-DBUILD_SUNDIALS_LIBRARY) -# Only build STATIC libraries (we cannot build shared libraries -# for the FCMIX interfaces due to unresolved symbol errors +# Only build STATIC libraries (we cannot build shared libraries +# for the FCMIX interfaces due to unresolved symbol errors # coming from inexistent user-provided functions) # Add the build target for the FCVODE library -ADD_LIBRARY(sundials_fcvode_static STATIC +add_library(sundials_fcvode_static STATIC ${fcvode_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ${sunnonlinsol_SOURCES}) # Set the library name and make sure it is not deleted -SET_TARGET_PROPERTIES(sundials_fcvode_static +set_target_properties(sundials_fcvode_static PROPERTIES OUTPUT_NAME sundials_fcvode CLEAN_DIRECT_OUTPUT 1) # Install the FCVODE library -INSTALL(TARGETS sundials_fcvode_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(TARGETS sundials_fcvode_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) # -MESSAGE(STATUS "Added CVODE FCMIX module") +message(STATUS "Added CVODE FCMIX module") diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvband.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvband.c index 855a0772b..2ea84304b 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvband.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvband.c @@ -4,7 +4,7 @@ * Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.c index 382fa0baf..29460e481 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.c @@ -1,10 +1,10 @@ /* - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Programmer(s): Daniel R. Reynolds @ SMU * Alan C. Hindmarsh, Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -36,7 +36,7 @@ extern "C" { #endif - extern void FCV_GLOCFN(long int *NLOC, realtype *T, + extern void FCV_GLOCFN(long int *NLOC, realtype *T, realtype *YLOC, realtype *GLOC, long int *IPAR, realtype *RPAR, int *ier); @@ -55,20 +55,26 @@ void FCV_BBDINIT(long int *Nloc, long int *mudq, long int *mldq, long int *mu, long int *ml, realtype* dqrely, int *ier) { - /* + /* First call CVBBDPrecInit to initialize CVBBDPRE module: Nloc is the local vector size mudq,mldq are the half-bandwidths for computing preconditioner blocks mu, ml are the half-bandwidths of the retained preconditioner blocks dqrely is the difference quotient relative increment factor FCVgloc is a pointer to the CVLocalFn function - FCVcfn is a pointer to the CVCommFn function + FCVcfn is a pointer to the CVCommFn function */ - *ier = CVBBDPrecInit(CV_cvodemem, *Nloc, *mudq, *mldq, *mu, *ml, *dqrely, + *ier = CVBBDPrecInit(CV_cvodemem, + (sunindextype)(*Nloc), + (sunindextype)(*mudq), + (sunindextype)(*mldq), + (sunindextype)(*mu), + (sunindextype)(*ml), + *dqrely, (CVLocalFn) FCVgloc, (CVCommFn) FCVcfn); - return; + return; } /***************************************************************************/ @@ -76,20 +82,23 @@ void FCV_BBDINIT(long int *Nloc, long int *mudq, long int *mldq, void FCV_BBDREINIT(long int *mudq, long int *mldq, realtype* dqrely, int *ier) { - /* + /* First call CVReInitBBD to re-initialize CVBBDPRE module: mudq,mldq are the half-bandwidths for computing preconditioner blocks dqrely is the difference quotient relative increment factor FCVgloc is a pointer to the CVLocalFn function - FCVcfn is a pointer to the CVCommFn function + FCVcfn is a pointer to the CVCommFn function */ - *ier = CVBBDPrecReInit(CV_cvodemem, *mudq, *mldq, *dqrely); + *ier = CVBBDPrecReInit(CV_cvodemem, + (sunindextype)(*mudq), + (sunindextype)(*mldq), + *dqrely); } /***************************************************************************/ -/* C function FCVgloc to interface between CVBBDPRE module and a Fortran +/* C function FCVgloc to interface between CVBBDPRE module and a Fortran subroutine FCVLOCFN. */ int FCVgloc(long int Nloc, realtype t, N_Vector yloc, N_Vector gloc, @@ -104,14 +113,14 @@ int FCVgloc(long int Nloc, realtype t, N_Vector yloc, N_Vector gloc, CV_userdata = (FCVUserData) user_data; - FCV_GLOCFN(&Nloc, &t, yloc_data, gloc_data, + FCV_GLOCFN(&Nloc, &t, yloc_data, gloc_data, CV_userdata->ipar, CV_userdata->rpar, &ier); return(ier); } /***************************************************************************/ -/* C function FCVcfn to interface between CVBBDPRE module and a Fortran +/* C function FCVcfn to interface between CVBBDPRE module and a Fortran subroutine FCVCOMMF. */ int FCVcfn(long int Nloc, realtype t, N_Vector y, void *user_data) diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.h b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.h index 849e575b8..b30f3c660 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.h @@ -4,7 +4,7 @@ * Alan Hindmarsh, Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbp.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbp.c index 695fc760a..152484399 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbp.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbp.c @@ -4,7 +4,7 @@ * Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -15,7 +15,7 @@ * ----------------------------------------------------------------- * This module contains the routines necessary to interface with the * CVBANDPRE module and user-supplied Fortran routines. - * The routines here call the generically named routines and provide + * The routines here call the generically named routines and provide * a standard interface to the C code of the CVBANDPRE package. * ----------------------------------------------------------------- */ @@ -32,13 +32,16 @@ void FCV_BPINIT(long int *N, long int *mu, long int *ml, int *ier) { - /* + /* Call CVBandPrecInit to initialize the CVBANDPRE module: N is the vector size mu, ml are the half-bandwidths of the retained preconditioner blocks */ - *ier = CVBandPrecInit(CV_cvodemem, *N, *mu, *ml); + *ier = CVBandPrecInit(CV_cvodemem, + (sunindextype)(*N), + (sunindextype)(*mu), + (sunindextype)(*ml)); return; } diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbp.h b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbp.h index 7f4725375..da16f56f5 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbp.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvbp.h @@ -4,7 +4,7 @@ * Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvdense.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvdense.c index e3c6a2a8b..a5e9bf931 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvdense.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvdense.c @@ -4,7 +4,7 @@ * Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvewt.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvewt.c index cecf847a0..a6adc3a4c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvewt.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvewt.c @@ -3,7 +3,7 @@ * Programmer: Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvjtimes.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvjtimes.c index 02ae44ebc..301c2cf09 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvjtimes.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvjtimes.c @@ -4,7 +4,7 @@ * Alan C. Hindmarsh, Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvnulllinsol.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvnulllinsol.c index be8ac27ef..c0ce7d097 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvnulllinsol.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvnulllinsol.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvnullmatrix.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvnullmatrix.c index 6f2323270..b2a4d6d94 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvnullmatrix.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvnullmatrix.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvnullnonlinsol.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvnullnonlinsol.c index 824fe0bef..86000945e 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvnullnonlinsol.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvnullnonlinsol.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvode.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvode.c index ca6767500..8bd971060 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvode.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvode.c @@ -1,10 +1,10 @@ /* - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Programmer(s): Daniel R. Reynolds @ SMU * Alan C. Hindmarsh, Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -25,7 +25,7 @@ #include #include -#include "fcvode.h" /* actual function names, prototypes, global vars.*/ +#include "fcvode.h" /* actual function names, prototypes, global vars.*/ #include "cvode_impl.h" /* definition of CVodeMem type */ #include #include @@ -95,7 +95,7 @@ void FCV_MALLOC(realtype *t0, realtype *y0, /* initialize global constants to disable each option */ CV_nrtfn = 0; CV_ls = -1; - + /* Create CVODE object */ lmm = (*meth == 1) ? CV_ADAMS : CV_BDF; CV_cvodemem = CVodeCreate(lmm); @@ -103,7 +103,7 @@ void FCV_MALLOC(realtype *t0, realtype *y0, *ier = -1; return; } - + /* Set and attach user data */ CV_userdata = NULL; CV_userdata = (FCVUserData) malloc(sizeof *CV_userdata); @@ -140,7 +140,7 @@ void FCV_MALLOC(realtype *t0, realtype *y0, /* Set tolerances */ switch (*iatol) { case 1: - *ier = CVodeSStolerances(CV_cvodemem, *rtol, *atol); + *ier = CVodeSStolerances(CV_cvodemem, *rtol, *atol); break; case 2: Vatol = NULL; @@ -175,8 +175,8 @@ void FCV_MALLOC(realtype *t0, realtype *y0, /***************************************************************************/ -void FCV_REINIT(realtype *t0, realtype *y0, - int *iatol, realtype *rtol, realtype *atol, +void FCV_REINIT(realtype *t0, realtype *y0, + int *iatol, realtype *rtol, realtype *atol, int *ier) { N_Vector Vatol; @@ -204,7 +204,7 @@ void FCV_REINIT(realtype *t0, realtype *y0, /* Set tolerances */ switch (*iatol) { case 1: - *ier = CVodeSStolerances(CV_cvodemem, *rtol, *atol); + *ier = CVodeSStolerances(CV_cvodemem, *rtol, *atol); break; case 2: Vatol = NULL; @@ -290,7 +290,7 @@ void FCV_SETVIN(char key_name[], realtype *vval, int *ier) return; } N_VSetArrayPointer(vval, Vec); - CVodeSetConstraints(CV_cvodemem, Vec); + *ier = CVodeSetConstraints(CV_cvodemem, Vec); N_VDestroy(Vec); } else { @@ -307,7 +307,7 @@ void FCV_LSINIT(int *ier) { *ier = -1; return; } - *ier = CVodeSetLinearSolver(CV_cvodemem, F2C_CVODE_linsol, + *ier = CVodeSetLinearSolver(CV_cvodemem, F2C_CVODE_linsol, F2C_CVODE_matrix); CV_ls = CV_LS_STD; return; @@ -351,12 +351,12 @@ void FCV_DIAG(int *ier) void FCV_CVODE(realtype *tout, realtype *t, realtype *y, int *itask, int *ier) { - /* + /* tout is the t value where output is desired F2C_CVODE_vec is the N_Vector containing the solution on return t is the returned independent variable value - itask is the task indicator (1 = CV_NORMAL, 2 = CV_ONE_STEP, - 3 = CV_NORMAL_TSTOP, 4 = CV_ONE_STEP_TSTOP) + itask is the task indicator (1 = CV_NORMAL, 2 = CV_ONE_STEP, + 3 = CV_NORMAL_TSTOP, 4 = CV_ONE_STEP_TSTOP) */ int qu, qcur; @@ -371,30 +371,30 @@ void FCV_CVODE(realtype *tout, realtype *t, realtype *y, int *itask, int *ier) CVodeGetWorkSpace(CV_cvodemem, &CV_iout[0], /* LENRW */ &CV_iout[1]); /* LENIW */ - CVodeGetIntegratorStats(CV_cvodemem, + CVodeGetIntegratorStats(CV_cvodemem, &CV_iout[2], /* NST */ - &CV_iout[3], /* NFE */ - &CV_iout[7], /* NSETUPS */ - &CV_iout[4], /* NETF */ + &CV_iout[3], /* NFE */ + &CV_iout[7], /* NSETUPS */ + &CV_iout[4], /* NETF */ &qu, /* QU */ &qcur, /* QCUR */ &CV_rout[0], /* H0U */ - &CV_rout[1], /* HU */ - &CV_rout[2], /* HCUR */ - &CV_rout[3]); /* TCUR */ + &CV_rout[1], /* HU */ + &CV_rout[2], /* HCUR */ + &CV_rout[3]); /* TCUR */ CV_iout[8] = (long int) qu; CV_iout[9] = (long int) qcur; - CVodeGetTolScaleFactor(CV_cvodemem, + CVodeGetTolScaleFactor(CV_cvodemem, &CV_rout[4]); /* TOLSFAC */ CVodeGetNonlinSolvStats(CV_cvodemem, &CV_iout[6], /* NNI */ &CV_iout[5]); /* NCFN */ CVodeGetNumStabLimOrderReds(CV_cvodemem, &CV_iout[10]); /* NOR */ - + /* Root finding is on */ if (CV_nrtfn != 0) CVodeGetNumGEvals(CV_cvodemem, &CV_iout[11]); /* NGE */ - + switch(CV_ls) { case CV_LS_STD: CVodeGetLinWorkSpace(CV_cvodemem, &CV_iout[12], &CV_iout[13]); /* LENRWLS,LENIWLS */ @@ -419,10 +419,10 @@ void FCV_CVODE(realtype *tout, realtype *t, realtype *y, int *itask, int *ier) void FCV_DKY (realtype *t, int *k, realtype *dky, int *ier) { - /* + /* t is the t value where output is desired k is the derivative order - F2C_CVODE_vec is the N_Vector containing the solution derivative on return + F2C_CVODE_vec is the N_Vector containing the solution derivative on return */ realtype *f2c_data = N_VGetArrayPointer(F2C_CVODE_vec); @@ -480,7 +480,7 @@ void FCV_FREE () if (cv_mem->cv_lfree) cv_mem->cv_lfree(cv_mem); cv_mem->cv_lmem = NULL; - + free(cv_mem->cv_user_data); cv_mem->cv_user_data = NULL; CVodeFree(&CV_cvodemem); @@ -491,19 +491,18 @@ void FCV_FREE () SUNMatDestroy(F2C_CVODE_matrix); if (F2C_CVODE_linsol) SUNLinSolFree(F2C_CVODE_linsol); - /* already freed by CVodeFree */ if (F2C_CVODE_nonlinsol) - F2C_CVODE_nonlinsol = NULL; + SUNNonlinSolFree(F2C_CVODE_nonlinsol); return; } /***************************************************************************/ -/* +/* * C function CVf to interface between CVODE and a Fortran subroutine FCVFUN. * Addresses of t, y, and ydot are passed to CVFUN, using the * routine N_VGetArrayPointer from the NVECTOR module. - * Auxiliary data is assumed to be communicated by Common. + * Auxiliary data is assumed to be communicated by Common. */ int FCVf(realtype t, N_Vector y, N_Vector ydot, void *user_data) @@ -522,7 +521,7 @@ int FCVf(realtype t, N_Vector y, N_Vector ydot, void *user_data) return(ier); } -/* Fortran interface to C routine CVodeSetNonlinearSolver; see +/* Fortran interface to C routine CVodeSetNonlinearSolver; see fcvode.h for further details */ void FCV_NLSINIT(int *ier) { if ( (CV_cvodemem == NULL) || (F2C_CVODE_nonlinsol == NULL) ) { diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvode.h b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvode.h index b16119ef1..650105088 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvode.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvode.h @@ -4,7 +4,7 @@ * Alan C. Hindmarsh, Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvpreco.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvpreco.c index b03404bfb..d78ea9db3 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvpreco.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvpreco.c @@ -4,7 +4,7 @@ * Alan C. Hindmarsh, Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvroot.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvroot.c index 2f99da050..d21d29a28 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvroot.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvroot.c @@ -3,7 +3,7 @@ * Programmer(s): Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvroot.h b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvroot.h index d92f192ed..66c4dff63 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvroot.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvroot.h @@ -3,7 +3,7 @@ * Programmer(s): Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvsparse.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvsparse.c index 33dacc1cc..b5155ac83 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvsparse.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fcmix/fcvsparse.c @@ -4,7 +4,7 @@ * Carol Woodward @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fmod/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/cvode/fmod/CMakeLists.txt new file mode 100644 index 000000000..ea617e271 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fmod/CMakeLists.txt @@ -0,0 +1,100 @@ +# --------------------------------------------------------------- +# Programmer(s): Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the F2003 CVODE object library +# --------------------------------------------------------------- + +set(cvode_SOURCES fcvode_mod.f90 fcvode_mod.c) + +if(BUILD_STATIC_LIBS) + sundials_add_f2003_interface_library(sundials_fcvode_mod_static STATIC + ${cvode_SOURCES} + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + + # include the directoy where the .mod files reside + target_include_directories(sundials_fcvode_mod_static + PUBLIC + $ + $ + ) + + # Set the library name and make sure it is not deleted + set_target_properties(sundials_fcvode_mod_static + PROPERTIES OUTPUT_NAME sundials_fcvode_mod CLEAN_DIRECT_OUTPUT 1) + + # install the library + install(TARGETS sundials_fcvode_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # install the cvode mod file from here since it won't go into the + # top level fortran mod file directory + install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_STATIC/fcvode_mod.mod + DESTINATION ${Fortran_INSTALL_MODDIR}) +endif() + +if(BUILD_SHARED_LIBS) + sundials_add_f2003_interface_library(sundials_fcvode_mod_shared SHARED + ${cvode_SOURCES} + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + + # include the directoy where the .mod files reside + target_include_directories(sundials_fcvode_mod_shared + PUBLIC + $ + $ + ) + + # Set the library name and make sure it is not deleted + set_target_properties(sundials_fcvode_mod_shared PROPERTIES + OUTPUT_NAME sundials_fcvode_mod + CLEAN_DIRECT_OUTPUT 1 + VERSION ${cvodelib_VERSION} + SOVERSION ${cvodelib_SOVERSION}) + + # install the library + install(TARGETS sundials_fcvode_mod_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # install the cvode mod file from here since it won't go into the + # top level fortran mod file directory + install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_SHARED/fcvode_mod.mod + DESTINATION ${Fortran_INSTALL_MODDIR}) +endif() + +message(STATUS "Added CVODE F2003 interface") diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fmod/fcvode_mod.c b/deps/AMICI/ThirdParty/sundials/src/cvode/fmod/fcvode_mod.c new file mode 100644 index 000000000..fd70cd90e --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fmod/fcvode_mod.c @@ -0,0 +1,1483 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "cvode/cvode.h" +#include "cvode/cvode_bandpre.h" +#include "cvode/cvode_bbdpre.h" +#include "cvode/cvode_diag.h" +#include "cvode/cvode_ls.h" + + +#include +#ifdef _MSC_VER +# ifndef strtoull +# define strtoull _strtoui64 +# endif +# ifndef strtoll +# define strtoll _strtoi64 +# endif +#endif + + +typedef struct { + void* data; + size_t size; +} SwigArrayWrapper; + + +SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() { + SwigArrayWrapper result; + result.data = NULL; + result.size = 0; + return result; +} + + +#include + +SWIGEXPORT void * _wrap_FCVodeCreate(int const *farg1) { + void * fresult ; + int arg1 ; + void *result = 0 ; + + arg1 = (int)(*farg1); + result = (void *)CVodeCreate(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeInit(void *farg1, CVRhsFn farg2, double const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + CVRhsFn arg2 = (CVRhsFn) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVRhsFn)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeReInit(void *farg1, double const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)CVodeReInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSStolerances(void *farg1, double const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)CVodeSStolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSVtolerances(void *farg1, double const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)CVodeSVtolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeWFtolerances(void *farg1, CVEwtFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + CVEwtFn arg2 = (CVEwtFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVEwtFn)(farg2); + result = (int)CVodeWFtolerances(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetErrHandlerFn(void *farg1, CVErrHandlerFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + CVErrHandlerFn arg2 = (CVErrHandlerFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVErrHandlerFn)(farg2); + arg3 = (void *)(farg3); + result = (int)CVodeSetErrHandlerFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetErrFile(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)CVodeSetErrFile(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetUserData(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + void *arg2 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (void *)(farg2); + result = (int)CVodeSetUserData(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxOrd(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetMaxOrd(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxNumSteps(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)CVodeSetMaxNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxHnilWarns(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetMaxHnilWarns(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetStabLimDet(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetStabLimDet(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetInitStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)CVodeSetInitStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMinStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)CVodeSetMinStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)CVodeSetMaxStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetStopTime(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)CVodeSetStopTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxErrTestFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetMaxErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxNonlinIters(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetMaxNonlinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxConvFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetMaxConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetNonlinConvCoef(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)CVodeSetNonlinConvCoef(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetConstraints(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)CVodeSetConstraints(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetNonlinearSolver(void *farg1, SUNNonlinearSolver farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNNonlinearSolver arg2 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNNonlinearSolver)(farg2); + result = (int)CVodeSetNonlinearSolver(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeRootInit(void *farg1, int const *farg2, CVRootFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVRootFn arg3 = (CVRootFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVRootFn)(farg3); + result = (int)CVodeRootInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetRootDirection(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)CVodeSetRootDirection(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetNoInactiveRootWarn(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)CVodeSetNoInactiveRootWarn(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVode(void *farg1, double const *farg2, N_Vector farg3, double *farg4, int const *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype *arg4 = (realtype *) 0 ; + int arg5 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + arg4 = (realtype *)(farg4); + arg5 = (int)(*farg5); + result = (int)CVode(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetDky(void *farg1, double const *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeGetDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVodeGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumSteps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumLinSolvSetups(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumLinSolvSetups(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumErrTestFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetLastOrder(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)CVodeGetLastOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetCurrentOrder(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)CVodeGetCurrentOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetCurrentGamma(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)CVodeGetCurrentGamma(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumStabLimOrderReds(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumStabLimOrderReds(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetActualInitStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)CVodeGetActualInitStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetLastStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)CVodeGetLastStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetCurrentStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)CVodeGetCurrentStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetCurrentState(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)CVodeGetCurrentState(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetCurrentTime(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)CVodeGetCurrentTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetTolScaleFactor(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)CVodeGetTolScaleFactor(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetErrWeights(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)CVodeGetErrWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetEstLocalErrors(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)CVodeGetEstLocalErrors(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumGEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumGEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetRootInfo(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)CVodeGetRootInfo(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetIntegratorStats(void *farg1, long *farg2, long *farg3, long *farg4, long *farg5, int *farg6, int *farg7, double *farg8, double *farg9, double *farg10, double *farg11) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + long *arg4 = (long *) 0 ; + long *arg5 = (long *) 0 ; + int *arg6 = (int *) 0 ; + int *arg7 = (int *) 0 ; + realtype *arg8 = (realtype *) 0 ; + realtype *arg9 = (realtype *) 0 ; + realtype *arg10 = (realtype *) 0 ; + realtype *arg11 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + arg4 = (long *)(farg4); + arg5 = (long *)(farg5); + arg6 = (int *)(farg6); + arg7 = (int *)(farg7); + arg8 = (realtype *)(farg8); + arg9 = (realtype *)(farg9); + arg10 = (realtype *)(farg10); + arg11 = (realtype *)(farg11); + result = (int)CVodeGetIntegratorStats(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumNonlinSolvIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumNonlinSolvIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumNonlinSolvConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumNonlinSolvConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNonlinSolvStats(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVodeGetNonlinSolvStats(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FCVodeGetReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)CVodeGetReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FCVodeFree(void *farg1) { + void **arg1 = (void **) 0 ; + + arg1 = (void **)(farg1); + CVodeFree(arg1); +} + + +SWIGEXPORT int _wrap_FCVBandPrecInit(void *farg1, int64_t const *farg2, int64_t const *farg3, int64_t const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + result = (int)CVBandPrecInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBandPrecGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVBandPrecGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBandPrecGetNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVBandPrecGetNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBBDPrecInit(void *farg1, int64_t const *farg2, int64_t const *farg3, int64_t const *farg4, int64_t const *farg5, int64_t const *farg6, double const *farg7, CVLocalFn farg8, CVCommFn farg9) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + sunindextype arg5 ; + sunindextype arg6 ; + realtype arg7 ; + CVLocalFn arg8 = (CVLocalFn) 0 ; + CVCommFn arg9 = (CVCommFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + arg5 = (sunindextype)(*farg5); + arg6 = (sunindextype)(*farg6); + arg7 = (realtype)(*farg7); + arg8 = (CVLocalFn)(farg8); + arg9 = (CVCommFn)(farg9); + result = (int)CVBBDPrecInit(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBBDPrecReInit(void *farg1, int64_t const *farg2, int64_t const *farg3, double const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + realtype arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (realtype)(*farg4); + result = (int)CVBBDPrecReInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBBDPrecGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVBBDPrecGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBBDPrecGetNumGfnEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVBBDPrecGetNumGfnEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVDiag(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)CVDiag(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVDiagGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVDiagGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVDiagGetNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVDiagGetNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVDiagGetLastFlag(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVDiagGetLastFlag(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FCVDiagGetReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)CVDiagGetReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetLinearSolver(void *farg1, SUNLinearSolver farg2, SUNMatrix farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNLinearSolver arg2 = (SUNLinearSolver) 0 ; + SUNMatrix arg3 = (SUNMatrix) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNLinearSolver)(farg2); + arg3 = (SUNMatrix)(farg3); + result = (int)CVodeSetLinearSolver(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetJacFn(void *farg1, CVLsJacFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + CVLsJacFn arg2 = (CVLsJacFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVLsJacFn)(farg2); + result = (int)CVodeSetJacFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxStepsBetweenJac(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)CVodeSetMaxStepsBetweenJac(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetLinearSolutionScaling(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetLinearSolutionScaling(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetEpsLin(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)CVodeSetEpsLin(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetPreconditioner(void *farg1, CVLsPrecSetupFn farg2, CVLsPrecSolveFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + CVLsPrecSetupFn arg2 = (CVLsPrecSetupFn) 0 ; + CVLsPrecSolveFn arg3 = (CVLsPrecSolveFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVLsPrecSetupFn)(farg2); + arg3 = (CVLsPrecSolveFn)(farg3); + result = (int)CVodeSetPreconditioner(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetJacTimes(void *farg1, CVLsJacTimesSetupFn farg2, CVLsJacTimesVecFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + CVLsJacTimesSetupFn arg2 = (CVLsJacTimesSetupFn) 0 ; + CVLsJacTimesVecFn arg3 = (CVLsJacTimesVecFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVLsJacTimesSetupFn)(farg2); + arg3 = (CVLsJacTimesVecFn)(farg3); + result = (int)CVodeSetJacTimes(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetLinSysFn(void *farg1, CVLsLinSysFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + CVLsLinSysFn arg2 = (CVLsLinSysFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVLsLinSysFn)(farg2); + result = (int)CVodeSetLinSysFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetLinWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVodeGetLinWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumJacEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumJacEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumPrecEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumPrecEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumPrecSolves(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumPrecSolves(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumLinIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumLinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumLinConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumLinConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumJTSetupEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumJTSetupEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumJtimesEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumJtimesEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumLinRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumLinRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetLastLinFlag(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetLastLinFlag(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FCVodeGetLinReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)CVodeGetLinReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/cvode/fmod/fcvode_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/cvode/fmod/fcvode_mod.f90 new file mode 100644 index 000000000..faf6d809e --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/cvode/fmod/fcvode_mod.f90 @@ -0,0 +1,2442 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fcvode_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_linearsolver_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_nonlinearsolver_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: CV_ADAMS = 1_C_INT + integer(C_INT), parameter, public :: CV_BDF = 2_C_INT + integer(C_INT), parameter, public :: CV_NORMAL = 1_C_INT + integer(C_INT), parameter, public :: CV_ONE_STEP = 2_C_INT + integer(C_INT), parameter, public :: CV_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: CV_TSTOP_RETURN = 1_C_INT + integer(C_INT), parameter, public :: CV_ROOT_RETURN = 2_C_INT + integer(C_INT), parameter, public :: CV_WARNING = 99_C_INT + integer(C_INT), parameter, public :: CV_TOO_MUCH_WORK = -1_C_INT + integer(C_INT), parameter, public :: CV_TOO_MUCH_ACC = -2_C_INT + integer(C_INT), parameter, public :: CV_ERR_FAILURE = -3_C_INT + integer(C_INT), parameter, public :: CV_CONV_FAILURE = -4_C_INT + integer(C_INT), parameter, public :: CV_LINIT_FAIL = -5_C_INT + integer(C_INT), parameter, public :: CV_LSETUP_FAIL = -6_C_INT + integer(C_INT), parameter, public :: CV_LSOLVE_FAIL = -7_C_INT + integer(C_INT), parameter, public :: CV_RHSFUNC_FAIL = -8_C_INT + integer(C_INT), parameter, public :: CV_FIRST_RHSFUNC_ERR = -9_C_INT + integer(C_INT), parameter, public :: CV_REPTD_RHSFUNC_ERR = -10_C_INT + integer(C_INT), parameter, public :: CV_UNREC_RHSFUNC_ERR = -11_C_INT + integer(C_INT), parameter, public :: CV_RTFUNC_FAIL = -12_C_INT + integer(C_INT), parameter, public :: CV_NLS_INIT_FAIL = -13_C_INT + integer(C_INT), parameter, public :: CV_NLS_SETUP_FAIL = -14_C_INT + integer(C_INT), parameter, public :: CV_CONSTR_FAIL = -15_C_INT + integer(C_INT), parameter, public :: CV_NLS_FAIL = -16_C_INT + integer(C_INT), parameter, public :: CV_MEM_FAIL = -20_C_INT + integer(C_INT), parameter, public :: CV_MEM_NULL = -21_C_INT + integer(C_INT), parameter, public :: CV_ILL_INPUT = -22_C_INT + integer(C_INT), parameter, public :: CV_NO_MALLOC = -23_C_INT + integer(C_INT), parameter, public :: CV_BAD_K = -24_C_INT + integer(C_INT), parameter, public :: CV_BAD_T = -25_C_INT + integer(C_INT), parameter, public :: CV_BAD_DKY = -26_C_INT + integer(C_INT), parameter, public :: CV_TOO_CLOSE = -27_C_INT + integer(C_INT), parameter, public :: CV_VECTOROP_ERR = -28_C_INT + integer(C_INT), parameter, public :: CV_UNRECOGNIZED_ERR = -99_C_INT + public :: FCVodeCreate + public :: FCVodeInit + public :: FCVodeReInit + public :: FCVodeSStolerances + public :: FCVodeSVtolerances + public :: FCVodeWFtolerances + public :: FCVodeSetErrHandlerFn + public :: FCVodeSetErrFile + public :: FCVodeSetUserData + public :: FCVodeSetMaxOrd + public :: FCVodeSetMaxNumSteps + public :: FCVodeSetMaxHnilWarns + public :: FCVodeSetStabLimDet + public :: FCVodeSetInitStep + public :: FCVodeSetMinStep + public :: FCVodeSetMaxStep + public :: FCVodeSetStopTime + public :: FCVodeSetMaxErrTestFails + public :: FCVodeSetMaxNonlinIters + public :: FCVodeSetMaxConvFails + public :: FCVodeSetNonlinConvCoef + public :: FCVodeSetConstraints + public :: FCVodeSetNonlinearSolver + public :: FCVodeRootInit + public :: FCVodeSetRootDirection + public :: FCVodeSetNoInactiveRootWarn + public :: FCVode + public :: FCVodeGetDky + public :: FCVodeGetWorkSpace + public :: FCVodeGetNumSteps + public :: FCVodeGetNumRhsEvals + public :: FCVodeGetNumLinSolvSetups + public :: FCVodeGetNumErrTestFails + public :: FCVodeGetLastOrder + public :: FCVodeGetCurrentOrder + public :: FCVodeGetCurrentGamma + public :: FCVodeGetNumStabLimOrderReds + public :: FCVodeGetActualInitStep + public :: FCVodeGetLastStep + public :: FCVodeGetCurrentStep + public :: FCVodeGetCurrentState + public :: FCVodeGetCurrentTime + public :: FCVodeGetTolScaleFactor + public :: FCVodeGetErrWeights + public :: FCVodeGetEstLocalErrors + public :: FCVodeGetNumGEvals + public :: FCVodeGetRootInfo + public :: FCVodeGetIntegratorStats + public :: FCVodeGetNumNonlinSolvIters + public :: FCVodeGetNumNonlinSolvConvFails + public :: FCVodeGetNonlinSolvStats + type, bind(C) :: SwigArrayWrapper + type(C_PTR), public :: data = C_NULL_PTR + integer(C_SIZE_T), public :: size = 0 + end type + public :: FCVodeGetReturnFlagName + public :: FCVodeFree + public :: FCVBandPrecInit + public :: FCVBandPrecGetWorkSpace + public :: FCVBandPrecGetNumRhsEvals + public :: FCVBBDPrecInit + public :: FCVBBDPrecReInit + public :: FCVBBDPrecGetWorkSpace + public :: FCVBBDPrecGetNumGfnEvals + integer(C_INT), parameter, public :: CVDIAG_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: CVDIAG_MEM_NULL = -1_C_INT + integer(C_INT), parameter, public :: CVDIAG_LMEM_NULL = -2_C_INT + integer(C_INT), parameter, public :: CVDIAG_ILL_INPUT = -3_C_INT + integer(C_INT), parameter, public :: CVDIAG_MEM_FAIL = -4_C_INT + integer(C_INT), parameter, public :: CVDIAG_INV_FAIL = -5_C_INT + integer(C_INT), parameter, public :: CVDIAG_RHSFUNC_UNRECVR = -6_C_INT + integer(C_INT), parameter, public :: CVDIAG_RHSFUNC_RECVR = -7_C_INT + public :: FCVDiag + public :: FCVDiagGetWorkSpace + public :: FCVDiagGetNumRhsEvals + public :: FCVDiagGetLastFlag + public :: FCVDiagGetReturnFlagName + integer(C_INT), parameter, public :: CVLS_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: CVLS_MEM_NULL = -1_C_INT + integer(C_INT), parameter, public :: CVLS_LMEM_NULL = -2_C_INT + integer(C_INT), parameter, public :: CVLS_ILL_INPUT = -3_C_INT + integer(C_INT), parameter, public :: CVLS_MEM_FAIL = -4_C_INT + integer(C_INT), parameter, public :: CVLS_PMEM_NULL = -5_C_INT + integer(C_INT), parameter, public :: CVLS_JACFUNC_UNRECVR = -6_C_INT + integer(C_INT), parameter, public :: CVLS_JACFUNC_RECVR = -7_C_INT + integer(C_INT), parameter, public :: CVLS_SUNMAT_FAIL = -8_C_INT + integer(C_INT), parameter, public :: CVLS_SUNLS_FAIL = -9_C_INT + public :: FCVodeSetLinearSolver + public :: FCVodeSetJacFn + public :: FCVodeSetMaxStepsBetweenJac + public :: FCVodeSetLinearSolutionScaling + public :: FCVodeSetEpsLin + public :: FCVodeSetPreconditioner + public :: FCVodeSetJacTimes + public :: FCVodeSetLinSysFn + public :: FCVodeGetLinWorkSpace + public :: FCVodeGetNumJacEvals + public :: FCVodeGetNumPrecEvals + public :: FCVodeGetNumPrecSolves + public :: FCVodeGetNumLinIters + public :: FCVodeGetNumLinConvFails + public :: FCVodeGetNumJTSetupEvals + public :: FCVodeGetNumJtimesEvals + public :: FCVodeGetNumLinRhsEvals + public :: FCVodeGetLastLinFlag + public :: FCVodeGetLinReturnFlagName + +! WRAPPER DECLARATIONS +interface +function swigc_FCVodeCreate(farg1) & +bind(C, name="_wrap_FCVodeCreate") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FCVodeInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeReInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSStolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSStolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSVtolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSVtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeWFtolerances(farg1, farg2) & +bind(C, name="_wrap_FCVodeWFtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetErrHandlerFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetErrHandlerFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetErrFile(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetErrFile") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetUserData(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetUserData") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxOrd(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxOrd") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxNumSteps(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxHnilWarns(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxHnilWarns") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetStabLimDet(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetStabLimDet") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetInitStep(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetInitStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMinStep(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMinStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxStep(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetStopTime(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetStopTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxNonlinIters(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxNonlinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxConvFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetNonlinConvCoef(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetNonlinConvCoef") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetConstraints(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetConstraints") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetNonlinearSolver(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetNonlinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeRootInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeRootInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetRootDirection(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetRootDirection") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetNoInactiveRootWarn(farg1) & +bind(C, name="_wrap_FCVodeSetNoInactiveRootWarn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FCVode(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVode") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeGetDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumSteps(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumLinSolvSetups(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumLinSolvSetups") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetLastOrder(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetLastOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetCurrentOrder(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetCurrentOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetCurrentGamma(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetCurrentGamma") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumStabLimOrderReds(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumStabLimOrderReds") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetActualInitStep(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetActualInitStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetLastStep(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetLastStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetCurrentStep(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetCurrentStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetCurrentState(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetCurrentState") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetCurrentTime(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetCurrentTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetTolScaleFactor(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetTolScaleFactor") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetErrWeights(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetErrWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetEstLocalErrors(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetEstLocalErrors") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumGEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumGEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetRootInfo(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetRootInfo") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetIntegratorStats(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10, farg11) & +bind(C, name="_wrap_FCVodeGetIntegratorStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +type(C_PTR), value :: farg7 +type(C_PTR), value :: farg8 +type(C_PTR), value :: farg9 +type(C_PTR), value :: farg10 +type(C_PTR), value :: farg11 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumNonlinSolvIters(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumNonlinSolvIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumNonlinSolvConvFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumNonlinSolvConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNonlinSolvStats(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetNonlinSolvStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + + subroutine SWIG_free(cptr) & + bind(C, name="free") + use, intrinsic :: ISO_C_BINDING + type(C_PTR), value :: cptr +end subroutine +function swigc_FCVodeGetReturnFlagName(farg1) & +bind(C, name="_wrap_FCVodeGetReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +subroutine swigc_FCVodeFree(farg1) & +bind(C, name="_wrap_FCVodeFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FCVBandPrecInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVBandPrecInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVBandPrecGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVBandPrecGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVBandPrecGetNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FCVBandPrecGetNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVBBDPrecInit(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) & +bind(C, name="_wrap_FCVBBDPrecInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +integer(C_INT64_T), intent(in) :: farg5 +integer(C_INT64_T), intent(in) :: farg6 +real(C_DOUBLE), intent(in) :: farg7 +type(C_FUNPTR), value :: farg8 +type(C_FUNPTR), value :: farg9 +integer(C_INT) :: fresult +end function + +function swigc_FCVBBDPrecReInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVBBDPrecReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVBBDPrecGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVBBDPrecGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVBBDPrecGetNumGfnEvals(farg1, farg2) & +bind(C, name="_wrap_FCVBBDPrecGetNumGfnEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVDiag(farg1) & +bind(C, name="_wrap_FCVDiag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FCVDiagGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVDiagGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVDiagGetNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FCVDiagGetNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVDiagGetLastFlag(farg1, farg2) & +bind(C, name="_wrap_FCVDiagGetLastFlag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVDiagGetReturnFlagName(farg1) & +bind(C, name="_wrap_FCVDiagGetReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +function swigc_FCVodeSetLinearSolver(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetLinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetJacFn(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetJacFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxStepsBetweenJac(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxStepsBetweenJac") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetLinearSolutionScaling(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetLinearSolutionScaling") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetEpsLin(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetEpsLin") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetPreconditioner(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetPreconditioner") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetJacTimes(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetJacTimes") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetLinSysFn(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetLinSysFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetLinWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetLinWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumJacEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumJacEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumPrecEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumPrecEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumPrecSolves(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumPrecSolves") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumLinIters(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumLinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumLinConvFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumLinConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumJTSetupEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumJTSetupEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumJtimesEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumJtimesEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumLinRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumLinRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetLastLinFlag(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetLastLinFlag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetLinReturnFlagName(farg1) & +bind(C, name="_wrap_FCVodeGetLinReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FCVodeCreate(lmm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: lmm +type(C_PTR) :: fresult +integer(C_INT) :: farg1 + +farg1 = lmm +fresult = swigc_FCVodeCreate(farg1) +swig_result = fresult +end function + +function FCVodeInit(cvode_mem, f, t0, y0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: f +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: y0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = f +farg3 = t0 +farg4 = c_loc(y0) +fresult = swigc_FCVodeInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeReInit(cvode_mem, t0, y0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: y0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = t0 +farg3 = c_loc(y0) +fresult = swigc_FCVodeReInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSStolerances(cvode_mem, reltol, abstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: reltol +real(C_DOUBLE), intent(in) :: abstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = cvode_mem +farg2 = reltol +farg3 = abstol +fresult = swigc_FCVodeSStolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSVtolerances(cvode_mem, reltol, abstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: reltol +type(N_Vector), target, intent(inout) :: abstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = reltol +farg3 = c_loc(abstol) +fresult = swigc_FCVodeSVtolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeWFtolerances(cvode_mem, efun) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: efun +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = cvode_mem +farg2 = efun +fresult = swigc_FCVodeWFtolerances(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetErrHandlerFn(cvode_mem, ehfun, eh_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: ehfun +type(C_PTR) :: eh_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = ehfun +farg3 = eh_data +fresult = swigc_FCVodeSetErrHandlerFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetErrFile(cvode_mem, errfp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_PTR) :: errfp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = errfp +fresult = swigc_FCVodeSetErrFile(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetUserData(cvode_mem, user_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_PTR) :: user_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = user_data +fresult = swigc_FCVodeSetUserData(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxOrd(cvode_mem, maxord) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: maxord +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = maxord +fresult = swigc_FCVodeSetMaxOrd(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxNumSteps(cvode_mem, mxsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), intent(in) :: mxsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = cvode_mem +farg2 = mxsteps +fresult = swigc_FCVodeSetMaxNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxHnilWarns(cvode_mem, mxhnil) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: mxhnil +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = mxhnil +fresult = swigc_FCVodeSetMaxHnilWarns(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetStabLimDet(cvode_mem, stldet) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: stldet +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = stldet +fresult = swigc_FCVodeSetStabLimDet(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetInitStep(cvode_mem, hin) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: hin +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = cvode_mem +farg2 = hin +fresult = swigc_FCVodeSetInitStep(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMinStep(cvode_mem, hmin) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: hmin +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = cvode_mem +farg2 = hmin +fresult = swigc_FCVodeSetMinStep(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxStep(cvode_mem, hmax) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: hmax +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = cvode_mem +farg2 = hmax +fresult = swigc_FCVodeSetMaxStep(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetStopTime(cvode_mem, tstop) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: tstop +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = cvode_mem +farg2 = tstop +fresult = swigc_FCVodeSetStopTime(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxErrTestFails(cvode_mem, maxnef) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: maxnef +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = maxnef +fresult = swigc_FCVodeSetMaxErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxNonlinIters(cvode_mem, maxcor) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: maxcor +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = maxcor +fresult = swigc_FCVodeSetMaxNonlinIters(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxConvFails(cvode_mem, maxncf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: maxncf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = maxncf +fresult = swigc_FCVodeSetMaxConvFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetNonlinConvCoef(cvode_mem, nlscoef) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: nlscoef +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = cvode_mem +farg2 = nlscoef +fresult = swigc_FCVodeSetNonlinConvCoef(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetConstraints(cvode_mem, constraints) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(N_Vector), target, intent(inout) :: constraints +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(constraints) +fresult = swigc_FCVodeSetConstraints(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetNonlinearSolver(cvode_mem, nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nls) +fresult = swigc_FCVodeSetNonlinearSolver(farg1, farg2) +swig_result = fresult +end function + +function FCVodeRootInit(cvode_mem, nrtfn, g) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: nrtfn +type(C_FUNPTR), intent(in), value :: g +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = cvode_mem +farg2 = nrtfn +farg3 = g +fresult = swigc_FCVodeRootInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetRootDirection(cvode_mem, rootdir) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootdir +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(rootdir(1)) +fresult = swigc_FCVodeSetRootDirection(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetNoInactiveRootWarn(cvode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = cvode_mem +fresult = swigc_FCVodeSetNoInactiveRootWarn(farg1) +swig_result = fresult +end function + +function FCVode(cvode_mem, tout, yout, tret, itask) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: tout +type(N_Vector), target, intent(inout) :: yout +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +integer(C_INT), intent(in) :: itask +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +integer(C_INT) :: farg5 + +farg1 = cvode_mem +farg2 = tout +farg3 = c_loc(yout) +farg4 = c_loc(tret(1)) +farg5 = itask +fresult = swigc_FCVode(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVodeGetDky(cvode_mem, t, k, dky) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(N_Vector), target, intent(inout) :: dky +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = t +farg3 = k +farg4 = c_loc(dky) +fresult = swigc_FCVodeGetDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeGetWorkSpace(cvode_mem, lenrw, leniw) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrw +integer(C_LONG), dimension(*), target, intent(inout) :: leniw +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(lenrw(1)) +farg3 = c_loc(leniw(1)) +fresult = swigc_FCVodeGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeGetNumSteps(cvode_mem, nsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nsteps(1)) +fresult = swigc_FCVodeGetNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumRhsEvals(cvode_mem, nfevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nfevals(1)) +fresult = swigc_FCVodeGetNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumLinSolvSetups(cvode_mem, nlinsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nlinsetups(1)) +fresult = swigc_FCVodeGetNumLinSolvSetups(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumErrTestFails(cvode_mem, netfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: netfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(netfails(1)) +fresult = swigc_FCVodeGetNumErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetLastOrder(cvode_mem, qlast) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), dimension(*), target, intent(inout) :: qlast +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(qlast(1)) +fresult = swigc_FCVodeGetLastOrder(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetCurrentOrder(cvode_mem, qcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), dimension(*), target, intent(inout) :: qcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(qcur(1)) +fresult = swigc_FCVodeGetCurrentOrder(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetCurrentGamma(cvode_mem, gamma) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: gamma +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(gamma(1)) +fresult = swigc_FCVodeGetCurrentGamma(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumStabLimOrderReds(cvode_mem, nslred) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nslred +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nslred(1)) +fresult = swigc_FCVodeGetNumStabLimOrderReds(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetActualInitStep(cvode_mem, hinused) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hinused +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(hinused(1)) +fresult = swigc_FCVodeGetActualInitStep(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetLastStep(cvode_mem, hlast) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(hlast(1)) +fresult = swigc_FCVodeGetLastStep(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetCurrentStep(cvode_mem, hcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(hcur(1)) +fresult = swigc_FCVodeGetCurrentStep(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetCurrentState(cvode_mem, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_PTR) :: y +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = y +fresult = swigc_FCVodeGetCurrentState(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetCurrentTime(cvode_mem, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(tcur(1)) +fresult = swigc_FCVodeGetCurrentTime(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetTolScaleFactor(cvode_mem, tolsfac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tolsfac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(tolsfac(1)) +fresult = swigc_FCVodeGetTolScaleFactor(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetErrWeights(cvode_mem, eweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(N_Vector), target, intent(inout) :: eweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(eweight) +fresult = swigc_FCVodeGetErrWeights(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetEstLocalErrors(cvode_mem, ele) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(N_Vector), target, intent(inout) :: ele +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(ele) +fresult = swigc_FCVodeGetEstLocalErrors(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumGEvals(cvode_mem, ngevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(ngevals(1)) +fresult = swigc_FCVodeGetNumGEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetRootInfo(cvode_mem, rootsfound) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootsfound +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(rootsfound(1)) +fresult = swigc_FCVodeGetRootInfo(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetIntegratorStats(cvode_mem, nsteps, nfevals, nlinsetups, netfails, qlast, qcur, hinused, hlast, hcur, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsteps +integer(C_LONG), dimension(*), target, intent(inout) :: nfevals +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetups +integer(C_LONG), dimension(*), target, intent(inout) :: netfails +integer(C_INT), dimension(*), target, intent(inout) :: qlast +integer(C_INT), dimension(*), target, intent(inout) :: qcur +real(C_DOUBLE), dimension(*), target, intent(inout) :: hinused +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +real(C_DOUBLE), dimension(*), target, intent(inout) :: hcur +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 +type(C_PTR) :: farg7 +type(C_PTR) :: farg8 +type(C_PTR) :: farg9 +type(C_PTR) :: farg10 +type(C_PTR) :: farg11 + +farg1 = cvode_mem +farg2 = c_loc(nsteps(1)) +farg3 = c_loc(nfevals(1)) +farg4 = c_loc(nlinsetups(1)) +farg5 = c_loc(netfails(1)) +farg6 = c_loc(qlast(1)) +farg7 = c_loc(qcur(1)) +farg8 = c_loc(hinused(1)) +farg9 = c_loc(hlast(1)) +farg10 = c_loc(hcur(1)) +farg11 = c_loc(tcur(1)) +fresult = swigc_FCVodeGetIntegratorStats(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10, farg11) +swig_result = fresult +end function + +function FCVodeGetNumNonlinSolvIters(cvode_mem, nniters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nniters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nniters(1)) +fresult = swigc_FCVodeGetNumNonlinSolvIters(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumNonlinSolvConvFails(cvode_mem, nncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nncfails(1)) +fresult = swigc_FCVodeGetNumNonlinSolvConvFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNonlinSolvStats(cvode_mem, nniters, nncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nniters +integer(C_LONG), dimension(*), target, intent(inout) :: nncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(nniters(1)) +farg3 = c_loc(nncfails(1)) +fresult = swigc_FCVodeGetNonlinSolvStats(farg1, farg2, farg3) +swig_result = fresult +end function + + +subroutine SWIG_chararray_to_string(wrap, string) + use, intrinsic :: ISO_C_BINDING + type(SwigArrayWrapper), intent(IN) :: wrap + character(kind=C_CHAR, len=:), allocatable, intent(OUT) :: string + character(kind=C_CHAR), dimension(:), pointer :: chars + integer(kind=C_SIZE_T) :: i + call c_f_pointer(wrap%data, chars, [wrap%size]) + allocate(character(kind=C_CHAR, len=wrap%size) :: string) + do i=1, wrap%size + string(i:i) = chars(i) + end do +end subroutine + +function FCVodeGetReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FCVodeGetReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +subroutine FCVodeFree(cvode_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), target, intent(inout) :: cvode_mem +type(C_PTR) :: farg1 + +farg1 = c_loc(cvode_mem) +call swigc_FCVodeFree(farg1) +end subroutine + +function FCVBandPrecInit(cvode_mem, n, mu, ml) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT64_T), intent(in) :: n +integer(C_INT64_T), intent(in) :: mu +integer(C_INT64_T), intent(in) :: ml +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 + +farg1 = cvode_mem +farg2 = n +farg3 = mu +farg4 = ml +fresult = swigc_FCVBandPrecInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVBandPrecGetWorkSpace(cvode_mem, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FCVBandPrecGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVBandPrecGetNumRhsEvals(cvode_mem, nfevalsbp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevalsbp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nfevalsbp(1)) +fresult = swigc_FCVBandPrecGetNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVBBDPrecInit(cvode_mem, nlocal, mudq, mldq, mukeep, mlkeep, dqrely, gloc, cfn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT64_T), intent(in) :: nlocal +integer(C_INT64_T), intent(in) :: mudq +integer(C_INT64_T), intent(in) :: mldq +integer(C_INT64_T), intent(in) :: mukeep +integer(C_INT64_T), intent(in) :: mlkeep +real(C_DOUBLE), intent(in) :: dqrely +type(C_FUNPTR), intent(in), value :: gloc +type(C_FUNPTR), intent(in), value :: cfn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 +integer(C_INT64_T) :: farg5 +integer(C_INT64_T) :: farg6 +real(C_DOUBLE) :: farg7 +type(C_FUNPTR) :: farg8 +type(C_FUNPTR) :: farg9 + +farg1 = cvode_mem +farg2 = nlocal +farg3 = mudq +farg4 = mldq +farg5 = mukeep +farg6 = mlkeep +farg7 = dqrely +farg8 = gloc +farg9 = cfn +fresult = swigc_FCVBBDPrecInit(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) +swig_result = fresult +end function + +function FCVBBDPrecReInit(cvode_mem, mudq, mldq, dqrely) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT64_T), intent(in) :: mudq +integer(C_INT64_T), intent(in) :: mldq +real(C_DOUBLE), intent(in) :: dqrely +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +real(C_DOUBLE) :: farg4 + +farg1 = cvode_mem +farg2 = mudq +farg3 = mldq +farg4 = dqrely +fresult = swigc_FCVBBDPrecReInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVBBDPrecGetWorkSpace(cvode_mem, lenrwbbdp, leniwbbdp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwbbdp +integer(C_LONG), dimension(*), target, intent(inout) :: leniwbbdp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(lenrwbbdp(1)) +farg3 = c_loc(leniwbbdp(1)) +fresult = swigc_FCVBBDPrecGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVBBDPrecGetNumGfnEvals(cvode_mem, ngevalsbbdp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevalsbbdp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(ngevalsbbdp(1)) +fresult = swigc_FCVBBDPrecGetNumGfnEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVDiag(cvode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = cvode_mem +fresult = swigc_FCVDiag(farg1) +swig_result = fresult +end function + +function FCVDiagGetWorkSpace(cvode_mem, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FCVDiagGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVDiagGetNumRhsEvals(cvode_mem, nfevalsls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevalsls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nfevalsls(1)) +fresult = swigc_FCVDiagGetNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVDiagGetLastFlag(cvode_mem, flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: flag +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(flag(1)) +fresult = swigc_FCVDiagGetLastFlag(farg1, farg2) +swig_result = fresult +end function + +function FCVDiagGetReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FCVDiagGetReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +function FCVodeSetLinearSolver(cvode_mem, ls, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(SUNLinearSolver), target, intent(inout) :: ls +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(ls) +farg3 = c_loc(a) +fresult = swigc_FCVodeSetLinearSolver(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetJacFn(cvode_mem, jac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: jac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = cvode_mem +farg2 = jac +fresult = swigc_FCVodeSetJacFn(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxStepsBetweenJac(cvode_mem, msbj) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), intent(in) :: msbj +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = cvode_mem +farg2 = msbj +fresult = swigc_FCVodeSetMaxStepsBetweenJac(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetLinearSolutionScaling(cvode_mem, onoff) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: onoff +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = onoff +fresult = swigc_FCVodeSetLinearSolutionScaling(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetEpsLin(cvode_mem, eplifac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: eplifac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = cvode_mem +farg2 = eplifac +fresult = swigc_FCVodeSetEpsLin(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetPreconditioner(cvode_mem, pset, psolve) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: pset +type(C_FUNPTR), intent(in), value :: psolve +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = cvode_mem +farg2 = pset +farg3 = psolve +fresult = swigc_FCVodeSetPreconditioner(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetJacTimes(cvode_mem, jtsetup, jtimes) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: jtsetup +type(C_FUNPTR), intent(in), value :: jtimes +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = cvode_mem +farg2 = jtsetup +farg3 = jtimes +fresult = swigc_FCVodeSetJacTimes(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetLinSysFn(cvode_mem, linsys) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: linsys +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = cvode_mem +farg2 = linsys +fresult = swigc_FCVodeSetLinSysFn(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetLinWorkSpace(cvode_mem, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FCVodeGetLinWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeGetNumJacEvals(cvode_mem, njevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(njevals(1)) +fresult = swigc_FCVodeGetNumJacEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumPrecEvals(cvode_mem, npevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: npevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(npevals(1)) +fresult = swigc_FCVodeGetNumPrecEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumPrecSolves(cvode_mem, npsolves) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: npsolves +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(npsolves(1)) +fresult = swigc_FCVodeGetNumPrecSolves(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumLinIters(cvode_mem, nliters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nliters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nliters(1)) +fresult = swigc_FCVodeGetNumLinIters(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumLinConvFails(cvode_mem, nlcfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nlcfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nlcfails(1)) +fresult = swigc_FCVodeGetNumLinConvFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumJTSetupEvals(cvode_mem, njtsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njtsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(njtsetups(1)) +fresult = swigc_FCVodeGetNumJTSetupEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumJtimesEvals(cvode_mem, njvevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njvevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(njvevals(1)) +fresult = swigc_FCVodeGetNumJtimesEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumLinRhsEvals(cvode_mem, nfevalsls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevalsls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nfevalsls(1)) +fresult = swigc_FCVodeGetNumLinRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetLastLinFlag(cvode_mem, flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: flag +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(flag(1)) +fresult = swigc_FCVodeGetLastLinFlag(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetLinReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FCVodeGetLinReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/cvodes/CMakeLists.txt index 692572a5a..15db6e3c0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/CMakeLists.txt @@ -1,9 +1,9 @@ # --------------------------------------------------------------- -# Programmer(s): Daniel R. Reynolds @ SMU -# Radu Serban @ LLNL +# Programmer(s): Daniel R. Reynolds @ SMU +# Radu Serban @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -13,11 +13,17 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the CVODES library +# --------------------------------------------------------------- + +install(CODE "MESSAGE(\"\nInstall CVODES\n\")") -INSTALL(CODE "MESSAGE(\"\nInstall CVODES\n\")") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) # Add variable cvodes_SOURCES with the sources for the CVODES library -SET(cvodes_SOURCES +set(cvodes_SOURCES cvodea.c cvodea_io.c cvodes.c @@ -36,7 +42,7 @@ SET(cvodes_SOURCES # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the CVODES library -SET(shared_SOURCES +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_matrix.c ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c @@ -48,12 +54,13 @@ SET(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c ${sundials_SOURCE_DIR}/src/sundials/sundials_version.c ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector_senswrapper.c + ${sundials_SOURCE_DIR}/src/sundials/sundials_futils.c ${sundials_SOURCE_DIR}/src/nvector/serial/nvector_serial.c ) # Add variable sunmatrix_SOURCES with the common SUNMatrix sources which will # also be included in the CVODES library -SET(sunmatrix_SOURCES +set(sunmatrix_SOURCES ${sundials_SOURCE_DIR}/src/sunmatrix/band/sunmatrix_band.c ${sundials_SOURCE_DIR}/src/sunmatrix/dense/sunmatrix_dense.c ${sundials_SOURCE_DIR}/src/sunmatrix/sparse/sunmatrix_sparse.c @@ -61,7 +68,7 @@ SET(sunmatrix_SOURCES # Add variable sunlinsol_SOURCES with the common SUNLinearSolver sources which will # also be included in the CVODES library -SET(sunlinsol_SOURCES +set(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/band/sunlinsol_band.c ${sundials_SOURCE_DIR}/src/sunlinsol/dense/sunlinsol_dense.c ${sundials_SOURCE_DIR}/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c @@ -73,13 +80,13 @@ SET(sunlinsol_SOURCES # Add variable sunnonlinsol_SOURCES with the common SUNNonlinearSolver sources # which will also be included in the CVODES library -SET(sunnonlinsol_SOURCES +set(sunnonlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunnonlinsol/newton/sunnonlinsol_newton.c ${sundials_SOURCE_DIR}/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c ) # Add variable cvodes_HEADERS with the exported CVODES header files -SET(cvodes_HEADERS +set(cvodes_HEADERS cvodes.h cvodes_bandpre.h cvodes_bbdpre.h @@ -90,60 +97,60 @@ SET(cvodes_HEADERS ) # Add prefix with complete path to the CVODES header files -ADD_PREFIX(${sundials_SOURCE_DIR}/include/cvodes/ cvodes_HEADERS) +add_prefix(${sundials_SOURCE_DIR}/include/cvodes/ cvodes_HEADERS) # Add source directories to include directories for access to # implementation only header files. -INCLUDE_DIRECTORIES(.) -INCLUDE_DIRECTORIES(../sundials) +include_directories(.) +include_directories(../sundials) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) # Build the static library -IF(BUILD_STATIC_LIBS) +if(BUILD_STATIC_LIBS) # Add the build target for the static CVODES library - ADD_LIBRARY(sundials_cvodes_static STATIC + add_library(sundials_cvodes_static STATIC ${cvodes_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ${sunnonlinsol_SOURCES}) # Set the library name and make sure it is not deleted - SET_TARGET_PROPERTIES(sundials_cvodes_static + set_target_properties(sundials_cvodes_static PROPERTIES OUTPUT_NAME sundials_cvodes CLEAN_DIRECT_OUTPUT 1) # Install the CVODES library - INSTALL(TARGETS sundials_cvodes_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS sundials_cvodes_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +endif(BUILD_STATIC_LIBS) # Build the shared library -IF(BUILD_SHARED_LIBS) +if(BUILD_SHARED_LIBS) # Add the build target for the CVODES library - ADD_LIBRARY(sundials_cvodes_shared SHARED + add_library(sundials_cvodes_shared SHARED ${cvodes_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ${sunnonlinsol_SOURCES}) - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_cvodes_shared m) - ENDIF() + if(UNIX) + target_link_libraries(sundials_cvodes_shared m) + endif() # Set the library name and make sure it is not deleted - SET_TARGET_PROPERTIES(sundials_cvodes_shared + set_target_properties(sundials_cvodes_shared PROPERTIES OUTPUT_NAME sundials_cvodes CLEAN_DIRECT_OUTPUT 1) # Set VERSION and SOVERSION for shared libraries - SET_TARGET_PROPERTIES(sundials_cvodes_shared + set_target_properties(sundials_cvodes_shared PROPERTIES VERSION ${cvodeslib_VERSION} SOVERSION ${cvodeslib_SOVERSION}) # Install the CVODES library - INSTALL(TARGETS sundials_cvodes_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS sundials_cvodes_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) +endif(BUILD_SHARED_LIBS) # Install the CVODES header files -INSTALL(FILES ${cvodes_HEADERS} DESTINATION include/cvodes) +install(FILES ${cvodes_HEADERS} DESTINATION include/cvodes) # -MESSAGE(STATUS "Added CVODES module") +message(STATUS "Added CVODES module") diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/README b/deps/AMICI/ThirdParty/sundials/src/cvodes/README deleted file mode 100644 index 3b2679113..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/README +++ /dev/null @@ -1,98 +0,0 @@ - CVODES - Release 4.1.0, Feb 2019 - Alan C. Hindmarsh and Radu Serban - Center for Applied Scientific Computing, LLNL - -CVODES is a solver for stiff and nonstiff ODE systems (initial value -problem) given in explicit form y' = f(t,y,p) with sensitivity analysis -capabilities (both forward and adjoint modes). -It is written in ANSI standard C. - -CVODES can be used both on serial and parallel computers. The -main difference is in the NVECTOR module of vector kernels. The desired -version is obtained when compiling the example files by linking the -appropriate library of NVECTOR kernels. In the parallel versions, -communication between processors is done with MPI, with OpenMP, or with Pthreads. - -When used with the serial NVECTOR module, CVODES provides both direct (dense -and band) and preconditioned Krylov (iterative) linear solvers. Three different -iterative solvers are available: scaled preconditioned GMRES (SPGMR), scaled -preconditioned BiCGStab (SPBCG), and scaled preconditioned TFQMR (SPTFQMR). -When CVODES is used with the parallel NVECTOR module, only the Krylov linear solvers -are available. (An approximate diagonal Jacobian option is available with both -versions.) For the serial version, there is a banded preconditioner module -called CVBANDPRE available for use with the Krylov solvers, while for the parallel -version there is a preconditioner module called CVBBDPRE which provides a -band-block-diagonal preconditioner. - -CVODES is part of a software family called SUNDIALS: SUite of Nonlinear and -DIfferential/ALgebraic equation Solvers [4]. This suite consists of CVODE, -CVODES, ARKode, IDA, IDAS, and KINSOL. The directory structure of the -package supplied reflects this family relationship. - -The notes below provide the location of documentation, directions for the -installation of the CVODES package, and relevant references. Following that -is a brief history of revisions to the package. - - -A. Documentation ----------------- - -/sundials/doc/cvodes/ contains PDF files for the CVODES User Guide [1] (cvs_guide.pdf) -and the CVODES Examples [2] (cvs_examples.pdf) documents. - - -B. Installation ---------------- - -For basic installation instructions see the file /sundials/INSTALL_GUIDE.pdf. -For complete installation instructions see the "Installation Procedure" -chapter in the CVODES User Guide. - - -C. References -------------- - -[1] A. C. Hindmarsh and R. Serban, "User Documentation for CVODES v2.9.0," - LLNL technical report UCRL-SM-208111, March 2016. - -[2] A. C. Hindmarsh and R. Serban, "Example Programs for CVODES v2.9.0," - LLNL technical report UCRL-SM-208115, March 2016. - -[3] R. Serban and A. C. Hindmarsh, "CVODES: the Sensitivity-Enabled ODE - solver in SUNDIALS," Proceedings of IDETC/CIE 2005, Sept. 2005, - Long Beach, CA. - -[4] A. C. Hindmarsh, P. N. Brown, K. E. Grant, S. L. Lee, R. Serban, - D. E. Shumaker, and C. S. Woodward, "SUNDIALS, Suite of Nonlinear and - Differential/Algebraic Equation Solvers," ACM Trans. Math. Softw., - 31(3), pp. 363-396, 2005. - - -D. Releases ------------ - -v. 4.1.0 - Feb. 2019 -v. 4.0.2 - Jan. 2019 -v. 4.0.1 - Dec. 2018 -v. 4.0.0 - Dec. 2018 -v. 3.2.1 - Oct. 2018 -v. 3.2.0 - Sep. 2018 -v. 3.1.2 - Jul. 2018 -v. 3.1.1 - May 2018 -v. 3.1.0 - Nov. 2017 -v. 3.0.0 - Sep. 2017 -v. 2.9.0 - Sep. 2016 -v. 2.8.2 - Aug. 2015 -v. 2.8.1 - Mar. 2015 -v. 2.8.0 - Mar. 2015 -v. 2.7.0 - Mar. 2012 -v. 2.6.0 - May 2009 -v. 2.5.0 - Nov. 2006 -v. 2.4.0 - Mar. 2006 -v. 2.3.0 - May. 2005 -v. 2.2.0 - Apr. 2005 -v. 2.1.2 - Mar. 2005 -v. 2.1.1 - Jan. 2005 -v. 2.1.0 - Dec. 2004 -v. 1.0 - Jul. 2002 (first SUNDIALS release) diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/README.md b/deps/AMICI/ThirdParty/sundials/src/cvodes/README.md new file mode 100644 index 000000000..df95639d4 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/README.md @@ -0,0 +1,57 @@ +# CVODES +### Version 5.2.0 (Mar 2020) + +**Alan C. Hindmarsh and Radu Serban + Center for Applied Scientific Computing, LLNL** + +CVODES is a package for the solution of stiff and nonstiff ordinary differential +equation (ODE) systems (initial value problem) given in explicit form +``` +dy/dt = f(t,y,p), y(t0) = y0(p) +``` +with sensitivity analysis capabilities (both forward and adjoint modes). CVODES +provides a choice of two variable-order, variable-coefficient multistep methods, +Adams-Moulton methods for non-stiff problems or BDF (Backward Differentiation +Formula) methods in fixed-leading-coefficient form for stiff problems. + +CVODES is part of the SUNDIALS Suite of Nonlinear and Differential/Algebraic +equation Solvers which consists of ARKode, CVODE, CVODES, IDA, IDAS and KINSOL. +It is written in ANSI standard C and can be used in a variety of computing +environments including serial, shared memory, distributed memory, and +accelerator-based (e.g., GPU) systems. This flexibility is obtained from a +modular design that leverages the shared vector, matrix, linear solver, and +nonlinear solver APIs used across SUNDIALS packages. + +## Documentation + +See the [CVODES User Guide](/doc/cvodes/cvs_guide.pdf) and +[CVODES Examples](/doc/cvodes/cvs_examples.pdf) document for more information +about CVODES usage and the provided example programs respectively. + +## Installation + +For installation instructions see the [INSTALL_GUIDE](/INSTALL_GUIDE.pdf) +or the "Installation Procedure" chapter in the CVODES User Guide. + +## Release History + +Information on recent changes to CVODES can be found in the "Introduction" +chapter of the CVODES User Guide and a complete release history is available in +the "SUNDIALS Release History" appendix of the CVODES User Guide. + +## References + +* A. C. Hindmarsh and R. Serban, "User Documentation for CVODES v5.2.0," + LLNL technical report UCRL-SM-208111, Mar 2020. + +* A. C. Hindmarsh and R. Serban, "Example Programs for CVODES v5.2.0," + LLNL technical report UCRL-SM-208115, Mar 2020. + +* R. Serban and A. C. Hindmarsh, "CVODES: the Sensitivity-Enabled ODE + solver in SUNDIALS," Proceedings of IDETC/CIE 2005, Sept. 2005, + Long Beach, CA. + +* A. C. Hindmarsh, P. N. Brown, K. E. Grant, S. L. Lee, R. Serban, + D. E. Shumaker, and C. S. Woodward, "SUNDIALS, Suite of Nonlinear and + Differential/Algebraic Equation Solvers," ACM Trans. Math. Softw., + 31(3), pp. 363-396, 2005. diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodea.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodea.c index ed51e23e7..9ee8c2ab6 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodea.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodea.c @@ -2,11 +2,11 @@ * ----------------------------------------------------------------- * $Revision$ * $Date$ - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Programmer(s): Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -19,7 +19,7 @@ * ----------------------------------------------------------------- */ -/* +/* * ================================================================= * IMPORTED HEADER FILES * ================================================================= @@ -33,7 +33,7 @@ #include #include -/* +/* * ================================================================= * CVODEA PRIVATE CONSTANTS * ================================================================= @@ -45,7 +45,7 @@ #define HUNDRED RCONST(100.0) /* real 100.0 */ #define FUZZ_FACTOR RCONST(1000000.0) /* fuzz factor for IMget */ -/* +/* * ================================================================= * PRIVATE FUNCTION PROTOTYPES * ================================================================= @@ -58,9 +58,9 @@ static void CVAckpntDelete(CkpntMem *ck_memPtr); static void CVAbckpbDelete(CVodeBMem *cvB_memPtr); static int CVAdataStore(CVodeMem cv_mem, CkpntMem ck_mem); -static int CVAckpntGet(CVodeMem cv_mem, CkpntMem ck_mem); +static int CVAckpntGet(CVodeMem cv_mem, CkpntMem ck_mem); -static int CVAfindIndex(CVodeMem cv_mem, realtype t, +static int CVAfindIndex(CVodeMem cv_mem, realtype t, long int *indx, booleantype *newpoint); static booleantype CVAhermiteMalloc(CVodeMem cv_mem); @@ -75,13 +75,13 @@ static int CVApolynomialStorePnt(CVodeMem cv_mem, DtpntMem d); /* Wrappers */ -static int CVArhs(realtype t, N_Vector yB, +static int CVArhs(realtype t, N_Vector yB, N_Vector yBdot, void *cvode_mem); -static int CVArhsQ(realtype t, N_Vector yB, +static int CVArhsQ(realtype t, N_Vector yB, N_Vector qBdot, void *cvode_mem); -/* +/* * ================================================================= * EXPORTED FUNCTIONS IMPLEMENTATION * ================================================================= @@ -90,7 +90,7 @@ static int CVArhsQ(realtype t, N_Vector yB, /* * CVodeAdjInit * - * This routine initializes ASA and allocates space for the adjoint + * This routine initializes ASA and allocates space for the adjoint * memory structure. */ @@ -118,7 +118,7 @@ int CVodeAdjInit(void *cvode_mem, long int steps, int interp) if ( (interp != CV_HERMITE) && (interp != CV_POLYNOMIAL) ) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeAdjInit", MSGCV_BAD_INTERP); return(CV_ILL_INPUT); - } + } /* ---------------------------- * Allocate CVODEA memory block @@ -173,7 +173,7 @@ int CVodeAdjInit(void *cvode_mem, long int steps, int interp) return(CV_MEM_FAIL); } - for (i=0; i<=steps; i++) { + for (i=0; i<=steps; i++) { ca_mem->dt_mem[i] = NULL; ca_mem->dt_mem[i] = (DtpntMem) malloc(sizeof(struct DtpntMemRec)); if (ca_mem->dt_mem[i] == NULL) { @@ -186,20 +186,20 @@ int CVodeAdjInit(void *cvode_mem, long int steps, int interp) } /* Attach functions for the appropriate interpolation module */ - + switch(interp) { case CV_HERMITE: - + ca_mem->ca_IMmalloc = CVAhermiteMalloc; ca_mem->ca_IMfree = CVAhermiteFree; ca_mem->ca_IMget = CVAhermiteGetY; ca_mem->ca_IMstore = CVAhermiteStorePnt; break; - + case CV_POLYNOMIAL: - + ca_mem->ca_IMmalloc = CVApolynomialMalloc; ca_mem->ca_IMfree = CVApolynomialFree; ca_mem->ca_IMget = CVApolynomialGetY; @@ -215,7 +215,7 @@ int CVodeAdjInit(void *cvode_mem, long int steps, int interp) /* By default we will store but not interpolate sensitivities * - IMstoreSensi will be set in CVodeF to SUNFALSE if FSA is not enabled - * or if the user can force this through CVodeSetAdjNoSensi + * or if the user can force this through CVodeSetAdjNoSensi * - IMinterpSensi will be set in CVodeB to SUNTRUE if IMstoreSensi is * SUNTRUE and if at least one backward problem requires sensitivities */ @@ -239,6 +239,8 @@ int CVodeAdjInit(void *cvode_mem, long int steps, int interp) ca_mem->ca_firstCVodeBcall = SUNTRUE; + ca_mem->ca_rootret = SUNFALSE; + /* --------------------------------------------- * ASA initialized and allocated * --------------------------------------------- */ @@ -247,7 +249,7 @@ int CVodeAdjInit(void *cvode_mem, long int steps, int interp) cv_mem->cv_adjMallocDone = SUNTRUE; return(CV_SUCCESS); -} +} /* CVodeAdjReInit * @@ -255,7 +257,7 @@ int CVodeAdjInit(void *cvode_mem, long int steps, int interp) * the number of steps between check points and the type of interpolation * remain unchanged. * The list of check points (and associated memory) is deleted. - * The list of backward problems is kept (however, new backward problems can + * The list of backward problems is kept (however, new backward problems can * be added to this list by calling CVodeCreateB). * The CVODES memory for the forward and backward problems can be reinitialized * separately by calling CVodeReInit and CVodeReInitB, respectively. @@ -280,7 +282,7 @@ int CVodeAdjReInit(void *cvode_mem) if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeAdjReInit", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; @@ -289,13 +291,13 @@ int CVodeAdjReInit(void *cvode_mem) while (ca_mem->ck_mem != NULL) CVAckpntDelete(&(ca_mem->ck_mem)); /* Initialization of check points */ - + ca_mem->ck_mem = NULL; ca_mem->ca_nckpnts = 0; ca_mem->ca_ckpntData = NULL; /* CVodeF and CVodeB not called yet */ - + ca_mem->ca_firstCVodeFcall = SUNTRUE; ca_mem->ca_tstopCVodeFcall = SUNFALSE; ca_mem->ca_firstCVodeBcall = SUNTRUE; @@ -314,7 +316,7 @@ void CVodeAdjFree(void *cvode_mem) CVodeMem cv_mem; CVadjMem ca_mem; long int i; - + if (cvode_mem == NULL) return; cv_mem = (CVodeMem) cvode_mem; @@ -351,14 +353,14 @@ void CVodeAdjFree(void *cvode_mem) * CVodeF * * This routine integrates to tout and returns solution into yout. - * In the same time, it stores check point data every 'steps' steps. - * + * In the same time, it stores check point data every 'steps' steps. + * * CVodeF can be called repeatedly by the user. * * ncheckPtr points to the number of check points stored so far. */ -int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, +int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, realtype *tret, int itask, int *ncheckPtr) { CVadjMem ca_mem; @@ -366,7 +368,8 @@ int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, CkpntMem tmp; DtpntMem *dt_mem; int flag, i; - booleantype iret, allocOK; + booleantype allocOK, earlyret; + realtype ttest; /* Check if cvode_mem exists */ if (cvode_mem == NULL) { @@ -379,7 +382,7 @@ int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeF", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; @@ -388,7 +391,7 @@ int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeF", MSGCV_YOUT_NULL); return(CV_ILL_INPUT); } - + /* Check for tret != NULL */ if (tret == NULL) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeF", MSGCV_TRET_NULL); @@ -411,17 +414,12 @@ int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, ca_mem->ca_tstopCVodeF = cv_mem->cv_tstop; } - /* We will call CVode in CV_ONE_STEP mode, regardless - * of what itask is, so flag if we need to return */ - if (itask == CV_ONE_STEP) iret = SUNTRUE; - else iret = SUNFALSE; - /* On the first step: * - set tinitial * - initialize list of check points * - if needed, initialize the interpolation module * - load dt_mem[0] - * On subsequent steps, test if taking a new step is necessary. + * On subsequent steps, test if taking a new step is necessary. */ if ( ca_mem->ca_firstCVodeFcall ) { @@ -460,18 +458,41 @@ int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, ca_mem->ca_firstCVodeFcall = SUNFALSE; - } else if ( (cv_mem->cv_tn - tout)*cv_mem->cv_h >= ZERO ) { + } else if ( itask == CV_NORMAL ) { + + /* When in normal mode, check if tout was passed or if a previous root was + not reported and return an interpolated solution. No changes to ck_mem + or dt_mem are needed. */ - /* If tout was passed, return interpolated solution. - No changes to ck_mem or dt_mem are needed. */ - *tret = tout; - flag = CVodeGetDky(cv_mem, tout, 0, yout); - *ncheckPtr = ca_mem->ca_nckpnts; - ca_mem->ca_IMnewData = SUNTRUE; - ca_mem->ca_ckpntData = ca_mem->ck_mem; - ca_mem->ca_np = cv_mem->cv_nst % ca_mem->ca_nsteps + 1; + /* flag to signal if an early return is needed */ + earlyret = SUNFALSE; - return(flag); + /* if a root needs to be reported compare tout to troot otherwise compare + to the current time tn */ + ttest = (ca_mem->ca_rootret) ? ca_mem->ca_troot : cv_mem->cv_tn; + + if ((ttest - tout)*cv_mem->cv_h >= ZERO) { + /* ttest is after tout, interpolate to tout */ + *tret = tout; + flag = CVodeGetDky(cv_mem, tout, 0, yout); + earlyret = SUNTRUE; + } else if (ca_mem->ca_rootret) { + /* tout is after troot, interpolate to troot */ + *tret = ca_mem->ca_troot; + flag = CVodeGetDky(cv_mem, ca_mem->ca_troot, 0, yout); + flag = CV_ROOT_RETURN; + ca_mem->ca_rootret = SUNFALSE; + earlyret = SUNTRUE; + } + + /* return if necessary */ + if (earlyret) { + *ncheckPtr = ca_mem->ca_nckpnts; + ca_mem->ca_IMnewData = SUNTRUE; + ca_mem->ca_ckpntData = ca_mem->ck_mem; + ca_mem->ca_np = cv_mem->cv_nst % ca_mem->ca_nsteps + 1; + return(flag); + } } @@ -487,7 +508,7 @@ int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, if ( cv_mem->cv_nst % ca_mem->ca_nsteps == 0 ) { - ca_mem->ck_mem->ck_t1 = *tret; + ca_mem->ck_mem->ck_t1 = cv_mem->cv_tn; /* Create a new check point, load it, and append it to the list */ tmp = CVAckpntNew(cv_mem); @@ -500,7 +521,7 @@ int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, ca_mem->ck_mem = tmp; ca_mem->ca_nckpnts++; cv_mem->cv_forceSetup = SUNTRUE; - + /* Reset i=0 and load dt_mem[0] */ dt_mem[0]->t = ca_mem->ck_mem->ck_t0; ca_mem->ca_IMstore(cv_mem, dt_mem[0]); @@ -508,7 +529,7 @@ int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, } else { /* Load next point in dt_mem */ - dt_mem[cv_mem->cv_nst % ca_mem->ca_nsteps]->t = *tret; + dt_mem[cv_mem->cv_nst % ca_mem->ca_nsteps]->t = cv_mem->cv_tn; ca_mem->ca_IMstore(cv_mem, dt_mem[cv_mem->cv_nst % ca_mem->ca_nsteps]); } @@ -516,32 +537,42 @@ int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, /* Set t1 field of the current ckeck point structure for the case in which there will be no future check points */ - ca_mem->ck_mem->ck_t1 = *tret; + ca_mem->ck_mem->ck_t1 = cv_mem->cv_tn; - /* tfinal is now set to *tret */ - ca_mem->ca_tfinal = *tret; + /* tfinal is now set to tn */ + ca_mem->ca_tfinal = cv_mem->cv_tn; /* Return if in CV_ONE_STEP mode */ - if (iret) break; + if (itask == CV_ONE_STEP) break; + + /* CV_NORMAL_STEP returns */ - /* Return if root reached */ - if ( flag == CV_ROOT_RETURN ) { - CVodeGetDky(cv_mem, *tret, 0, yout); - break; - } /* Return if tout reached */ if ( (*tret - tout)*cv_mem->cv_h >= ZERO ) { + + /* If this was a root return, save the root time to return later */ + if (flag == CV_ROOT_RETURN) { + ca_mem->ca_rootret = SUNTRUE; + ca_mem->ca_troot = *tret; + } + + /* Get solution value at tout to return now */ *tret = tout; - CVodeGetDky(cv_mem, tout, 0, yout); - /* Reset tretlast in cv_mem so that CVodeGetQuad and CVodeGetSens + flag = CVodeGetDky(cv_mem, tout, 0, yout); + + /* Reset tretlast in cv_mem so that CVodeGetQuad and CVodeGetSens * evaluate quadratures and/or sensitivities at the proper time */ cv_mem->cv_tretlast = tout; + break; } - } /* end of for(;;)() */ + /* Return if tstop or a root was found */ + if ( (flag == CV_TSTOP_RETURN) || (flag == CV_ROOT_RETURN) ) break; + + } /* end of for(;;) */ - /* Get ncheck from ca_mem */ + /* Get ncheck from ca_mem */ *ncheckPtr = ca_mem->ca_nckpnts; /* Data is available for the last interval */ @@ -554,7 +585,7 @@ int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, -/* +/* * ================================================================= * FUNCTIONS FOR BACKWARD PROBLEMS * ================================================================= @@ -634,9 +665,9 @@ int CVodeCreateB(void *cvode_mem, int lmmB, int *which) new_cvB_mem->cv_next = ca_mem->cvB_mem; ca_mem->cvB_mem = new_cvB_mem; - + /* Return the index of the newly created CVodeBMem object. - * This must be passed to CVodeInitB and to other ***B + * This must be passed to CVodeInitB and to other ***B * functions to set optional inputs for this backward problem */ *which = ca_mem->ca_nbckpbs; @@ -646,7 +677,7 @@ int CVodeCreateB(void *cvode_mem, int lmmB, int *which) return(CV_SUCCESS); } -int CVodeInitB(void *cvode_mem, int which, +int CVodeInitB(void *cvode_mem, int which, CVRhsFnB fB, realtype tB0, N_Vector yB0) { @@ -669,7 +700,7 @@ int CVodeInitB(void *cvode_mem, int which, if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeInitB", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; /* Check the value of which */ @@ -688,7 +719,7 @@ int CVodeInitB(void *cvode_mem, int which, } cvodeB_mem = (void *) (cvB_mem->cv_mem); - + /* Allocate and set the CVODES object */ flag = CVodeInit(cvodeB_mem, CVArhs, tB0, yB0); @@ -709,7 +740,7 @@ int CVodeInitB(void *cvode_mem, int which, return(CV_SUCCESS); } -int CVodeInitBS(void *cvode_mem, int which, +int CVodeInitBS(void *cvode_mem, int which, CVRhsFnBS fBs, realtype tB0, N_Vector yB0) { @@ -732,7 +763,7 @@ int CVodeInitBS(void *cvode_mem, int which, if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeInitBS", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; /* Check the value of which */ @@ -751,7 +782,7 @@ int CVodeInitBS(void *cvode_mem, int which, } cvodeB_mem = (void *) (cvB_mem->cv_mem); - + /* Allocate and set the CVODES object */ flag = CVodeInit(cvodeB_mem, CVArhs, tB0, yB0); @@ -840,7 +871,7 @@ int CVodeSStolerancesB(void *cvode_mem, int which, realtype reltolB, realtype ab if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeSStolerancesB", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; /* Check the value of which */ @@ -889,7 +920,7 @@ int CVodeSVtolerancesB(void *cvode_mem, int which, realtype reltolB, N_Vector ab if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeSVtolerancesB", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; /* Check the value of which */ @@ -937,7 +968,7 @@ int CVodeQuadInitB(void *cvode_mem, int which, if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeQuadInitB", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; /* Check which */ @@ -984,7 +1015,7 @@ int CVodeQuadInitBS(void *cvode_mem, int which, if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeQuadInitBS", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; /* Check which */ @@ -1030,7 +1061,7 @@ int CVodeQuadReInitB(void *cvode_mem, int which, N_Vector yQB0) if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeQuadReInitB", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; /* Check the value of which */ @@ -1073,7 +1104,7 @@ int CVodeQuadSStolerancesB(void *cvode_mem, int which, realtype reltolQB, realty if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeQuadSStolerancesB", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; /* Check which */ @@ -1115,7 +1146,7 @@ int CVodeQuadSVtolerancesB(void *cvode_mem, int which, realtype reltolQB, N_Vect if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeQuadSStolerancesB", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; /* Check which */ @@ -1143,7 +1174,7 @@ int CVodeQuadSVtolerancesB(void *cvode_mem, int which, realtype reltolQB, N_Vect * * This routine performs the backward integration towards tBout * of all backward problems that were defined. - * When necessary, it performs a forward integration between two + * When necessary, it performs a forward integration between two * consecutive check points to update interpolation data. * * On a successful return, CVodeB returns CV_SUCCESS. @@ -1166,7 +1197,7 @@ int CVodeB(void *cvode_mem, realtype tBout, int itaskB) int sign, flag=0; realtype tfuzz, tBret, tBn; booleantype gotCheckpoint, isActive, reachedTBout; - + /* Check if cvode_mem exists */ if (cvode_mem == NULL) { @@ -1325,7 +1356,7 @@ int CVodeB(void *cvode_mem, realtype tBout, int itaskB) if ( isActive ) { - /* Store the address of current backward problem memory + /* Store the address of current backward problem memory * in ca_mem to be used in the wrapper functions */ ca_mem->ca_bckpbCrt = tmp_cvB_mem; @@ -1380,7 +1411,7 @@ int CVodeB(void *cvode_mem, realtype tBout, int itaskB) ck_mem = ck_mem->ck_next; - } + } return(flag); } @@ -1403,7 +1434,7 @@ int CVodeGetB(void *cvode_mem, int which, realtype *tret, N_Vector yB) if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeGetB", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; @@ -1418,7 +1449,7 @@ int CVodeGetB(void *cvode_mem, int which, realtype *tret, N_Vector yB) while (cvB_mem != NULL) { if ( which == cvB_mem->cv_index ) break; cvB_mem = cvB_mem->cv_next; - } + } N_VScale(ONE, cvB_mem->cv_y, yB); *tret = cvB_mem->cv_tout; @@ -1451,7 +1482,7 @@ int CVodeGetQuadB(void *cvode_mem, int which, realtype *tret, N_Vector qB) if (cv_mem->cv_adjMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeGetQuadB", MSGCV_NO_ADJ); return(CV_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; @@ -1466,7 +1497,7 @@ int CVodeGetQuadB(void *cvode_mem, int which, realtype *tret, N_Vector qB) while (cvB_mem != NULL) { if ( which == cvB_mem->cv_index ) break; cvB_mem = cvB_mem->cv_next; - } + } cvodeB_mem = (void *) (cvB_mem->cv_mem); @@ -1474,7 +1505,7 @@ int CVodeGetQuadB(void *cvode_mem, int which, realtype *tret, N_Vector qB) * simply return the current value of qB (i.e. the final conditions) */ flag = CVodeGetNumSteps(cvodeB_mem, &nstB); - + if (nstB == 0) { N_VScale(ONE, cvB_mem->cv_mem->cv_znQ[0], qB); *tret = cvB_mem->cv_tout; @@ -1486,7 +1517,7 @@ int CVodeGetQuadB(void *cvode_mem, int which, realtype *tret, N_Vector qB) } -/* +/* * ================================================================= * PRIVATE FUNCTIONS FOR CHECK POINTS * ================================================================= @@ -1495,7 +1526,7 @@ int CVodeGetQuadB(void *cvode_mem, int which, realtype *tret, N_Vector qB) /* * CVAckpntInit * - * This routine initializes the check point linked list with + * This routine initializes the check point linked list with * information from the initial time. */ @@ -1514,7 +1545,7 @@ static CkpntMem CVAckpntInit(CVodeMem cv_mem) free(ck_mem); ck_mem = NULL; return(NULL); } - + ck_mem->ck_zn[1] = N_VClone(cv_mem->cv_tempv); if (ck_mem->ck_zn[1] == NULL) { N_VDestroy(ck_mem->ck_zn[0]); @@ -1531,7 +1562,7 @@ static CkpntMem CVAckpntInit(CVodeMem cv_mem) ck_mem->ck_nst = 0; ck_mem->ck_q = 1; ck_mem->ck_h = 0.0; - + /* Do we need to carry quadratures */ ck_mem->ck_quadr = cv_mem->cv_quadr && cv_mem->cv_errconQ; @@ -1585,7 +1616,7 @@ static CkpntMem CVAckpntInit(CVodeMem cv_mem) free(ck_mem); ck_mem = NULL; return(NULL); } - + for (is=0; iscv_Ns; is++) cv_mem->cv_cvals[is] = ONE; @@ -1602,7 +1633,7 @@ static CkpntMem CVAckpntInit(CVodeMem cv_mem) /* * CVAckpntNew * - * This routine allocates space for a new check point and sets + * This routine allocates space for a new check point and sets * its data from current values in cv_mem. */ @@ -1782,7 +1813,7 @@ static CkpntMem CVAckpntNew(CVodeMem cv_mem) cv_mem->cv_Zvecs[j*cv_mem->cv_Ns+is] = ck_mem->ck_znS[j][is]; } } - + (void) N_VScaleVectorArray(cv_mem->cv_Ns*(cv_mem->cv_q+1), cv_mem->cv_cvals, cv_mem->cv_Xvecs, cv_mem->cv_Zvecs); @@ -1795,7 +1826,7 @@ static CkpntMem CVAckpntNew(CVodeMem cv_mem) cv_mem->cv_znS[qmax], ck_mem->ck_znS[qmax]); } } - + if (ck_mem->ck_quadr_sensi) { for (j=0; j<=cv_mem->cv_q; j++) { for (is=0; iscv_Ns; is++) { @@ -1862,8 +1893,8 @@ static void CVAckpntDelete(CkpntMem *ck_memPtr) for (j=0;j<=tmp->ck_q;j++) N_VDestroy(tmp->ck_zn[j]); if (tmp->ck_zqm != 0) N_VDestroy(tmp->ck_zn[tmp->ck_zqm]); - /* free N_Vectors for quadratures in tmp - * Note that at the check point at t_initial, only znQ_[0] + /* free N_Vectors for quadratures in tmp + * Note that at the check point at t_initial, only znQ_[0] * was allocated */ if (tmp->ck_quadr) { @@ -1873,42 +1904,42 @@ static void CVAckpntDelete(CkpntMem *ck_memPtr) } else { N_VDestroy(tmp->ck_znQ[0]); } - + } /* free N_Vectors for sensitivities in tmp - * Note that at the check point at t_initial, only znS_[0] + * Note that at the check point at t_initial, only znS_[0] * was allocated */ if (tmp->ck_sensi) { - + if (tmp->ck_next != NULL) { for (j=0;j<=tmp->ck_q;j++) N_VDestroyVectorArray(tmp->ck_znS[j], tmp->ck_Ns); if (tmp->ck_zqm != 0) N_VDestroyVectorArray(tmp->ck_znS[tmp->ck_zqm], tmp->ck_Ns); } else { N_VDestroyVectorArray(tmp->ck_znS[0], tmp->ck_Ns); } - + } /* free N_Vectors for quadrature sensitivities in tmp - * Note that at the check point at t_initial, only znQS_[0] + * Note that at the check point at t_initial, only znQS_[0] * was allocated */ if (tmp->ck_quadr_sensi) { - + if (tmp->ck_next != NULL) { for (j=0;j<=tmp->ck_q;j++) N_VDestroyVectorArray(tmp->ck_znQS[j], tmp->ck_Ns); if (tmp->ck_zqm != 0) N_VDestroyVectorArray(tmp->ck_znQS[tmp->ck_zqm], tmp->ck_Ns); } else { N_VDestroyVectorArray(tmp->ck_znQS[0], tmp->ck_Ns); } - + } free(tmp); tmp = NULL; } -/* +/* * ================================================================= * PRIVATE FUNCTIONS FOR BACKWARD PROBLEMS * ================================================================= @@ -1946,7 +1977,7 @@ static void CVAbckpbDelete(CVodeBMem *cvB_memPtr) } -/* +/* * ================================================================= * PRIVATE FUNCTIONS FOR INTERPOLATION * ================================================================= @@ -2020,14 +2051,14 @@ static int CVAdataStore(CVodeMem cv_mem, CkpntMem ck_mem) * the check point ck_mem */ -static int CVAckpntGet(CVodeMem cv_mem, CkpntMem ck_mem) +static int CVAckpntGet(CVodeMem cv_mem, CkpntMem ck_mem) { int flag, j, is, qmax, retval; if (ck_mem->ck_next == NULL) { /* In this case, we just call the reinitialization routine, - * but make sure we use the same initial stepsize as on + * but make sure we use the same initial stepsize as on * the first run. */ CVodeSetInitStep(cv_mem, cv_mem->cv_h0u); @@ -2051,7 +2082,7 @@ static int CVAckpntGet(CVodeMem cv_mem, CkpntMem ck_mem) } } else { - + qmax = cv_mem->cv_qmax; /* Copy parameters from check point data structure */ @@ -2070,7 +2101,7 @@ static int CVAckpntGet(CVodeMem cv_mem, CkpntMem ck_mem) cv_mem->cv_etamax = ck_mem->ck_etamax; cv_mem->cv_tn = ck_mem->ck_t0; cv_mem->cv_saved_tq5 = ck_mem->ck_saved_tq5; - + /* Copy the arrays from check point data structure */ for (j=0; j<=cv_mem->cv_q; j++) @@ -2127,7 +2158,7 @@ static int CVAckpntGet(CVodeMem cv_mem, CkpntMem ck_mem) cv_mem->cv_Zvecs[j*cv_mem->cv_Ns+is] = cv_mem->cv_znQS[j][is]; } } - + retval = N_VScaleVectorArray(cv_mem->cv_Ns*(cv_mem->cv_q+1), cv_mem->cv_cvals, cv_mem->cv_Xvecs, cv_mem->cv_Zvecs); @@ -2146,7 +2177,7 @@ static int CVAckpntGet(CVodeMem cv_mem, CkpntMem ck_mem) for (j=0; j<=L_MAX; j++) cv_mem->cv_tau[j] = ck_mem->ck_tau[j]; for (j=0; j<=NUM_TESTS; j++) cv_mem->cv_tq[j] = ck_mem->ck_tq[j]; for (j=0; j<=cv_mem->cv_q; j++) cv_mem->cv_l[j] = ck_mem->ck_l[j]; - + /* Force a call to setup */ cv_mem->cv_forceSetup = SUNTRUE; @@ -2156,7 +2187,7 @@ static int CVAckpntGet(CVodeMem cv_mem, CkpntMem ck_mem) return(CV_SUCCESS); } -/* +/* * ----------------------------------------------------------------- * Functions for interpolation * ----------------------------------------------------------------- @@ -2175,7 +2206,7 @@ static int CVAckpntGet(CVodeMem cv_mem, CkpntMem ck_mem) * find indx (t is too far beyond limits). */ -static int CVAfindIndex(CVodeMem cv_mem, realtype t, +static int CVAfindIndex(CVodeMem cv_mem, realtype t, long int *indx, booleantype *newpoint) { CVadjMem ca_mem; @@ -2206,7 +2237,7 @@ static int CVAfindIndex(CVodeMem cv_mem, realtype t, /* look for a new indx to the left */ *newpoint = SUNTRUE; - + *indx = ca_mem->ca_ilast; for(;;) { if ( *indx == 0 ) break; @@ -2220,7 +2251,7 @@ static int CVAfindIndex(CVodeMem cv_mem, realtype t, ca_mem->ca_ilast = *indx; if ( *indx == 0 ) { - /* t is beyond leftmost limit. Is it too far? */ + /* t is beyond leftmost limit. Is it too far? */ if ( SUNRabs(t - dt_mem[0]->t) > FUZZ_FACTOR * cv_mem->cv_uround ) { return(CV_GETY_BADT); } @@ -2278,7 +2309,7 @@ int CVodeGetAdjY(void *cvode_mem, realtype t, N_Vector y) return(flag); } -/* +/* * ----------------------------------------------------------------- * Functions specific to cubic Hermite interpolation * ----------------------------------------------------------------- @@ -2288,8 +2319,8 @@ int CVodeGetAdjY(void *cvode_mem, realtype t, N_Vector y) * CVAhermiteMalloc * * This routine allocates memory for storing information at all - * intermediate points between two consecutive check points. - * This data is then used to interpolate the forward solution + * intermediate points between two consecutive check points. + * This data is then used to interpolate the forward solution * at any other time. */ @@ -2373,12 +2404,12 @@ static booleantype CVAhermiteMalloc(CVodeMem cv_mem) allocOK = SUNFALSE; break; } - + } - + dt_mem[i]->content = content; - } + } /* If an error occurred, deallocate and return */ @@ -2413,7 +2444,7 @@ static booleantype CVAhermiteMalloc(CVodeMem cv_mem) */ static void CVAhermiteFree(CVodeMem cv_mem) -{ +{ CVadjMem ca_mem; DtpntMem *dt_mem; HermiteDataMem content; @@ -2462,7 +2493,7 @@ static int CVAhermiteStorePnt(CVodeMem cv_mem, DtpntMem d) /* Load solution */ N_VScale(ONE, cv_mem->cv_zn[0], content->y); - + if (ca_mem->ca_IMstoreSensi) { for (is=0; iscv_Ns; is++) cv_mem->cv_cvals[is] = ONE; @@ -2505,8 +2536,8 @@ static int CVAhermiteStorePnt(CVodeMem cv_mem, DtpntMem d) /* * CVAhermiteGetY ( -> IMget ) * - * This routine uses cubic piece-wise Hermite interpolation for - * the forward solution vector. + * This routine uses cubic piece-wise Hermite interpolation for + * the forward solution vector. * It is typically called by the wrapper routines before calling * user provided routines (fB, djacB, bjacB, jtimesB, psolB) but * can be directly called by the user through CVodeGetAdjY @@ -2534,12 +2565,12 @@ static int CVAhermiteGetY(CVodeMem cv_mem, realtype t, realtype cvals[4]; N_Vector Xvecs[4]; N_Vector* XXvecs[4]; - + ca_mem = cv_mem->cv_adj_mem; dt_mem = ca_mem->dt_mem; - + /* Local value of Ns */ - + NS = (ca_mem->ca_IMinterpSensi && (yS != NULL)) ? cv_mem->cv_Ns : 0; /* Get the index in dt_mem */ @@ -2562,7 +2593,7 @@ static int CVAhermiteGetY(CVodeMem cv_mem, realtype t, content0->yS, yS); if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); } - + return(CV_SUCCESS); } @@ -2581,7 +2612,7 @@ static int CVAhermiteGetY(CVodeMem cv_mem, realtype t, } if (newpoint) { - + /* Recompute Y0 and Y1 */ content1 = (HermiteDataMem) (dt_mem[indx]->content); @@ -2673,7 +2704,7 @@ static int CVAhermiteGetY(CVodeMem cv_mem, realtype t, return(CV_SUCCESS); } -/* +/* * ----------------------------------------------------------------- * Functions specific to Polynomial interpolation * ----------------------------------------------------------------- @@ -2683,8 +2714,8 @@ static int CVAhermiteGetY(CVodeMem cv_mem, realtype t, * CVApolynomialMalloc * * This routine allocates memory for storing information at all - * intermediate points between two consecutive check points. - * This data is then used to interpolate the forward solution + * intermediate points between two consecutive check points. + * This data is then used to interpolate the forward solution * at any other time. */ @@ -2752,7 +2783,7 @@ static booleantype CVApolynomialMalloc(CVodeMem cv_mem) dt_mem[i]->content = content; - } + } /* If an error occurred, deallocate and return */ @@ -2848,7 +2879,7 @@ static int CVApolynomialStorePnt(CVodeMem cv_mem, DtpntMem d) /* * CVApolynomialGetY ( -> IMget ) * - * This routine uses polynomial interpolation for the forward solution vector. + * This routine uses polynomial interpolation for the forward solution vector. * It is typically called by the wrapper routines before calling * user provided routines (fB, djacB, bjacB, jtimesB, psolB)) but * can be directly called by the user through CVodeGetAdjY. @@ -2868,9 +2899,9 @@ static int CVApolynomialGetY(CVodeMem cv_mem, realtype t, ca_mem = cv_mem->cv_adj_mem; dt_mem = ca_mem->dt_mem; - + /* Local value of Ns */ - + NS = (ca_mem->ca_IMinterpSensi && (yS != NULL)) ? cv_mem->cv_Ns : 0; /* Get the index in dt_mem */ @@ -2987,7 +3018,7 @@ static int CVApolynomialGetY(CVodeMem cv_mem, realtype t, } -/* +/* * ================================================================= * WRAPPERS FOR ADJOINT SYSTEM * ================================================================= @@ -2995,11 +3026,11 @@ static int CVApolynomialGetY(CVodeMem cv_mem, realtype t, /* * CVArhs * - * This routine interfaces to the CVRhsFnB (or CVRhsFnBS) routine + * This routine interfaces to the CVRhsFnB (or CVRhsFnBS) routine * provided by the user. */ -static int CVArhs(realtype t, N_Vector yB, +static int CVArhs(realtype t, N_Vector yB, N_Vector yBdot, void *cvode_mem) { CVodeMem cv_mem; @@ -3017,7 +3048,7 @@ static int CVArhs(realtype t, N_Vector yB, if (ca_mem->ca_IMinterpSensi) flag = ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, ca_mem->ca_yStmp); - else + else flag = ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, NULL); if (flag != CV_SUCCESS) { @@ -3042,7 +3073,7 @@ static int CVArhs(realtype t, N_Vector yB, * provided by the user. */ -static int CVArhsQ(realtype t, N_Vector yB, +static int CVArhsQ(realtype t, N_Vector yB, N_Vector qBdot, void *cvode_mem) { CVodeMem cv_mem; @@ -3061,7 +3092,7 @@ static int CVArhsQ(realtype t, N_Vector yB, if (ca_mem->ca_IMinterpSensi) /* flag = */ ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, ca_mem->ca_yStmp); - else + else /* flag = */ ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, NULL); /* Call the user's RHS function */ diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodea_io.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodea_io.c index 167b2eb40..edc5b74ee 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodea_io.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodea_io.c @@ -6,7 +6,7 @@ * Programmer: Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes.c index 025f3e903..e0e03ce8f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes.c @@ -1,12 +1,8 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -18,7 +14,7 @@ * This is the implementation file for the main CVODES integrator * with sensitivity analysis capabilities. * ----------------------------------------------------------------- - * + * * EXPORTED FUNCTIONS * ------------------ * @@ -26,20 +22,20 @@ * * CVodeCreate * - * CVodeInit + * CVodeInit * CVodeReInit * CVodeSStolerances * CVodeSVtolerances * CVodeWFtolerances * * CVodeQuadInit - * CVodeQuadReInit + * CVodeQuadReInit * CVodeQuadSStolerances * CVodeQuadSVtolerances * * CVodeSensInit * CVodeSensInit1 - * CVodeSensReInit + * CVodeSensReInit * CVodeSensSStolerances * CVodeSensSVtolerances * CVodeSensEEtolerances @@ -49,29 +45,29 @@ * * CVodeSensToggleOff * - * CVodeRootInit + * CVodeRootInit * * Main solver function * CVode * * Interpolated output and extraction functions * CVodeGetDky - * CVodeGetQuad + * CVodeGetQuad * CVodeGetQuadDky - * CVodeGetSens + * CVodeGetSens * CVodeGetSens1 - * CVodeGetSensDky + * CVodeGetSensDky * CVodeGetSensDky1 - * CVodeGetQuadSens + * CVodeGetQuadSens * CVodeGetQuadSens1 - * CVodeGetQuadSensDky + * CVodeGetQuadSensDky * CVodeGetQuadSensDky1 * * Deallocation functions - * CVodeFree + * CVodeFree * CVodeQuadFree - * CVodeSensFree - * CVodeQuadSensFree + * CVodeSensFree + * CVodeQuadSensFree * * PRIVATE FUNCTIONS * ----------------- @@ -79,35 +75,35 @@ * cvCheckNvector * * Memory allocation/deallocation - * cvAllocVectors + * cvAllocVectors * cvFreeVectors - * cvQuadAllocVectors + * cvQuadAllocVectors * cvQuadFreeVectors - * cvSensAllocVectors + * cvSensAllocVectors * cvSensFreeVectors - * cvQuadSensAllocVectors + * cvQuadSensAllocVectors * cvQuadSensFreeVectors * * Initial stepsize calculation - * cvHin + * cvHin * cvUpperBoundH0 - * cvYddNorm + * cvYddNorm * * Initial setup * cvInitialSetup - * cvEwtSet + * cvEwtSet * cvEwtSetSS - * cvEwtSetSV + * cvEwtSetSV * cvQuadEwtSet - * cvQuadEwtSetSS + * cvQuadEwtSetSS * cvQuadEwtSetSV - * cvSensEwtSet + * cvSensEwtSet * cvSensEwtSetEE - * cvSensEwtSetSS + * cvSensEwtSetSS * cvSensEwtSetSV - * cvQuadSensEwtSet + * cvQuadSensEwtSet * cvQuadSensEwtSetEE - * cvQuadSensEwtSetSS + * cvQuadSensEwtSetSS * cvQuadSensEwtSetSV * * Main cvStep function @@ -115,82 +111,79 @@ * * Functions called at beginning of step * cvAdjustParams - * cvAdjustOrder + * cvAdjustOrder * cvAdjustAdams - * cvAdjustBDF + * cvAdjustBDF * cvIncreaseBDF - * cvDecreaseBDF + * cvDecreaseBDF * cvRescale - * cvPredict + * cvPredict * cvSet - * cvSetAdams + * cvSetAdams * cvAdamsStart - * cvAdamsFinish + * cvAdamsFinish * cvAltSum - * cvSetBDF + * cvSetBDF * cvSetTqBDF * * Nonlinear solver functions - * cvNls - * cvQuadNls + * cvNls + * cvQuadNls * cvStgrNls * cvStgr1Nls - * cvQuadSensNls + * cvQuadSensNls * cvHandleNFlag - * cvRestore + * cvRestore * * Error Test * cvDoErrorTest * * Functions called after a successful step - * cvCompleteStep + * cvCompleteStep * cvPrepareNextStep - * cvSetEta + * cvSetEta * cvComputeEtaqm1 - * cvComputeEtaqp1 + * cvComputeEtaqp1 * cvChooseEta * * Function to handle failures - * cvHandleFailure + * cvHandleFailure * - * Functions for BDF Stability Limit Detection + * Functions for BDF Stability Limit Detection * cvBDFStab - * cvSLdet + * cvSLdet * * Functions for rootfinding * cvRcheck1 - * cvRcheck2 + * cvRcheck2 * cvRcheck3 - * cvRootfind + * cvRootfind * * Functions for combined norms * cvQuadUpdateNorm * cvSensNorm - * cvSensUpdateNorm + * cvSensUpdateNorm * cvQuadSensNorm - * cvQuadSensUpdateNorm + * cvQuadSensUpdateNorm * * Wrappers for sensitivity RHS - * cvSensRhsWrapper + * cvSensRhsWrapper * cvSensRhs1Wrapper * * Internal DQ approximations for sensitivity RHS - * cvSensRhsInternalDQ + * cvSensRhsInternalDQ * cvSensRhs1InternalDQ - * cvQuadSensRhsDQ + * cvQuadSensRhsDQ * * Error message handling functions - * cvProcessError + * cvProcessError * cvErrHandler * - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ -/* - * ================================================================= - * IMPORTED HEADER FILES - * ================================================================= - */ +/*=================================================================*/ +/* Import Header Files */ +/*=================================================================*/ #include #include @@ -200,38 +193,34 @@ #include "cvodes_impl.h" #include #include -#include "sunnonlinsol/sunnonlinsol_newton.h" - -/* - * ================================================================= - * CVODES PRIVATE CONSTANTS - * ================================================================= - */ - -#define ZERO RCONST(0.0) -#define TINY RCONST(1.0e-10) -#define PT1 RCONST(0.1) -#define POINT2 RCONST(0.2) -#define FOURTH RCONST(0.25) -#define HALF RCONST(0.5) -#define PT9 RCONST(0.9) -#define ONE RCONST(1.0) -#define ONEPT5 RCONST(1.5) -#define TWO RCONST(2.0) -#define THREE RCONST(3.0) -#define FOUR RCONST(4.0) -#define FIVE RCONST(5.0) -#define TWELVE RCONST(12.0) -#define HUNDRED RCONST(100.0) - -/* - * ================================================================= - * CVODES ROUTINE-SPECIFIC CONSTANTS - * ================================================================= - */ +#include + +/*=================================================================*/ +/* CVODE Private Constants */ +/*=================================================================*/ + +#define ZERO RCONST(0.0) /* real 0.0 */ +#define TINY RCONST(1.0e-10) /* small number */ +#define PT1 RCONST(0.1) /* real 0.1 */ +#define POINT2 RCONST(0.2) /* real 0.2 */ +#define FOURTH RCONST(0.25) /* real 0.25 */ +#define HALF RCONST(0.5) /* real 0.5 */ +#define PT9 RCONST(0.9) /* real 0.9 */ +#define ONE RCONST(1.0) /* real 1.0 */ +#define ONEPT5 RCONST(1.50) /* real 1.5 */ +#define TWO RCONST(2.0) /* real 2.0 */ +#define THREE RCONST(3.0) /* real 3.0 */ +#define FOUR RCONST(4.0) /* real 4.0 */ +#define FIVE RCONST(5.0) /* real 5.0 */ +#define TWELVE RCONST(12.0) /* real 12.0 */ +#define HUNDRED RCONST(100.0) /* real 100.0 */ + +/*=================================================================*/ +/* CVODE Routine-Specific Constants */ +/*=================================================================*/ -/* - * Control constants for lower-level functions used by cvStep +/* + * Control constants for lower-level functions used by cvStep * ---------------------------------------------------------- * * cvHin return values: @@ -245,12 +234,12 @@ * DO_ERROR_TEST * PREDICT_AGAIN * - * cvStep return values: + * cvStep return values: * CV_SUCCESS, * CV_CONV_FAILURE, CV_ERR_FAILURE, - * CV_LSETUP_FAIL, CV_LSOLVE_FAIL, + * CV_LSETUP_FAIL, CV_LSOLVE_FAIL, * CV_RTFUNC_FAIL, - * CV_RHSFUNC_FAIL, CV_QRHSFUNC_FAIL, CV_SRHSFUNC_FAIL, CV_QSRHSFUNC_FAIL, + * CV_RHSFUNC_FAIL, CV_QRHSFUNC_FAIL, CV_SRHSFUNC_FAIL, CV_QSRHSFUNC_FAIL, * CV_FIRST_RHSFUNC_ERR, CV_FIRST_QRHSFUNC_ERR, CV_FIRST_SRHSFUNC_ERR, CV_FIRST_QSRHSFUNC_ERR, * CV_UNREC_RHSFUNC_ERR, CV_UNREC_QRHSFUNC_ERR, CV_UNREC_SRHSFUNC_ERR, CV_UNREC_QSRHSFUNC_ERR, * CV_REPTD_RHSFUNC_ERR, CV_REPTD_QRHSFUNC_ERR, CV_REPTD_SRHSFUNC_ERR, CV_REPTD_QSRHSFUNC_ERR, @@ -272,7 +261,7 @@ #define DO_ERROR_TEST +2 #define PREDICT_AGAIN +3 -#define CONV_FAIL +4 +#define CONV_FAIL +4 #define TRY_AGAIN +5 #define FIRST_CALL +6 #define PREV_CONV_FAIL +7 @@ -288,20 +277,20 @@ * ------------------------------------------------------- * * cvRcheck1 return values: - * CV_SUCCESS, - * CV_RTFUNC_FAIL, + * CV_SUCCESS + * CV_RTFUNC_FAIL * cvRcheck2 return values: - * CV_SUCCESS, - * CV_RTFUNC_FAIL, - * CLOSERT, + * CV_SUCCESS + * CV_RTFUNC_FAIL + * CLOSERT * RTFOUND * cvRcheck3 return values: - * CV_SUCCESS, - * CV_RTFUNC_FAIL, + * CV_SUCCESS + * CV_RTFUNC_FAIL * RTFOUND * cvRootfind return values: - * CV_SUCCESS, - * CV_RTFUNC_FAIL, + * CV_SUCCESS + * CV_RTFUNC_FAIL * RTFOUND */ @@ -352,7 +341,7 @@ * H_BIAS bias factor in selection of initial step size * MAX_ITERS maximum attempts to compute the initial step size * - * CVodeCreate + * CVodeCreate * * CORTES constant in nonlinear iteration convergence test * @@ -371,7 +360,7 @@ * BIAS3 -+ * ONEPSM (1+epsilon) used in testing if the step size is below its bound * - * SMALL_NST nst > SMALL_NST => use ETAMX3 + * SMALL_NST nst > SMALL_NST => use ETAMX3 * MXNCF max no. of convergence failures during one step try * MXNEF max no. of error test failures during one step try * MXNEF1 max no. of error test failures before forcing a reduction of order @@ -398,7 +387,7 @@ #define CORTES RCONST(0.1) #define THRESH RCONST(1.5) -#define ETAMX1 RCONST(10000.0) +#define ETAMX1 RCONST(10000.0) #define ETAMX2 RCONST(10.0) #define ETAMX3 RCONST(10.0) #define ETAMXF RCONST(0.2) @@ -420,14 +409,16 @@ #define DGMAX RCONST(0.3) #define MSBP 20 -/* - * ================================================================= - * PRIVATE FUNCTION PROTOTYPES - * ================================================================= - */ +/*=================================================================*/ +/* Private Helper Functions Prototypes */ +/*=================================================================*/ static booleantype cvCheckNvector(N_Vector tmpl); +/* Initial setup */ + +static int cvInitialSetup(CVodeMem cv_mem); + /* Memory allocation/deallocation */ static booleantype cvAllocVectors(CVodeMem cv_mem, N_Vector tmpl); @@ -442,15 +433,6 @@ static void cvSensFreeVectors(CVodeMem cv_mem); static booleantype cvQuadSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl); static void cvQuadSensFreeVectors(CVodeMem cv_mem); -/* Initial stepsize calculation */ - -static int cvHin(CVodeMem cv_mem, realtype tout); -static realtype cvUpperBoundH0(CVodeMem cv_mem, realtype tdist); -static int cvYddNorm(CVodeMem cv_mem, realtype hg, realtype *yddnrm); - -/* Initial setup */ - -static int cvInitialSetup(CVodeMem cv_mem); static int cvEwtSetSS(CVodeMem cv_mem, N_Vector ycur, N_Vector weight); static int cvEwtSetSV(CVodeMem cv_mem, N_Vector ycur, N_Vector weight); @@ -469,6 +451,13 @@ static int cvQuadSensEwtSetEE(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weigh static int cvQuadSensEwtSetSS(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS); static int cvQuadSensEwtSetSV(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS); + +/* Initial stepsize calculation */ + +static int cvHin(CVodeMem cv_mem, realtype tout); +static realtype cvUpperBoundH0(CVodeMem cv_mem, realtype tdist); +static int cvYddNorm(CVodeMem cv_mem, realtype hg, realtype *yddnrm); + /* Main cvStep function */ static int cvStep(CVodeMem cv_mem); @@ -509,7 +498,7 @@ static void cvRestore(CVodeMem cv_mem, realtype saved_t); /* Error Test */ -static int cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, +static int cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, realtype acor_nrm, int *nefPtr, long int *netfPtr, realtype *dsmPtr); @@ -549,38 +538,38 @@ static realtype cvQuadSensUpdateNorm(CVodeMem cv_mem, realtype old_nrm, /* Internal sensitivity RHS DQ functions */ -static int cvQuadSensRhsInternalDQ(int Ns, realtype t, +static int cvQuadSensRhsInternalDQ(int Ns, realtype t, N_Vector y, N_Vector *yS, N_Vector yQdot, N_Vector *yQSdot, - void *cvode_mem, + void *cvode_mem, N_Vector tmp, N_Vector tmpQ); -static int cvQuadSensRhs1InternalDQ(CVodeMem cv_mem, int is, realtype t, +static int cvQuadSensRhs1InternalDQ(CVodeMem cv_mem, int is, realtype t, N_Vector y, N_Vector yS, - N_Vector yQdot, N_Vector yQSdot, + N_Vector yQdot, N_Vector yQSdot, N_Vector tmp, N_Vector tmpQ); -/* +/* * ================================================================= - * EXPORTED FUNCTIONS IMPLEMENTATION + * Exported Functions Implementation * ================================================================= */ -/* +/* * ----------------------------------------------------------------- * Creation, allocation and re-initialization functions * ----------------------------------------------------------------- */ -/* +/* * CVodeCreate * - * CVodeCreate creates an internal memory block for a problem to + * CVodeCreate creates an internal memory block for a problem to * be solved by CVODES. - * If successful, CVodeCreate returns a pointer to the problem memory. - * This pointer should be passed to CVodeInit. - * If an initialization error occurs, CVodeCreate prints an error - * message to standard err and returns NULL. + * If successful, CVodeCreate returns a pointer to the problem memory. + * This pointer should be passed to CVodeInit. + * If an initialization error occurs, CVodeCreate prints an error + * message to standard err and returns NULL. */ void *CVodeCreate(int lmm) @@ -607,37 +596,35 @@ void *CVodeCreate(int lmm) maxord = (lmm == CV_ADAMS) ? ADAMS_Q_MAX : BDF_Q_MAX; - /* copy input parameter into cv_mem */ - + /* copy input parameters into cv_mem */ cv_mem->cv_lmm = lmm; /* Set uround */ - cv_mem->cv_uround = UNIT_ROUNDOFF; /* Set default values for integrator optional inputs */ - - cv_mem->cv_f = NULL; - cv_mem->cv_user_data = NULL; - cv_mem->cv_itol = CV_NN; - cv_mem->cv_user_efun = SUNFALSE; - cv_mem->cv_efun = NULL; - cv_mem->cv_e_data = NULL; - cv_mem->cv_ehfun = cvErrHandler; - cv_mem->cv_eh_data = cv_mem; - cv_mem->cv_errfp = stderr; - cv_mem->cv_qmax = maxord; - cv_mem->cv_mxstep = MXSTEP_DEFAULT; - cv_mem->cv_mxhnil = MXHNIL_DEFAULT; - cv_mem->cv_sldeton = SUNFALSE; - cv_mem->cv_hin = ZERO; - cv_mem->cv_hmin = HMIN_DEFAULT; - cv_mem->cv_hmax_inv = HMAX_INV_DEFAULT; - cv_mem->cv_tstopset = SUNFALSE; - cv_mem->cv_maxnef = MXNEF; - cv_mem->cv_maxncf = MXNCF; - cv_mem->cv_nlscoef = CORTES; - cv_mem->convfail = CV_NO_FAILURES; + cv_mem->cv_f = NULL; + cv_mem->cv_user_data = NULL; + cv_mem->cv_itol = CV_NN; + cv_mem->cv_atolmin0 = SUNTRUE; + cv_mem->cv_user_efun = SUNFALSE; + cv_mem->cv_efun = NULL; + cv_mem->cv_e_data = NULL; + cv_mem->cv_ehfun = cvErrHandler; + cv_mem->cv_eh_data = cv_mem; + cv_mem->cv_errfp = stderr; + cv_mem->cv_qmax = maxord; + cv_mem->cv_mxstep = MXSTEP_DEFAULT; + cv_mem->cv_mxhnil = MXHNIL_DEFAULT; + cv_mem->cv_sldeton = SUNFALSE; + cv_mem->cv_hin = ZERO; + cv_mem->cv_hmin = HMIN_DEFAULT; + cv_mem->cv_hmax_inv = HMAX_INV_DEFAULT; + cv_mem->cv_tstopset = SUNFALSE; + cv_mem->cv_maxnef = MXNEF; + cv_mem->cv_maxncf = MXNCF; + cv_mem->cv_nlscoef = CORTES; + cv_mem->convfail = CV_NO_FAILURES; cv_mem->cv_constraints = NULL; cv_mem->cv_constraintsSet = SUNFALSE; @@ -649,7 +636,7 @@ void *CVodeCreate(int lmm) cv_mem->cv_iroots = NULL; cv_mem->cv_rootdir = NULL; cv_mem->cv_gfun = NULL; - cv_mem->cv_nrtfn = 0; + cv_mem->cv_nrtfn = 0; cv_mem->cv_gactive = NULL; cv_mem->cv_mxgnull = 1; @@ -659,6 +646,7 @@ void *CVodeCreate(int lmm) cv_mem->cv_fQ = NULL; cv_mem->cv_errconQ = SUNFALSE; cv_mem->cv_itolQ = CV_NN; + cv_mem->cv_atolQmin0 = SUNTRUE; /* Set default values for sensi. optional inputs */ @@ -678,6 +666,7 @@ void *CVodeCreate(int lmm) cv_mem->cv_ncfnS1 = NULL; cv_mem->cv_nniS1 = NULL; cv_mem->cv_itolS = CV_NN; + cv_mem->cv_atolSmin0 = NULL; /* Set default values for quad. sensi. optional inputs */ @@ -687,13 +676,14 @@ void *CVodeCreate(int lmm) cv_mem->cv_fQSDQ = SUNTRUE; cv_mem->cv_errconQS = SUNFALSE; cv_mem->cv_itolQS = CV_NN; + cv_mem->cv_atolQSmin0 = NULL; /* Set default for ASA */ cv_mem->cv_adj = SUNFALSE; cv_mem->cv_adj_mem = NULL; - /* Set the saved values for qmax_alloc */ + /* Set the saved value for qmax_alloc */ cv_mem->cv_qmax_alloc = maxord; cv_mem->cv_qmax_allocQ = maxord; @@ -729,18 +719,18 @@ void *CVodeCreate(int lmm) cv_mem->NLSsim = NULL; cv_mem->ownNLSsim = SUNFALSE; - cv_mem->ycor0Sim = NULL; + cv_mem->zn0Sim = NULL; cv_mem->ycorSim = NULL; cv_mem->ewtSim = NULL; cv_mem->simMallocDone = SUNFALSE; cv_mem->NLSstg = NULL; cv_mem->ownNLSstg = SUNFALSE; - cv_mem->ycor0Stg = NULL; + cv_mem->zn0Stg = NULL; cv_mem->ycorStg = NULL; cv_mem->ewtStg = NULL; cv_mem->stgMallocDone = SUNFALSE; - + cv_mem->NLSstg1 = NULL; cv_mem->ownNLSstg1 = SUNFALSE; @@ -756,10 +746,10 @@ void *CVodeCreate(int lmm) /* * CVodeInit - * - * CVodeInit allocates and initializes memory for a problem. All - * problem inputs are checked for errors. If any error occurs during - * initialization, it is reported to the file whose file pointer is + * + * CVodeInit allocates and initializes memory for a problem. All + * problem inputs are checked for errors. If any error occurs during + * initialization, it is reported to the file whose file pointer is * errfp and an error flag is returned. Otherwise, it returns CV_SUCCESS */ @@ -774,8 +764,7 @@ int CVodeInit(void *cvode_mem, CVRhsFn f, realtype t0, N_Vector y0) /* Check cvode_mem */ if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeInit", - MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeInit", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -783,14 +772,12 @@ int CVodeInit(void *cvode_mem, CVRhsFn f, realtype t0, N_Vector y0) /* Check for legal input parameters */ if (y0==NULL) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeInit", - MSGCV_NULL_Y0); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeInit", MSGCV_NULL_Y0); return(CV_ILL_INPUT); } if (f == NULL) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeInit", - MSGCV_NULL_F); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeInit", MSGCV_NULL_F); return(CV_ILL_INPUT); } @@ -818,8 +805,7 @@ int CVodeInit(void *cvode_mem, CVRhsFn f, realtype t0, N_Vector y0) allocOK = cvAllocVectors(cv_mem, y0); if (!allocOK) { - cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeInit", - MSGCV_MEM_FAIL); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeInit", MSGCV_MEM_FAIL); return(CV_MEM_FAIL); } @@ -881,9 +867,9 @@ int CVodeInit(void *cvode_mem, CVRhsFn f, realtype t0, N_Vector y0) cv_mem->cv_qwait = cv_mem->cv_L; cv_mem->cv_etamax = ETAMX1; - cv_mem->cv_qu = 0; - cv_mem->cv_hu = ZERO; - cv_mem->cv_tolsf = ONE; + cv_mem->cv_qu = 0; + cv_mem->cv_hu = ZERO; + cv_mem->cv_tolsf = ONE; /* Set the linear solver addresses to NULL. (We check != NULL later, in CVode) */ @@ -930,7 +916,7 @@ int CVodeInit(void *cvode_mem, CVRhsFn f, realtype t0, N_Vector y0) cv_mem->cv_nor = 0; for (i = 1; i <= 5; i++) - for (k = 1; k <= 3; k++) + for (k = 1; k <= 3; k++) cv_mem->cv_ssdat[i-1][k-1] = ZERO; /* Problem has been successfully initialized */ @@ -958,12 +944,11 @@ int CVodeReInit(void *cvode_mem, realtype t0, N_Vector y0) { CVodeMem cv_mem; int i,k; - + /* Check cvode_mem */ if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeReInit", - MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeReInit", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -983,7 +968,7 @@ int CVodeReInit(void *cvode_mem, realtype t0, N_Vector y0) MSGCV_NULL_Y0); return(CV_ILL_INPUT); } - + /* Copy the input parameters into CVODES state */ cv_mem->cv_tn = t0; @@ -995,9 +980,9 @@ int CVodeReInit(void *cvode_mem, realtype t0, N_Vector y0) cv_mem->cv_qwait = cv_mem->cv_L; cv_mem->cv_etamax = ETAMX1; - cv_mem->cv_qu = 0; - cv_mem->cv_hu = ZERO; - cv_mem->cv_tolsf = ONE; + cv_mem->cv_qu = 0; + cv_mem->cv_hu = ZERO; + cv_mem->cv_tolsf = ONE; /* Set forceSetup to SUNFALSE */ @@ -1006,7 +991,7 @@ int CVodeReInit(void *cvode_mem, realtype t0, N_Vector y0) /* Initialize zn[0] in the history array */ N_VScale(ONE, y0, cv_mem->cv_zn[0]); - + /* Initialize all the counters */ cv_mem->cv_nst = 0; @@ -1032,9 +1017,9 @@ int CVodeReInit(void *cvode_mem, realtype t0, N_Vector y0) cv_mem->cv_nor = 0; for (i = 1; i <= 5; i++) - for (k = 1; k <= 3; k++) + for (k = 1; k <= 3; k++) cv_mem->cv_ssdat[i-1][k-1] = ZERO; - + /* Problem has been successfully re-initialized */ return(CV_SUCCESS); @@ -1052,7 +1037,7 @@ int CVodeReInit(void *cvode_mem, realtype t0, N_Vector y0) * * CVodeSStolerances specifies scalar relative and absolute tolerances. * CVodeSVtolerances specifies scalar relative tolerance and a vector - * absolute tolerance (a potentially different absolute tolerance + * absolute tolerance (a potentially different absolute tolerance * for each vector component). * CVodeWFtolerances specifies a user-provides function (of type CVEwtFn) * which will be called to set the error weight vector. @@ -1063,36 +1048,37 @@ int CVodeSStolerances(void *cvode_mem, realtype reltol, realtype abstol) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", - "CVodeSStolerances", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSStolerances", + MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_MallocDone == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_MALLOC, "CVODES", - "CVodeSStolerances", MSGCV_NO_MALLOC); + cvProcessError(cv_mem, CV_NO_MALLOC, "CVODES", "CVodeSStolerances", + MSGCV_NO_MALLOC); return(CV_NO_MALLOC); } /* Check inputs */ if (reltol < ZERO) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", - "CVodeSStolerances", MSGCV_BAD_RELTOL); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSStolerances", + MSGCV_BAD_RELTOL); return(CV_ILL_INPUT); } if (abstol < ZERO) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", - "CVodeSStolerances", MSGCV_BAD_ABSTOL); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSStolerances", + MSGCV_BAD_ABSTOL); return(CV_ILL_INPUT); } /* Copy tolerances into memory */ - + cv_mem->cv_reltol = reltol; cv_mem->cv_Sabstol = abstol; + cv_mem->cv_atolmin0 = (abstol == ZERO); cv_mem->cv_itol = CV_SS; @@ -1107,36 +1093,43 @@ int CVodeSStolerances(void *cvode_mem, realtype reltol, realtype abstol) int CVodeSVtolerances(void *cvode_mem, realtype reltol, N_Vector abstol) { CVodeMem cv_mem; + realtype atolmin; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", - "CVodeSVtolerances", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSVtolerances", + MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_MallocDone == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_MALLOC, "CVODES", - "CVodeSVtolerances", MSGCV_NO_MALLOC); + cvProcessError(cv_mem, CV_NO_MALLOC, "CVODES", "CVodeSVtolerances", + MSGCV_NO_MALLOC); return(CV_NO_MALLOC); } /* Check inputs */ if (reltol < ZERO) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", - "CVodeSVtolerances", MSGCV_BAD_RELTOL); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSVtolerances", + MSGCV_BAD_RELTOL); return(CV_ILL_INPUT); } - if (N_VMin(abstol) < ZERO) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", - "CVodeSVtolerances", MSGCV_BAD_ABSTOL); + if (abstol->ops->nvmin == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSVtolerances", + "Missing N_VMin routine from N_Vector"); + return(CV_ILL_INPUT); + } + atolmin = N_VMin(abstol); + if (atolmin < ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSVtolerances", + MSGCV_BAD_ABSTOL); return(CV_ILL_INPUT); } /* Copy tolerances into memory */ - + if ( !(cv_mem->cv_VabstolMallocDone) ) { cv_mem->cv_Vabstol = N_VClone(cv_mem->cv_ewt); cv_mem->cv_lrw += cv_mem->cv_lrw1; @@ -1146,6 +1139,7 @@ int CVodeSVtolerances(void *cvode_mem, realtype reltol, N_Vector abstol) cv_mem->cv_reltol = reltol; N_VScale(ONE, abstol, cv_mem->cv_Vabstol); + cv_mem->cv_atolmin0 = (atolmin == ZERO); cv_mem->cv_itol = CV_SV; @@ -1162,15 +1156,15 @@ int CVodeWFtolerances(void *cvode_mem, CVEwtFn efun) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", - "CVodeWFtolerances", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeWFtolerances", + MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_MallocDone == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_MALLOC, "CVODES", - "CVodeWFtolerances", MSGCV_NO_MALLOC); + cvProcessError(cv_mem, CV_NO_MALLOC, "CVODES", "CVodeWFtolerances", + MSGCV_NO_MALLOC); return(CV_NO_MALLOC); } @@ -1188,10 +1182,10 @@ int CVodeWFtolerances(void *cvode_mem, CVEwtFn efun) /* * CVodeQuadInit * - * CVodeQuadInit allocates and initializes quadrature related - * memory for a problem. All problem specification inputs are - * checked for errors. If any error occurs during initialization, - * it is reported to the file whose file pointer is errfp. + * CVodeQuadInit allocates and initializes quadrature related + * memory for a problem. All problem specification inputs are + * checked for errors. If any error occurs during initialization, + * it is reported to the file whose file pointer is errfp. * The return value is CV_SUCCESS = 0 if no errors occurred, or * a negative value otherwise. */ @@ -1246,9 +1240,9 @@ int CVodeQuadInit(void *cvode_mem, CVQuadRhsFn fQ, N_Vector yQ0) /* * CVodeQuadReInit * - * CVodeQuadReInit re-initializes CVODES's quadrature related memory - * for a problem, assuming it has already been allocated in prior - * calls to CVodeInit and CVodeQuadInit. + * CVodeQuadReInit re-initializes CVODES's quadrature related memory + * for a problem, assuming it has already been allocated in prior + * calls to CVodeInit and CVodeQuadInit. * All problem specification inputs are checked for errors. * If any error occurs during initialization, it is reported to the * file whose file pointer is errfp. @@ -1296,7 +1290,7 @@ int CVodeQuadReInit(void *cvode_mem, N_Vector yQ0) * CVodeQuadSVtolerances * * These functions specify the integration tolerances for sensitivity - * variables. One of them MUST be called before the first call to + * variables. One of them MUST be called before the first call to * CVode IF error control on the quadrature variables is enabled * (see CVodeSetQuadErrCon). * @@ -1312,7 +1306,7 @@ int CVodeQuadSStolerances(void *cvode_mem, realtype reltolQ, realtype abstolQ) if (cvode_mem==NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", - "CVodeQuadSStolerances", MSGCV_NO_MEM); + "CVodeQuadSStolerances", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -1321,7 +1315,7 @@ int CVodeQuadSStolerances(void *cvode_mem, realtype reltolQ, realtype abstolQ) if (cv_mem->cv_QuadMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", - "CVodeQuadSStolerances", MSGCV_NO_QUAD); + "CVodeQuadSStolerances", MSGCV_NO_QUAD); return(CV_NO_QUAD); } @@ -1345,6 +1339,7 @@ int CVodeQuadSStolerances(void *cvode_mem, realtype reltolQ, realtype abstolQ) cv_mem->cv_reltolQ = reltolQ; cv_mem->cv_SabstolQ = abstolQ; + cv_mem->cv_atolQmin0 = (abstolQ == ZERO); return(CV_SUCCESS); } @@ -1352,10 +1347,11 @@ int CVodeQuadSStolerances(void *cvode_mem, realtype reltolQ, realtype abstolQ) int CVodeQuadSVtolerances(void *cvode_mem, realtype reltolQ, N_Vector abstolQ) { CVodeMem cv_mem; + realtype atolmin; if (cvode_mem==NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", - "CVodeQuadSVtolerances", MSGCV_NO_MEM); + "CVodeQuadSVtolerances", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -1364,7 +1360,7 @@ int CVodeQuadSVtolerances(void *cvode_mem, realtype reltolQ, N_Vector abstolQ) if (cv_mem->cv_QuadMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", - "CVodeQuadSVtolerances", MSGCV_NO_QUAD); + "CVodeQuadSVtolerances", MSGCV_NO_QUAD); return(CV_NO_QUAD); } @@ -1382,7 +1378,14 @@ int CVodeQuadSVtolerances(void *cvode_mem, realtype reltolQ, N_Vector abstolQ) return(CV_ILL_INPUT); } - if (N_VMin(abstolQ) < ZERO) { + if (abstolQ->ops->nvmin == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSVtolerances", + "Missing N_VMin routine from N_Vector"); + return(CV_ILL_INPUT); + } + atolmin = N_VMin(abstolQ); + if (atolmin < ZERO) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeQuadSVtolerances", MSGCV_BAD_ABSTOLQ); return(CV_ILL_INPUT); @@ -1400,8 +1403,9 @@ int CVodeQuadSVtolerances(void *cvode_mem, realtype reltolQ, N_Vector abstolQ) cv_mem->cv_liw += cv_mem->cv_liw1Q; cv_mem->cv_VabstolQMallocDone = SUNTRUE; } - + N_VScale(ONE, abstolQ, cv_mem->cv_VabstolQ); + cv_mem->cv_atolQmin0 = (atolmin == ZERO); return(CV_SUCCESS); } @@ -1412,9 +1416,9 @@ int CVodeQuadSVtolerances(void *cvode_mem, realtype reltolQ, N_Vector abstolQ) /* * CVodeSensInit * - * CVodeSensInit allocates and initializes sensitivity related + * CVodeSensInit allocates and initializes sensitivity related * memory for a problem (using a sensitivity RHS function of type - * CVSensRhsFn). All problem specification inputs are checked for + * CVSensRhsFn). All problem specification inputs are checked for * errors. * The return value is CV_SUCCESS = 0 if no errors occurred, or * a negative value otherwise. @@ -1509,7 +1513,7 @@ int CVodeSensInit(void *cvode_mem, int Ns, int ism, CVSensRhsFn fS, N_Vector *yS MSGCV_MEM_FAIL); return(CV_MEM_FAIL); } - + /* Check if larger temporary work arrays are needed for fused vector ops */ if (Ns*L_MAX > L_MAX) { free(cv_mem->cv_cvals); cv_mem->cv_cvals = NULL; @@ -1530,15 +1534,15 @@ int CVodeSensInit(void *cvode_mem, int Ns, int ism, CVSensRhsFn fS, N_Vector *yS } } - /*---------------------------------------------- - All error checking is complete at this point + /*---------------------------------------------- + All error checking is complete at this point -----------------------------------------------*/ /* Initialize znS[0] in the history array */ for (is=0; iscv_cvals[is] = ONE; - + retval = N_VScaleVectorArray(Ns, cv_mem->cv_cvals, yS0, cv_mem->cv_znS[0]); if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); @@ -1605,9 +1609,9 @@ int CVodeSensInit(void *cvode_mem, int Ns, int ism, CVSensRhsFn fS, N_Vector *yS /* * CVodeSensInit1 * - * CVodeSensInit1 allocates and initializes sensitivity related + * CVodeSensInit1 allocates and initializes sensitivity related * memory for a problem (using a sensitivity RHS function of type - * CVSensRhs1Fn). All problem specification inputs are checked for + * CVSensRhs1Fn). All problem specification inputs are checked for * errors. * The return value is CV_SUCCESS = 0 if no errors occurred, or * a negative value otherwise. @@ -1619,7 +1623,7 @@ int CVodeSensInit1(void *cvode_mem, int Ns, int ism, CVSensRhs1Fn fS1, N_Vector booleantype allocOK; int is, retval; SUNNonlinearSolver NLS; - + /* Check cvode_mem */ if (cvode_mem==NULL) { @@ -1741,16 +1745,16 @@ int CVodeSensInit1(void *cvode_mem, int Ns, int ism, CVSensRhs1Fn fS1, N_Vector return(CV_MEM_FAIL); } } - - /*---------------------------------------------- - All error checking is complete at this point + + /*---------------------------------------------- + All error checking is complete at this point -----------------------------------------------*/ /* Initialize znS[0] in the history array */ for (is=0; iscv_cvals[is] = ONE; - + retval = N_VScaleVectorArray(Ns, cv_mem->cv_cvals, yS0, cv_mem->cv_znS[0]); if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); @@ -1830,9 +1834,9 @@ int CVodeSensInit1(void *cvode_mem, int Ns, int ism, CVSensRhs1Fn fS1, N_Vector /* * CVodeSensReInit * - * CVodeSensReInit re-initializes CVODES's sensitivity related memory - * for a problem, assuming it has already been allocated in prior - * calls to CVodeInit and CVodeSensInit/CVodeSensInit1. + * CVodeSensReInit re-initializes CVODES's sensitivity related memory + * for a problem, assuming it has already been allocated in prior + * calls to CVodeInit and CVodeSensInit/CVodeSensInit1. * All problem specification inputs are checked for errors. * The number of sensitivities Ns is assumed to be unchanged since * the previous call to CVodeSensInit. @@ -1840,7 +1844,7 @@ int CVodeSensInit1(void *cvode_mem, int Ns, int ism, CVSensRhs1Fn fS1, N_Vector * file whose file pointer is errfp. * The return value is CV_SUCCESS = 0 if no errors occurred, or * a negative value otherwise. - */ + */ int CVodeSensReInit(void *cvode_mem, int ism, N_Vector *yS0) { @@ -1863,7 +1867,7 @@ int CVodeSensReInit(void *cvode_mem, int ism, N_Vector *yS0) cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeSensReInit", MSGCV_NO_SENSI); return(CV_NO_SENS); - } + } /* Check if ism is compatible */ @@ -1872,7 +1876,7 @@ int CVodeSensReInit(void *cvode_mem, int ism, N_Vector *yS0) "CVodeSensReInit", MSGCV_BAD_ISM_IFS); return(CV_ILL_INPUT); } - + /* Check if ism is legal */ if ((ism!=CV_SIMULTANEOUS) && (ism!=CV_STAGGERED) && (ism!=CV_STAGGERED1)) { @@ -1888,7 +1892,7 @@ int CVodeSensReInit(void *cvode_mem, int ism, N_Vector *yS0) cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensReInit", MSGCV_NULL_YS0); return(CV_ILL_INPUT); - } + } /* Allocate ncfS1, ncfnS1, and nniS1 if needed */ @@ -1909,15 +1913,15 @@ int CVodeSensReInit(void *cvode_mem, int ism, N_Vector *yS0) } } - /*---------------------------------------------- - All error checking is complete at this point + /*---------------------------------------------- + All error checking is complete at this point -----------------------------------------------*/ /* Initialize znS[0] in the history array */ for (is=0; iscv_Ns; is++) cv_mem->cv_cvals[is] = ONE; - + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, yS0, cv_mem->cv_znS[0]); if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); @@ -2029,7 +2033,7 @@ int CVodeSensSStolerances(void *cvode_mem, realtype reltolS, realtype *abstolS) if (cvode_mem==NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensSStolerances", - MSGCV_NO_MEM); + MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -2040,10 +2044,10 @@ int CVodeSensSStolerances(void *cvode_mem, realtype reltolS, realtype *abstolS) cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeSensSStolerances", MSGCV_NO_SENSI); return(CV_NO_SENS); - } + } /* Test user-supplied tolerances */ - + if (reltolS < ZERO) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensSStolerances", MSGCV_BAD_RELTOLS); @@ -2072,12 +2076,15 @@ int CVodeSensSStolerances(void *cvode_mem, realtype reltolS, realtype *abstolS) if ( !(cv_mem->cv_SabstolSMallocDone) ) { cv_mem->cv_SabstolS = NULL; cv_mem->cv_SabstolS = (realtype *)malloc(cv_mem->cv_Ns*sizeof(realtype)); + cv_mem->cv_atolSmin0 = (booleantype *)malloc(cv_mem->cv_Ns*sizeof(booleantype)); cv_mem->cv_lrw += cv_mem->cv_Ns; cv_mem->cv_SabstolSMallocDone = SUNTRUE; } - for (is=0; iscv_Ns; is++) + for (is=0; iscv_Ns; is++) { cv_mem->cv_SabstolS[is] = abstolS[is]; + cv_mem->cv_atolSmin0[is] = (abstolS[is] == ZERO); + } return(CV_SUCCESS); } @@ -2086,10 +2093,11 @@ int CVodeSensSVtolerances(void *cvode_mem, realtype reltolS, N_Vector *abstolS) { CVodeMem cv_mem; int is, retval; + realtype *atolmin; if (cvode_mem==NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensSVtolerances", - MSGCV_NO_MEM); + MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -2100,10 +2108,10 @@ int CVodeSensSVtolerances(void *cvode_mem, realtype reltolS, N_Vector *abstolS) cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeSensSVtolerances", MSGCV_NO_SENSI); return(CV_NO_SENS); - } + } /* Test user-supplied tolerances */ - + if (reltolS < ZERO) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensSVtolerances", MSGCV_BAD_RELTOLS); @@ -2116,12 +2124,22 @@ int CVodeSensSVtolerances(void *cvode_mem, realtype reltolS, N_Vector *abstolS) return(CV_ILL_INPUT); } - for (is=0; iscv_Ns; is++) - if (N_VMin(abstolS[is]) < ZERO) { + if (cv_mem->cv_tempv->ops->nvmin == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSensSVtolerances", + "Missing N_VMin routine from N_Vector"); + return(CV_ILL_INPUT); + } + atolmin = (realtype *)malloc(cv_mem->cv_Ns*sizeof(realtype)); + for (is=0; iscv_Ns; is++) { + atolmin[is] = N_VMin(abstolS[is]); + if (atolmin[is] < ZERO) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensSVtolerances", MSGCV_BAD_ABSTOLS); + free(atolmin); return(CV_ILL_INPUT); } + } /* Copy tolerances into memory */ @@ -2131,13 +2149,17 @@ int CVodeSensSVtolerances(void *cvode_mem, realtype reltolS, N_Vector *abstolS) if ( !(cv_mem->cv_VabstolSMallocDone) ) { cv_mem->cv_VabstolS = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempv); + cv_mem->cv_atolSmin0 = (booleantype *)malloc(cv_mem->cv_Ns*sizeof(booleantype)); cv_mem->cv_lrw += cv_mem->cv_Ns*cv_mem->cv_lrw1; cv_mem->cv_liw += cv_mem->cv_Ns*cv_mem->cv_liw1; cv_mem->cv_VabstolSMallocDone = SUNTRUE; } - - for (is=0; iscv_Ns; is++) + + for (is=0; iscv_Ns; is++) { cv_mem->cv_cvals[is] = ONE; + cv_mem->cv_atolSmin0[is] = (atolmin[is] == ZERO); + } + free(atolmin); retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, abstolS, cv_mem->cv_VabstolS); @@ -2153,7 +2175,7 @@ int CVodeSensEEtolerances(void *cvode_mem) if (cvode_mem==NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensEEtolerances", - MSGCV_NO_MEM); + MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -2164,7 +2186,7 @@ int CVodeSensEEtolerances(void *cvode_mem) cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeSensEEtolerances", MSGCV_NO_SENSI); return(CV_NO_SENS); - } + } cv_mem->cv_itolS = CV_EE; @@ -2215,8 +2237,8 @@ int CVodeQuadSensInit(void *cvode_mem, CVQuadSensRhsFn fQS, N_Vector *yQS0) return(CV_MEM_FAIL); } - /*---------------------------------------------- - All error checking is complete at this point + /*---------------------------------------------- + All error checking is complete at this point -----------------------------------------------*/ /* Set fQS */ @@ -2239,7 +2261,7 @@ int CVodeQuadSensInit(void *cvode_mem, CVQuadSensRhsFn fQS, N_Vector *yQS0) /* Initialize znQS[0] in the history array */ for (is=0; iscv_Ns; is++) cv_mem->cv_cvals[is] = ONE; - + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, yQS0, cv_mem->cv_znQS[0]); if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); @@ -2248,7 +2270,7 @@ int CVodeQuadSensInit(void *cvode_mem, CVQuadSensRhsFn fQS, N_Vector *yQS0) cv_mem->cv_nfQSe = 0; cv_mem->cv_nfQeS = 0; cv_mem->cv_netfQS = 0; - + /* Quadrature sensitivities will be computed */ cv_mem->cv_quadr_sensi = SUNTRUE; cv_mem->cv_QuadSensMallocDone = SUNTRUE; @@ -2287,7 +2309,7 @@ int CVodeQuadSensReInit(void *cvode_mem, N_Vector *yQS0) cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeQuadSensReInit", MSGCV_NO_QUADSENSI); return(CV_NO_QUADSENS); - } + } /* Check if yQS0 is non-null */ if (yQS0 == NULL) { @@ -2296,14 +2318,14 @@ int CVodeQuadSensReInit(void *cvode_mem, N_Vector *yQS0) return(CV_ILL_INPUT); } - /*---------------------------------------------- - All error checking is complete at this point + /*---------------------------------------------- + All error checking is complete at this point -----------------------------------------------*/ /* Initialize znQS[0] in the history array */ - for (is=0; iscv_Ns; is++) + for (is=0; iscv_Ns; is++) cv_mem->cv_cvals[is] = ONE; - + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, yQS0, cv_mem->cv_znQS[0]); if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); @@ -2347,7 +2369,7 @@ int CVodeQuadSensSStolerances(void *cvode_mem, realtype reltolQS, realtype *abst if (cvode_mem==NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", - "CVodeQuadSensSStolerances", MSGCV_NO_MEM); + "CVodeQuadSensSStolerances", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -2358,18 +2380,18 @@ int CVodeQuadSensSStolerances(void *cvode_mem, realtype reltolQS, realtype *abst cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeQuadSensSStolerances", MSGCV_NO_SENSI); return(CV_NO_SENS); - } + } /* Ckeck if quadrature sensitivity was initialized? */ if (cv_mem->cv_QuadSensMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", - "CVodeQuadSSensSStolerances", MSGCV_NO_QUADSENSI); + "CVodeQuadSSensSStolerances", MSGCV_NO_QUADSENSI); return(CV_NO_QUAD); } /* Test user-supplied tolerances */ - + if (reltolQS < ZERO) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeQuadSensSStolerances", MSGCV_BAD_RELTOLQS); @@ -2398,12 +2420,15 @@ int CVodeQuadSensSStolerances(void *cvode_mem, realtype reltolQS, realtype *abst if ( !(cv_mem->cv_SabstolQSMallocDone) ) { cv_mem->cv_SabstolQS = NULL; cv_mem->cv_SabstolQS = (realtype *)malloc(cv_mem->cv_Ns*sizeof(realtype)); + cv_mem->cv_atolQSmin0 = (booleantype *)malloc(cv_mem->cv_Ns*sizeof(booleantype)); cv_mem->cv_lrw += cv_mem->cv_Ns; cv_mem->cv_SabstolQSMallocDone = SUNTRUE; } - - for (is=0; iscv_Ns; is++) + + for (is=0; iscv_Ns; is++) { cv_mem->cv_SabstolQS[is] = abstolQS[is]; + cv_mem->cv_atolQSmin0[is] = (abstolQS[is] == ZERO); + } return(CV_SUCCESS); } @@ -2412,10 +2437,11 @@ int CVodeQuadSensSVtolerances(void *cvode_mem, realtype reltolQS, N_Vector *abs { CVodeMem cv_mem; int is, retval; + realtype *atolmin; if (cvode_mem==NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", - "CVodeQuadSensSVtolerances", MSGCV_NO_MEM); + "CVodeQuadSensSVtolerances", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -2426,18 +2452,18 @@ int CVodeQuadSensSVtolerances(void *cvode_mem, realtype reltolQS, N_Vector *abs cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeQuadSensSVtolerances", MSGCV_NO_SENSI); return(CV_NO_SENS); - } + } /* Ckeck if quadrature sensitivity was initialized? */ if (cv_mem->cv_QuadSensMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", - "CVodeQuadSensSVtolerances", MSGCV_NO_QUADSENSI); + "CVodeQuadSensSVtolerances", MSGCV_NO_QUADSENSI); return(CV_NO_QUAD); } /* Test user-supplied tolerances */ - + if (reltolQS < ZERO) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeQuadSensSVtolerances", MSGCV_BAD_RELTOLQS); @@ -2446,16 +2472,26 @@ int CVodeQuadSensSVtolerances(void *cvode_mem, realtype reltolQS, N_Vector *abs if (abstolQS == NULL) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", - "CVodeSensSVtolerances", MSGCV_NULL_ABSTOLQS); + "CVodeQuadSensSVtolerances", MSGCV_NULL_ABSTOLQS); return(CV_ILL_INPUT); } - for (is=0; iscv_Ns; is++) - if (N_VMin(abstolQS[is]) < ZERO) { + if (cv_mem->cv_tempv->ops->nvmin == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSensSVtolerances", + "Missing N_VMin routine from N_Vector"); + return(CV_ILL_INPUT); + } + atolmin = (realtype *)malloc(cv_mem->cv_Ns*sizeof(realtype)); + for (is=0; iscv_Ns; is++) { + atolmin[is] = N_VMin(abstolQS[is]); + if (atolmin[is] < ZERO) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeQuadSensSVtolerances", MSGCV_BAD_ABSTOLQS); + free(atolmin); return(CV_ILL_INPUT); } + } /* Copy tolerances into memory */ @@ -2465,13 +2501,17 @@ int CVodeQuadSensSVtolerances(void *cvode_mem, realtype reltolQS, N_Vector *abs if ( !(cv_mem->cv_VabstolQSMallocDone) ) { cv_mem->cv_VabstolQS = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempvQ); + cv_mem->cv_atolQSmin0 = (booleantype *)malloc(cv_mem->cv_Ns*sizeof(booleantype)); cv_mem->cv_lrw += cv_mem->cv_Ns*cv_mem->cv_lrw1Q; cv_mem->cv_liw += cv_mem->cv_Ns*cv_mem->cv_liw1Q; cv_mem->cv_VabstolQSMallocDone = SUNTRUE; } - - for (is=0; iscv_Ns; is++) + + for (is=0; iscv_Ns; is++) { cv_mem->cv_cvals[is] = ONE; + cv_mem->cv_atolQSmin0[is] = (atolmin[is] == ZERO); + } + free(atolmin); retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, abstolQS, cv_mem->cv_VabstolQS); @@ -2487,7 +2527,7 @@ int CVodeQuadSensEEtolerances(void *cvode_mem) if (cvode_mem==NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", - "CVodeQuadSensEEtolerances", MSGCV_NO_MEM); + "CVodeQuadSensEEtolerances", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -2498,13 +2538,13 @@ int CVodeQuadSensEEtolerances(void *cvode_mem) cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeQuadSensEEtolerances", MSGCV_NO_SENSI); return(CV_NO_SENS); - } + } /* Ckeck if quadrature sensitivity was initialized? */ if (cv_mem->cv_QuadSensMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", - "CVodeQuadSensEEtolerances", MSGCV_NO_QUADSENSI); + "CVodeQuadSensEEtolerances", MSGCV_NO_QUADSENSI); return(CV_NO_QUAD); } @@ -2558,10 +2598,9 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) CVodeMem cv_mem; int i, nrt; - /* Check cvode_mem */ - if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeRootInit", - MSGCV_NO_MEM); + /* Check cvode_mem pointer */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeRootInit", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -2581,7 +2620,6 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) cv_mem->cv_lrw -= 3 * (cv_mem->cv_nrtfn); cv_mem->cv_liw -= 3 * (cv_mem->cv_nrtfn); - } /* If CVodeRootInit() was called with nrtfn == 0, then set cv_nrtfn to @@ -2600,10 +2638,10 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) if (nrt == cv_mem->cv_nrtfn) { if (g != cv_mem->cv_gfun) { if (g == NULL) { - free(cv_mem->cv_glo); cv_mem->cv_glo = NULL; - free(cv_mem->cv_ghi); cv_mem->cv_ghi = NULL; - free(cv_mem->cv_grout); cv_mem->cv_grout = NULL; - free(cv_mem->cv_iroots); cv_mem->cv_iroots = NULL; + free(cv_mem->cv_glo); cv_mem->cv_glo = NULL; + free(cv_mem->cv_ghi); cv_mem->cv_ghi = NULL; + free(cv_mem->cv_grout); cv_mem->cv_grout = NULL; + free(cv_mem->cv_iroots); cv_mem->cv_iroots = NULL; free(cv_mem->cv_rootdir); cv_mem->cv_rootdir = NULL; free(cv_mem->cv_gactive); cv_mem->cv_gactive = NULL; @@ -2615,7 +2653,7 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) return(CV_ILL_INPUT); } else { - cv_mem->cv_gfun = g; + cv_mem->cv_gfun = g; return(CV_SUCCESS); } } @@ -2639,7 +2677,7 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) MSGCV_MEM_FAIL); return(CV_MEM_FAIL); } - + cv_mem->cv_ghi = NULL; cv_mem->cv_ghi = (realtype *) malloc(nrt*sizeof(realtype)); if (cv_mem->cv_ghi == NULL) { @@ -2648,7 +2686,7 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) MSGCV_MEM_FAIL); return(CV_MEM_FAIL); } - + cv_mem->cv_grout = NULL; cv_mem->cv_grout = (realtype *) malloc(nrt*sizeof(realtype)); if (cv_mem->cv_grout == NULL) { @@ -2673,7 +2711,7 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) cv_mem->cv_rootdir = NULL; cv_mem->cv_rootdir = (int *) malloc(nrt*sizeof(int)); if (cv_mem->cv_rootdir == NULL) { - free(cv_mem->cv_glo); cv_mem->cv_glo = NULL; + free(cv_mem->cv_glo); cv_mem->cv_glo = NULL; free(cv_mem->cv_ghi); cv_mem->cv_ghi = NULL; free(cv_mem->cv_grout); cv_mem->cv_grout = NULL; free(cv_mem->cv_iroots); cv_mem->cv_iroots = NULL; @@ -2682,11 +2720,10 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) return(CV_MEM_FAIL); } - cv_mem->cv_gactive = NULL; cv_mem->cv_gactive = (booleantype *) malloc(nrt*sizeof(booleantype)); if (cv_mem->cv_gactive == NULL) { - free(cv_mem->cv_glo); cv_mem->cv_glo = NULL; + free(cv_mem->cv_glo); cv_mem->cv_glo = NULL; free(cv_mem->cv_ghi); cv_mem->cv_ghi = NULL; free(cv_mem->cv_grout); cv_mem->cv_grout = NULL; free(cv_mem->cv_iroots); cv_mem->cv_iroots = NULL; @@ -2696,7 +2733,6 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) return(CV_MEM_FAIL); } - /* Set default values for rootdir (both directions) */ for(i=0; icv_rootdir[i] = 0; @@ -2709,7 +2745,7 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) return(CV_SUCCESS); } -/* +/* * ----------------------------------------------------------------- * Main solver function * ----------------------------------------------------------------- @@ -2718,7 +2754,7 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) /* * CVode * - * This routine is the main driver of the CVODES package. + * This routine is the main driver of the CVODES package. * * It integrates over a time interval defined by the user, by calling * cvStep to do internal time steps. @@ -2732,11 +2768,11 @@ int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) * In the CV_ONE_STEP mode, it takes one internal step and returns. */ -int CVode(void *cvode_mem, realtype tout, N_Vector yout, +int CVode(void *cvode_mem, realtype tout, N_Vector yout, realtype *tret, int itask) { CVodeMem cv_mem; - long int nstloc; + long int nstloc; int retval, hflag, kflag, istate, is, ir, ier, irfndp; realtype troundoff, tout_hin, rh, nrm; booleantype inactive_roots; @@ -2749,37 +2785,32 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, /* Check if cvode_mem exists */ if (cvode_mem == NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVode", - MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVode", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; /* Check if cvode_mem was allocated */ if (cv_mem->cv_MallocDone == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_MALLOC, "CVODES", "CVode", - MSGCV_NO_MALLOC); + cvProcessError(cv_mem, CV_NO_MALLOC, "CVODES", "CVode", MSGCV_NO_MALLOC); return(CV_NO_MALLOC); } - + /* Check for yout != NULL */ if ((cv_mem->cv_y = yout) == NULL) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", - MSGCV_YOUT_NULL); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_YOUT_NULL); return(CV_ILL_INPUT); } - + /* Check for tret != NULL */ if (tret == NULL) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", - MSGCV_TRET_NULL); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_TRET_NULL); return(CV_ILL_INPUT); } /* Check for valid itask */ if ( (itask != CV_NORMAL) && (itask != CV_ONE_STEP) ) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", - MSGCV_BAD_ITASK); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_BAD_ITASK); return(CV_ILL_INPUT); } @@ -2807,15 +2838,15 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, ier = cvInitialSetup(cv_mem); if (ier!= CV_SUCCESS) return(ier); - /* - * Call f at (t0,y0), set zn[1] = y'(t0). + /* + * Call f at (t0,y0), set zn[1] = y'(t0). * If computing any quadratures, call fQ at (t0,y0), set znQ[1] = yQ'(t0) * If computing sensitivities, call fS at (t0,y0,yS0), set znS[1][is] = yS'(t0), is=1,...,Ns. * If computing quadr. sensi., call fQS at (t0,y0,yS0), set znQS[1][is] = yQS'(t0), is=1,...,Ns. */ retval = cv_mem->cv_f(cv_mem->cv_tn, cv_mem->cv_zn[0], - cv_mem->cv_zn[1], cv_mem->cv_user_data); + cv_mem->cv_zn[1], cv_mem->cv_user_data); cv_mem->cv_nfe++; if (retval < 0) { cvProcessError(cv_mem, CV_RHSFUNC_FAIL, "CVODES", "CVode", @@ -2853,7 +2884,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, cvProcessError(cv_mem, CV_SRHSFUNC_FAIL, "CVODES", "CVode", MSGCV_SRHSFUNC_FAILED, cv_mem->cv_tn); return(CV_SRHSFUNC_FAIL); - } + } if (retval > 0) { cvProcessError(cv_mem, CV_FIRST_SRHSFUNC_ERR, "CVODES", "CVode", MSGCV_SRHSFUNC_FIRST); @@ -2865,13 +2896,13 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, retval = cv_mem->cv_fQS(cv_mem->cv_Ns, cv_mem->cv_tn, cv_mem->cv_zn[0], cv_mem->cv_znS[0], cv_mem->cv_znQ[1], cv_mem->cv_znQS[1], cv_mem->cv_fQS_data, - cv_mem->cv_tempv, cv_mem->cv_tempvQ); + cv_mem->cv_tempv, cv_mem->cv_tempvQ); cv_mem->cv_nfQSe++; if (retval < 0) { cvProcessError(cv_mem, CV_QSRHSFUNC_FAIL, "CVODES", "CVode", MSGCV_QSRHSFUNC_FAILED, cv_mem->cv_tn); return(CV_QSRHSFUNC_FAIL); - } + } if (retval > 0) { cvProcessError(cv_mem, CV_FIRST_QSRHSFUNC_ERR, "CVODES", "CVode", MSGCV_QSRHSFUNC_FIRST); @@ -2890,7 +2921,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, } /* Set initial h (from H0 or cvHin). */ - + cv_mem->cv_h = cv_mem->cv_hin; if ( (cv_mem->cv_h != ZERO) && ((tout-cv_mem->cv_tn)*cv_mem->cv_h < ZERO) ) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_BAD_H0); @@ -2900,7 +2931,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, tout_hin = tout; if ( cv_mem->cv_tstopset && (tout-cv_mem->cv_tn)*(tout-cv_mem->cv_tstop) > ZERO ) - tout_hin = cv_mem->cv_tstop; + tout_hin = cv_mem->cv_tstop; hflag = cvHin(cv_mem, tout_hin); if (hflag != CV_SUCCESS) { istate = cvHandleFailure(cv_mem, hflag); @@ -2915,15 +2946,15 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, /* Check for approach to tstop */ if (cv_mem->cv_tstopset) { - if ( (cv_mem->cv_tn + cv_mem->cv_h - cv_mem->cv_tstop)*cv_mem->cv_h > ZERO ) + if ( (cv_mem->cv_tn + cv_mem->cv_h - cv_mem->cv_tstop)*cv_mem->cv_h > ZERO ) cv_mem->cv_h = (cv_mem->cv_tstop - cv_mem->cv_tn)*(ONE-FOUR*cv_mem->cv_uround); } - /* + /* * Scale zn[1] by h. * If computing any quadratures, scale znQ[1] by h. - * If computing sensitivities, scale znS[1][is] by h. - * If computing quadrature sensitivities, scale znQS[1][is] by h. + * If computing sensitivities, scale znS[1][is] by h. + * If computing quadrature sensitivities, scale znQS[1][is] by h. */ cv_mem->cv_hscale = cv_mem->cv_h; @@ -2931,7 +2962,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, cv_mem->cv_hprime = cv_mem->cv_h; N_VScale(cv_mem->cv_h, cv_mem->cv_zn[1], cv_mem->cv_zn[1]); - + if (cv_mem->cv_quadr) N_VScale(cv_mem->cv_h, cv_mem->cv_znQ[1], cv_mem->cv_znQ[1]); @@ -2952,7 +2983,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, cv_mem->cv_znQS[1], cv_mem->cv_znQS[1]); if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); } - + /* Check for zeros of root function g at and near t0. */ if (cv_mem->cv_nrtfn > 0) { @@ -2967,7 +2998,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, } - } /* end first call block */ + } /* end of first call block */ /* * ------------------------------------------------------ @@ -2984,18 +3015,18 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, if (cv_mem->cv_nst > 0) { /* Estimate an infinitesimal time interval to be used as - a roundoff for time quantities (based on current time + a roundoff for time quantities (based on current time and step size) */ troundoff = FUZZ_FACTOR * cv_mem->cv_uround * (SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_h)); - /* First check for a root in the last step taken, other than the + /* First, check for a root in the last step taken, other than the last root found, if any. If itask = CV_ONE_STEP and y(tn) was not returned because of an intervening root, return y(tn) now. */ if (cv_mem->cv_nrtfn > 0) { - + irfndp = cv_mem->cv_irfnd; - + retval = cvRcheck2(cv_mem); if (retval == CLOSERT) { @@ -3010,7 +3041,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, cv_mem->cv_tretlast = *tret = cv_mem->cv_tlo; return(CV_ROOT_RETURN); } - + /* If tn is distinct from tretlast (within roundoff), check remaining interval for roots */ if ( SUNRabs(cv_mem->cv_tn - cv_mem->cv_tretlast) > troundoff ) { @@ -3029,15 +3060,15 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, cv_mem->cv_tretlast = *tret = cv_mem->cv_tlo; return(CV_ROOT_RETURN); } else if (retval == CV_RTFUNC_FAIL) { /* g failed */ - cvProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODES", "cvRcheck3", + cvProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODES", "cvRcheck3", MSGCV_RTFUNC_FAILED, cv_mem->cv_tlo); return(CV_RTFUNC_FAIL); } } - + } /* end of root stop check */ - + /* In CV_NORMAL mode, test if tout was reached */ if ( (itask == CV_NORMAL) && ((cv_mem->cv_tn-tout)*cv_mem->cv_h >= ZERO) ) { cv_mem->cv_tretlast = *tret = tout; @@ -3049,7 +3080,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, } return(CV_SUCCESS); } - + /* In CV_ONE_STEP mode, test if tn was returned */ if ( itask == CV_ONE_STEP && SUNRabs(cv_mem->cv_tn - cv_mem->cv_tretlast) > troundoff ) { @@ -3057,10 +3088,10 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, N_VScale(ONE, cv_mem->cv_zn[0], yout); return(CV_SUCCESS); } - + /* Test for tn at tstop or near tstop */ if ( cv_mem->cv_tstopset ) { - + if ( SUNRabs(cv_mem->cv_tn - cv_mem->cv_tstop) <= troundoff ) { ier = CVodeGetDky(cv_mem, cv_mem->cv_tstop, 0, yout); if (ier != CV_SUCCESS) { @@ -3072,17 +3103,17 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, cv_mem->cv_tstopset = SUNFALSE; return(CV_TSTOP_RETURN); } - + /* If next step would overtake tstop, adjust stepsize */ if ( (cv_mem->cv_tn + cv_mem->cv_hprime - cv_mem->cv_tstop)*cv_mem->cv_h > ZERO ) { cv_mem->cv_hprime = (cv_mem->cv_tstop - cv_mem->cv_tn)*(ONE-FOUR*cv_mem->cv_uround); cv_mem->cv_eta = cv_mem->cv_hprime / cv_mem->cv_h; } - + } - - } /* end stopping tests block at nst>0 */ - + + } /* end stopping tests block */ + /* * -------------------------------------------------- * 4. Looping point for internal steps @@ -3090,22 +3121,22 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, * 4.1. check for errors (too many steps, too much * accuracy requested, step size too small) * 4.2. take a new step (call cvStep) - * 4.3. stop on error + * 4.3. stop on error * 4.4. perform stop tests: * - check for root in last step * - check if tout was passed * - check if close to tstop * - check if in ONE_STEP mode (must return) * -------------------------------------------------- - */ - + */ + nstloc = 0; for(;;) { - + cv_mem->cv_next_h = cv_mem->cv_h; cv_mem->cv_next_q = cv_mem->cv_q; - - /* Reset and check ewt, ewtQ, ewtS */ + + /* Reset and check ewt, ewtQ, ewtS */ if (cv_mem->cv_nst > 0) { ier = cv_mem->cv_efun(cv_mem->cv_zn[0], cv_mem->cv_ewt, cv_mem->cv_e_data); @@ -3116,6 +3147,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, else cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_EWT_NOW_BAD, cv_mem->cv_tn); + istate = CV_ILL_INPUT; cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; N_VScale(ONE, cv_mem->cv_zn[0], yout); @@ -3173,7 +3205,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, /* Check for too much accuracy requested */ nrm = N_VWrmsNorm(cv_mem->cv_zn[0], cv_mem->cv_ewt); if (cv_mem->cv_quadr && cv_mem->cv_errconQ) { - nrm = cvQuadUpdateNorm(cv_mem, nrm, cv_mem->cv_znQ[0], cv_mem->cv_ewtQ); + nrm = cvQuadUpdateNorm(cv_mem, nrm, cv_mem->cv_znQ[0], cv_mem->cv_ewtQ); } if (cv_mem->cv_sensi && cv_mem->cv_errconS) { nrm = cvSensUpdateNorm(cv_mem, nrm, cv_mem->cv_znS[0], cv_mem->cv_ewtS); @@ -3193,14 +3225,14 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, } else { cv_mem->cv_tolsf = ONE; } - + /* Check for h below roundoff level in tn */ if (cv_mem->cv_tn + cv_mem->cv_h == cv_mem->cv_tn) { cv_mem->cv_nhnil++; - if (cv_mem->cv_nhnil <= cv_mem->cv_mxhnil) + if (cv_mem->cv_nhnil <= cv_mem->cv_mxhnil) cvProcessError(cv_mem, CV_WARNING, "CVODES", "CVode", MSGCV_HNIL, cv_mem->cv_tn, cv_mem->cv_h); - if (cv_mem->cv_nhnil == cv_mem->cv_mxhnil) + if (cv_mem->cv_nhnil == cv_mem->cv_mxhnil) cvProcessError(cv_mem, CV_WARNING, "CVODES", "CVode", MSGCV_HNIL_DONE); } @@ -3214,7 +3246,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, N_VScale(ONE, cv_mem->cv_zn[0], yout); break; } - + nstloc++; /* If tstop is set and was reached, reset tn = tstop */ @@ -3225,11 +3257,11 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, cv_mem->cv_tn = cv_mem->cv_tstop; } - /* Check for root in last step taken. */ + /* Check for root in last step taken. */ if (cv_mem->cv_nrtfn > 0) { - + retval = cvRcheck3(cv_mem); - + if (retval == RTFOUND) { /* A new root was found */ cv_mem->cv_irfnd = 1; istate = CV_ROOT_RETURN; @@ -3249,7 +3281,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, if (cv_mem->cv_nst==1) { inactive_roots = SUNFALSE; - for (ir=0; ircv_nrtfn; ir++) { + for (ir=0; ircv_nrtfn; ir++) { if (!cv_mem->cv_gactive[ir]) { inactive_roots = SUNTRUE; break; @@ -3273,7 +3305,7 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, break; } - /* Check if tn is at tstop, or about to pass tstop */ + /* Check if tn is at tstop or near tstop */ if ( cv_mem->cv_tstopset ) { troundoff = FUZZ_FACTOR * cv_mem->cv_uround * @@ -3304,9 +3336,9 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, } } /* end looping for internal steps */ - + /* Load optional output */ - if (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_STAGGERED1)) { + if (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_STAGGERED1)) { cv_mem->cv_nniS = 0; cv_mem->cv_ncfnS = 0; for (is=0; iscv_Ns; is++) { @@ -3314,12 +3346,11 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, cv_mem->cv_ncfnS += cv_mem->cv_ncfnS1[is]; } } - - return(istate); + return(istate); } -/* +/* * ----------------------------------------------------------------- * Interpolated output and extraction functions * ----------------------------------------------------------------- @@ -3331,9 +3362,9 @@ int CVode(void *cvode_mem, realtype tout, N_Vector yout, * This routine computes the k-th derivative of the interpolating * polynomial at the time t and stores the result in the vector dky. * The formula is: - * q - * dky = SUM c(j,k) * (t - tn)^(j-k) * h^(-j) * zn[j] , - * j=k + * q + * dky = SUM c(j,k) * (t - tn)^(j-k) * h^(-j) * zn[j] , + * j=k * where c(j,k) = j*(j-1)*...*(j-k+1), q is the current order, and * zn[j] is the j-th column of the Nordsieck history array. * @@ -3347,9 +3378,9 @@ int CVodeGetDky(void *cvode_mem, realtype t, int k, N_Vector dky) realtype tfuzz, tp, tn1; int i, j, nvec, ier; CVodeMem cv_mem; - + /* Check all inputs for legality */ - + if (cvode_mem == NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetDky", MSGCV_NO_MEM); return(CV_MEM_NULL); @@ -3365,7 +3396,7 @@ int CVodeGetDky(void *cvode_mem, realtype t, int k, N_Vector dky) cvProcessError(cv_mem, CV_BAD_K, "CVODES", "CVodeGetDky", MSGCV_BAD_K); return(CV_BAD_K); } - + /* Allow for some slack */ tfuzz = FUZZ_FACTOR * cv_mem->cv_uround * (SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_hu)); @@ -3398,17 +3429,16 @@ int CVodeGetDky(void *cvode_mem, realtype t, int k, N_Vector dky) r = SUNRpowerI(cv_mem->cv_h, -k); N_VScale(r, dky, dky); return(CV_SUCCESS); - } -/* +/* * CVodeGetQuad * * This routine extracts quadrature solution into yQout at the * time which CVode returned the solution. * This is just a wrapper that calls CVodeGetQuadDky with k=0. */ - + int CVodeGetQuad(void *cvode_mem, realtype *tret, N_Vector yQout) { CVodeMem cv_mem; @@ -3418,10 +3448,10 @@ int CVodeGetQuad(void *cvode_mem, realtype *tret, N_Vector yQout) cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuad", MSGCV_NO_MEM); return(CV_MEM_NULL); } - cv_mem = (CVodeMem) cvode_mem; + cv_mem = (CVodeMem) cvode_mem; *tret = cv_mem->cv_tretlast; - + flag = CVodeGetQuadDky(cvode_mem,cv_mem->cv_tretlast,0,yQout); return(flag); @@ -3431,30 +3461,30 @@ int CVodeGetQuad(void *cvode_mem, realtype *tret, N_Vector yQout) * CVodeGetQuadDky * * CVodeQuadDky computes the kth derivative of the yQ function at - * time t, where tn-hu <= t <= tn, tn denotes the current - * internal time reached, and hu is the last internal step size - * successfully used by the solver. The user may request - * k=0, 1, ..., qu, where qu is the current order. - * The derivative vector is returned in dky. This vector - * must be allocated by the caller. It is only legal to call this + * time t, where tn-hu <= t <= tn, tn denotes the current + * internal time reached, and hu is the last internal step size + * successfully used by the solver. The user may request + * k=0, 1, ..., qu, where qu is the current order. + * The derivative vector is returned in dky. This vector + * must be allocated by the caller. It is only legal to call this * function after a successful return from CVode with quadrature * computation enabled. */ int CVodeGetQuadDky(void *cvode_mem, realtype t, int k, N_Vector dkyQ) -{ +{ realtype s, r; realtype tfuzz, tp, tn1; int i, j, nvec, ier; CVodeMem cv_mem; - + /* Check all inputs for legality */ - + if (cvode_mem == NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadDky", MSGCV_NO_MEM); return(CV_MEM_NULL); } - cv_mem = (CVodeMem) cvode_mem; + cv_mem = (CVodeMem) cvode_mem; if(cv_mem->cv_quadr != SUNTRUE) { cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadDky", MSGCV_NO_QUAD); @@ -3465,12 +3495,12 @@ int CVodeGetQuadDky(void *cvode_mem, realtype t, int k, N_Vector dkyQ) cvProcessError(cv_mem, CV_BAD_DKY, "CVODES", "CVodeGetQuadDky", MSGCV_NULL_DKY); return(CV_BAD_DKY); } - + if ((k < 0) || (k > cv_mem->cv_q)) { cvProcessError(cv_mem, CV_BAD_K, "CVODES", "CVodeGetQuadDky", MSGCV_BAD_K); return(CV_BAD_K); } - + /* Allow for some slack */ tfuzz = FUZZ_FACTOR * cv_mem->cv_uround * (SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_hu)); @@ -3481,7 +3511,7 @@ int CVodeGetQuadDky(void *cvode_mem, realtype t, int k, N_Vector dkyQ) cvProcessError(cv_mem, CV_BAD_T, "CVODES", "CVodeGetQuadDky", MSGCV_BAD_T); return(CV_BAD_T); } - + /* Sum the differentiated interpolating polynomial */ nvec = 0; @@ -3502,17 +3532,17 @@ int CVodeGetQuadDky(void *cvode_mem, realtype t, int k, N_Vector dkyQ) r = SUNRpowerI(cv_mem->cv_h, -k); N_VScale(r, dkyQ, dkyQ); return(CV_SUCCESS); - + } -/* +/* * CVodeGetSens * * This routine extracts sensitivity solution into ySout at the * time at which CVode returned the solution. * This is just a wrapper that calls CVodeSensDky with k=0. */ - + int CVodeGetSens(void *cvode_mem, realtype *tret, N_Vector *ySout) { CVodeMem cv_mem; @@ -3522,7 +3552,7 @@ int CVodeGetSens(void *cvode_mem, realtype *tret, N_Vector *ySout) cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSens", MSGCV_NO_MEM); return(CV_MEM_NULL); } - cv_mem = (CVodeMem) cvode_mem; + cv_mem = (CVodeMem) cvode_mem; *tret = cv_mem->cv_tretlast; @@ -3530,15 +3560,15 @@ int CVodeGetSens(void *cvode_mem, realtype *tret, N_Vector *ySout) return(flag); } - -/* + +/* * CVodeGetSens1 * * This routine extracts the is-th sensitivity solution into ySout * at the time at which CVode returned the solution. * This is just a wrapper that calls CVodeSensDky1 with k=0. */ - + int CVodeGetSens1(void *cvode_mem, realtype *tret, int is, N_Vector ySout) { CVodeMem cv_mem; @@ -3548,7 +3578,7 @@ int CVodeGetSens1(void *cvode_mem, realtype *tret, int is, N_Vector ySout) cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSens1", MSGCV_NO_MEM); return(CV_MEM_NULL); } - cv_mem = (CVodeMem) cvode_mem; + cv_mem = (CVodeMem) cvode_mem; *tret = cv_mem->cv_tretlast; @@ -3556,13 +3586,13 @@ int CVodeGetSens1(void *cvode_mem, realtype *tret, int is, N_Vector ySout) return(flag); } - + /* * CVodeGetSensDky * * If the user calls directly CVodeSensDky then s must be allocated - * prior to this call. When CVodeSensDky is called by - * CVodeGetSens, only ier=CV_SUCCESS, ier=CV_NO_SENS, or + * prior to this call. When CVodeSensDky is called by + * CVodeGetSens, only ier=CV_SUCCESS, ier=CV_NO_SENS, or * ier=CV_BAD_T are possible. */ @@ -3571,57 +3601,57 @@ int CVodeGetSensDky(void *cvode_mem, realtype t, int k, N_Vector *dkyS) int ier=CV_SUCCESS; int is; CVodeMem cv_mem; - + if (cvode_mem == NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensDky", MSGCV_NO_MEM); return(CV_MEM_NULL); } - cv_mem = (CVodeMem) cvode_mem; - + cv_mem = (CVodeMem) cvode_mem; + if (dkyS == NULL) { cvProcessError(cv_mem, CV_BAD_DKY, "CVODES", "CVodeGetSensDky", MSGCV_NULL_DKYA); return(CV_BAD_DKY); } - + for (is=0; iscv_Ns; is++) { ier = CVodeGetSensDky1(cvode_mem,t,k,is,dkyS[is]); if (ier!=CV_SUCCESS) break; } - + return(ier); } - + /* * CVodeGetSensDky1 * * CVodeSensDky1 computes the kth derivative of the yS[is] function at - * time t, where tn-hu <= t <= tn, tn denotes the current - * internal time reached, and hu is the last internal step size - * successfully used by the solver. The user may request + * time t, where tn-hu <= t <= tn, tn denotes the current + * internal time reached, and hu is the last internal step size + * successfully used by the solver. The user may request * is=0, 1, ..., Ns-1 and k=0, 1, ..., qu, where qu is the current - * order. The derivative vector is returned in dky. This vector - * must be allocated by the caller. It is only legal to call this - * function after a successful return from CVode with sensitivity + * order. The derivative vector is returned in dky. This vector + * must be allocated by the caller. It is only legal to call this + * function after a successful return from CVode with sensitivity * computation enabled. */ int CVodeGetSensDky1(void *cvode_mem, realtype t, int k, int is, N_Vector dkyS) -{ +{ realtype s, r; realtype tfuzz, tp, tn1; int i, j, nvec, ier; CVodeMem cv_mem; - + /* Check all inputs for legality */ - + if (cvode_mem == NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensDky1", MSGCV_NO_MEM); return(CV_MEM_NULL); } - cv_mem = (CVodeMem) cvode_mem; - + cv_mem = (CVodeMem) cvode_mem; + if(cv_mem->cv_sensi != SUNTRUE) { cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetSensDky1", MSGCV_NO_SENSI); @@ -3633,19 +3663,19 @@ int CVodeGetSensDky1(void *cvode_mem, realtype t, int k, int is, N_Vector dkyS) MSGCV_NULL_DKY); return(CV_BAD_DKY); } - + if ((k < 0) || (k > cv_mem->cv_q)) { cvProcessError(cv_mem, CV_BAD_K, "CVODES", "CVodeGetSensDky1", MSGCV_BAD_K); return(CV_BAD_K); } - + if ((is < 0) || (is > cv_mem->cv_Ns-1)) { cvProcessError(cv_mem, CV_BAD_IS, "CVODES", "CVodeGetSensDky1", MSGCV_BAD_IS); return(CV_BAD_IS); } - + /* Allow for some slack */ tfuzz = FUZZ_FACTOR * cv_mem->cv_uround * (SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_hu)); @@ -3657,7 +3687,7 @@ int CVodeGetSensDky1(void *cvode_mem, realtype t, int k, int is, N_Vector dkyS) MSGCV_BAD_T); return(CV_BAD_T); } - + /* Sum the differentiated interpolating polynomial */ nvec = 0; @@ -3678,10 +3708,10 @@ int CVodeGetSensDky1(void *cvode_mem, realtype t, int k, int is, N_Vector dkyS) r = SUNRpowerI(cv_mem->cv_h, -k); N_VScale(r, dkyS, dkyS); return(CV_SUCCESS); - + } -/* +/* * CVodeGetQuadSens and CVodeGetQuadSens1 * * Extraction functions for all or only one of the quadrature sensitivity @@ -3698,7 +3728,7 @@ int CVodeGetQuadSens(void *cvode_mem, realtype *tret, N_Vector *yQSout) MSGCV_NO_MEM); return(CV_MEM_NULL); } - cv_mem = (CVodeMem) cvode_mem; + cv_mem = (CVodeMem) cvode_mem; *tret = cv_mem->cv_tretlast; @@ -3717,7 +3747,7 @@ int CVodeGetQuadSens1(void *cvode_mem, realtype *tret, int is, N_Vector yQSout) MSGCV_NO_MEM); return(CV_MEM_NULL); } - cv_mem = (CVodeMem) cvode_mem; + cv_mem = (CVodeMem) cvode_mem; *tret = cv_mem->cv_tretlast; @@ -3726,7 +3756,7 @@ int CVodeGetQuadSens1(void *cvode_mem, realtype *tret, int is, N_Vector yQSout) return(flag); } -/* +/* * CVodeGetQuadSensDky and CVodeGetQuadSensDky1 * * Dense output functions for all or only one of the quadrature sensitivity @@ -3738,25 +3768,25 @@ int CVodeGetQuadSensDky(void *cvode_mem, realtype t, int k, N_Vector *dkyQS_all) int ier=CV_SUCCESS; int is; CVodeMem cv_mem; - + if (cvode_mem == NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadSensDky", MSGCV_NO_MEM); return(CV_MEM_NULL); } - cv_mem = (CVodeMem) cvode_mem; - + cv_mem = (CVodeMem) cvode_mem; + if (dkyQS_all == NULL) { cvProcessError(cv_mem, CV_BAD_DKY, "CVODES", "CVodeGetSensDky", MSGCV_NULL_DKYA); return(CV_BAD_DKY); } - + for (is=0; iscv_Ns; is++) { ier = CVodeGetQuadSensDky1(cvode_mem,t,k,is,dkyQS_all[is]); if (ier!=CV_SUCCESS) break; } - + return(ier); } @@ -3766,16 +3796,16 @@ int CVodeGetQuadSensDky1(void *cvode_mem, realtype t, int k, int is, N_Vector dk realtype tfuzz, tp, tn1; int i, j, nvec, ier; CVodeMem cv_mem; - + /* Check all inputs for legality */ - + if (cvode_mem == NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadSensDky1", MSGCV_NO_MEM); return(CV_MEM_NULL); } - cv_mem = (CVodeMem) cvode_mem; - + cv_mem = (CVodeMem) cvode_mem; + if(cv_mem->cv_quadr_sensi != SUNTRUE) { cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeGetQuadSensDky1", MSGCV_NO_QUADSENSI); @@ -3787,19 +3817,19 @@ int CVodeGetQuadSensDky1(void *cvode_mem, realtype t, int k, int is, N_Vector dk MSGCV_NULL_DKY); return(CV_BAD_DKY); } - + if ((k < 0) || (k > cv_mem->cv_q)) { cvProcessError(cv_mem, CV_BAD_K, "CVODES", "CVodeGetQuadSensDky1", MSGCV_BAD_K); return(CV_BAD_K); } - + if ((is < 0) || (is > cv_mem->cv_Ns-1)) { cvProcessError(cv_mem, CV_BAD_IS, "CVODES", "CVodeGetQuadSensDky1", MSGCV_BAD_IS); return(CV_BAD_IS); } - + /* Allow for some slack */ tfuzz = FUZZ_FACTOR * cv_mem->cv_uround * (SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_hu)); @@ -3811,10 +3841,10 @@ int CVodeGetQuadSensDky1(void *cvode_mem, realtype t, int k, int is, N_Vector dk MSGCV_BAD_T); return(CV_BAD_T); } - + /* Sum the differentiated interpolating polynomial */ nvec = 0; - + s = (t - cv_mem->cv_tn) / cv_mem->cv_h; for (j=cv_mem->cv_q; j >= k; j--) { cv_mem->cv_cvals[nvec] = ONE; @@ -3835,7 +3865,7 @@ int CVodeGetQuadSensDky1(void *cvode_mem, realtype t, int k, int is, N_Vector dk } -/* +/* * ----------------------------------------------------------------- * Deallocation functions * ----------------------------------------------------------------- @@ -3847,7 +3877,7 @@ int CVodeGetQuadSensDky1(void *cvode_mem, realtype t, int k, int is, N_Vector dk * This routine frees the problem memory allocated by CVodeInit. * Such memory includes all the vectors allocated by cvAllocVectors, * and the memory lmem for the linear solver (deallocated by a call - * to lfree), as well as (if Ns!=0) all memory allocated for + * to lfree), as well as (if Ns!=0) all memory allocated for * sensitivity computations by CVodeSensInit. */ @@ -3858,9 +3888,10 @@ void CVodeFree(void **cvode_mem) if (*cvode_mem == NULL) return; cv_mem = (CVodeMem) (*cvode_mem); - + cvFreeVectors(cv_mem); + /* if CVODE created the nonlinear solver object then free it */ if (cv_mem->ownNLS) { SUNNonlinSolFree(cv_mem->NLS); cv_mem->ownNLS = SUNFALSE; @@ -3878,9 +3909,9 @@ void CVodeFree(void **cvode_mem) if (cv_mem->cv_lfree != NULL) cv_mem->cv_lfree(cv_mem); if (cv_mem->cv_nrtfn > 0) { - free(cv_mem->cv_glo); cv_mem->cv_glo = NULL; - free(cv_mem->cv_ghi); cv_mem->cv_ghi = NULL; - free(cv_mem->cv_grout); cv_mem->cv_grout = NULL; + free(cv_mem->cv_glo); cv_mem->cv_glo = NULL; + free(cv_mem->cv_ghi); cv_mem->cv_ghi = NULL; + free(cv_mem->cv_grout); cv_mem->cv_grout = NULL; free(cv_mem->cv_iroots); cv_mem->cv_iroots = NULL; free(cv_mem->cv_rootdir); cv_mem->cv_rootdir = NULL; free(cv_mem->cv_gactive); cv_mem->cv_gactive = NULL; @@ -3899,13 +3930,13 @@ void CVodeFree(void **cvode_mem) * * CVodeQuadFree frees the problem memory in cvode_mem allocated * for quadrature integration. Its only argument is the pointer - * cvode_mem returned by CVodeCreate. + * cvode_mem returned by CVodeCreate. */ void CVodeQuadFree(void *cvode_mem) { CVodeMem cv_mem; - + if (cvode_mem == NULL) return; cv_mem = (CVodeMem) cvode_mem; @@ -3921,21 +3952,21 @@ void CVodeQuadFree(void *cvode_mem) * * CVodeSensFree frees the problem memory in cvode_mem allocated * for sensitivity analysis. Its only argument is the pointer - * cvode_mem returned by CVodeCreate. + * cvode_mem returned by CVodeCreate. */ void CVodeSensFree(void *cvode_mem) { CVodeMem cv_mem; - + if (cvode_mem == NULL) return; cv_mem = (CVodeMem) cvode_mem; if(cv_mem->cv_SensMallocDone) { if (cv_mem->cv_stgr1alloc) { - free(cv_mem->cv_ncfS1); cv_mem->cv_ncfS1 = NULL; + free(cv_mem->cv_ncfS1); cv_mem->cv_ncfS1 = NULL; free(cv_mem->cv_ncfnS1); cv_mem->cv_ncfnS1 = NULL; - free(cv_mem->cv_nniS1); cv_mem->cv_nniS1 = NULL; + free(cv_mem->cv_nniS1); cv_mem->cv_nniS1 = NULL; cv_mem->cv_stgr1alloc = SUNFALSE; } cvSensFreeVectors(cv_mem); @@ -3945,15 +3976,15 @@ void CVodeSensFree(void *cvode_mem) /* free any vector wrappers */ if (cv_mem->simMallocDone) { - N_VDestroy(cv_mem->ycor0Sim); cv_mem->ycor0Sim = NULL; - N_VDestroy(cv_mem->ycorSim); cv_mem->ycorSim = NULL; - N_VDestroy(cv_mem->ewtSim); cv_mem->ewtSim = NULL; + N_VDestroy(cv_mem->zn0Sim); cv_mem->zn0Sim = NULL; + N_VDestroy(cv_mem->ycorSim); cv_mem->ycorSim = NULL; + N_VDestroy(cv_mem->ewtSim); cv_mem->ewtSim = NULL; cv_mem->simMallocDone = SUNFALSE; } if (cv_mem->stgMallocDone) { - N_VDestroy(cv_mem->ycor0Stg); cv_mem->ycor0Stg = NULL; - N_VDestroy(cv_mem->ycorStg); cv_mem->ycorStg = NULL; - N_VDestroy(cv_mem->ewtStg); cv_mem->ewtStg = NULL; + N_VDestroy(cv_mem->zn0Stg); cv_mem->zn0Stg = NULL; + N_VDestroy(cv_mem->ycorStg); cv_mem->ycorStg = NULL; + N_VDestroy(cv_mem->ewtStg); cv_mem->ewtStg = NULL; cv_mem->stgMallocDone = SUNFALSE; } @@ -3974,6 +4005,11 @@ void CVodeSensFree(void *cvode_mem) cv_mem->NLSstg1 = NULL; } + /* free min atol array if necessary */ + if (cv_mem->cv_atolSmin0) { + free(cv_mem->cv_atolSmin0); + cv_mem->cv_atolSmin0 = NULL; + } } /* @@ -3981,13 +4017,13 @@ void CVodeSensFree(void *cvode_mem) * * CVodeQuadSensFree frees the problem memory in cvode_mem allocated * for quadrature sensitivity analysis. Its only argument is the pointer - * cvode_mem returned by CVodeCreate. + * cvode_mem returned by CVodeCreate. */ void CVodeQuadSensFree(void *cvode_mem) { CVodeMem cv_mem; - + if (cvode_mem == NULL) return; cv_mem = (CVodeMem) cvode_mem; @@ -3996,12 +4032,18 @@ void CVodeQuadSensFree(void *cvode_mem) cv_mem->cv_QuadSensMallocDone = SUNFALSE; cv_mem->cv_quadr_sensi = SUNFALSE; } + + /* free min atol array if necessary */ + if (cv_mem->cv_atolQSmin0) { + free(cv_mem->cv_atolQSmin0); + cv_mem->cv_atolQSmin0 = NULL; + } } -/* +/* * ================================================================= - * PRIVATE FUNCTIONS + * Private Functions Implementation * ================================================================= */ @@ -4024,14 +4066,13 @@ static booleantype cvCheckNvector(N_Vector tmpl) (tmpl->ops->nvinv == NULL) || (tmpl->ops->nvaddconst == NULL) || (tmpl->ops->nvmaxnorm == NULL) || - (tmpl->ops->nvwrmsnorm == NULL) || - (tmpl->ops->nvmin == NULL)) + (tmpl->ops->nvwrmsnorm == NULL)) return(SUNFALSE); else return(SUNTRUE); } -/* +/* * ----------------------------------------------------------------- * Memory allocation/deallocation * ----------------------------------------------------------------- @@ -4042,7 +4083,7 @@ static booleantype cvCheckNvector(N_Vector tmpl) * * This routine allocates the CVODES vectors ewt, acor, tempv, ftemp, and * zn[0], ..., zn[maxord]. - * If all memory allocations are successful, cvAllocVectors returns SUNTRUE. + * If all memory allocations are successful, cvAllocVectors returns SUNTRUE. * Otherwise all allocated memory is freed and cvAllocVectors returns SUNFALSE. * This routine also sets the optional outputs lrw and liw, which are * (respectively) the lengths of the real and integer work spaces @@ -4054,7 +4095,7 @@ static booleantype cvAllocVectors(CVodeMem cv_mem, N_Vector tmpl) int i, j; /* Allocate ewt, acor, tempv, ftemp */ - + cv_mem->cv_ewt = N_VClone(tmpl); if (cv_mem->cv_ewt == NULL) return(SUNFALSE); @@ -4136,16 +4177,16 @@ static booleantype cvAllocVectors(CVodeMem cv_mem, N_Vector tmpl) return(SUNTRUE); } -/* +/* * cvFreeVectors * - * This routine frees the CVODES vectors allocated in cvAllocVectors. + * This routine frees the vectors allocated in cvAllocVectors. */ static void cvFreeVectors(CVodeMem cv_mem) { int j, maxord; - + maxord = cv_mem->cv_qmax_alloc; N_VDestroy(cv_mem->cv_ewt); @@ -4176,15 +4217,15 @@ static void cvFreeVectors(CVodeMem cv_mem) /* * CVodeQuadAllocVectors * - * NOTE: Space for ewtQ is allocated even when errconQ=SUNFALSE, + * NOTE: Space for ewtQ is allocated even when errconQ=SUNFALSE, * although in this case, ewtQ is never used. The reason for this * decision is to allow the user to re-initialize the quadrature * computation with errconQ=SUNTRUE, after an initialization with - * errconQ=SUNFALSE, without new memory allocation within + * errconQ=SUNFALSE, without new memory allocation within * CVodeQuadReInit. */ -static booleantype cvQuadAllocVectors(CVodeMem cv_mem, N_Vector tmpl) +static booleantype cvQuadAllocVectors(CVodeMem cv_mem, N_Vector tmpl) { int i, j; @@ -4193,7 +4234,7 @@ static booleantype cvQuadAllocVectors(CVodeMem cv_mem, N_Vector tmpl) if (cv_mem->cv_ewtQ == NULL) { return(SUNFALSE); } - + /* Allocate acorQ */ cv_mem->cv_acorQ = N_VClone(tmpl); if (cv_mem->cv_acorQ == NULL) { @@ -4251,14 +4292,14 @@ static booleantype cvQuadAllocVectors(CVodeMem cv_mem, N_Vector tmpl) static void cvQuadFreeVectors(CVodeMem cv_mem) { int j, maxord; - + maxord = cv_mem->cv_qmax_allocQ; N_VDestroy(cv_mem->cv_ewtQ); N_VDestroy(cv_mem->cv_acorQ); N_VDestroy(cv_mem->cv_yQ); N_VDestroy(cv_mem->cv_tempvQ); - + for (j=0; j<=maxord; j++) N_VDestroy(cv_mem->cv_znQ[j]); cv_mem->cv_lrw -= (maxord + 5)*cv_mem->cv_lrw1Q; @@ -4276,14 +4317,14 @@ static void cvQuadFreeVectors(CVodeMem cv_mem) /* * cvSensAllocVectors * - * Create (through duplication) N_Vectors used for sensitivity analysis, + * Create (through duplication) N_Vectors used for sensitivity analysis, * using the N_Vector 'tmpl' as a template. */ -static booleantype cvSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) +static booleantype cvSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) { int i, j; - + /* Allocate yS */ cv_mem->cv_yS = N_VCloneVectorArray(cv_mem->cv_Ns, tmpl); if (cv_mem->cv_yS == NULL) { @@ -4296,7 +4337,7 @@ static booleantype cvSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) N_VDestroyVectorArray(cv_mem->cv_yS, cv_mem->cv_Ns); return(SUNFALSE); } - + /* Allocate acorS */ cv_mem->cv_acorS = N_VCloneVectorArray(cv_mem->cv_Ns, tmpl); if (cv_mem->cv_acorS == NULL) { @@ -4304,7 +4345,7 @@ static booleantype cvSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) N_VDestroyVectorArray(cv_mem->cv_ewtS, cv_mem->cv_Ns); return(SUNFALSE); } - + /* Allocate tempvS */ cv_mem->cv_tempvS = N_VCloneVectorArray(cv_mem->cv_Ns, tmpl); if (cv_mem->cv_tempvS == NULL) { @@ -4313,7 +4354,7 @@ static booleantype cvSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) N_VDestroyVectorArray(cv_mem->cv_acorS, cv_mem->cv_Ns); return(SUNFALSE); } - + /* Allocate ftempS */ cv_mem->cv_ftempS = N_VCloneVectorArray(cv_mem->cv_Ns, tmpl); if (cv_mem->cv_ftempS == NULL) { @@ -4323,7 +4364,7 @@ static booleantype cvSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) N_VDestroyVectorArray(cv_mem->cv_tempvS, cv_mem->cv_Ns); return(SUNFALSE); } - + /* Allocate znS */ for (j=0; j<=cv_mem->cv_qmax; j++) { cv_mem->cv_znS[j] = N_VCloneVectorArray(cv_mem->cv_Ns, tmpl); @@ -4338,7 +4379,7 @@ static booleantype cvSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) return(SUNFALSE); } } - + /* Allocate space for pbar and plist */ cv_mem->cv_pbar = NULL; cv_mem->cv_pbar = (realtype *)malloc(cv_mem->cv_Ns*sizeof(realtype)); @@ -4370,7 +4411,7 @@ static booleantype cvSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) /* Update solver workspace lengths */ cv_mem->cv_lrw += (cv_mem->cv_qmax + 6)*cv_mem->cv_Ns*cv_mem->cv_lrw1 + cv_mem->cv_Ns; cv_mem->cv_liw += (cv_mem->cv_qmax + 6)*cv_mem->cv_Ns*cv_mem->cv_liw1 + cv_mem->cv_Ns; - + /* Store the value of qmax used here */ cv_mem->cv_qmax_allocS = cv_mem->cv_qmax; @@ -4383,10 +4424,10 @@ static booleantype cvSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) * This routine frees the CVODES vectors allocated in cvSensAllocVectors. */ -static void cvSensFreeVectors(CVodeMem cv_mem) +static void cvSensFreeVectors(CVodeMem cv_mem) { int j, maxord; - + maxord = cv_mem->cv_qmax_allocS; N_VDestroyVectorArray(cv_mem->cv_yS, cv_mem->cv_Ns); @@ -4394,9 +4435,9 @@ static void cvSensFreeVectors(CVodeMem cv_mem) N_VDestroyVectorArray(cv_mem->cv_acorS, cv_mem->cv_Ns); N_VDestroyVectorArray(cv_mem->cv_tempvS, cv_mem->cv_Ns); N_VDestroyVectorArray(cv_mem->cv_ftempS, cv_mem->cv_Ns); - + for (j=0; j<=maxord; j++) - N_VDestroyVectorArray(cv_mem->cv_znS[j], cv_mem->cv_Ns); + N_VDestroyVectorArray(cv_mem->cv_znS[j], cv_mem->cv_Ns); free(cv_mem->cv_pbar); cv_mem->cv_pbar = NULL; free(cv_mem->cv_plist); cv_mem->cv_plist = NULL; @@ -4420,11 +4461,11 @@ static void cvSensFreeVectors(CVodeMem cv_mem) /* * cvQuadSensAllocVectors * - * Create (through duplication) N_Vectors used for quadrature sensitivity analysis, + * Create (through duplication) N_Vectors used for quadrature sensitivity analysis, * using the N_Vector 'tmpl' as a template. */ -static booleantype cvQuadSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) +static booleantype cvQuadSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) { int i, j; @@ -4457,7 +4498,7 @@ static booleantype cvQuadSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) N_VDestroyVectorArray(cv_mem->cv_ewtQS, cv_mem->cv_Ns); return(SUNFALSE); } - + /* Allocate tempvQS */ cv_mem->cv_tempvQS = N_VCloneVectorArray(cv_mem->cv_Ns, tmpl); if (cv_mem->cv_tempvQS == NULL) { @@ -4502,7 +4543,7 @@ static booleantype cvQuadSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) static void cvQuadSensFreeVectors(CVodeMem cv_mem) { int j, maxord; - + maxord = cv_mem->cv_qmax_allocQS; N_VDestroy(cv_mem->cv_ftempQ); @@ -4511,9 +4552,9 @@ static void cvQuadSensFreeVectors(CVodeMem cv_mem) N_VDestroyVectorArray(cv_mem->cv_ewtQS, cv_mem->cv_Ns); N_VDestroyVectorArray(cv_mem->cv_acorQS, cv_mem->cv_Ns); N_VDestroyVectorArray(cv_mem->cv_tempvQS, cv_mem->cv_Ns); - + for (j=0; j<=maxord; j++) - N_VDestroyVectorArray(cv_mem->cv_znQS[j], cv_mem->cv_Ns); + N_VDestroyVectorArray(cv_mem->cv_znQS[j], cv_mem->cv_Ns); cv_mem->cv_lrw -= (maxord + 5)*cv_mem->cv_Ns*cv_mem->cv_lrw1Q; cv_mem->cv_liw -= (maxord + 5)*cv_mem->cv_Ns*cv_mem->cv_liw1Q; @@ -4533,7 +4574,234 @@ static void cvQuadSensFreeVectors(CVodeMem cv_mem) } -/* +/* + * ----------------------------------------------------------------- + * Initial setup + * ----------------------------------------------------------------- + */ + + +/* + * cvInitialSetup + * + * This routine performs input consistency checks at the first step. + * If needed, it also checks the linear solver module and calls the + * linear solver initialization routine. + */ + +static int cvInitialSetup(CVodeMem cv_mem) +{ + int ier; + booleantype conOK; + + /* Did the user specify tolerances? */ + if (cv_mem->cv_itol == CV_NN) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_NO_TOL); + return(CV_ILL_INPUT); + } + + /* If using a built-in routine for error weights with abstol==0, + ensure that N_VMin is available */ + if ((!cv_mem->cv_user_efun) && (cv_mem->cv_atolmin0) && (!cv_mem->cv_tempv->ops->nvmin)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + "Missing N_VMin routine from N_Vector"); + return(CV_ILL_INPUT); + } + + /* Set data for efun */ + if (cv_mem->cv_user_efun) cv_mem->cv_e_data = cv_mem->cv_user_data; + else cv_mem->cv_e_data = cv_mem; + + /* Check to see if y0 satisfies constraints */ + if (cv_mem->cv_constraintsSet) { + + if (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_SIMULTANEOUS)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", MSGCV_BAD_ISM_CONSTR); + return(CV_ILL_INPUT); + } + + conOK = N_VConstrMask(cv_mem->cv_constraints, cv_mem->cv_zn[0], cv_mem->cv_tempv); + if (!conOK) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_Y0_FAIL_CONSTR); + return(CV_ILL_INPUT); + } + } + + /* Load initial error weights */ + ier = cv_mem->cv_efun(cv_mem->cv_zn[0], cv_mem->cv_ewt, cv_mem->cv_e_data); + if (ier != 0) { + if (cv_mem->cv_itol == CV_WF) + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_EWT_FAIL); + else + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_BAD_EWT); + return(CV_ILL_INPUT); + } + + /* Quadrature initial setup */ + + if (cv_mem->cv_quadr && cv_mem->cv_errconQ) { + + /* Did the user specify tolerances? */ + if (cv_mem->cv_itolQ == CV_NN) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_NO_TOLQ); + return(CV_ILL_INPUT); + } + + /* Load ewtQ */ + ier = cvQuadEwtSet(cv_mem, cv_mem->cv_znQ[0], cv_mem->cv_ewtQ); + if (ier != 0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_BAD_EWTQ); + return(CV_ILL_INPUT); + } + + } + + if (!cv_mem->cv_quadr) cv_mem->cv_errconQ = SUNFALSE; + + /* Forward sensitivity initial setup */ + + if (cv_mem->cv_sensi) { + + /* Did the user specify tolerances? */ + if (cv_mem->cv_itolS == CV_NN) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_NO_TOLS); + return(CV_ILL_INPUT); + } + + /* If using the internal DQ functions, we must have access to the problem parameters */ + if(cv_mem->cv_fSDQ && (cv_mem->cv_p == NULL)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_NULL_P); + return(CV_ILL_INPUT); + } + + /* Load ewtS */ + ier = cvSensEwtSet(cv_mem, cv_mem->cv_znS[0], cv_mem->cv_ewtS); + if (ier != 0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_BAD_EWTS); + return(CV_ILL_INPUT); + } + + } + + /* FSA of quadrature variables */ + + if (cv_mem->cv_quadr_sensi) { + + /* If using the internal DQ functions, we must have access to fQ + * (i.e. quadrature integration must be enabled) and to the problem parameters */ + + if (cv_mem->cv_fQSDQ) { + + /* Test if quadratures are defined, so we can use fQ */ + if (!cv_mem->cv_quadr) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_NULL_FQ); + return(CV_ILL_INPUT); + } + + /* Test if we have the problem parameters */ + if(cv_mem->cv_p == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_NULL_P); + return(CV_ILL_INPUT); + } + + } + + if (cv_mem->cv_errconQS) { + + /* Did the user specify tolerances? */ + if (cv_mem->cv_itolQS == CV_NN) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_NO_TOLQS); + return(CV_ILL_INPUT); + } + + /* If needed, did the user provide quadrature tolerances? */ + if ( (cv_mem->cv_itolQS == CV_EE) && (cv_mem->cv_itolQ == CV_NN) ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_NO_TOLQ); + return(CV_ILL_INPUT); + } + + /* Load ewtQS */ + ier = cvQuadSensEwtSet(cv_mem, cv_mem->cv_znQS[0], cv_mem->cv_ewtQS); + if (ier != 0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", + MSGCV_BAD_EWTQS); + return(CV_ILL_INPUT); + } + + } + + } else { + + cv_mem->cv_errconQS = SUNFALSE; + + } + + /* Call linit function (if it exists) */ + if (cv_mem->cv_linit != NULL) { + ier = cv_mem->cv_linit(cv_mem); + if (ier != 0) { + cvProcessError(cv_mem, CV_LINIT_FAIL, "CVODES", "cvInitialSetup", + MSGCV_LINIT_FAIL); + return(CV_LINIT_FAIL); + } + } + + /* Initialize the nonlinear solver (must occur after linear solver is + initialized) so that lsetup and lsolve pointer have been set */ + + /* always initialize the ODE NLS in case the user disables sensitivities */ + ier = cvNlsInit(cv_mem); + if (ier != 0) { + cvProcessError(cv_mem, CV_NLS_INIT_FAIL, "CVODES", "cvInitialSetup", + MSGCV_NLS_INIT_FAIL); + return(CV_NLS_INIT_FAIL); + } + + if (cv_mem->NLSsim != NULL) { + ier = cvNlsInitSensSim(cv_mem); + if (ier != 0) { + cvProcessError(cv_mem, CV_NLS_INIT_FAIL, "CVODES", + "cvInitialSetup", MSGCV_NLS_INIT_FAIL); + return(CV_NLS_INIT_FAIL); + } + } + + if (cv_mem->NLSstg != NULL) { + ier = cvNlsInitSensStg(cv_mem); + if (ier != 0) { + cvProcessError(cv_mem, CV_NLS_INIT_FAIL, "CVODES", + "cvInitialSetup", MSGCV_NLS_INIT_FAIL); + return(CV_NLS_INIT_FAIL); + } + } + + if (cv_mem->NLSstg1 != NULL) { + ier = cvNlsInitSensStg1(cv_mem); + if (ier != 0) { + cvProcessError(cv_mem, CV_NLS_INIT_FAIL, "CVODES", + "cvInitialSetup", MSGCV_NLS_INIT_FAIL); + return(CV_NLS_INIT_FAIL); + } + } + + return(CV_SUCCESS); +} + + +/* * ----------------------------------------------------------------- * Initial stepsize calculation * ----------------------------------------------------------------- @@ -4542,10 +4810,10 @@ static void cvQuadSensFreeVectors(CVodeMem cv_mem) /* * cvHin * - * This routine computes a tentative initial step size h0. + * This routine computes a tentative initial step size h0. * If tout is too close to tn (= t0), then cvHin returns CV_TOO_CLOSE * and h remains uninitialized. Note that here tout is either the value - * passed to CVode at the first call or the value of tstop (if tstop is + * passed to CVode at the first call or the value of tstop (if tstop is * enabled and it is closer to t0=tn than tout). * If any RHS function fails unrecoverably, cvHin returns CV_*RHSFUNC_FAIL. * If any RHS function fails recoverably too many times and recovery is @@ -4553,7 +4821,7 @@ static void cvQuadSensFreeVectors(CVodeMem cv_mem) * Otherwise, cvHin sets h to the chosen value h0 and returns CV_SUCCESS. * * The algorithm used seeks to find h0 as a solution of - * (WRMS norm of (h0^2 ydd / 2)) = 1, + * (WRMS norm of (h0^2 ydd / 2)) = 1, * where ydd = estimated second derivative of y. Here, y includes * all variables considered in the error test. * @@ -4563,8 +4831,8 @@ static void cvQuadSensFreeVectors(CVodeMem cv_mem) * Loop up to MAX_ITERS times to find h0. * Stop if new and previous values differ by a factor < 2. * Stop if hnew/hg > 2 after one iteration, as this probably means - * that the ydd value is bad because of cancellation error. - * + * that the ydd value is bad because of cancellation error. + * * For each new proposed hg, we allow MAX_ITERS attempts to * resolve a possible recoverable failure from f() by reducing * the proposed stepsize by a factor of 0.2. If a legal stepsize @@ -4582,17 +4850,17 @@ static int cvHin(CVodeMem cv_mem, realtype tout) booleantype hgOK; /* If tout is too close to tn, give up */ - + if ((tdiff = tout-cv_mem->cv_tn) == ZERO) return(CV_TOO_CLOSE); - + sign = (tdiff > ZERO) ? 1 : -1; tdist = SUNRabs(tdiff); tround = cv_mem->cv_uround * SUNMAX(SUNRabs(cv_mem->cv_tn), SUNRabs(tout)); if (tdist < TWO*tround) return(CV_TOO_CLOSE); - - /* - Set lower and upper bounds on h0, and take geometric mean + + /* + Set lower and upper bounds on h0, and take geometric mean as first trial value. Exit with this value if the bounds cross each other. */ @@ -4607,7 +4875,7 @@ static int cvHin(CVodeMem cv_mem, realtype tout) else cv_mem->cv_h = hg; return(CV_SUCCESS); } - + /* Outer loop */ hs = hg; /* safeguard against 'uninitialized variable' warning */ @@ -4625,7 +4893,7 @@ static int cvHin(CVodeMem cv_mem, realtype tout) if (retval < 0) return(retval); /* If successful, we can use ydd */ if (retval == CV_SUCCESS) {hgOK = SUNTRUE; break;} - /* A RHS function failed recoverably; cut step size and test it again */ + /* A RHS function failed recoverably; cut step size and test again */ hg *= POINT2; } @@ -4649,12 +4917,12 @@ static int cvHin(CVodeMem cv_mem, realtype tout) /* Propose new step size */ hnew = (yddnrm*hub*hub > TWO) ? SUNRsqrt(TWO/yddnrm) : SUNRsqrt(hg*hub); - + /* If last pass, stop now with hnew */ if (count1 == MAX_ITERS) break; - + hrat = hnew/hg; - + /* Accept hnew if it does not differ from hg by more than a factor of 2 */ if ((hrat > HALF) && (hrat < TWO)) break; @@ -4696,10 +4964,10 @@ static realtype cvUpperBoundH0(CVodeMem cv_mem, realtype tdist) N_Vector *tempQS1; int is; - /* + /* * Bound based on |y|/|y'| -- allow at most an increase of - * HUB_FACTOR in y0 (based on a forward Euler step). The weight - * factor is used as a safeguard against zero components in y0. + * HUB_FACTOR in y0 (based on a forward Euler step). The weight + * factor is used as a safeguard against zero components in y0. */ temp1 = cv_mem->cv_tempv; @@ -4716,7 +4984,7 @@ static realtype cvUpperBoundH0(CVodeMem cv_mem, realtype tdist) hub_inv = N_VMaxNorm(temp1); /* Bound based on |yQ|/|yQ'| */ - + if (cv_mem->cv_quadr && cv_mem->cv_errconQ) { tempQ1 = cv_mem->cv_tempvQ; @@ -4726,9 +4994,9 @@ static realtype cvUpperBoundH0(CVodeMem cv_mem, realtype tdist) cvQuadEwtSet(cv_mem, cv_mem->cv_znQ[0], tempQ1); N_VInv(tempQ1, tempQ1); N_VLinearSum(HUB_FACTOR, tempQ2, ONE, tempQ1, tempQ1); - + N_VAbs(cv_mem->cv_znQ[1], tempQ2); - + N_VDiv(tempQ2, tempQ1, tempQ1); hubQ_inv = N_VMaxNorm(tempQ1); @@ -4748,9 +5016,9 @@ static realtype cvUpperBoundH0(CVodeMem cv_mem, realtype tdist) N_VAbs(cv_mem->cv_znS[0][is], temp2); N_VInv(tempS1[is], temp1); N_VLinearSum(HUB_FACTOR, temp2, ONE, temp1, temp1); - + N_VAbs(cv_mem->cv_znS[1][is], temp2); - + N_VDiv(temp2, temp1, temp1); hubS_inv = N_VMaxNorm(temp1); @@ -4775,9 +5043,9 @@ static realtype cvUpperBoundH0(CVodeMem cv_mem, realtype tdist) N_VAbs(cv_mem->cv_znQS[0][is], tempQ2); N_VInv(tempQS1[is], tempQ1); N_VLinearSum(HUB_FACTOR, tempQ2, ONE, tempQ1, tempQ1); - + N_VAbs(cv_mem->cv_znQS[1][is], tempQ2); - + N_VDiv(tempQ2, tempQ1, tempQ1); hubQS_inv = N_VMaxNorm(tempQ1); @@ -4792,10 +5060,10 @@ static realtype cvUpperBoundH0(CVodeMem cv_mem, realtype tdist) * bound based on tdist -- allow at most a step of magnitude * HUB_FACTOR * tdist */ - + hub = HUB_FACTOR*tdist; - /* Use the smaler of the two */ + /* Use the smaller of the two */ if (hub*hub_inv > ONE) hub = ONE/hub_inv; @@ -4808,18 +5076,18 @@ static realtype cvUpperBoundH0(CVodeMem cv_mem, realtype tdist) * This routine computes an estimate of the second derivative of Y * using a difference quotient, and returns its WRMS norm. * - * Y contains all variables included in the error test. + * Y contains all variables included in the error test. */ static int cvYddNorm(CVodeMem cv_mem, realtype hg, realtype *yddnrm) { int retval; N_Vector wrk1, wrk2; - + /* y <- h*y'(t) + y(t) */ - + N_VLinearSum(hg, cv_mem->cv_zn[1], ONE, cv_mem->cv_zn[0], cv_mem->cv_y); - + if (cv_mem->cv_sensi && cv_mem->cv_errconS) { retval = N_VLinearSumVectorArray(cv_mem->cv_Ns, hg, cv_mem->cv_znS[1], @@ -4827,7 +5095,7 @@ static int cvYddNorm(CVodeMem cv_mem, realtype hg, realtype *yddnrm) cv_mem->cv_yS); if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); } - + /* tempv <- f(t+h, h*y'(t)+y(t)) */ retval = cv_mem->cv_f(cv_mem->cv_tn+hg, cv_mem->cv_y, @@ -4852,7 +5120,7 @@ static int cvYddNorm(CVodeMem cv_mem, realtype hg, realtype *yddnrm) cv_mem->cv_tempvS, wrk1, wrk2); if (retval < 0) return(CV_SRHSFUNC_FAIL); if (retval > 0) return(SRHSFUNC_RECVR); - } + } if (cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS) { wrk1 = cv_mem->cv_ftemp; @@ -4865,11 +5133,11 @@ static int cvYddNorm(CVodeMem cv_mem, realtype hg, realtype *yddnrm) cv_mem->cv_nfQSe++; if (retval < 0) return(CV_QSRHSFUNC_FAIL); if (retval > 0) return(QSRHSFUNC_RECVR); - } + } /* Load estimate of ||y''|| into tempv: * tempv <- (1/h) * f(t+h, h*y'(t)+y(t)) - y'(t) */ - + N_VLinearSum(ONE/hg, cv_mem->cv_tempv, -ONE/hg, cv_mem->cv_zn[1], cv_mem->cv_tempv); *yddnrm = N_VWrmsNorm(cv_mem->cv_tempv, cv_mem->cv_ewt); @@ -4907,2406 +5175,1888 @@ static int cvYddNorm(CVodeMem cv_mem, realtype hg, realtype *yddnrm) return(CV_SUCCESS); } -/* + +/* * ----------------------------------------------------------------- - * Initial setup + * Main cvStep function * ----------------------------------------------------------------- */ -/* - * cvInitialSetup +/* + * cvStep * - * This routine performs input consistency checks at the first step. - * If needed, it also checks the linear solver module and calls the - * linear solver initialization routine. + * This routine performs one internal cvode step, from tn to tn + h. + * It calls other routines to do all the work. + * + * The main operations done here are as follows: + * - preliminary adjustments if a new step size was chosen; + * - prediction of the Nordsieck history array zn at tn + h; + * - setting of multistep method coefficients and test quantities; + * - solution of the nonlinear system; + * - testing the local error; + * - updating zn and other state data if successful; + * - resetting stepsize and order for the next step. + * - if SLDET is on, check for stability, reduce order if necessary. + * On a failure in the nonlinear system solution or error test, the + * step may be reattempted, depending on the nature of the failure. */ -static int cvInitialSetup(CVodeMem cv_mem) +static int cvStep(CVodeMem cv_mem) { - int ier; - booleantype conOK; + realtype saved_t, dsm, dsmQ, dsmS, dsmQS; + booleantype do_sensi_stg, do_sensi_stg1; + int ncf, ncfS; + int nef, nefQ, nefS, nefQS; + int nflag, kflag, eflag; + int retval, is; - /* Did the user specify tolerances? */ - if (cv_mem->cv_itol == CV_NN) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_NO_TOL); - return(CV_ILL_INPUT); + /* Are we computing sensitivities with a staggered approach? */ + + do_sensi_stg = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_STAGGERED)); + do_sensi_stg1 = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_STAGGERED1)); + + /* Initialize local counters for convergence and error test failures */ + + ncf = nef = 0; + nefQ = nefQS = 0; + ncfS = nefS = 0; + if (do_sensi_stg1) { + for (is=0; iscv_Ns; is++) + cv_mem->cv_ncfS1[is] = 0; } - /* Set data for efun */ - if (cv_mem->cv_user_efun) cv_mem->cv_e_data = cv_mem->cv_user_data; - else cv_mem->cv_e_data = cv_mem; + /* If needed, adjust method parameters */ - /* Check to see if y0 satisfies constraints */ - if (cv_mem->cv_constraintsSet) { + if ((cv_mem->cv_nst > 0) && (cv_mem->cv_hprime != cv_mem->cv_h)) + cvAdjustParams(cv_mem); - if (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_SIMULTANEOUS)) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", MSGCV_BAD_ISM_CONSTR); - return(CV_ILL_INPUT); - } + /* Looping point for attempts to take a step */ - conOK = N_VConstrMask(cv_mem->cv_constraints, cv_mem->cv_zn[0], cv_mem->cv_tempv); - if (!conOK) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", MSGCV_Y0_FAIL_CONSTR); - return(CV_ILL_INPUT); - } - } + saved_t = cv_mem->cv_tn; + nflag = FIRST_CALL; - /* Load initial error weights */ - ier = cv_mem->cv_efun(cv_mem->cv_zn[0], cv_mem->cv_ewt, - cv_mem->cv_e_data); - if (ier != 0) { - if (cv_mem->cv_itol == CV_WF) - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_EWT_FAIL); - else - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_BAD_EWT); - return(CV_ILL_INPUT); - } - - /* Quadrature initial setup */ + for(;;) { - if (cv_mem->cv_quadr && cv_mem->cv_errconQ) { + cvPredict(cv_mem); + cvSet(cv_mem); - /* Did the user specify tolerances? */ - if (cv_mem->cv_itolQ == CV_NN) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_NO_TOLQ); - return(CV_ILL_INPUT); - } + /* ------ Correct state variables ------ */ - /* Load ewtQ */ - ier = cvQuadEwtSet(cv_mem, cv_mem->cv_znQ[0], cv_mem->cv_ewtQ); - if (ier != 0) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_BAD_EWTQ); - return(CV_ILL_INPUT); - } + nflag = cvNls(cv_mem, nflag); + kflag = cvHandleNFlag(cv_mem, &nflag, saved_t, &ncf, &(cv_mem->cv_ncfn)); - } + /* Go back in loop if we need to predict again (nflag=PREV_CONV_FAIL) */ + if (kflag == PREDICT_AGAIN) continue; - if (!cv_mem->cv_quadr) cv_mem->cv_errconQ = SUNFALSE; + /* Return if nonlinear solve failed and recovery not possible. */ + if (kflag != DO_ERROR_TEST) return(kflag); - /* Forward sensitivity initial setup */ + /* Perform error test (nflag=CV_SUCCESS) */ + eflag = cvDoErrorTest(cv_mem, &nflag, saved_t, cv_mem->cv_acnrm, + &nef, &(cv_mem->cv_netf), &dsm); - if (cv_mem->cv_sensi) { + /* Go back in loop if we need to predict again (nflag=PREV_ERR_FAIL) */ + if (eflag == TRY_AGAIN) continue; - /* Did the user specify tolerances? */ - if (cv_mem->cv_itolS == CV_NN) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_NO_TOLS); - return(CV_ILL_INPUT); - } + /* Return if error test failed and recovery not possible. */ + if (eflag != CV_SUCCESS) return(eflag); - /* If using the internal DQ functions, we must have access to the problem parameters */ - if(cv_mem->cv_fSDQ && (cv_mem->cv_p == NULL)) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_NULL_P); - return(CV_ILL_INPUT); - } + /* Error test passed (eflag=CV_SUCCESS, nflag=CV_SUCCESS), go on */ - /* Load ewtS */ - ier = cvSensEwtSet(cv_mem, cv_mem->cv_znS[0], cv_mem->cv_ewtS); - if (ier != 0) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_BAD_EWTS); - return(CV_ILL_INPUT); - } + /* ------ Correct the quadrature variables ------ */ - } + if (cv_mem->cv_quadr) { - /* FSA of quadrature variables */ + ncf = nef = 0; /* reset counters for states */ - if (cv_mem->cv_quadr_sensi) { + nflag = cvQuadNls(cv_mem); + kflag = cvHandleNFlag(cv_mem, &nflag, saved_t, &ncf, &(cv_mem->cv_ncfn)); - /* If using the internal DQ functions, we must have access to fQ - * (i.e. quadrature integration must be enabled) and to the problem parameters */ + if (kflag == PREDICT_AGAIN) continue; + if (kflag != DO_ERROR_TEST) return(kflag); - if (cv_mem->cv_fQSDQ) { + /* Error test on quadratures */ + if (cv_mem->cv_errconQ) { + cv_mem->cv_acnrmQ = N_VWrmsNorm(cv_mem->cv_acorQ, cv_mem->cv_ewtQ); + eflag = cvDoErrorTest(cv_mem, &nflag, saved_t, cv_mem->cv_acnrmQ, + &nefQ, &(cv_mem->cv_netfQ), &dsmQ); - /* Test if quadratures are defined, so we can use fQ */ - if (!cv_mem->cv_quadr) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_NULL_FQ); - return(CV_ILL_INPUT); - } + if (eflag == TRY_AGAIN) continue; + if (eflag != CV_SUCCESS) return(eflag); - /* Test if we have the problem parameters */ - if(cv_mem->cv_p == NULL) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_NULL_P); - return(CV_ILL_INPUT); + /* Set dsm = max(dsm, dsmQ) to be used in cvPrepareNextStep */ + if (dsmQ > dsm) dsm = dsmQ; } } - if (cv_mem->cv_errconQS) { - - /* Did the user specify tolerances? */ - if (cv_mem->cv_itolQS == CV_NN) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_NO_TOLQS); - return(CV_ILL_INPUT); - } + /* ------ Correct the sensitivity variables (STAGGERED or STAGGERED1) ------- */ - /* If needed, did the user provide quadrature tolerances? */ - if ( (cv_mem->cv_itolQS == CV_EE) && (cv_mem->cv_itolQ == CV_NN) ) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_NO_TOLQ); - return(CV_ILL_INPUT); + if (do_sensi_stg || do_sensi_stg1) { + + ncf = nef = 0; /* reset counters for states */ + if (cv_mem->cv_quadr) nefQ = 0; /* reset counter for quadratures */ + + /* Evaluate f at converged y, needed for future evaluations of sens. RHS + * If f() fails recoverably, treat it as a convergence failure and + * attempt the step again */ + + retval = cv_mem->cv_f(cv_mem->cv_tn, cv_mem->cv_y, + cv_mem->cv_ftemp, cv_mem->cv_user_data); + cv_mem->cv_nfe++; + if (retval < 0) return(CV_RHSFUNC_FAIL); + if (retval > 0) { + nflag = PREV_CONV_FAIL; + continue; } - /* Load ewtQS */ - ier = cvQuadSensEwtSet(cv_mem, cv_mem->cv_znQS[0], cv_mem->cv_ewtQS); - if (ier != 0) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvInitialSetup", - MSGCV_BAD_EWTQS); - return(CV_ILL_INPUT); + if (do_sensi_stg) { + /* Nonlinear solve for sensitivities (all-at-once) */ + nflag = cvStgrNls(cv_mem); + kflag = cvHandleNFlag(cv_mem, &nflag, saved_t, &ncfS, + &(cv_mem->cv_ncfnS)); + } else { + /* Nonlinear solve for sensitivities (one-by-one) */ + for (is=0; iscv_Ns; is++) { + cv_mem->sens_solve_idx = is; + nflag = cvStgr1Nls(cv_mem, is); + kflag = cvHandleNFlag(cv_mem, &nflag, saved_t, + &(cv_mem->cv_ncfS1[is]), + &(cv_mem->cv_ncfnS1[is])); + if (kflag != DO_ERROR_TEST) break; + } } - } + if (kflag == PREDICT_AGAIN) continue; + if (kflag != DO_ERROR_TEST) return(kflag); - } else { + /* Error test on sensitivities */ + if (cv_mem->cv_errconS) { - cv_mem->cv_errconQS = SUNFALSE; + if (!cv_mem->cv_acnrmScur) + cv_mem->cv_acnrmS = cvSensNorm(cv_mem, cv_mem->cv_acorS, cv_mem->cv_ewtS); - } + eflag = cvDoErrorTest(cv_mem, &nflag, saved_t, cv_mem->cv_acnrmS, + &nefS, &(cv_mem->cv_netfS), &dsmS); - /* Call linit function (if it exists) */ - if (cv_mem->cv_linit != NULL) { - ier = cv_mem->cv_linit(cv_mem); - if (ier != 0) { - cvProcessError(cv_mem, CV_LINIT_FAIL, "CVODES", "cvInitialSetup", - MSGCV_LINIT_FAIL); - return(CV_LINIT_FAIL); - } - } + if (eflag == TRY_AGAIN) continue; + if (eflag != CV_SUCCESS) return(eflag); - /* Initialize the nonlinear solver (must occur after linear solver is - initialized) so that lsetup and lsolve pointer have been set */ + /* Set dsm = max(dsm, dsmS) to be used in cvPrepareNextStep */ + if (dsmS > dsm) dsm = dsmS; - /* always initialize the ODE NLS in case the user disables sensitivities */ - ier = cvNlsInit(cv_mem); - if (ier != 0) { - cvProcessError(cv_mem, CV_NLS_INIT_FAIL, "CVODES", - "cvInitialSetup", MSGCV_NLS_INIT_FAIL); - return(CV_NLS_INIT_FAIL); - } + } - if (cv_mem->NLSsim != NULL) { - ier = cvNlsInitSensSim(cv_mem); - if (ier != 0) { - cvProcessError(cv_mem, CV_NLS_INIT_FAIL, "CVODES", - "cvInitialSetup", MSGCV_NLS_INIT_FAIL); - return(CV_NLS_INIT_FAIL); } - } - if (cv_mem->NLSstg != NULL) { - ier = cvNlsInitSensStg(cv_mem); - if (ier != 0) { - cvProcessError(cv_mem, CV_NLS_INIT_FAIL, "CVODES", - "cvInitialSetup", MSGCV_NLS_INIT_FAIL); - return(CV_NLS_INIT_FAIL); - } - } + /* ------ Correct the quadrature sensitivity variables ------ */ - if (cv_mem->NLSstg1 != NULL) { - ier = cvNlsInitSensStg1(cv_mem); - if (ier != 0) { - cvProcessError(cv_mem, CV_NLS_INIT_FAIL, "CVODES", - "cvInitialSetup", MSGCV_NLS_INIT_FAIL); - return(CV_NLS_INIT_FAIL); - } - } + if (cv_mem->cv_quadr_sensi) { - return(CV_SUCCESS); -} + /* Reset local convergence and error test failure counters */ + ncf = nef = 0; + if (cv_mem->cv_quadr) nefQ = 0; + if (do_sensi_stg) ncfS = nefS = 0; + if (do_sensi_stg1) { + for (is=0; iscv_Ns; is++) + cv_mem->cv_ncfS1[is] = 0; + nefS = 0; + } -/* - * cvEwtSet - * - * This routine is responsible for setting the error weight vector ewt, - * according to tol_type, as follows: - * - * (1) ewt[i] = 1 / (reltol * SUNRabs(ycur[i]) + *abstol), i=0,...,neq-1 - * if tol_type = CV_SS - * (2) ewt[i] = 1 / (reltol * SUNRabs(ycur[i]) + abstol[i]), i=0,...,neq-1 - * if tol_type = CV_SV - * - * cvEwtSet returns 0 if ewt is successfully set as above to a - * positive vector and -1 otherwise. In the latter case, ewt is - * considered undefined. - * - * All the real work is done in the routines cvEwtSetSS, cvEwtSetSV. - */ + /* Note that ftempQ contains yQdot evaluated at the converged y + * (stored in cvQuadNls) and can be used in evaluating fQS */ -int cvEwtSet(N_Vector ycur, N_Vector weight, void *data) -{ - CVodeMem cv_mem; - int flag = 0; + nflag = cvQuadSensNls(cv_mem); + kflag = cvHandleNFlag(cv_mem, &nflag, saved_t, &ncf, &(cv_mem->cv_ncfn)); - /* data points to cv_mem here */ + if (kflag == PREDICT_AGAIN) continue; + if (kflag != DO_ERROR_TEST) return(kflag); - cv_mem = (CVodeMem) data; + /* Error test on quadrature sensitivities */ + if (cv_mem->cv_errconQS) { + cv_mem->cv_acnrmQS = cvQuadSensNorm(cv_mem, cv_mem->cv_acorQS, + cv_mem->cv_ewtQS); + eflag = cvDoErrorTest(cv_mem, &nflag, saved_t, cv_mem->cv_acnrmQS, + &nefQS, &(cv_mem->cv_netfQS), &dsmQS); - switch(cv_mem->cv_itol) { - case CV_SS: - flag = cvEwtSetSS(cv_mem, ycur, weight); - break; - case CV_SV: - flag = cvEwtSetSV(cv_mem, ycur, weight); + if (eflag == TRY_AGAIN) continue; + if (eflag != CV_SUCCESS) return(eflag); + + /* Set dsm = max(dsm, dsmQS) to be used in cvPrepareNextStep */ + if (dsmQS > dsm) dsm = dsmQS; + } + + } + + /* Error test passed (eflag=CV_SUCCESS), break from loop */ break; + } - return(flag); -} + /* Nonlinear system solve and error test were both successful. + Update data, and consider change of step and/or order. */ -/* - * cvEwtSetSS - * - * This routine sets ewt as decribed above in the case tol_type = CV_SS. - * It tests for non-positive components before inverting. cvEwtSetSS - * returns 0 if ewt is successfully set to a positive vector - * and -1 otherwise. In the latter case, ewt is considered undefined. - */ + cvCompleteStep(cv_mem); -static int cvEwtSetSS(CVodeMem cv_mem, N_Vector ycur, N_Vector weight) -{ - N_VAbs(ycur, cv_mem->cv_tempv); - N_VScale(cv_mem->cv_reltol, cv_mem->cv_tempv, cv_mem->cv_tempv); - N_VAddConst(cv_mem->cv_tempv, cv_mem->cv_Sabstol, cv_mem->cv_tempv); - if (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); - N_VInv(cv_mem->cv_tempv, weight); + cvPrepareNextStep(cv_mem, dsm); - return(0); -} + /* If Stablilty Limit Detection is turned on, call stability limit + detection routine for possible order reduction. */ -/* - * cvEwtSetSV - * - * This routine sets ewt as decribed above in the case tol_type = CV_SV. - * It tests for non-positive components before inverting. cvEwtSetSV - * returns 0 if ewt is successfully set to a positive vector - * and -1 otherwise. In the latter case, ewt is considered undefined. - */ + if (cv_mem->cv_sldeton) cvBDFStab(cv_mem); -static int cvEwtSetSV(CVodeMem cv_mem, N_Vector ycur, N_Vector weight) -{ - N_VAbs(ycur, cv_mem->cv_tempv); - N_VLinearSum(cv_mem->cv_reltol, cv_mem->cv_tempv, ONE, - cv_mem->cv_Vabstol, cv_mem->cv_tempv); - if (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); - N_VInv(cv_mem->cv_tempv, weight); - return(0); -} + cv_mem->cv_etamax = (cv_mem->cv_nst <= SMALL_NST) ? ETAMX2 : ETAMX3; -/* - * cvQuadEwtSet - * - */ + /* Finally, we rescale the acor array to be the + estimated local error vector. */ -static int cvQuadEwtSet(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ) -{ - int flag=0; + N_VScale(cv_mem->cv_tq[2], cv_mem->cv_acor, cv_mem->cv_acor); - switch (cv_mem->cv_itolQ) { - case CV_SS: - flag = cvQuadEwtSetSS(cv_mem, qcur, weightQ); - break; - case CV_SV: - flag = cvQuadEwtSetSV(cv_mem, qcur, weightQ); - break; + if (cv_mem->cv_quadr) + N_VScale(cv_mem->cv_tq[2], cv_mem->cv_acorQ, cv_mem->cv_acorQ); + + if (cv_mem->cv_sensi) { + for (is=0; iscv_Ns; is++) + cv_mem->cv_cvals[is] = cv_mem->cv_tq[2]; + + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_acorS, cv_mem->cv_acorS); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); } - return(flag); + if (cv_mem->cv_quadr_sensi) { + for (is=0; iscv_Ns; is++) + cv_mem->cv_cvals[is] = cv_mem->cv_tq[2]; + + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_acorQS, cv_mem->cv_acorQS); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + return(CV_SUCCESS); } /* - * cvQuadEwtSetSS - * + * ----------------------------------------------------------------- + * Function called at beginning of step + * ----------------------------------------------------------------- */ -static int cvQuadEwtSetSS(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ) -{ - N_VAbs(qcur, cv_mem->cv_tempvQ); - N_VScale(cv_mem->cv_reltolQ, cv_mem->cv_tempvQ, cv_mem->cv_tempvQ); - N_VAddConst(cv_mem->cv_tempvQ, cv_mem->cv_SabstolQ, cv_mem->cv_tempvQ); - if (N_VMin(cv_mem->cv_tempvQ) <= ZERO) return(-1); - N_VInv(cv_mem->cv_tempvQ, weightQ); - - return(0); -} - /* - * cvQuadEwtSetSV + * cvAdjustParams * + * This routine is called when a change in step size was decided upon, + * and it handles the required adjustments to the history array zn. + * If there is to be a change in order, we call cvAdjustOrder and reset + * q, L = q+1, and qwait. Then in any case, we call cvRescale, which + * resets h and rescales the Nordsieck array. */ -static int cvQuadEwtSetSV(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ) +static void cvAdjustParams(CVodeMem cv_mem) { - N_VAbs(qcur, cv_mem->cv_tempvQ); - N_VLinearSum(cv_mem->cv_reltolQ, cv_mem->cv_tempvQ, ONE, - cv_mem->cv_VabstolQ, cv_mem->cv_tempvQ); - if (N_VMin(cv_mem->cv_tempvQ) <= ZERO) return(-1); - N_VInv(cv_mem->cv_tempvQ, weightQ); - - return(0); + if (cv_mem->cv_qprime != cv_mem->cv_q) { + cvAdjustOrder(cv_mem, cv_mem->cv_qprime-cv_mem->cv_q); + cv_mem->cv_q = cv_mem->cv_qprime; + cv_mem->cv_L = cv_mem->cv_q+1; + cv_mem->cv_qwait = cv_mem->cv_L; + } + cvRescale(cv_mem); } /* - * cvSensEwtSet + * cvAdjustOrder * + * This routine is a high level routine which handles an order + * change by an amount deltaq (= +1 or -1). If a decrease in order + * is requested and q==2, then the routine returns immediately. + * Otherwise cvAdjustAdams or cvAdjustBDF is called to handle the + * order change (depending on the value of lmm). */ -static int cvSensEwtSet(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS) +static void cvAdjustOrder(CVodeMem cv_mem, int deltaq) { - int flag=0; + if ((cv_mem->cv_q==2) && (deltaq != 1)) return; - switch (cv_mem->cv_itolS) { - case CV_EE: - flag = cvSensEwtSetEE(cv_mem, yScur, weightS); - break; - case CV_SS: - flag = cvSensEwtSetSS(cv_mem, yScur, weightS); + switch(cv_mem->cv_lmm){ + case CV_ADAMS: + cvAdjustAdams(cv_mem, deltaq); break; - case CV_SV: - flag = cvSensEwtSetSV(cv_mem, yScur, weightS); + case CV_BDF: + cvAdjustBDF(cv_mem, deltaq); break; } - - return(flag); } /* - * cvSensEwtSetEE - * - * In this case, the error weight vector for the i-th sensitivity is set to - * - * ewtS_i = pbar_i * efun(pbar_i*yS_i) - * - * In other words, the scaled sensitivity pbar_i * yS_i has the same error - * weight vector calculation as the solution vector. + * cvAdjustAdams * + * This routine adjusts the history array on a change of order q by + * deltaq, in the case that lmm == CV_ADAMS. */ -static int cvSensEwtSetEE(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS) +static void cvAdjustAdams(CVodeMem cv_mem, int deltaq) { - int is; - N_Vector pyS; - int flag; - - /* Use tempvS[0] as temporary storage for the scaled sensitivity */ - pyS = cv_mem->cv_tempvS[0]; - - for (is=0; iscv_Ns; is++) { - N_VScale(cv_mem->cv_pbar[is], yScur[is], pyS); - flag = cv_mem->cv_efun(pyS, weightS[is], cv_mem->cv_e_data); - if (flag != 0) return(-1); - N_VScale(cv_mem->cv_pbar[is], weightS[is], weightS[is]); - } + int i, j; + realtype xi, hsum; - return(0); -} + /* On an order increase, set new column of zn to zero and return */ -/* - * cvSensEwtSetSS - * - */ + if (deltaq==1) { + N_VConst(ZERO, cv_mem->cv_zn[cv_mem->cv_L]); + if (cv_mem->cv_quadr) + N_VConst(ZERO, cv_mem->cv_znQ[cv_mem->cv_L]); + if (cv_mem->cv_sensi) + (void) N_VConstVectorArray(cv_mem->cv_Ns, ZERO, + cv_mem->cv_znS[cv_mem->cv_L]); + return; + } -static int cvSensEwtSetSS(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS) -{ - int is; - - for (is=0; iscv_Ns; is++) { - N_VAbs(yScur[is], cv_mem->cv_tempv); - N_VScale(cv_mem->cv_reltolS, cv_mem->cv_tempv, cv_mem->cv_tempv); - N_VAddConst(cv_mem->cv_tempv, cv_mem->cv_SabstolS[is], cv_mem->cv_tempv); - if (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); - N_VInv(cv_mem->cv_tempv, weightS[is]); + /* + * On an order decrease, each zn[j] is adjusted by a multiple of zn[q]. + * The coeffs. in the adjustment are the coeffs. of the polynomial: + * x + * q * INT { u * ( u + xi_1 ) * ... * ( u + xi_{q-2} ) } du + * 0 + * where xi_j = [t_n - t_(n-j)]/h => xi_0 = 0 + */ + + for (i=0; i <= cv_mem->cv_qmax; i++) cv_mem->cv_l[i] = ZERO; + cv_mem->cv_l[1] = ONE; + hsum = ZERO; + for (j=1; j <= cv_mem->cv_q-2; j++) { + hsum += cv_mem->cv_tau[j]; + xi = hsum / cv_mem->cv_hscale; + for (i=j+1; i >= 1; i--) + cv_mem->cv_l[i] = cv_mem->cv_l[i]*xi + cv_mem->cv_l[i-1]; } - return(0); -} -/* - * cvSensEwtSetSV - * - */ + for (j=1; j <= cv_mem->cv_q-2; j++) + cv_mem->cv_l[j+1] = cv_mem->cv_q * (cv_mem->cv_l[j] / (j+1)); -static int cvSensEwtSetSV(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS) -{ - int is; - - for (is=0; iscv_Ns; is++) { - N_VAbs(yScur[is], cv_mem->cv_tempv); - N_VLinearSum(cv_mem->cv_reltolS, cv_mem->cv_tempv, ONE, - cv_mem->cv_VabstolS[is], cv_mem->cv_tempv); - if (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); - N_VInv(cv_mem->cv_tempv, weightS[is]); + if (cv_mem->cv_q > 2) { + + for (j=2; j < cv_mem->cv_q; j++) + cv_mem->cv_cvals[j-2] = -cv_mem->cv_l[j]; + + (void) N_VScaleAddMulti(cv_mem->cv_q-2, cv_mem->cv_cvals, + cv_mem->cv_zn[cv_mem->cv_q], + cv_mem->cv_zn+2, cv_mem->cv_zn+2); + + if (cv_mem->cv_quadr) + (void) N_VScaleAddMulti(cv_mem->cv_q-2, cv_mem->cv_cvals, + cv_mem->cv_znQ[cv_mem->cv_q], + cv_mem->cv_znQ+2, cv_mem->cv_znQ+2); + + if (cv_mem->cv_sensi) + (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q-2, + cv_mem->cv_cvals, + cv_mem->cv_znS[cv_mem->cv_q], + cv_mem->cv_znS+2, + cv_mem->cv_znS+2); } - return(0); } /* - * cvQuadSensEwtSet + * cvAdjustBDF * + * This is a high level routine which handles adjustments to the + * history array on a change of order by deltaq in the case that + * lmm == CV_BDF. cvAdjustBDF calls cvIncreaseBDF if deltaq = +1 and + * cvDecreaseBDF if deltaq = -1 to do the actual work. */ -static int cvQuadSensEwtSet(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS) +static void cvAdjustBDF(CVodeMem cv_mem, int deltaq) { - int flag=0; - - switch (cv_mem->cv_itolQS) { - case CV_EE: - flag = cvQuadSensEwtSetEE(cv_mem, yQScur, weightQS); - break; - case CV_SS: - flag = cvQuadSensEwtSetSS(cv_mem, yQScur, weightQS); - break; - case CV_SV: - flag = cvQuadSensEwtSetSV(cv_mem, yQScur, weightQS); - break; + switch(deltaq) { + case 1: + cvIncreaseBDF(cv_mem); + return; + case -1: + cvDecreaseBDF(cv_mem); + return; } - - return(flag); } /* - * cvQuadSensEwtSetEE - * - * In this case, the error weight vector for the i-th quadrature sensitivity - * is set to - * - * ewtQS_i = pbar_i * cvQuadEwtSet(pbar_i*yQS_i) - * - * In other words, the scaled sensitivity pbar_i * yQS_i has the same error - * weight vector calculation as the quadrature vector. + * cvIncreaseBDF * + * This routine adjusts the history array on an increase in the + * order q in the case that lmm == CV_BDF. + * A new column zn[q+1] is set equal to a multiple of the saved + * vector (= acor) in zn[indx_acor]. Then each zn[j] is adjusted by + * a multiple of zn[q+1]. The coefficients in the adjustment are the + * coefficients of the polynomial x*x*(x+xi_1)*...*(x+xi_j), + * where xi_j = [t_n - t_(n-j)]/h. */ -static int cvQuadSensEwtSetEE(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS) + +static void cvIncreaseBDF(CVodeMem cv_mem) { + realtype alpha0, alpha1, prod, xi, xiold, hsum, A1; + int i, j; int is; - N_Vector pyS; - int flag; - - /* Use tempvQS[0] as temporary storage for the scaled sensitivity */ - pyS = cv_mem->cv_tempvQS[0]; - for (is=0; iscv_Ns; is++) { - N_VScale(cv_mem->cv_pbar[is], yQScur[is], pyS); - flag = cvQuadEwtSet(cv_mem, pyS, weightQS[is]); - if (flag != 0) return(-1); - N_VScale(cv_mem->cv_pbar[is], weightQS[is], weightQS[is]); + for (i=0; i <= cv_mem->cv_qmax; i++) cv_mem->cv_l[i] = ZERO; + cv_mem->cv_l[2] = alpha1 = prod = xiold = ONE; + alpha0 = -ONE; + hsum = cv_mem->cv_hscale; + if (cv_mem->cv_q > 1) { + for (j=1; j < cv_mem->cv_q; j++) { + hsum += cv_mem->cv_tau[j+1]; + xi = hsum / cv_mem->cv_hscale; + prod *= xi; + alpha0 -= ONE / (j+1); + alpha1 += ONE / xi; + for (i=j+2; i >= 2; i--) + cv_mem->cv_l[i] = cv_mem->cv_l[i]*xiold + cv_mem->cv_l[i-1]; + xiold = xi; + } } + A1 = (-alpha0 - alpha1) / prod; - return(0); -} + /* + zn[indx_acor] contains the value Delta_n = y_n - y_n(0) + This value was stored there at the previous successful + step (in cvCompleteStep) -static int cvQuadSensEwtSetSS(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS) -{ - int is; + A1 contains dbar = (1/xi* - 1/xi_q)/prod(xi_j) + */ - for (is=0; iscv_Ns; is++) { - N_VAbs(yQScur[is], cv_mem->cv_tempvQ); - N_VScale(cv_mem->cv_reltolQS, cv_mem->cv_tempvQ, cv_mem->cv_tempvQ); - N_VAddConst(cv_mem->cv_tempvQ, cv_mem->cv_SabstolQS[is], cv_mem->cv_tempvQ); - if (N_VMin(cv_mem->cv_tempvQ) <= ZERO) return(-1); - N_VInv(cv_mem->cv_tempvQ, weightQS[is]); + N_VScale(A1, cv_mem->cv_zn[cv_mem->cv_indx_acor], + cv_mem->cv_zn[cv_mem->cv_L]); + + /* for (j=2; j <= cv_mem->cv_q; j++) */ + if (cv_mem->cv_q > 1) + (void) N_VScaleAddMulti(cv_mem->cv_q-1, cv_mem->cv_l+2, + cv_mem->cv_zn[cv_mem->cv_L], + cv_mem->cv_zn+2, cv_mem->cv_zn+2); + + if (cv_mem->cv_quadr) { + N_VScale(A1, cv_mem->cv_znQ[cv_mem->cv_indx_acor], + cv_mem->cv_znQ[cv_mem->cv_L]); + + /* for (j=2; j <= cv_mem->cv_q; j++) */ + if (cv_mem->cv_q > 1) + (void) N_VScaleAddMulti(cv_mem->cv_q-1, cv_mem->cv_l+2, + cv_mem->cv_znQ[cv_mem->cv_L], + cv_mem->cv_znQ+2, cv_mem->cv_znQ+2); } - return(0); -} + if (cv_mem->cv_sensi) { -static int cvQuadSensEwtSetSV(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS) -{ - int is; - - for (is=0; iscv_Ns; is++) { - N_VAbs(yQScur[is], cv_mem->cv_tempvQ); - N_VLinearSum(cv_mem->cv_reltolQS, cv_mem->cv_tempvQ, ONE, - cv_mem->cv_VabstolQS[is], cv_mem->cv_tempvQ); - if (N_VMin(cv_mem->cv_tempvQ) <= ZERO) return(-1); - N_VInv(cv_mem->cv_tempvQ, weightQS[is]); + for (is=0; iscv_Ns; is++) + cv_mem->cv_cvals[is] = A1; + + (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_znS[cv_mem->cv_indx_acor], + cv_mem->cv_znS[cv_mem->cv_L]); + + /* for (j=2; j <= cv_mem->cv_q; j++) */ + if (cv_mem->cv_q > 1) + (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q-1, + cv_mem->cv_l+2, + cv_mem->cv_znS[cv_mem->cv_L], + cv_mem->cv_znS+2, + cv_mem->cv_znS+2); } - return(0); -} + if (cv_mem->cv_quadr_sensi) { + for (is=0; iscv_Ns; is++) + cv_mem->cv_cvals[is] = A1; + (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_znQS[cv_mem->cv_indx_acor], + cv_mem->cv_znQS[cv_mem->cv_L]); -/* - * ----------------------------------------------------------------- - * Main cvStep function - * ----------------------------------------------------------------- - */ + /* for (j=2; j <= cv_mem->cv_q; j++) */ + if (cv_mem->cv_q > 1) + (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q-1, + cv_mem->cv_l+2, + cv_mem->cv_znQS[cv_mem->cv_L], + cv_mem->cv_znQS+2, + cv_mem->cv_znQS+2); + } -/* - * cvStep - * - * This routine performs one internal cvode step, from tn to tn + h. - * It calls other routines to do all the work. +} + +/* + * cvDecreaseBDF * - * The main operations done here are as follows: - * - preliminary adjustments if a new step size was chosen; - * - prediction of the Nordsieck history array zn at tn + h; - * - setting of multistep method coefficients and test quantities; - * - solution of the nonlinear system; - * - testing the local error; - * - updating zn and other state data if successful; - * - resetting stepsize and order for the next step. - * - if SLDET is on, check for stability, reduce order if necessary. - * On a failure in the nonlinear system solution or error test, the - * step may be reattempted, depending on the nature of the failure. + * This routine adjusts the history array on a decrease in the + * order q in the case that lmm == CV_BDF. + * Each zn[j] is adjusted by a multiple of zn[q]. The coefficients + * in the adjustment are the coefficients of the polynomial + * x*x*(x+xi_1)*...*(x+xi_j), where xi_j = [t_n - t_(n-j)]/h. */ -static int cvStep(CVodeMem cv_mem) +static void cvDecreaseBDF(CVodeMem cv_mem) { - realtype saved_t, dsm, dsmQ, dsmS, dsmQS; - booleantype do_sensi_stg, do_sensi_stg1; - int ncf, ncfS; - int nef, nefQ, nefS, nefQS; - int nflag, kflag, eflag; - int retval, is; + realtype hsum, xi; + int i, j; - /* Are we computing sensitivities with a staggered approach? */ + for (i=0; i <= cv_mem->cv_qmax; i++) cv_mem->cv_l[i] = ZERO; + cv_mem->cv_l[2] = ONE; + hsum = ZERO; + for (j=1; j <= cv_mem->cv_q-2; j++) { + hsum += cv_mem->cv_tau[j]; + xi = hsum / cv_mem->cv_hscale; + for (i=j+2; i >= 2; i--) + cv_mem->cv_l[i] = cv_mem->cv_l[i]*xi + cv_mem->cv_l[i-1]; + } - do_sensi_stg = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_STAGGERED)); - do_sensi_stg1 = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_STAGGERED1)); + if (cv_mem->cv_q > 2) { - /* Initialize local counters for convergence and error test failures */ + for (j=2; j < cv_mem->cv_q; j++) + cv_mem->cv_cvals[j-2] = -cv_mem->cv_l[j]; - ncf = nef = 0; - nefQ = nefQS = 0; - ncfS = nefS = 0; - if (do_sensi_stg1) { - for (is=0; iscv_Ns; is++) - cv_mem->cv_ncfS1[is] = 0; + (void) N_VScaleAddMulti(cv_mem->cv_q-2, cv_mem->cv_cvals, + cv_mem->cv_zn[cv_mem->cv_q], + cv_mem->cv_zn+2, cv_mem->cv_zn+2); + + if (cv_mem->cv_quadr) + (void) N_VScaleAddMulti(cv_mem->cv_q-2, cv_mem->cv_cvals, + cv_mem->cv_znQ[cv_mem->cv_q], + cv_mem->cv_znQ+2, cv_mem->cv_znQ+2); + + if (cv_mem->cv_sensi) + (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q-2, + cv_mem->cv_cvals, + cv_mem->cv_znS[cv_mem->cv_q], + cv_mem->cv_znS+2, + cv_mem->cv_znS+2); + + if (cv_mem->cv_quadr_sensi) + (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q-2, + cv_mem->cv_cvals, + cv_mem->cv_znQS[cv_mem->cv_q], + cv_mem->cv_znQS+2, + cv_mem->cv_znQS+2); } - /* If needed, adjust method parameters */ +} - if ((cv_mem->cv_nst > 0) && (cv_mem->cv_hprime != cv_mem->cv_h)) - cvAdjustParams(cv_mem); +/* + * cvRescale + * + * This routine rescales the Nordsieck array by multiplying the + * jth column zn[j] by eta^j, j = 1, ..., q. Then the value of + * h is rescaled by eta, and hscale is reset to h. + */ - /* Looping point for attempts to take a step */ +static void cvRescale(CVodeMem cv_mem) +{ + int j; + int is; - saved_t = cv_mem->cv_tn; - nflag = FIRST_CALL; + /* compute scaling factors */ + cv_mem->cv_cvals[0] = cv_mem->cv_eta; + for (j=1; j <= cv_mem->cv_q; j++) + cv_mem->cv_cvals[j] = cv_mem->cv_eta * cv_mem->cv_cvals[j-1]; - for(;;) { + (void) N_VScaleVectorArray(cv_mem->cv_q, cv_mem->cv_cvals, + cv_mem->cv_zn+1, cv_mem->cv_zn+1); - cvPredict(cv_mem); - cvSet(cv_mem); + if (cv_mem->cv_quadr) + (void) N_VScaleVectorArray(cv_mem->cv_q, cv_mem->cv_cvals, + cv_mem->cv_znQ+1, cv_mem->cv_znQ+1); - /* ------ Correct state variables ------ */ - - nflag = cvNls(cv_mem, nflag); - kflag = cvHandleNFlag(cv_mem, &nflag, saved_t, &ncf, &(cv_mem->cv_ncfn)); + /* compute sensi scaling factors */ + if (cv_mem->cv_sensi || cv_mem->cv_quadr_sensi) { + for (is=0; iscv_Ns; is++) + cv_mem->cv_cvals[is] = cv_mem->cv_eta; + for (j=1; j <= cv_mem->cv_q; j++) + for (is=0; iscv_Ns; is++) + cv_mem->cv_cvals[j*cv_mem->cv_Ns+is] = + cv_mem->cv_eta * cv_mem->cv_cvals[(j-1)*cv_mem->cv_Ns+is]; + } - /* Go back in loop if we need to predict again (nflag=PREV_CONV_FAIL) */ - if (kflag == PREDICT_AGAIN) continue; + if (cv_mem->cv_sensi) { + for (j=1; j <= cv_mem->cv_q; j++) + for (is=0; iscv_Ns; is++) + cv_mem->cv_Xvecs[(j-1)*cv_mem->cv_Ns+is] = cv_mem->cv_znS[j][is]; - /* Return if nonlinear solve failed and recovery not possible. */ - if (kflag != DO_ERROR_TEST) return(kflag); + (void) N_VScaleVectorArray(cv_mem->cv_q*cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_Xvecs, cv_mem->cv_Xvecs); + } - /* Perform error test (nflag=CV_SUCCESS) */ - eflag = cvDoErrorTest(cv_mem, &nflag, saved_t, cv_mem->cv_acnrm, - &nef, &(cv_mem->cv_netf), &dsm); + if (cv_mem->cv_quadr_sensi) { + for (j=1; j <= cv_mem->cv_q; j++) + for (is=0; iscv_Ns; is++) + cv_mem->cv_Xvecs[(j-1)*cv_mem->cv_Ns+is] = cv_mem->cv_znQS[j][is]; - /* Go back in loop if we need to predict again (nflag=PREV_ERR_FAIL) */ - if (eflag == TRY_AGAIN) continue; + (void) N_VScaleVectorArray(cv_mem->cv_q*cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_Xvecs, cv_mem->cv_Xvecs); + } - /* Return if error test failed and recovery not possible. */ - if (eflag != CV_SUCCESS) return(eflag); + cv_mem->cv_h = cv_mem->cv_hscale * cv_mem->cv_eta; + cv_mem->cv_next_h = cv_mem->cv_h; + cv_mem->cv_hscale = cv_mem->cv_h; + cv_mem->cv_nscon = 0; +} - /* Error test passed (eflag=CV_SUCCESS, nflag=CV_SUCCESS), go on */ +/* + * cvPredict + * + * This routine advances tn by the tentative step size h, and computes + * the predicted array z_n(0), which is overwritten on zn. The + * prediction of zn is done by repeated additions. + * If tstop is enabled, it is possible for tn + h to be past tstop by roundoff, + * and in that case, we reset tn (after incrementing by h) to tstop. + */ - /* ------ Correct the quadrature variables ------ */ +static void cvPredict(CVodeMem cv_mem) +{ + int j, k; - if (cv_mem->cv_quadr) { + cv_mem->cv_tn += cv_mem->cv_h; + if (cv_mem->cv_tstopset) { + if ((cv_mem->cv_tn - cv_mem->cv_tstop)*cv_mem->cv_h > ZERO) + cv_mem->cv_tn = cv_mem->cv_tstop; + } - ncf = nef = 0; /* reset counters for states */ + for (k = 1; k <= cv_mem->cv_q; k++) + for (j = cv_mem->cv_q; j >= k; j--) + N_VLinearSum(ONE, cv_mem->cv_zn[j-1], ONE, + cv_mem->cv_zn[j], cv_mem->cv_zn[j-1]); - nflag = cvQuadNls(cv_mem); - kflag = cvHandleNFlag(cv_mem, &nflag, saved_t, &ncf, &(cv_mem->cv_ncfn)); + if (cv_mem->cv_quadr) { + for (k = 1; k <= cv_mem->cv_q; k++) + for (j = cv_mem->cv_q; j >= k; j--) + N_VLinearSum(ONE, cv_mem->cv_znQ[j-1], ONE, + cv_mem->cv_znQ[j], cv_mem->cv_znQ[j-1]); + } - if (kflag == PREDICT_AGAIN) continue; - if (kflag != DO_ERROR_TEST) return(kflag); + if (cv_mem->cv_sensi) { + for (k = 1; k <= cv_mem->cv_q; k++) + for (j = cv_mem->cv_q; j >= k; j--) + (void) N_VLinearSumVectorArray(cv_mem->cv_Ns, + ONE, cv_mem->cv_znS[j-1], + ONE, cv_mem->cv_znS[j], + cv_mem->cv_znS[j-1]); + } - /* Error test on quadratures */ - if (cv_mem->cv_errconQ) { - cv_mem->cv_acnrmQ = N_VWrmsNorm(cv_mem->cv_acorQ, cv_mem->cv_ewtQ); - eflag = cvDoErrorTest(cv_mem, &nflag, saved_t, cv_mem->cv_acnrmQ, - &nefQ, &(cv_mem->cv_netfQ), &dsmQ); + if (cv_mem->cv_quadr_sensi) { + for (k = 1; k <= cv_mem->cv_q; k++) + for (j = cv_mem->cv_q; j >= k; j--) + (void) N_VLinearSumVectorArray(cv_mem->cv_Ns, + ONE, cv_mem->cv_znQS[j-1], + ONE, cv_mem->cv_znQS[j], + cv_mem->cv_znQS[j-1]); + } - if (eflag == TRY_AGAIN) continue; - if (eflag != CV_SUCCESS) return(eflag); +} - /* Set dsm = max(dsm, dsmQ) to be used in cvPrepareNextStep */ - if (dsmQ > dsm) dsm = dsmQ; - } +/* + * cvSet + * + * This routine is a high level routine which calls cvSetAdams or + * cvSetBDF to set the polynomial l, the test quantity array tq, + * and the related variables rl1, gamma, and gamrat. + * + * The array tq is loaded with constants used in the control of estimated + * local errors and in the nonlinear convergence test. Specifically, while + * running at order q, the components of tq are as follows: + * tq[1] = a coefficient used to get the est. local error at order q-1 + * tq[2] = a coefficient used to get the est. local error at order q + * tq[3] = a coefficient used to get the est. local error at order q+1 + * tq[4] = constant used in nonlinear iteration convergence test + * tq[5] = coefficient used to get the order q+2 derivative vector used in + * the est. local error at order q+1 + */ - } +static void cvSet(CVodeMem cv_mem) +{ + switch(cv_mem->cv_lmm) { + case CV_ADAMS: + cvSetAdams(cv_mem); + break; + case CV_BDF: + cvSetBDF(cv_mem); + break; + } + cv_mem->cv_rl1 = ONE / cv_mem->cv_l[1]; + cv_mem->cv_gamma = cv_mem->cv_h * cv_mem->cv_rl1; + if (cv_mem->cv_nst == 0) cv_mem->cv_gammap = cv_mem->cv_gamma; + cv_mem->cv_gamrat = (cv_mem->cv_nst > 0) ? + cv_mem->cv_gamma / cv_mem->cv_gammap : ONE; /* protect x / x != 1.0 */ +} - /* ------ Correct the sensitivity variables (STAGGERED or STAGGERED1) ------- */ +/* + * cvSetAdams + * + * This routine handles the computation of l and tq for the + * case lmm == CV_ADAMS. + * + * The components of the array l are the coefficients of a + * polynomial Lambda(x) = l_0 + l_1 x + ... + l_q x^q, given by + * q-1 + * (d/dx) Lambda(x) = c * PRODUCT (1 + x / xi_i) , where + * i=1 + * Lambda(-1) = 0, Lambda(0) = 1, and c is a normalization factor. + * Here xi_i = [t_n - t_(n-i)] / h. + * + * The array tq is set to test quantities used in the convergence + * test, the error test, and the selection of h at a new order. + */ - if (do_sensi_stg || do_sensi_stg1) { +static void cvSetAdams(CVodeMem cv_mem) +{ + realtype m[L_MAX], M[3], hsum; - ncf = nef = 0; /* reset counters for states */ - if (cv_mem->cv_quadr) nefQ = 0; /* reset counter for quadratures */ + if (cv_mem->cv_q == 1) { + cv_mem->cv_l[0] = cv_mem->cv_l[1] = cv_mem->cv_tq[1] = cv_mem->cv_tq[5] = ONE; + cv_mem->cv_tq[2] = HALF; + cv_mem->cv_tq[3] = ONE/TWELVE; + cv_mem->cv_tq[4] = cv_mem->cv_nlscoef / cv_mem->cv_tq[2]; /* = 0.1 / tq[2] */ + return; + } - /* Evaluate f at converged y, needed for future evaluations of sens. RHS - * If f() fails recoverably, treat it as a convergence failure and - * attempt the step again */ + hsum = cvAdamsStart(cv_mem, m); - retval = cv_mem->cv_f(cv_mem->cv_tn, cv_mem->cv_y, - cv_mem->cv_ftemp, cv_mem->cv_user_data); - cv_mem->cv_nfe++; - if (retval < 0) return(CV_RHSFUNC_FAIL); - if (retval > 0) { - nflag = PREV_CONV_FAIL; - continue; - } + M[0] = cvAltSum(cv_mem->cv_q-1, m, 1); + M[1] = cvAltSum(cv_mem->cv_q-1, m, 2); - if (do_sensi_stg) { - /* Nonlinear solve for sensitivities (all-at-once) */ - nflag = cvStgrNls(cv_mem); - kflag = cvHandleNFlag(cv_mem, &nflag, saved_t, &ncfS, - &(cv_mem->cv_ncfnS)); - } else { - /* Nonlinear solve for sensitivities (one-by-one) */ - for (is=0; iscv_Ns; is++) { - cv_mem->sens_solve_idx = is; - nflag = cvStgr1Nls(cv_mem, is); - kflag = cvHandleNFlag(cv_mem, &nflag, saved_t, - &(cv_mem->cv_ncfS1[is]), - &(cv_mem->cv_ncfnS1[is])); - if (kflag != DO_ERROR_TEST) break; - } - } - - if (kflag == PREDICT_AGAIN) continue; - if (kflag != DO_ERROR_TEST) return(kflag); - - /* Error test on sensitivities */ - if (cv_mem->cv_errconS) { - - if (do_sensi_stg1) - cv_mem->cv_acnrmS = cvSensNorm(cv_mem, cv_mem->cv_acorS, cv_mem->cv_ewtS); - - eflag = cvDoErrorTest(cv_mem, &nflag, saved_t, cv_mem->cv_acnrmS, - &nefS, &(cv_mem->cv_netfS), &dsmS); - - if (eflag == TRY_AGAIN) continue; - if (eflag != CV_SUCCESS) return(eflag); - - /* Set dsm = max(dsm, dsmS) to be used in cvPrepareNextStep */ - if (dsmS > dsm) dsm = dsmS; - - } - - } - - /* ------ Correct the quadrature sensitivity variables ------ */ - - if (cv_mem->cv_quadr_sensi) { - - /* Reset local convergence and error test failure counters */ - ncf = nef = 0; - if (cv_mem->cv_quadr) nefQ = 0; - if (do_sensi_stg) ncfS = nefS = 0; - if (do_sensi_stg1) { - for (is=0; iscv_Ns; is++) - cv_mem->cv_ncfS1[is] = 0; - nefS = 0; - } - - /* Note that ftempQ contains yQdot evaluated at the converged y - * (stored in cvQuadNls) and can be used in evaluating fQS */ - - nflag = cvQuadSensNls(cv_mem); - kflag = cvHandleNFlag(cv_mem, &nflag, saved_t, &ncf, &(cv_mem->cv_ncfn)); - - if (kflag == PREDICT_AGAIN) continue; - if (kflag != DO_ERROR_TEST) return(kflag); - - /* Error test on quadrature sensitivities */ - if (cv_mem->cv_errconQS) { - cv_mem->cv_acnrmQS = cvQuadSensNorm(cv_mem, cv_mem->cv_acorQS, - cv_mem->cv_ewtQS); - eflag = cvDoErrorTest(cv_mem, &nflag, saved_t, cv_mem->cv_acnrmQS, - &nefQS, &(cv_mem->cv_netfQS), &dsmQS); - - if (eflag == TRY_AGAIN) continue; - if (eflag != CV_SUCCESS) return(eflag); + cvAdamsFinish(cv_mem, m, M, hsum); +} - /* Set dsm = max(dsm, dsmQS) to be used in cvPrepareNextStep */ - if (dsmQS > dsm) dsm = dsmQS; - } +/* + * cvAdamsStart + * + * This routine generates in m[] the coefficients of the product + * polynomial needed for the Adams l and tq coefficients for q > 1. + */ +static realtype cvAdamsStart(CVodeMem cv_mem, realtype m[]) +{ + realtype hsum, xi_inv, sum; + int i, j; + hsum = cv_mem->cv_h; + m[0] = ONE; + for (i=1; i <= cv_mem->cv_q; i++) m[i] = ZERO; + for (j=1; j < cv_mem->cv_q; j++) { + if ((j==cv_mem->cv_q-1) && (cv_mem->cv_qwait == 1)) { + sum = cvAltSum(cv_mem->cv_q-2, m, 2); + cv_mem->cv_tq[1] = cv_mem->cv_q * sum / m[cv_mem->cv_q-2]; } - - - /* Everything went fine; exit loop */ - break; - + xi_inv = cv_mem->cv_h / hsum; + for (i=j; i >= 1; i--) m[i] += m[i-1] * xi_inv; + hsum += cv_mem->cv_tau[j]; + /* The m[i] are coefficients of product(1 to j) (1 + x/xi_i) */ } + return(hsum); +} - /* Nonlinear system solve and error test were both successful. - Update data, and consider change of step and/or order. */ - - cvCompleteStep(cv_mem); - - cvPrepareNextStep(cv_mem, dsm); - - /* If Stablilty Limit Detection is turned on, call stability limit - detection routine for possible order reduction. */ - - if (cv_mem->cv_sldeton) cvBDFStab(cv_mem); - - cv_mem->cv_etamax = (cv_mem->cv_nst <= SMALL_NST) ? ETAMX2 : ETAMX3; - - /* Finally, we rescale the acor array to be the - estimated local error vector. */ - - N_VScale(cv_mem->cv_tq[2], cv_mem->cv_acor, cv_mem->cv_acor); +/* + * cvAdamsFinish + * + * This routine completes the calculation of the Adams l and tq. + */ - if (cv_mem->cv_quadr) - N_VScale(cv_mem->cv_tq[2], cv_mem->cv_acorQ, cv_mem->cv_acorQ); +static void cvAdamsFinish(CVodeMem cv_mem, realtype m[], realtype M[], realtype hsum) +{ + int i; + realtype M0_inv, xi, xi_inv; - if (cv_mem->cv_sensi) { - for (is=0; iscv_Ns; is++) - cv_mem->cv_cvals[is] = cv_mem->cv_tq[2]; + M0_inv = ONE / M[0]; - retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, - cv_mem->cv_acorS, cv_mem->cv_acorS); - if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); - } + cv_mem->cv_l[0] = ONE; + for (i=1; i <= cv_mem->cv_q; i++) + cv_mem->cv_l[i] = M0_inv * (m[i-1] / i); + xi = hsum / cv_mem->cv_h; + xi_inv = ONE / xi; - if (cv_mem->cv_quadr_sensi) { - for (is=0; iscv_Ns; is++) - cv_mem->cv_cvals[is] = cv_mem->cv_tq[2]; + cv_mem->cv_tq[2] = M[1] * M0_inv / xi; + cv_mem->cv_tq[5] = xi / cv_mem->cv_l[cv_mem->cv_q]; - retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, - cv_mem->cv_acorQS, cv_mem->cv_acorQS); - if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + if (cv_mem->cv_qwait == 1) { + for (i=cv_mem->cv_q; i >= 1; i--) m[i] += m[i-1] * xi_inv; + M[2] = cvAltSum(cv_mem->cv_q, m, 2); + cv_mem->cv_tq[3] = M[2] * M0_inv / cv_mem->cv_L; } - return(CV_SUCCESS); - + cv_mem->cv_tq[4] = cv_mem->cv_nlscoef / cv_mem->cv_tq[2]; } -/* - * ----------------------------------------------------------------- - * Function called at beginning of step - * ----------------------------------------------------------------- - */ - /* - * cvAdjustParams + * cvAltSum * - * This routine is called when a change in step size was decided upon, - * and it handles the required adjustments to the history array zn. - * If there is to be a change in order, we call cvAdjustOrder and reset - * q, L = q+1, and qwait. Then in any case, we call cvRescale, which - * resets h and rescales the Nordsieck array. + * cvAltSum returns the value of the alternating sum + * sum (i= 0 ... iend) [ (-1)^i * (a[i] / (i + k)) ]. + * If iend < 0 then cvAltSum returns 0. + * This operation is needed to compute the integral, from -1 to 0, + * of a polynomial x^(k-1) M(x) given the coefficients of M(x). */ -static void cvAdjustParams(CVodeMem cv_mem) +static realtype cvAltSum(int iend, realtype a[], int k) { - if (cv_mem->cv_qprime != cv_mem->cv_q) { - cvAdjustOrder(cv_mem, cv_mem->cv_qprime-cv_mem->cv_q); - cv_mem->cv_q = cv_mem->cv_qprime; - cv_mem->cv_L = cv_mem->cv_q+1; - cv_mem->cv_qwait = cv_mem->cv_L; + int i, sign; + realtype sum; + + if (iend < 0) return(ZERO); + + sum = ZERO; + sign = 1; + for (i=0; i <= iend; i++) { + sum += sign * (a[i] / (i+k)); + sign = -sign; } - cvRescale(cv_mem); + return(sum); } /* - * cvAdjustOrder + * cvSetBDF * - * This routine is a high level routine which handles an order - * change by an amount deltaq (= +1 or -1). If a decrease in order - * is requested and q==2, then the routine returns immediately. - * Otherwise cvAdjustAdams or cvAdjustBDF is called to handle the - * order change (depending on the value of lmm). + * This routine computes the coefficients l and tq in the case + * lmm == CV_BDF. cvSetBDF calls cvSetTqBDF to set the test + * quantity array tq. + * + * The components of the array l are the coefficients of a + * polynomial Lambda(x) = l_0 + l_1 x + ... + l_q x^q, given by + * q-1 + * Lambda(x) = (1 + x / xi*_q) * PRODUCT (1 + x / xi_i) , where + * i=1 + * xi_i = [t_n - t_(n-i)] / h. + * + * The array tq is set to test quantities used in the convergence + * test, the error test, and the selection of h at a new order. */ -static void cvAdjustOrder(CVodeMem cv_mem, int deltaq) +static void cvSetBDF(CVodeMem cv_mem) { - if ((cv_mem->cv_q==2) && (deltaq != 1)) return; - - switch(cv_mem->cv_lmm){ - case CV_ADAMS: - cvAdjustAdams(cv_mem, deltaq); - break; - case CV_BDF: - cvAdjustBDF(cv_mem, deltaq); - break; + realtype alpha0, alpha0_hat, xi_inv, xistar_inv, hsum; + int i,j; + + cv_mem->cv_l[0] = cv_mem->cv_l[1] = xi_inv = xistar_inv = ONE; + for (i=2; i <= cv_mem->cv_q; i++) cv_mem->cv_l[i] = ZERO; + alpha0 = alpha0_hat = -ONE; + hsum = cv_mem->cv_h; + if (cv_mem->cv_q > 1) { + for (j=2; j < cv_mem->cv_q; j++) { + hsum += cv_mem->cv_tau[j-1]; + xi_inv = cv_mem->cv_h / hsum; + alpha0 -= ONE / j; + for (i=j; i >= 1; i--) cv_mem->cv_l[i] += cv_mem->cv_l[i-1]*xi_inv; + /* The l[i] are coefficients of product(1 to j) (1 + x/xi_i) */ + } + + /* j = q */ + alpha0 -= ONE / cv_mem->cv_q; + xistar_inv = -cv_mem->cv_l[1] - alpha0; + hsum += cv_mem->cv_tau[cv_mem->cv_q-1]; + xi_inv = cv_mem->cv_h / hsum; + alpha0_hat = -cv_mem->cv_l[1] - xi_inv; + for (i=cv_mem->cv_q; i >= 1; i--) + cv_mem->cv_l[i] += cv_mem->cv_l[i-1]*xistar_inv; } + + cvSetTqBDF(cv_mem, hsum, alpha0, alpha0_hat, xi_inv, xistar_inv); } /* - * cvAdjustAdams + * cvSetTqBDF * - * This routine adjusts the history array on a change of order q by - * deltaq, in the case that lmm == CV_ADAMS. + * This routine sets the test quantity array tq in the case + * lmm == CV_BDF. */ -static void cvAdjustAdams(CVodeMem cv_mem, int deltaq) +static void cvSetTqBDF(CVodeMem cv_mem, realtype hsum, realtype alpha0, + realtype alpha0_hat, realtype xi_inv, realtype xistar_inv) { - int i, j; - realtype xi, hsum; + realtype A1, A2, A3, A4, A5, A6; + realtype C, Cpinv, Cppinv; - /* On an order increase, set new column of zn to zero and return */ - - if (deltaq==1) { - N_VConst(ZERO, cv_mem->cv_zn[cv_mem->cv_L]); - if (cv_mem->cv_quadr) - N_VConst(ZERO, cv_mem->cv_znQ[cv_mem->cv_L]); - if (cv_mem->cv_sensi) - (void) N_VConstVectorArray(cv_mem->cv_Ns, ZERO, - cv_mem->cv_znS[cv_mem->cv_L]); - return; - } - - /* - * On an order decrease, each zn[j] is adjusted by a multiple of zn[q]. - * The coeffs. in the adjustment are the coeffs. of the polynomial: - * x - * q * INT { u * ( u + xi_1 ) * ... * ( u + xi_{q-2} ) } du - * 0 - * where xi_j = [t_n - t_(n-j)]/h => xi_0 = 0 - */ - - for (i=0; i <= cv_mem->cv_qmax; i++) cv_mem->cv_l[i] = ZERO; - cv_mem->cv_l[1] = ONE; - hsum = ZERO; - for (j=1; j <= cv_mem->cv_q-2; j++) { - hsum += cv_mem->cv_tau[j]; - xi = hsum / cv_mem->cv_hscale; - for (i=j+1; i >= 1; i--) - cv_mem->cv_l[i] = cv_mem->cv_l[i]*xi + cv_mem->cv_l[i-1]; - } - - for (j=1; j <= cv_mem->cv_q-2; j++) - cv_mem->cv_l[j+1] = cv_mem->cv_q * (cv_mem->cv_l[j] / (j+1)); - - if (cv_mem->cv_q > 2) { - - for (j=2; j < cv_mem->cv_q; j++) - cv_mem->cv_cvals[j-2] = -cv_mem->cv_l[j]; - - (void) N_VScaleAddMulti(cv_mem->cv_q-2, cv_mem->cv_cvals, - cv_mem->cv_zn[cv_mem->cv_q], - cv_mem->cv_zn+2, cv_mem->cv_zn+2); - - if (cv_mem->cv_quadr) - (void) N_VScaleAddMulti(cv_mem->cv_q-2, cv_mem->cv_cvals, - cv_mem->cv_znQ[cv_mem->cv_q], - cv_mem->cv_znQ+2, cv_mem->cv_znQ+2); - - if (cv_mem->cv_sensi) - (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q-2, - cv_mem->cv_cvals, - cv_mem->cv_znS[cv_mem->cv_q], - cv_mem->cv_znS+2, - cv_mem->cv_znS+2); + A1 = ONE - alpha0_hat + alpha0; + A2 = ONE + cv_mem->cv_q * A1; + cv_mem->cv_tq[2] = SUNRabs(A1 / (alpha0 * A2)); + cv_mem->cv_tq[5] = SUNRabs(A2 * xistar_inv / (cv_mem->cv_l[cv_mem->cv_q] * xi_inv)); + if (cv_mem->cv_qwait == 1) { + if (cv_mem->cv_q > 1) { + C = xistar_inv / cv_mem->cv_l[cv_mem->cv_q]; + A3 = alpha0 + ONE / cv_mem->cv_q; + A4 = alpha0_hat + xi_inv; + Cpinv = (ONE - A4 + A3) / A3; + cv_mem->cv_tq[1] = SUNRabs(C * Cpinv); + } + else cv_mem->cv_tq[1] = ONE; + hsum += cv_mem->cv_tau[cv_mem->cv_q]; + xi_inv = cv_mem->cv_h / hsum; + A5 = alpha0 - (ONE / (cv_mem->cv_q+1)); + A6 = alpha0_hat - xi_inv; + Cppinv = (ONE - A6 + A5) / A2; + cv_mem->cv_tq[3] = SUNRabs(Cppinv / (xi_inv * (cv_mem->cv_q+2) * A5)); } - + cv_mem->cv_tq[4] = cv_mem->cv_nlscoef / cv_mem->cv_tq[2]; } /* - * cvAdjustBDF - * - * This is a high level routine which handles adjustments to the - * history array on a change of order by deltaq in the case that - * lmm == CV_BDF. cvAdjustBDF calls cvIncreaseBDF if deltaq = +1 and - * cvDecreaseBDF if deltaq = -1 to do the actual work. + * ----------------------------------------------------------------- + * Nonlinear solver functions + * ----------------------------------------------------------------- */ -static void cvAdjustBDF(CVodeMem cv_mem, int deltaq) -{ - switch(deltaq) { - case 1: - cvIncreaseBDF(cv_mem); - return; - case -1: - cvDecreaseBDF(cv_mem); - return; - } -} - /* - * cvIncreaseBDF + * cvNls * - * This routine adjusts the history array on an increase in the - * order q in the case that lmm == CV_BDF. - * A new column zn[q+1] is set equal to a multiple of the saved - * vector (= acor) in zn[indx_acor]. Then each zn[j] is adjusted by - * a multiple of zn[q+1]. The coefficients in the adjustment are the - * coefficients of the polynomial x*x*(x+xi_1)*...*(x+xi_j), - * where xi_j = [t_n - t_(n-j)]/h. + * This routine attempts to solve the nonlinear system associated + * with a single implicit step of the linear multistep method. */ -static void cvIncreaseBDF(CVodeMem cv_mem) +static int cvNls(CVodeMem cv_mem, int nflag) { - realtype alpha0, alpha1, prod, xi, xiold, hsum, A1; - int i, j; - int is; + int flag = CV_SUCCESS; + booleantype callSetup; + booleantype do_sensi_sim; - for (i=0; i <= cv_mem->cv_qmax; i++) - cv_mem->cv_l[i] = ZERO; - cv_mem->cv_l[2] = alpha1 = prod = xiold = ONE; - alpha0 = -ONE; - hsum = cv_mem->cv_hscale; - if (cv_mem->cv_q > 1) { - for (j=1; j < cv_mem->cv_q; j++) { - hsum += cv_mem->cv_tau[j+1]; - xi = hsum / cv_mem->cv_hscale; - prod *= xi; - alpha0 -= ONE / (j+1); - alpha1 += ONE / xi; - for (i=j+2; i >= 2; i--) - cv_mem->cv_l[i] = cv_mem->cv_l[i]*xiold + cv_mem->cv_l[i-1]; - xiold = xi; + /* Are we computing sensitivities with the CV_SIMULTANEOUS approach? */ + do_sensi_sim = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_SIMULTANEOUS)); + + /* Decide whether or not to call setup routine (if one exists) and */ + /* set flag convfail (input to lsetup for its evaluation decision) */ + if (cv_mem->cv_lsetup) { + cv_mem->convfail = ((nflag == FIRST_CALL) || (nflag == PREV_ERR_FAIL)) ? + CV_NO_FAILURES : CV_FAIL_OTHER; + + callSetup = (nflag == PREV_CONV_FAIL) || (nflag == PREV_ERR_FAIL) || + (cv_mem->cv_nst == 0) || + (cv_mem->cv_nst >= cv_mem->cv_nstlp + MSBP) || + (SUNRabs(cv_mem->cv_gamrat-ONE) > DGMAX); + + /* Decide whether to force a call to setup */ + if (cv_mem->cv_forceSetup) { + callSetup = SUNTRUE; + cv_mem->convfail = CV_FAIL_OTHER; } + } else { + cv_mem->cv_crate = ONE; + cv_mem->cv_crateS = ONE; /* if NO lsetup all conv. rates are set to ONE */ + callSetup = SUNFALSE; } - A1 = (-alpha0 - alpha1) / prod; - - /* - zn[indx_acor] contains the value Delta_n = y_n - y_n(0) - This value was stored there at the previous successful - step (in cvCompleteStep) - - A1 contains dbar = (1/xi* - 1/xi_q)/prod(xi_j) - */ - - N_VScale(A1, cv_mem->cv_zn[cv_mem->cv_indx_acor], - cv_mem->cv_zn[cv_mem->cv_L]); - /* for (j=2; j <= cv_mem->cv_q; j++) */ - if (cv_mem->cv_q > 1) - (void) N_VScaleAddMulti(cv_mem->cv_q-1, cv_mem->cv_l+2, - cv_mem->cv_zn[cv_mem->cv_L], - cv_mem->cv_zn+2, cv_mem->cv_zn+2); + /* initial guess for the correction to the predictor */ + if (do_sensi_sim) + N_VConst(ZERO, cv_mem->ycorSim); + else + N_VConst(ZERO, cv_mem->cv_acor); - if (cv_mem->cv_quadr) { - N_VScale(A1, cv_mem->cv_znQ[cv_mem->cv_indx_acor], - cv_mem->cv_znQ[cv_mem->cv_L]); + /* call nonlinear solver setup if it exists */ + if ((cv_mem->NLS)->ops->setup) { + if (do_sensi_sim) + flag = SUNNonlinSolSetup(cv_mem->NLS, cv_mem->ycorSim, cv_mem); + else + flag = SUNNonlinSolSetup(cv_mem->NLS, cv_mem->cv_acor, cv_mem); - /* for (j=2; j <= cv_mem->cv_q; j++) */ - if (cv_mem->cv_q > 1) - (void) N_VScaleAddMulti(cv_mem->cv_q-1, cv_mem->cv_l+2, - cv_mem->cv_znQ[cv_mem->cv_L], - cv_mem->cv_znQ+2, cv_mem->cv_znQ+2); + if (flag < 0) return(CV_NLS_SETUP_FAIL); + if (flag > 0) return(SUN_NLS_CONV_RECVR); } - if (cv_mem->cv_sensi) { + /* solve the nonlinear system */ + if (do_sensi_sim) + flag = SUNNonlinSolSolve(cv_mem->NLSsim, cv_mem->zn0Sim, cv_mem->ycorSim, + cv_mem->ewtSim, cv_mem->cv_tq[4], callSetup, cv_mem); + else + flag = SUNNonlinSolSolve(cv_mem->NLS, cv_mem->cv_zn[0], cv_mem->cv_acor, + cv_mem->cv_ewt, cv_mem->cv_tq[4], callSetup, cv_mem); - for (is=0; iscv_Ns; is++) - cv_mem->cv_cvals[is] = A1; + /* if the solve failed return */ + if (flag != CV_SUCCESS) return(flag); - (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, - cv_mem->cv_znS[cv_mem->cv_indx_acor], - cv_mem->cv_znS[cv_mem->cv_L]); + /* solve successful */ - /* for (j=2; j <= cv_mem->cv_q; j++) */ - if (cv_mem->cv_q > 1) - (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q-1, - cv_mem->cv_l+2, - cv_mem->cv_znS[cv_mem->cv_L], - cv_mem->cv_znS+2, - cv_mem->cv_znS+2); - } + /* update the state based on the final correction from the nonlinear solver */ + N_VLinearSum(ONE, cv_mem->cv_zn[0], ONE, cv_mem->cv_acor, cv_mem->cv_y); - if (cv_mem->cv_quadr_sensi) { + /* update the sensitivities based on the final correction from the nonlinear solver */ + if (do_sensi_sim) { + N_VLinearSumVectorArray(cv_mem->cv_Ns, + ONE, cv_mem->cv_znS[0], + ONE, cv_mem->cv_acorS, cv_mem->cv_yS); + } - for (is=0; iscv_Ns; is++) - cv_mem->cv_cvals[is] = A1; + /* compute acnrm if is was not already done by the nonlinear solver */ + if (!cv_mem->cv_acnrmcur) { + if (do_sensi_sim && cv_mem->cv_errconS) + cv_mem->cv_acnrm = N_VWrmsNorm(cv_mem->ycorSim, cv_mem->ewtSim); + else + cv_mem->cv_acnrm = N_VWrmsNorm(cv_mem->cv_acor, cv_mem->cv_ewt); + } - (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, - cv_mem->cv_znQS[cv_mem->cv_indx_acor], - cv_mem->cv_znQS[cv_mem->cv_L]); + /* update Jacobian status */ + cv_mem->cv_jcur = SUNFALSE; - /* for (j=2; j <= cv_mem->cv_q; j++) */ - if (cv_mem->cv_q > 1) - (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q-1, - cv_mem->cv_l+2, - cv_mem->cv_znQS[cv_mem->cv_L], - cv_mem->cv_znQS+2, - cv_mem->cv_znQS+2); - } + /* check inequality constraints */ + if (cv_mem->cv_constraintsSet) + flag = cvCheckConstraints(cv_mem); + return(flag); } /* - * cvDecreaseBDF + * cvCheckConstraints * - * This routine adjusts the history array on a decrease in the - * order q in the case that lmm == CV_BDF. - * Each zn[j] is adjusted by a multiple of zn[q]. The coefficients - * in the adjustment are the coefficients of the polynomial - * x*x*(x+xi_1)*...*(x+xi_j), where xi_j = [t_n - t_(n-j)]/h. + * This routine determines if the constraints of the problem + * are satisfied by the proposed step + * + * Possible return values are: + * + * CV_SUCCESS ---> allows stepping forward + * + * CONSTR_RECVR ---> values failed to satisfy constraints + * + * CV_CONSTR_FAIL ---> values failed to satisfy constraints with hmin */ -static void cvDecreaseBDF(CVodeMem cv_mem) +static int cvCheckConstraints(CVodeMem cv_mem) { - realtype hsum, xi; - int i, j; - - for (i=0; i <= cv_mem->cv_qmax; i++) - cv_mem->cv_l[i] = ZERO; - cv_mem->cv_l[2] = ONE; - hsum = ZERO; - for (j=1; j <= cv_mem->cv_q-2; j++) { - hsum += cv_mem->cv_tau[j]; - xi = hsum / cv_mem->cv_hscale; - for (i=j+2; i >= 2; i--) - cv_mem->cv_l[i] = cv_mem->cv_l[i]*xi + cv_mem->cv_l[i-1]; - } - - if (cv_mem->cv_q > 2) { + booleantype constraintsPassed; + realtype vnorm; + N_Vector mm = cv_mem->cv_ftemp; + N_Vector tmp = cv_mem->cv_tempv; - for (j=2; j < cv_mem->cv_q; j++) - cv_mem->cv_cvals[j-2] = -cv_mem->cv_l[j]; + /* Get mask vector mm, set where constraints failed */ + constraintsPassed = N_VConstrMask(cv_mem->cv_constraints, cv_mem->cv_y, mm); + if (constraintsPassed) return(CV_SUCCESS); - (void) N_VScaleAddMulti(cv_mem->cv_q-2, cv_mem->cv_cvals, - cv_mem->cv_zn[cv_mem->cv_q], - cv_mem->cv_zn+2, cv_mem->cv_zn+2); + /* Constraints not met */ - if (cv_mem->cv_quadr) - (void) N_VScaleAddMulti(cv_mem->cv_q-2, cv_mem->cv_cvals, - cv_mem->cv_znQ[cv_mem->cv_q], - cv_mem->cv_znQ+2, cv_mem->cv_znQ+2); + /* Compute correction to satisfy constraints */ + N_VCompare(ONEPT5, cv_mem->cv_constraints, tmp); /* a[i]=1 when |c[i]|=2 */ + N_VProd(tmp, cv_mem->cv_constraints, tmp); /* a * c */ + N_VDiv(tmp, cv_mem->cv_ewt, tmp); /* a * c * wt */ + N_VLinearSum(ONE, cv_mem->cv_y, -PT1, tmp, tmp); /* y - 0.1 * a * c * wt */ + N_VProd(tmp, mm, tmp); /* v = mm*(y-0.1*a*c*wt) */ - if (cv_mem->cv_sensi) - (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q-2, - cv_mem->cv_cvals, - cv_mem->cv_znS[cv_mem->cv_q], - cv_mem->cv_znS+2, - cv_mem->cv_znS+2); + vnorm = N_VWrmsNorm(tmp, cv_mem->cv_ewt); /* ||v|| */ - if (cv_mem->cv_quadr_sensi) - (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q-2, - cv_mem->cv_cvals, - cv_mem->cv_znQS[cv_mem->cv_q], - cv_mem->cv_znQS+2, - cv_mem->cv_znQS+2); + /* If vector v of constraint corrections is small in norm, correct and + accept this step */ + if (vnorm <= cv_mem->cv_tq[4]) { + N_VLinearSum(ONE, cv_mem->cv_acor, + -ONE, tmp, cv_mem->cv_acor); /* acor <- acor - v */ + return(CV_SUCCESS); } -} + /* Return with error if |h| == hmin */ + if (SUNRabs(cv_mem->cv_h) <= cv_mem->cv_hmin*ONEPSM) return(CV_CONSTR_FAIL); + /* Constraint correction is too large, reduce h by computing eta = h'/h */ + N_VLinearSum(ONE, cv_mem->cv_zn[0], -ONE, cv_mem->cv_y, tmp); + N_VProd(mm, tmp, tmp); + cv_mem->cv_eta = PT9*N_VMinQuotient(cv_mem->cv_zn[0], tmp); + cv_mem->cv_eta = SUNMAX(cv_mem->cv_eta, PT1); + cv_mem->cv_eta = SUNMAX(cv_mem->cv_eta, + cv_mem->cv_hmin / SUNRabs(cv_mem->cv_h)); + + /* Reattempt step with new step size */ + return(CONSTR_RECVR); +} /* - * cvRescale + * cvQuadNls + * + * This routine solves for the quadrature variables at the new step. + * It does not solve a nonlinear system, but rather updates the + * quadrature variables. The name for this function is just for + * uniformity purposes. + * + * Possible return values (interpreted by cvHandleNFlag) + * + * CV_SUCCESS -> continue with error test + * CV_QRHSFUNC_FAIL -> halt the integration + * QRHSFUNC_RECVR -> predict again or stop if too many * - * This routine rescales the Nordsieck array by multiplying the - * jth column zn[j] by eta^j, j = 1, ..., q. Then the value of - * h is rescaled by eta, and hscale is reset to h. */ -static void cvRescale(CVodeMem cv_mem) +static int cvQuadNls(CVodeMem cv_mem) { - int j; - int is; - - /* compute scaling factors */ - cv_mem->cv_cvals[0] = cv_mem->cv_eta; - for (j=1; j < cv_mem->cv_q; j++) - cv_mem->cv_cvals[j] = cv_mem->cv_eta * cv_mem->cv_cvals[j-1]; - - (void) N_VScaleVectorArray(cv_mem->cv_q, cv_mem->cv_cvals, - cv_mem->cv_zn+1, cv_mem->cv_zn+1); - - if (cv_mem->cv_quadr) - (void) N_VScaleVectorArray(cv_mem->cv_q, cv_mem->cv_cvals, - cv_mem->cv_znQ+1, cv_mem->cv_znQ+1); - - /* compute sensi scaling factors */ - if (cv_mem->cv_sensi || cv_mem->cv_quadr_sensi) { - for (is=0; iscv_Ns; is++) - cv_mem->cv_cvals[is] = cv_mem->cv_eta; - for (j=1; j < cv_mem->cv_q; j++) - for (is=0; iscv_Ns; is++) - cv_mem->cv_cvals[j*cv_mem->cv_Ns+is] = - cv_mem->cv_eta * cv_mem->cv_cvals[(j-1)*cv_mem->cv_Ns+is]; - } + int retval; - if (cv_mem->cv_sensi) { - for (j=1; j <= cv_mem->cv_q; j++) - for (is=0; iscv_Ns; is++) - cv_mem->cv_Xvecs[(j-1)*cv_mem->cv_Ns+is] = cv_mem->cv_znS[j][is]; - - (void) N_VScaleVectorArray(cv_mem->cv_q*cv_mem->cv_Ns, cv_mem->cv_cvals, - cv_mem->cv_Xvecs, cv_mem->cv_Xvecs); - } + /* Save quadrature correction in acorQ */ + retval = cv_mem->cv_fQ(cv_mem->cv_tn, cv_mem->cv_y, + cv_mem->cv_acorQ, cv_mem->cv_user_data); + cv_mem->cv_nfQe++; + if (retval < 0) return(CV_QRHSFUNC_FAIL); + if (retval > 0) return(QRHSFUNC_RECVR); + /* If needed, save the value of yQdot = fQ into ftempQ + * for use in evaluating fQS */ if (cv_mem->cv_quadr_sensi) { - for (j=1; j <= cv_mem->cv_q; j++) - for (is=0; iscv_Ns; is++) - cv_mem->cv_Xvecs[(j-1)*cv_mem->cv_Ns+is] = cv_mem->cv_znQS[j][is]; - - (void) N_VScaleVectorArray(cv_mem->cv_q*cv_mem->cv_Ns, cv_mem->cv_cvals, - cv_mem->cv_Xvecs, cv_mem->cv_Xvecs); + N_VScale(ONE, cv_mem->cv_acorQ, cv_mem->cv_ftempQ); } - cv_mem->cv_h = cv_mem->cv_hscale * cv_mem->cv_eta; - cv_mem->cv_next_h = cv_mem->cv_h; - cv_mem->cv_hscale = cv_mem->cv_h; - cv_mem->cv_nscon = 0; + N_VLinearSum(cv_mem->cv_h, cv_mem->cv_acorQ, -ONE, + cv_mem->cv_znQ[1], cv_mem->cv_acorQ); + N_VScale(cv_mem->cv_rl1, cv_mem->cv_acorQ, cv_mem->cv_acorQ); + + /* Apply correction to quadrature variables */ + N_VLinearSum(ONE, cv_mem->cv_znQ[0], ONE, cv_mem->cv_acorQ, cv_mem->cv_yQ); + return(CV_SUCCESS); } /* - * cvPredict + * cvQuadSensNls + * + * This routine solves for the quadrature sensitivity variables + * at the new step. It does not solve a nonlinear system, but + * rather updates the quadrature variables. The name for this + * function is just for uniformity purposes. + * + * Possible return values (interpreted by cvHandleNFlag) + * + * CV_SUCCESS -> continue with error test + * CV_QSRHSFUNC_FAIL -> halt the integration + * QSRHSFUNC_RECVR -> predict again or stop if too many * - * This routine advances tn by the tentative step size h, and computes - * the predicted array z_n(0), which is overwritten on zn. The - * prediction of zn is done by repeated additions. - * If tstop is enabled, it is possible for tn + h to be past tstop by roundoff, - * and in that case, we reset tn (after incrementing by h) to tstop. */ -static void cvPredict(CVodeMem cv_mem) +static int cvQuadSensNls(CVodeMem cv_mem) { - int j, k; - - cv_mem->cv_tn += cv_mem->cv_h; - if (cv_mem->cv_tstopset) { - if ((cv_mem->cv_tn - cv_mem->cv_tstop)*cv_mem->cv_h > ZERO) - cv_mem->cv_tn = cv_mem->cv_tstop; - } - - for (k = 1; k <= cv_mem->cv_q; k++) - for (j = cv_mem->cv_q; j >= k; j--) - N_VLinearSum(ONE, cv_mem->cv_zn[j-1], ONE, - cv_mem->cv_zn[j], cv_mem->cv_zn[j-1]); + int is, retval; - if (cv_mem->cv_quadr) { - for (k = 1; k <= cv_mem->cv_q; k++) - for (j = cv_mem->cv_q; j >= k; j--) - N_VLinearSum(ONE, cv_mem->cv_znQ[j-1], ONE, - cv_mem->cv_znQ[j], cv_mem->cv_znQ[j-1]); - } + /* Save quadrature correction in acorQ */ + retval = cv_mem->cv_fQS(cv_mem->cv_Ns, cv_mem->cv_tn, cv_mem->cv_y, + cv_mem->cv_yS, cv_mem->cv_ftempQ, + cv_mem->cv_acorQS, cv_mem->cv_user_data, + cv_mem->cv_tempv, cv_mem->cv_tempvQ); + cv_mem->cv_nfQSe++; + if (retval < 0) return(CV_QSRHSFUNC_FAIL); + if (retval > 0) return(QSRHSFUNC_RECVR); - if (cv_mem->cv_sensi) { - for (k = 1; k <= cv_mem->cv_q; k++) - for (j = cv_mem->cv_q; j >= k; j--) - (void) N_VLinearSumVectorArray(cv_mem->cv_Ns, - ONE, cv_mem->cv_znS[j-1], - ONE, cv_mem->cv_znS[j], - cv_mem->cv_znS[j-1]); - } - if (cv_mem->cv_quadr_sensi) { - for (k = 1; k <= cv_mem->cv_q; k++) - for (j = cv_mem->cv_q; j >= k; j--) - (void) N_VLinearSumVectorArray(cv_mem->cv_Ns, - ONE, cv_mem->cv_znQS[j-1], - ONE, cv_mem->cv_znQS[j], - cv_mem->cv_znQS[j-1]); + for (is=0; iscv_Ns; is++) { + N_VLinearSum(cv_mem->cv_h, cv_mem->cv_acorQS[is], -ONE, + cv_mem->cv_znQS[1][is], cv_mem->cv_acorQS[is]); + N_VScale(cv_mem->cv_rl1, cv_mem->cv_acorQS[is], cv_mem->cv_acorQS[is]); + /* Apply correction to quadrature sensitivity variables */ + N_VLinearSum(ONE, cv_mem->cv_znQS[0][is], ONE, + cv_mem->cv_acorQS[is], cv_mem->cv_yQS[is]); } + return(CV_SUCCESS); } + /* - * cvSet - * - * This routine is a high level routine which calls cvSetAdams or - * cvSetBDF to set the polynomial l, the test quantity array tq, - * and the related variables rl1, gamma, and gamrat. + * cvStgrNls * - * The array tq is loaded with constants used in the control of estimated - * local errors and in the nonlinear convergence test. Specifically, while - * running at order q, the components of tq are as follows: - * tq[1] = a coefficient used to get the est. local error at order q-1 - * tq[2] = a coefficient used to get the est. local error at order q - * tq[3] = a coefficient used to get the est. local error at order q+1 - * tq[4] = constant used in nonlinear iteration convergence test - * tq[5] = coefficient used to get the order q+2 derivative vector used in - * the est. local error at order q+1 + * This is a high-level routine that attempts to solve the + * sensitivity linear systems using the attached nonlinear solver + * once the states y_n were obtained and passed the error test. */ -static void cvSet(CVodeMem cv_mem) +static int cvStgrNls(CVodeMem cv_mem) { - switch(cv_mem->cv_lmm) { - case CV_ADAMS: - cvSetAdams(cv_mem); - break; - case CV_BDF: - cvSetBDF(cv_mem); - break; - } - cv_mem->cv_rl1 = ONE / cv_mem->cv_l[1]; - cv_mem->cv_gamma = cv_mem->cv_h * cv_mem->cv_rl1; - if (cv_mem->cv_nst == 0) cv_mem->cv_gammap = cv_mem->cv_gamma; - cv_mem->cv_gamrat = (cv_mem->cv_nst > 0) ? - cv_mem->cv_gamma / cv_mem->cv_gammap : ONE; /* protect x / x != 1.0 */ -} + booleantype callSetup; + int flag=CV_SUCCESS; -/* - * cvSetAdams - * - * This routine handles the computation of l and tq for the - * case lmm == CV_ADAMS. - * - * The components of the array l are the coefficients of a - * polynomial Lambda(x) = l_0 + l_1 x + ... + l_q x^q, given by - * q-1 - * (d/dx) Lambda(x) = c * PRODUCT (1 + x / xi_i) , where - * i=1 - * Lambda(-1) = 0, Lambda(0) = 1, and c is a normalization factor. - * Here xi_i = [t_n - t_(n-i)] / h. - * - * The array tq is set to test quantities used in the convergence - * test, the error test, and the selection of h at a new order. - */ + callSetup = SUNFALSE; + if (cv_mem->cv_lsetup == NULL) + cv_mem->cv_crateS = ONE; -static void cvSetAdams(CVodeMem cv_mem) -{ - realtype m[L_MAX], M[3], hsum; - - if (cv_mem->cv_q == 1) { - cv_mem->cv_l[0] = cv_mem->cv_l[1] = cv_mem->cv_tq[1] = cv_mem->cv_tq[5] = ONE; - cv_mem->cv_tq[2] = HALF; - cv_mem->cv_tq[3] = ONE/TWELVE; - cv_mem->cv_tq[4] = cv_mem->cv_nlscoef / cv_mem->cv_tq[2]; /* = 0.1 / tq[2] */ - return; - } - - hsum = cvAdamsStart(cv_mem, m); - - M[0] = cvAltSum(cv_mem->cv_q-1, m, 1); - M[1] = cvAltSum(cv_mem->cv_q-1, m, 2); - - cvAdamsFinish(cv_mem, m, M, hsum); + /* initial guess for the correction to the predictor */ + N_VConst(ZERO, cv_mem->ycorStg); + + /* set sens solve flag */ + cv_mem->sens_solve = SUNTRUE; + + /* solve the nonlinear system */ + flag = SUNNonlinSolSolve(cv_mem->NLSstg, cv_mem->zn0Stg, cv_mem->ycorStg, + cv_mem->ewtStg, cv_mem->cv_tq[4], callSetup, cv_mem); + + /* reset sens solve flag */ + cv_mem->sens_solve = SUNFALSE; + + /* if the solve failed return */ + if (flag != CV_SUCCESS) return(flag); + + /* solve successful */ + + /* update the sensitivities based on the final correction from the nonlinear solver */ + N_VLinearSumVectorArray(cv_mem->cv_Ns, + ONE, cv_mem->cv_znS[0], + ONE, cv_mem->cv_acorS, cv_mem->cv_yS); + + /* update Jacobian status */ + cv_mem->cv_jcur = SUNFALSE; + + return(flag); } /* - * cvAdamsStart + * cvStgr1Nls * - * This routine generates in m[] the coefficients of the product - * polynomial needed for the Adams l and tq coefficients for q > 1. + * This is a high-level routine that attempts to solve the i-th + * sensitivity linear system using the attached nonlinear solver + * once the states y_n were obtained and passed the error test. */ -static realtype cvAdamsStart(CVodeMem cv_mem, realtype m[]) +static int cvStgr1Nls(CVodeMem cv_mem, int is) { - realtype hsum, xi_inv, sum; - int i, j; - - hsum = cv_mem->cv_h; - m[0] = ONE; - for (i=1; i <= cv_mem->cv_q; i++) m[i] = ZERO; - for (j=1; j < cv_mem->cv_q; j++) { - if ((j==cv_mem->cv_q-1) && (cv_mem->cv_qwait == 1)) { - sum = cvAltSum(cv_mem->cv_q-2, m, 2); - cv_mem->cv_tq[1] = cv_mem->cv_q * sum / m[cv_mem->cv_q-2]; - } - xi_inv = cv_mem->cv_h / hsum; - for (i=j; i >= 1; i--) - m[i] += m[i-1] * xi_inv; - hsum += cv_mem->cv_tau[j]; - /* The m[i] are coefficients of product(1 to j) (1 + x/xi_i) */ - } - return(hsum); -} - -/* - * cvAdamsFinish - * - * This routine completes the calculation of the Adams l and tq. - */ + booleantype callSetup; + long int nni; + int flag=CV_SUCCESS; -static void cvAdamsFinish(CVodeMem cv_mem, realtype m[], realtype M[], realtype hsum) -{ - int i; - realtype M0_inv, xi, xi_inv; - - M0_inv = ONE / M[0]; - - cv_mem->cv_l[0] = ONE; - for (i=1; i <= cv_mem->cv_q; i++) - cv_mem->cv_l[i] = M0_inv * (m[i-1] / i); - xi = hsum / cv_mem->cv_h; - xi_inv = ONE / xi; - - cv_mem->cv_tq[2] = M[1] * M0_inv / xi; - cv_mem->cv_tq[5] = xi / cv_mem->cv_l[cv_mem->cv_q]; + callSetup = SUNFALSE; + if (cv_mem->cv_lsetup == NULL) + cv_mem->cv_crateS = ONE; - if (cv_mem->cv_qwait == 1) { - for (i=cv_mem->cv_q; i >= 1; i--) - m[i] += m[i-1] * xi_inv; - M[2] = cvAltSum(cv_mem->cv_q, m, 2); - cv_mem->cv_tq[3] = M[2] * M0_inv / cv_mem->cv_L; - } + /* initial guess for the correction to the predictor */ + N_VConst(ZERO, cv_mem->cv_acorS[is]); - cv_mem->cv_tq[4] = cv_mem->cv_nlscoef / cv_mem->cv_tq[2]; -} + /* set sens solve flag */ + cv_mem->sens_solve = SUNTRUE; -/* - * cvAltSum - * - * cvAltSum returns the value of the alternating sum - * sum (i= 0 ... iend) [ (-1)^i * (a[i] / (i + k)) ]. - * If iend < 0 then cvAltSum returns 0. - * This operation is needed to compute the integral, from -1 to 0, - * of a polynomial x^(k-1) M(x) given the coefficients of M(x). - */ + /* solve the nonlinear system */ + flag = SUNNonlinSolSolve(cv_mem->NLSstg1, + cv_mem->cv_znS[0][is], cv_mem->cv_acorS[is], + cv_mem->cv_ewtS[is], cv_mem->cv_tq[4], callSetup, cv_mem); -static realtype cvAltSum(int iend, realtype a[], int k) -{ - int i, sign; - realtype sum; - - if (iend < 0) return(ZERO); - - sum = ZERO; - sign = 1; - for (i=0; i <= iend; i++) { - sum += sign * (a[i] / (i+k)); - sign = -sign; - } - return(sum); + /* reset sens solve flag */ + cv_mem->sens_solve = SUNFALSE; + + /* update nniS iteration count */ + (void) SUNNonlinSolGetNumIters(cv_mem->NLSstg1, &nni); + cv_mem->cv_nniS1[is] += nni - cv_mem->nnip; + cv_mem->nnip = nni; + + /* if the solve failed return */ + if (flag != CV_SUCCESS) return(flag); + + /* solve successful */ + + /* update the sensitivity with the final correction from the nonlinear solver */ + N_VLinearSum(ONE, cv_mem->cv_znS[0][is], + ONE, cv_mem->cv_acorS[is], cv_mem->cv_yS[is]); + + /* update Jacobian status */ + cv_mem->cv_jcur = SUNFALSE; + + return(flag); } /* - * cvSetBDF + * cvHandleNFlag * - * This routine computes the coefficients l and tq in the case - * lmm == CV_BDF. cvSetBDF calls cvSetTqBDF to set the test - * quantity array tq. - * - * The components of the array l are the coefficients of a - * polynomial Lambda(x) = l_0 + l_1 x + ... + l_q x^q, given by - * q-1 - * Lambda(x) = (1 + x / xi*_q) * PRODUCT (1 + x / xi_i) , where - * i=1 - * xi_i = [t_n - t_(n-i)] / h. + * This routine takes action on the return value nflag = *nflagPtr + * returned by cvNls, as follows: + * + * If cvNls succeeded in solving the nonlinear system, then + * cvHandleNFlag returns the constant DO_ERROR_TEST, which tells cvStep + * to perform the error test. + * + * If the nonlinear system was not solved successfully, then ncfn and + * ncf = *ncfPtr are incremented and Nordsieck array zn is restored. + * + * If the solution of the nonlinear system failed due to an + * unrecoverable failure by setup, we return the value CV_LSETUP_FAIL. + * + * If it failed due to an unrecoverable failure in solve, then we return + * the value CV_LSOLVE_FAIL. + * + * If it failed due to an unrecoverable failure in rhs, then we return + * the value CV_RHSFUNC_FAIL. + * + * If it failed due to an unrecoverable failure in quad rhs, then we return + * the value CV_QRHSFUNC_FAIL. + * + * If it failed due to an unrecoverable failure in sensi rhs, then we return + * the value CV_SRHSFUNC_FAIL. + * + * If it failed due to an unrecoverable failure in sensi quad rhs, then we + * return the value CV_QSRHSFUNC_FAIL. + * + * Otherwise, a recoverable failure occurred when solving the nonlinear system + * (cvNls returned SUN_NLS_CONV_RECVR, RHSFUNC_RECVR, or SRHSFUNC_RECVR). + * + * If ncf is now equal to maxncf or |h| = hmin, we return the value + * CV_CONV_FAILURE (if SUN_NLS_CONV_RECVR), + * CV_REPTD_RHSFUNC_ERR (if RHSFUNC_RECVR), or + * CV_REPTD_SRHSFUNC_ERR (if SRHSFUNC_RECVR). + * Otherwise, we set *nflagPtr = PREV_CONV_FAIL and return the value + * PREDICT_AGAIN, telling cvStep to reattempt the step. * - * The array tq is set to test quantities used in the convergence - * test, the error test, and the selection of h at a new order. */ -static void cvSetBDF(CVodeMem cv_mem) +static int cvHandleNFlag(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, + int *ncfPtr, long int *ncfnPtr) { - realtype alpha0, alpha0_hat, xi_inv, xistar_inv, hsum; - int i,j; - - cv_mem->cv_l[0] = cv_mem->cv_l[1] = xi_inv = xistar_inv = ONE; - for (i=2; i <= cv_mem->cv_q; i++) cv_mem->cv_l[i] = ZERO; - alpha0 = alpha0_hat = -ONE; - hsum = cv_mem->cv_h; - if (cv_mem->cv_q > 1) { - for (j=2; j < cv_mem->cv_q; j++) { - hsum += cv_mem->cv_tau[j-1]; - xi_inv = cv_mem->cv_h / hsum; - alpha0 -= ONE / j; - for (i=j; i >= 1; i--) - cv_mem->cv_l[i] += cv_mem->cv_l[i-1]*xi_inv; - /* The l[i] are coefficients of product(1 to j) (1 + x/xi_i) */ - } - - /* j = q */ - alpha0 -= ONE / cv_mem->cv_q; - xistar_inv = -cv_mem->cv_l[1] - alpha0; - hsum += cv_mem->cv_tau[cv_mem->cv_q-1]; - xi_inv = cv_mem->cv_h / hsum; - alpha0_hat = -cv_mem->cv_l[1] - xi_inv; - for (i=cv_mem->cv_q; i >= 1; i--) - cv_mem->cv_l[i] += cv_mem->cv_l[i-1]*xistar_inv; + int nflag; + + nflag = *nflagPtr; + + if (nflag == CV_SUCCESS) return(DO_ERROR_TEST); + + /* The nonlinear soln. failed; increment ncfn and restore zn */ + (*ncfnPtr)++; + cvRestore(cv_mem, saved_t); + + /* Return if failed unrecoverably */ + if (nflag < 0) { + if (nflag == CV_LSETUP_FAIL) return(CV_LSETUP_FAIL); + else if (nflag == CV_LSOLVE_FAIL) return(CV_LSOLVE_FAIL); + else if (nflag == CV_RHSFUNC_FAIL) return(CV_RHSFUNC_FAIL); + else if (nflag == CV_QRHSFUNC_FAIL) return(CV_QRHSFUNC_FAIL); + else if (nflag == CV_SRHSFUNC_FAIL) return(CV_SRHSFUNC_FAIL); + else if (nflag == CV_QSRHSFUNC_FAIL) return(CV_QSRHSFUNC_FAIL); + else return(CV_NLS_FAIL); } - cvSetTqBDF(cv_mem, hsum, alpha0, alpha0_hat, xi_inv, xistar_inv); + /* At this point, a recoverable error occured. */ + + (*ncfPtr)++; + cv_mem->cv_etamax = ONE; + + /* If we had maxncf failures or |h| = hmin, return failure. */ + + if ((SUNRabs(cv_mem->cv_h) <= cv_mem->cv_hmin*ONEPSM) || + (*ncfPtr == cv_mem->cv_maxncf)) { + if (nflag == SUN_NLS_CONV_RECVR) return(CV_CONV_FAILURE); + if (nflag == CONSTR_RECVR) return(CV_CONSTR_FAIL); + if (nflag == RHSFUNC_RECVR) return(CV_REPTD_RHSFUNC_ERR); + if (nflag == QRHSFUNC_RECVR) return(CV_REPTD_QRHSFUNC_ERR); + if (nflag == SRHSFUNC_RECVR) return(CV_REPTD_SRHSFUNC_ERR); + if (nflag == QSRHSFUNC_RECVR) return(CV_REPTD_QSRHSFUNC_ERR); + } + + /* Reduce step size; return to reattempt the step + Note that if nflag = CONSTR_RECVR, then eta was already set in cvCheckConstraints */ + if (nflag != CONSTR_RECVR) + cv_mem->cv_eta = SUNMAX(ETACF, cv_mem->cv_hmin / SUNRabs(cv_mem->cv_h)); + *nflagPtr = PREV_CONV_FAIL; + cvRescale(cv_mem); + + return(PREDICT_AGAIN); } /* - * cvSetTqBDF + * cvRestore * - * This routine sets the test quantity array tq in the case - * lmm == CV_BDF. + * This routine restores the value of tn to saved_t and undoes the + * prediction. After execution of cvRestore, the Nordsieck array zn has + * the same values as before the call to cvPredict. */ -static void cvSetTqBDF(CVodeMem cv_mem, realtype hsum, realtype alpha0, - realtype alpha0_hat, realtype xi_inv, realtype xistar_inv) +static void cvRestore(CVodeMem cv_mem, realtype saved_t) { - realtype A1, A2, A3, A4, A5, A6; - realtype C, Cpinv, Cppinv; - - A1 = ONE - alpha0_hat + alpha0; - A2 = ONE + cv_mem->cv_q * A1; - cv_mem->cv_tq[2] = SUNRabs(A1 / (alpha0 * A2)); - cv_mem->cv_tq[5] = SUNRabs(A2 * xistar_inv / (cv_mem->cv_l[cv_mem->cv_q] * xi_inv)); - if (cv_mem->cv_qwait == 1) { - if (cv_mem->cv_q > 1) { - C = xistar_inv / cv_mem->cv_l[cv_mem->cv_q]; - A3 = alpha0 + ONE / cv_mem->cv_q; - A4 = alpha0_hat + xi_inv; - Cpinv = (ONE - A4 + A3) / A3; - cv_mem->cv_tq[1] = SUNRabs(C * Cpinv); - } - else cv_mem->cv_tq[1] = ONE; - hsum += cv_mem->cv_tau[cv_mem->cv_q]; - xi_inv = cv_mem->cv_h / hsum; - A5 = alpha0 - (ONE / (cv_mem->cv_q+1)); - A6 = alpha0_hat - xi_inv; - Cppinv = (ONE - A6 + A5) / A2; - cv_mem->cv_tq[3] = SUNRabs(Cppinv / (xi_inv * (cv_mem->cv_q+2) * A5)); + int j, k; + + cv_mem->cv_tn = saved_t; + for (k = 1; k <= cv_mem->cv_q; k++) + for (j = cv_mem->cv_q; j >= k; j--) + N_VLinearSum(ONE, cv_mem->cv_zn[j-1], -ONE, + cv_mem->cv_zn[j], cv_mem->cv_zn[j-1]); + + if (cv_mem->cv_quadr) { + for (k = 1; k <= cv_mem->cv_q; k++) + for (j = cv_mem->cv_q; j >= k; j--) + N_VLinearSum(ONE, cv_mem->cv_znQ[j-1], -ONE, + cv_mem->cv_znQ[j], cv_mem->cv_znQ[j-1]); + } + + if (cv_mem->cv_sensi) { + for (k = 1; k <= cv_mem->cv_q; k++) + for (j = cv_mem->cv_q; j >= k; j--) + (void) N_VLinearSumVectorArray(cv_mem->cv_Ns, + ONE, cv_mem->cv_znS[j-1], + -ONE, cv_mem->cv_znS[j], + cv_mem->cv_znS[j-1]); + } + + if (cv_mem->cv_quadr_sensi) { + for (k = 1; k <= cv_mem->cv_q; k++) + for (j = cv_mem->cv_q; j >= k; j--) + (void) N_VLinearSumVectorArray(cv_mem->cv_Ns, + ONE, cv_mem->cv_znQS[j-1], + -ONE, cv_mem->cv_znQS[j], + cv_mem->cv_znQS[j-1]); } - cv_mem->cv_tq[4] = cv_mem->cv_nlscoef / cv_mem->cv_tq[2]; } -/* +/* * ----------------------------------------------------------------- - * Nonlinear solver functions + * Error Test * ----------------------------------------------------------------- */ /* - * cvNls + * cvDoErrorTest + * + * This routine performs the local error test, for the state, quadrature, + * or sensitivity variables. Its last three arguments change depending + * on which variables the error test is to be performed on. + * + * The weighted local error norm dsm is loaded into *dsmPtr, and + * the test dsm ?<= 1 is made. + * + * If the test passes, cvDoErrorTest returns CV_SUCCESS. + * + * If the test fails, we undo the step just taken (call cvRestore) and + * + * - if maxnef error test failures have occurred or if SUNRabs(h) = hmin, + * we return CV_ERR_FAILURE. + * + * - if more than MXNEF1 error test failures have occurred, an order + * reduction is forced. If already at order 1, restart by reloading + * zn from scratch (also znQ and znS if appropriate). + * If f() fails, we return CV_RHSFUNC_FAIL or CV_UNREC_RHSFUNC_ERR; + * if fQ() fails, we return CV_QRHSFUNC_FAIL or CV_UNREC_QRHSFUNC_ERR; + * if cvSensRhsWrapper() fails, we return CV_SRHSFUNC_FAIL or CV_UNREC_SRHSFUNC_ERR; + * (no recovery is possible at this stage). + * + * - otherwise, set *nflagPtr to PREV_ERR_FAIL, and return TRY_AGAIN. * - * This routine attempts to solve the nonlinear system associated - * with a single implicit step of the linear multistep method. */ -static int cvNls(CVodeMem cv_mem, int nflag) -{ - int flag = CV_SUCCESS; - booleantype callSetup; - booleantype do_sensi_sim; - - /* Are we computing sensitivities with the CV_SIMULTANEOUS approach? */ - do_sensi_sim = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_SIMULTANEOUS)); +static int cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, + realtype acor_nrm, + int *nefPtr, long int *netfPtr, realtype *dsmPtr) +{ + realtype dsm; + int retval, is; + N_Vector wrk1, wrk2; - /* Decide whether or not to call setup routine (if one exists) and */ - /* set flag convfail (input to lsetup for its evaluation decision) */ - if (cv_mem->cv_lsetup) { - cv_mem->convfail = ((nflag == FIRST_CALL) || (nflag == PREV_ERR_FAIL)) ? - CV_NO_FAILURES : CV_FAIL_OTHER; + dsm = acor_nrm * cv_mem->cv_tq[2]; - callSetup = (nflag == PREV_CONV_FAIL) || (nflag == PREV_ERR_FAIL) || - (cv_mem->cv_nst == 0) || - (cv_mem->cv_nst >= cv_mem->cv_nstlp + MSBP) || - (SUNRabs(cv_mem->cv_gamrat-ONE) > DGMAX); + /* If est. local error norm dsm passes test, return CV_SUCCESS */ + *dsmPtr = dsm; + if (dsm <= ONE) return(CV_SUCCESS); - /* Decide whether to force a call to setup */ - if (cv_mem->cv_forceSetup) { - callSetup = SUNTRUE; - cv_mem->convfail = CV_FAIL_OTHER; - } - } else { - cv_mem->cv_crate = ONE; - cv_mem->cv_crateS = ONE; /* if NO lsetup all conv. rates are set to ONE */ - callSetup = SUNFALSE; - } + /* Test failed; increment counters, set nflag, and restore zn array */ + (*nefPtr)++; + (*netfPtr)++; + *nflagPtr = PREV_ERR_FAIL; + cvRestore(cv_mem, saved_t); - /* initial guess for the correction to the predictor */ - if (do_sensi_sim) - N_VConst(ZERO, cv_mem->ycor0Sim); - else - N_VConst(ZERO, cv_mem->cv_tempv); + /* At maxnef failures or |h| = hmin, return CV_ERR_FAILURE */ + if ((SUNRabs(cv_mem->cv_h) <= cv_mem->cv_hmin*ONEPSM) || + (*nefPtr == cv_mem->cv_maxnef)) + return(CV_ERR_FAILURE); - /* call nonlinear solver setup if it exists */ - if ((cv_mem->NLS)->ops->setup) { - if (do_sensi_sim) - flag = SUNNonlinSolSetup(cv_mem->NLS, cv_mem->ycor0Sim, cv_mem); - else - flag = SUNNonlinSolSetup(cv_mem->NLS, cv_mem->cv_tempv, cv_mem); + /* Set etamax = 1 to prevent step size increase at end of this step */ + cv_mem->cv_etamax = ONE; - if (flag < 0) return(CV_NLS_SETUP_FAIL); - if (flag > 0) return(SUN_NLS_CONV_RECVR); + /* Set h ratio eta from dsm, rescale, and return for retry of step */ + if (*nefPtr <= MXNEF1) { + cv_mem->cv_eta = ONE / (SUNRpowerR(BIAS2*dsm,ONE/cv_mem->cv_L) + ADDON); + cv_mem->cv_eta = SUNMAX(ETAMIN, SUNMAX(cv_mem->cv_eta, + cv_mem->cv_hmin / SUNRabs(cv_mem->cv_h))); + if (*nefPtr >= SMALL_NEF) cv_mem->cv_eta = SUNMIN(cv_mem->cv_eta, ETAMXF); + cvRescale(cv_mem); + return(TRY_AGAIN); } - /* solve the nonlinear system */ - if (do_sensi_sim) - flag = SUNNonlinSolSolve(cv_mem->NLSsim, cv_mem->ycor0Sim, cv_mem->ycorSim, - cv_mem->ewtSim, cv_mem->cv_tq[4], callSetup, cv_mem); - else - flag = SUNNonlinSolSolve(cv_mem->NLS, cv_mem->cv_tempv, cv_mem->cv_acor, - cv_mem->cv_ewt, cv_mem->cv_tq[4], callSetup, cv_mem); - - /* update the state based on the final correction from the nonlinear solver */ - N_VLinearSum(ONE, cv_mem->cv_zn[0], ONE, cv_mem->cv_acor, cv_mem->cv_y); - - /* update the sensitivities based on the final correction from the nonlinear solver */ - if (do_sensi_sim) { - N_VLinearSumVectorArray(cv_mem->cv_Ns, - ONE, cv_mem->cv_znS[0], - ONE, cv_mem->cv_acorS, cv_mem->cv_yS); + /* After MXNEF1 failures, force an order reduction and retry step */ + if (cv_mem->cv_q > 1) { + cv_mem->cv_eta = SUNMAX(ETAMIN, cv_mem->cv_hmin / SUNRabs(cv_mem->cv_h)); + cvAdjustOrder(cv_mem,-1); + cv_mem->cv_L = cv_mem->cv_q; + cv_mem->cv_q--; + cv_mem->cv_qwait = cv_mem->cv_L; + cvRescale(cv_mem); + return(TRY_AGAIN); } - /* if the solve failed return */ - if (flag != CV_SUCCESS) return(flag); - - /* solve successful, update Jacobian status and check constraints */ - cv_mem->cv_jcur = SUNFALSE; + /* If already at order 1, restart: reload zn, znQ, znS, znQS from scratch */ - if (cv_mem->cv_constraintsSet) - flag = cvCheckConstraints(cv_mem); + cv_mem->cv_eta = SUNMAX(ETAMIN, cv_mem->cv_hmin / SUNRabs(cv_mem->cv_h)); + cv_mem->cv_h *= cv_mem->cv_eta; + cv_mem->cv_next_h = cv_mem->cv_h; + cv_mem->cv_hscale = cv_mem->cv_h; + cv_mem->cv_qwait = LONG_WAIT; + cv_mem->cv_nscon = 0; - return(flag); + retval = cv_mem->cv_f(cv_mem->cv_tn, cv_mem->cv_zn[0], + cv_mem->cv_tempv, cv_mem->cv_user_data); + cv_mem->cv_nfe++; + if (retval < 0) return(CV_RHSFUNC_FAIL); + if (retval > 0) return(CV_UNREC_RHSFUNC_ERR); -} + N_VScale(cv_mem->cv_h, cv_mem->cv_tempv, cv_mem->cv_zn[1]); -/* - * cvCheckConstraints - * - * This routine determines if the constraints of the problem - * are satisfied by the proposed step - * - * Possible return values are: - * - * CV_SUCCESS ---> allows stepping forward - * - * CONSTR_RECVR ---> values failed to satisfy constraints - */ + if (cv_mem->cv_quadr) { -static int cvCheckConstraints(CVodeMem cv_mem) -{ - booleantype constraintsPassed; - realtype vnorm; - cv_mem->cv_mm = cv_mem->cv_ftemp; + retval = cv_mem->cv_fQ(cv_mem->cv_tn, cv_mem->cv_zn[0], + cv_mem->cv_tempvQ, cv_mem->cv_user_data); + cv_mem->cv_nfQe++; + if (retval < 0) return(CV_QRHSFUNC_FAIL); + if (retval > 0) return(CV_UNREC_QRHSFUNC_ERR); - /* Get mask vector mm, set where constraints failed */ + N_VScale(cv_mem->cv_h, cv_mem->cv_tempvQ, cv_mem->cv_znQ[1]); - constraintsPassed = N_VConstrMask(cv_mem->cv_constraints, - cv_mem->cv_y, cv_mem->cv_mm); - if (constraintsPassed) return(CV_SUCCESS); - else { - N_VCompare(ONEPT5, cv_mem->cv_constraints, cv_mem->cv_tempv); - /* a, where a[i]=1 when |c[i]|=2; c the vector of constraints */ - N_VProd(cv_mem->cv_tempv, cv_mem->cv_constraints, - cv_mem->cv_tempv); /* a * c */ - N_VDiv(cv_mem->cv_tempv, cv_mem->cv_ewt, - cv_mem->cv_tempv); /* a * c * wt */ - N_VLinearSum(ONE, cv_mem->cv_y, -PT1, - cv_mem->cv_tempv, cv_mem->cv_tempv); /* y - 0.1 * a * c * wt */ - N_VProd(cv_mem->cv_tempv, cv_mem->cv_mm, - cv_mem->cv_tempv); /* v = mm*(y-0.1*a*c*wt) */ - - vnorm = N_VWrmsNorm(cv_mem->cv_tempv, cv_mem->cv_ewt); /* ||v|| */ - - /* If vector v of constraint corrections is small in - norm, correct and accept this step */ - if (vnorm <= cv_mem->cv_tq[4]) { - N_VLinearSum(ONE, cv_mem->cv_acor, -ONE, - cv_mem->cv_tempv, cv_mem->cv_acor); /* acor <- acor - v */ - return(CV_SUCCESS); - } - else { - /* Constraints not met - reduce h by computing eta = h'/h */ - N_VLinearSum(ONE, cv_mem->cv_zn[0], -ONE, cv_mem->cv_y, cv_mem->cv_tempv); - N_VProd(cv_mem->cv_mm, cv_mem->cv_tempv, cv_mem->cv_tempv); - cv_mem->cv_eta = PT9*N_VMinQuotient(cv_mem->cv_zn[0], cv_mem->cv_tempv); - cv_mem->cv_eta = SUNMAX(cv_mem->cv_eta, PT1); - return(CONSTR_RECVR); - } } - return(CV_SUCCESS); -} - -/* - * cvQuadNls - * - * This routine solves for the quadrature variables at the new step. - * It does not solve a nonlinear system, but rather updates the - * quadrature variables. The name for this function is just for - * uniformity purposes. - * - * Possible return values (interpreted by cvHandleNFlag) - * - * CV_SUCCESS -> continue with error test - * CV_QRHSFUNC_FAIL -> halt the integration - * QRHSFUNC_RECVR -> predict again or stop if too many - * - */ - -static int cvQuadNls(CVodeMem cv_mem) -{ - int retval; - /* Save quadrature correction in acorQ */ - retval = cv_mem->cv_fQ(cv_mem->cv_tn, cv_mem->cv_y, - cv_mem->cv_acorQ, cv_mem->cv_user_data); - cv_mem->cv_nfQe++; - if (retval < 0) return(CV_QRHSFUNC_FAIL); - if (retval > 0) return(QRHSFUNC_RECVR); + if (cv_mem->cv_sensi) { - /* If needed, save the value of yQdot = fQ into ftempQ - * for use in evaluating fQS */ - if (cv_mem->cv_quadr_sensi) { - N_VScale(ONE, cv_mem->cv_acorQ, cv_mem->cv_ftempQ); - } + wrk1 = cv_mem->cv_ftemp; + wrk2 = cv_mem->cv_ftempS[0]; - N_VLinearSum(cv_mem->cv_h, cv_mem->cv_acorQ, -ONE, - cv_mem->cv_znQ[1], cv_mem->cv_acorQ); - N_VScale(cv_mem->cv_rl1, cv_mem->cv_acorQ, cv_mem->cv_acorQ); + retval = cvSensRhsWrapper(cv_mem, cv_mem->cv_tn, cv_mem->cv_zn[0], + cv_mem->cv_tempv, cv_mem->cv_znS[0], + cv_mem->cv_tempvS, wrk1, wrk2); + if (retval < 0) return(CV_SRHSFUNC_FAIL); + if (retval > 0) return(CV_UNREC_SRHSFUNC_ERR); - /* Apply correction to quadrature variables */ - N_VLinearSum(ONE, cv_mem->cv_znQ[0], ONE, cv_mem->cv_acorQ, cv_mem->cv_yQ); + for (is=0; iscv_Ns; is++) + cv_mem->cv_cvals[is] = cv_mem->cv_h; - return(CV_SUCCESS); -} + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_tempvS, cv_mem->cv_znS[1]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } -/* - * cvQuadSensNls - * - * This routine solves for the quadrature sensitivity variables - * at the new step. It does not solve a nonlinear system, but - * rather updates the quadrature variables. The name for this - * function is just for uniformity purposes. - * - * Possible return values (interpreted by cvHandleNFlag) - * - * CV_SUCCESS -> continue with error test - * CV_QSRHSFUNC_FAIL -> halt the integration - * QSRHSFUNC_RECVR -> predict again or stop if too many - * - */ + if (cv_mem->cv_quadr_sensi) { -static int cvQuadSensNls(CVodeMem cv_mem) -{ - int is, retval; + wrk1 = cv_mem->cv_ftemp; + wrk2 = cv_mem->cv_ftempQ; - /* Save quadrature correction in acorQ */ - retval = cv_mem->cv_fQS(cv_mem->cv_Ns, cv_mem->cv_tn, cv_mem->cv_y, - cv_mem->cv_yS, cv_mem->cv_ftempQ, - cv_mem->cv_acorQS, cv_mem->cv_user_data, - cv_mem->cv_tempv, cv_mem->cv_tempvQ); - cv_mem->cv_nfQSe++; - if (retval < 0) return(CV_QSRHSFUNC_FAIL); - if (retval > 0) return(QSRHSFUNC_RECVR); + retval = cv_mem->cv_fQS(cv_mem->cv_Ns, cv_mem->cv_tn, + cv_mem->cv_zn[0], cv_mem->cv_znS[0], + cv_mem->cv_tempvQ, cv_mem->cv_tempvQS, + cv_mem->cv_fQS_data, wrk1, wrk2); + cv_mem->cv_nfQSe++; + if (retval < 0) return(CV_QSRHSFUNC_FAIL); + if (retval > 0) return(CV_UNREC_QSRHSFUNC_ERR); + for (is=0; iscv_Ns; is++) + cv_mem->cv_cvals[is] = cv_mem->cv_h; - for (is=0; iscv_Ns; is++) { - N_VLinearSum(cv_mem->cv_h, cv_mem->cv_acorQS[is], -ONE, - cv_mem->cv_znQS[1][is], cv_mem->cv_acorQS[is]); - N_VScale(cv_mem->cv_rl1, cv_mem->cv_acorQS[is], cv_mem->cv_acorQS[is]); - /* Apply correction to quadrature sensitivity variables */ - N_VLinearSum(ONE, cv_mem->cv_znQS[0][is], ONE, - cv_mem->cv_acorQS[is], cv_mem->cv_yQS[is]); + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_tempvQS, cv_mem->cv_znQS[1]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); } - return(CV_SUCCESS); + return(TRY_AGAIN); } +/* + * ----------------------------------------------------------------- + * Functions called after a successful step + * ----------------------------------------------------------------- + */ /* - * cvStgrNls + * cvCompleteStep * - * This is a high-level routine that attempts to solve the - * sensitivity linear systems using the attached nonlinear solver - * once the states y_n were obtained and passed the error test. + * This routine performs various update operations when the solution + * to the nonlinear system has passed the local error test. + * We increment the step counter nst, record the values hu and qu, + * update the tau array, and apply the corrections to the zn array. + * The tau[i] are the last q values of h, with tau[1] the most recent. + * The counter qwait is decremented, and if qwait == 1 (and q < qmax) + * we save acor and tq[5] for a possible order increase. */ -static int cvStgrNls(CVodeMem cv_mem) +static void cvCompleteStep(CVodeMem cv_mem) { - booleantype callSetup; - int flag=CV_SUCCESS; - - cv_mem->sens_solve = SUNTRUE; + int i; + int is; - callSetup = SUNFALSE; - if (cv_mem->cv_lsetup == NULL) - cv_mem->cv_crateS = ONE; + cv_mem->cv_nst++; + cv_mem->cv_nscon++; + cv_mem->cv_hu = cv_mem->cv_h; + cv_mem->cv_qu = cv_mem->cv_q; - /* initial guess for the correction to the predictor */ - N_VConst(ZERO, cv_mem->ycor0Stg); + for (i=cv_mem->cv_q; i >= 2; i--) cv_mem->cv_tau[i] = cv_mem->cv_tau[i-1]; + if ((cv_mem->cv_q==1) && (cv_mem->cv_nst > 1)) + cv_mem->cv_tau[2] = cv_mem->cv_tau[1]; + cv_mem->cv_tau[1] = cv_mem->cv_h; - /* solve the nonlinear system */ - flag = SUNNonlinSolSolve(cv_mem->NLSstg, cv_mem->ycor0Stg, cv_mem->ycorStg, - cv_mem->ewtStg, cv_mem->cv_tq[4], callSetup, cv_mem); + /* Apply correction to column j of zn: l_j * Delta_n */ + (void) N_VScaleAddMulti(cv_mem->cv_q+1, cv_mem->cv_l, cv_mem->cv_acor, + cv_mem->cv_zn, cv_mem->cv_zn); - /* update the sensitivities based on the final correction from the nonlinear solver */ - N_VLinearSumVectorArray(cv_mem->cv_Ns, - ONE, cv_mem->cv_znS[0], - ONE, cv_mem->cv_acorS, cv_mem->cv_yS); + if (cv_mem->cv_quadr) + (void) N_VScaleAddMulti(cv_mem->cv_q+1, cv_mem->cv_l, cv_mem->cv_acorQ, + cv_mem->cv_znQ, cv_mem->cv_znQ); - /* if the solve is successful, update Jacobian status */ - if (flag == CV_SUCCESS) cv_mem->cv_jcur = SUNFALSE; + if (cv_mem->cv_sensi) + (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q+1, + cv_mem->cv_l, cv_mem->cv_acorS, + cv_mem->cv_znS, cv_mem->cv_znS); - cv_mem->sens_solve = SUNFALSE; + if (cv_mem->cv_quadr_sensi) + (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q+1, + cv_mem->cv_l, cv_mem->cv_acorQS, + cv_mem->cv_znQS, cv_mem->cv_znQS); - return(flag); + /* If necessary, store Delta_n in zn[qmax] to be used in order increase. + * This actually will be Delta_{n-1} in the ELTE at q+1 since it happens at + * the next to last step of order q before a possible one at order q+1 + */ -} + cv_mem->cv_qwait--; + if ((cv_mem->cv_qwait == 1) && (cv_mem->cv_q != cv_mem->cv_qmax)) { -/* - * cvStgr1Nls - * - * This is a high-level routine that attempts to solve the i-th - * sensitivity linear system using the attached nonlinear solver - * once the states y_n were obtained and passed the error test. - */ + N_VScale(ONE, cv_mem->cv_acor, cv_mem->cv_zn[cv_mem->cv_qmax]); -static int cvStgr1Nls(CVodeMem cv_mem, int is) -{ - booleantype callSetup; - long int nni; - int flag=CV_SUCCESS; + if (cv_mem->cv_quadr) + N_VScale(ONE, cv_mem->cv_acorQ, cv_mem->cv_znQ[cv_mem->cv_qmax]); - cv_mem->sens_solve = SUNTRUE; + if (cv_mem->cv_sensi) { + for (is=0; iscv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; - callSetup = SUNFALSE; - if (cv_mem->cv_lsetup == NULL) - cv_mem->cv_crateS = ONE; + (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_acorS, cv_mem->cv_znS[cv_mem->cv_qmax]); + } - /* initial guess for the correction to the predictor */ - N_VConst(ZERO, cv_mem->cv_tempvS[is]); + if (cv_mem->cv_quadr_sensi) { + for (is=0; iscv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; - /* solve the nonlinear system */ - flag = SUNNonlinSolSolve(cv_mem->NLSstg1, - cv_mem->cv_tempvS[is], cv_mem->cv_acorS[is], - cv_mem->cv_ewtS[is], cv_mem->cv_tq[4], callSetup, cv_mem); + (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_acorQS, cv_mem->cv_znQS[cv_mem->cv_qmax]); + } - /* update the sensitivity with the final correction from the nonlinear solver */ - N_VLinearSum(ONE, cv_mem->cv_znS[0][is], - ONE, cv_mem->cv_acorS[is], cv_mem->cv_yS[is]); + cv_mem->cv_saved_tq5 = cv_mem->cv_tq[5]; + cv_mem->cv_indx_acor = cv_mem->cv_qmax; + } +} - /* if the solve is successful, update Jacobian status */ - if (flag == CV_SUCCESS) cv_mem->cv_jcur = SUNFALSE; +/* + * cvPrepareNextStep + * + * This routine handles the setting of stepsize and order for the + * next step -- hprime and qprime. Along with hprime, it sets the + * ratio eta = hprime/h. It also updates other state variables + * related to a change of step size or order. + */ - /* update nniS iteration count */ - (void) SUNNonlinSolGetNumIters(cv_mem->NLSstg1, &nni); - cv_mem->cv_nniS1[is] += nni - cv_mem->nnip; - cv_mem->nnip = nni; +static void cvPrepareNextStep(CVodeMem cv_mem, realtype dsm) +{ + /* If etamax = 1, defer step size or order changes */ + if (cv_mem->cv_etamax == ONE) { + cv_mem->cv_qwait = SUNMAX(cv_mem->cv_qwait, 2); + cv_mem->cv_qprime = cv_mem->cv_q; + cv_mem->cv_hprime = cv_mem->cv_h; + cv_mem->cv_eta = ONE; + return; + } - cv_mem->sens_solve = SUNFALSE; + /* etaq is the ratio of new to old h at the current order */ + cv_mem->cv_etaq = ONE /(SUNRpowerR(BIAS2*dsm,ONE/cv_mem->cv_L) + ADDON); - return(flag); + /* If no order change, adjust eta and acor in cvSetEta and return */ + if (cv_mem->cv_qwait != 0) { + cv_mem->cv_eta = cv_mem->cv_etaq; + cv_mem->cv_qprime = cv_mem->cv_q; + cvSetEta(cv_mem); + return; + } + /* If qwait = 0, consider an order change. etaqm1 and etaqp1 are + the ratios of new to old h at orders q-1 and q+1, respectively. + cvChooseEta selects the largest; cvSetEta adjusts eta and acor */ + cv_mem->cv_qwait = 2; + cv_mem->cv_etaqm1 = cvComputeEtaqm1(cv_mem); + cv_mem->cv_etaqp1 = cvComputeEtaqp1(cv_mem); + cvChooseEta(cv_mem); + cvSetEta(cv_mem); } /* - * cvHandleNFlag - * - * This routine takes action on the return value nflag = *nflagPtr - * returned by cvNls, as follows: - * - * If cvNls succeeded in solving the nonlinear system, then - * cvHandleNFlag returns the constant DO_ERROR_TEST, which tells cvStep - * to perform the error test. - * - * If the nonlinear system was not solved successfully, then ncfn and - * ncf = *ncfPtr are incremented and Nordsieck array zn is restored. - * - * If the solution of the nonlinear system failed due to an - * unrecoverable failure by setup, we return the value CV_LSETUP_FAIL. - * - * If it failed due to an unrecoverable failure in solve, then we return - * the value CV_LSOLVE_FAIL. - * - * If it failed due to an unrecoverable failure in rhs, then we return - * the value CV_RHSFUNC_FAIL. - * - * If it failed due to an unrecoverable failure in quad rhs, then we return - * the value CV_QRHSFUNC_FAIL. - * - * If it failed due to an unrecoverable failure in sensi rhs, then we return - * the value CV_SRHSFUNC_FAIL. - * - * Otherwise, a recoverable failure occurred when solving the - * nonlinear system (cvNls returned nflag = SUN_NLS_CONV_RECVT, RHSFUNC_RECVR, - * or SRHSFUNC_RECVR). - * In this case, if ncf is now equal to maxncf or |h| = hmin, - * we return the value CV_CONV_FAILURE (if nflag=SUN_NLS_CONV_RECVR), or - * CV_REPTD_RHSFUNC_ERR (if nflag=RHSFUNC_RECVR), or CV_REPTD_SRHSFUNC_ERR - * (if nflag=SRHSFUNC_RECVR). - * If not, we set *nflagPtr = PREV_CONV_FAIL and return the value - * PREDICT_AGAIN, telling cvStep to reattempt the step. + * cvSetEta * + * This routine adjusts the value of eta according to the various + * heuristic limits and the optional input hmax. */ -static int cvHandleNFlag(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, - int *ncfPtr, long int *ncfnPtr) +static void cvSetEta(CVodeMem cv_mem) { - int nflag; - - nflag = *nflagPtr; - - if (nflag == CV_SUCCESS) return(DO_ERROR_TEST); - - /* The nonlinear soln. failed; increment ncfn and restore zn */ - (*ncfnPtr)++; - cvRestore(cv_mem, saved_t); - - /* Return if failed unrecoverably */ - if (nflag < 0) return(nflag); - - /* At this point, nflag = SUN_NLS_CONV_RECVR, CONSTR_RECVR, RHSFUNC_RECVR, - or SRHSFUNC_RECVR; increment ncf */ - - (*ncfPtr)++; - cv_mem->cv_etamax = ONE; - /* If we had maxncf failures or |h| = hmin, - return CV_CONV_FAILURE, CV_CONSTR_FAIL, - CV_REPTD_RHSFUNC_ERR, CV_REPTD_QRHSFUNC_ERR, - CV_REPTD_SRHSFUNC_ERR, or CV_CONSTR_FAIL */ - - if ((SUNRabs(cv_mem->cv_h) <= cv_mem->cv_hmin*ONEPSM) || - (*ncfPtr == cv_mem->cv_maxncf)) { - if (nflag == SUN_NLS_CONV_RECVR) return(CV_CONV_FAILURE); - if (nflag == CONSTR_RECVR) return(CV_CONSTR_FAIL); - if (nflag == RHSFUNC_RECVR) return(CV_REPTD_RHSFUNC_ERR); - if (nflag == QRHSFUNC_RECVR) return(CV_REPTD_QRHSFUNC_ERR); - if (nflag == SRHSFUNC_RECVR) return(CV_REPTD_SRHSFUNC_ERR); - if (nflag == QSRHSFUNC_RECVR) return(CV_REPTD_QSRHSFUNC_ERR); + /* If eta below the threshhold THRESH, reject a change of step size */ + if (cv_mem->cv_eta < THRESH) { + cv_mem->cv_eta = ONE; + cv_mem->cv_hprime = cv_mem->cv_h; + } else { + /* Limit eta by etamax and hmax, then set hprime */ + cv_mem->cv_eta = SUNMIN(cv_mem->cv_eta, cv_mem->cv_etamax); + cv_mem->cv_eta /= SUNMAX(ONE, SUNRabs(cv_mem->cv_h) * + cv_mem->cv_hmax_inv*cv_mem->cv_eta); + cv_mem->cv_hprime = cv_mem->cv_h * cv_mem->cv_eta; + if (cv_mem->cv_qprime < cv_mem->cv_q) cv_mem->cv_nscon = 0; } - - /* Reduce step size; return to reattempt the step - Note that if nflag=CONSTR_RECVR then eta was already set in CVNls */ - if (nflag != CONSTR_RECVR) - cv_mem->cv_eta = SUNMAX(ETACF, cv_mem->cv_hmin / SUNRabs(cv_mem->cv_h)); - *nflagPtr = PREV_CONV_FAIL; - cvRescale(cv_mem); - - return(PREDICT_AGAIN); } /* - * cvRestore + * cvComputeEtaqm1 * - * This routine restores the value of cv_mem->cv_tn to saved_t and undoes the - * prediction. After execution of cvRestore, the Nordsieck array zn has - * the same values as before the call to cvPredict. + * This routine computes and returns the value of etaqm1 for a + * possible decrease in order by 1. */ -static void cvRestore(CVodeMem cv_mem, realtype saved_t) +static realtype cvComputeEtaqm1(CVodeMem cv_mem) { - int j, k; + realtype ddn; - cv_mem->cv_tn = saved_t; - for (k = 1; k <= cv_mem->cv_q; k++) - for (j = cv_mem->cv_q; j >= k; j--) - N_VLinearSum(ONE, cv_mem->cv_zn[j-1], -ONE, - cv_mem->cv_zn[j], cv_mem->cv_zn[j-1]); + cv_mem->cv_etaqm1 = ZERO; + if (cv_mem->cv_q > 1) { + ddn = N_VWrmsNorm(cv_mem->cv_zn[cv_mem->cv_q], cv_mem->cv_ewt); - if (cv_mem->cv_quadr) { - for (k = 1; k <= cv_mem->cv_q; k++) - for (j = cv_mem->cv_q; j >= k; j--) - N_VLinearSum(ONE, cv_mem->cv_znQ[j-1], -ONE, - cv_mem->cv_znQ[j], cv_mem->cv_znQ[j-1]); - } + if ( cv_mem->cv_quadr && cv_mem->cv_errconQ ) + ddn = cvQuadUpdateNorm(cv_mem, ddn, cv_mem->cv_znQ[cv_mem->cv_q], + cv_mem->cv_ewtQ); - if (cv_mem->cv_sensi) { - for (k = 1; k <= cv_mem->cv_q; k++) - for (j = cv_mem->cv_q; j >= k; j--) - (void) N_VLinearSumVectorArray(cv_mem->cv_Ns, - ONE, cv_mem->cv_znS[j-1], - -ONE, cv_mem->cv_znS[j], - cv_mem->cv_znS[j-1]); - } + if ( cv_mem->cv_sensi && cv_mem->cv_errconS ) + ddn = cvSensUpdateNorm(cv_mem, ddn, cv_mem->cv_znS[cv_mem->cv_q], + cv_mem->cv_ewtS); - if (cv_mem->cv_quadr_sensi) { - for (k = 1; k <= cv_mem->cv_q; k++) - for (j = cv_mem->cv_q; j >= k; j--) - (void) N_VLinearSumVectorArray(cv_mem->cv_Ns, - ONE, cv_mem->cv_znQS[j-1], - -ONE, cv_mem->cv_znQS[j], - cv_mem->cv_znQS[j-1]); + if ( cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS ) + ddn = cvQuadSensUpdateNorm(cv_mem, ddn, cv_mem->cv_znQS[cv_mem->cv_q], + cv_mem->cv_ewtQS); + + ddn = ddn * cv_mem->cv_tq[1]; + cv_mem->cv_etaqm1 = ONE/(SUNRpowerR(BIAS1*ddn, ONE/cv_mem->cv_q) + ADDON); } + return(cv_mem->cv_etaqm1); } -/* - * ----------------------------------------------------------------- - * Error Test - * ----------------------------------------------------------------- - */ - /* - * cvDoErrorTest - * - * This routine performs the local error test, for the state, quadrature, - * or sensitivity variables. Its last three arguments change depending - * on which variables the error test is to be performed on. - * - * The weighted local error norm dsm is loaded into *dsmPtr, and - * the test dsm ?<= 1 is made. - * - * If the test passes, cvDoErrorTest returns CV_SUCCESS. - * - * If the test fails, we undo the step just taken (call cvRestore) and - * - * - if maxnef error test failures have occurred or if SUNRabs(h) = hmin, - * we return CV_ERR_FAILURE. - * - * - if more than MXNEF1 error test failures have occurred, an order - * reduction is forced. If already at order 1, restart by reloading - * zn from scratch (also znQ and znS if appropriate). - * If f() fails, we return CV_RHSFUNC_FAIL or CV_UNREC_RHSFUNC_ERR; - * if fQ() fails, we return CV_QRHSFUNC_FAIL or CV_UNREC_QRHSFUNC_ERR; - * if cvSensRhsWrapper() fails, we return CV_SRHSFUNC_FAIL or CV_UNREC_SRHSFUNC_ERR; - * (no recovery is possible at this stage). - * - * - otherwise, set *nflagPtr to PREV_ERR_FAIL, and return TRY_AGAIN. + * cvComputeEtaqp1 * + * This routine computes and returns the value of etaqp1 for a + * possible increase in order by 1. */ -static int cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, - realtype acor_nrm, - int *nefPtr, long int *netfPtr, realtype *dsmPtr) +static realtype cvComputeEtaqp1(CVodeMem cv_mem) { - realtype dsm; - int retval, is; - N_Vector wrk1, wrk2; + realtype dup, cquot; - dsm = acor_nrm * cv_mem->cv_tq[2]; + cv_mem->cv_etaqp1 = ZERO; + if (cv_mem->cv_q != cv_mem->cv_qmax) { + if (cv_mem->cv_saved_tq5 == ZERO) return(cv_mem->cv_etaqp1); + cquot = (cv_mem->cv_tq[5] / cv_mem->cv_saved_tq5) * + SUNRpowerI(cv_mem->cv_h/cv_mem->cv_tau[2], cv_mem->cv_L); + N_VLinearSum(-cquot, cv_mem->cv_zn[cv_mem->cv_qmax], ONE, + cv_mem->cv_acor, cv_mem->cv_tempv); + dup = N_VWrmsNorm(cv_mem->cv_tempv, cv_mem->cv_ewt); - /* If est. local error norm dsm passes test, return CV_SUCCESS */ - *dsmPtr = dsm; - if (dsm <= ONE) return(CV_SUCCESS); - - /* Test failed; increment counters, set nflag, and restore zn array */ - (*nefPtr)++; - (*netfPtr)++; - *nflagPtr = PREV_ERR_FAIL; - cvRestore(cv_mem, saved_t); + if ( cv_mem->cv_quadr && cv_mem->cv_errconQ ) { + N_VLinearSum(-cquot, cv_mem->cv_znQ[cv_mem->cv_qmax], ONE, + cv_mem->cv_acorQ, cv_mem->cv_tempvQ); + dup = cvQuadUpdateNorm(cv_mem, dup, cv_mem->cv_tempvQ, cv_mem->cv_ewtQ); + } - /* At maxnef failures or |h| = hmin, return CV_ERR_FAILURE */ - if ((SUNRabs(cv_mem->cv_h) <= cv_mem->cv_hmin*ONEPSM) || - (*nefPtr == cv_mem->cv_maxnef)) - return(CV_ERR_FAILURE); + if ( cv_mem->cv_sensi && cv_mem->cv_errconS ) { + (void) N_VLinearSumVectorArray(cv_mem->cv_Ns, + -cquot, cv_mem->cv_znS[cv_mem->cv_qmax], + ONE, cv_mem->cv_acorS, + cv_mem->cv_tempvS); - /* Set etamax = 1 to prevent step size increase at end of this step */ - cv_mem->cv_etamax = ONE; + dup = cvSensUpdateNorm(cv_mem, dup, cv_mem->cv_tempvS, cv_mem->cv_ewtS); + } - /* Set h ratio eta from dsm, rescale, and return for retry of step */ - if (*nefPtr <= MXNEF1) { - cv_mem->cv_eta = ONE / (SUNRpowerR(BIAS2*dsm,ONE/cv_mem->cv_L) + ADDON); - cv_mem->cv_eta = SUNMAX(ETAMIN, SUNMAX(cv_mem->cv_eta, - cv_mem->cv_hmin / SUNRabs(cv_mem->cv_h))); - if (*nefPtr >= SMALL_NEF) - cv_mem->cv_eta = SUNMIN(cv_mem->cv_eta, ETAMXF); - cvRescale(cv_mem); - return(TRY_AGAIN); - } - - /* After MXNEF1 failures, force an order reduction and retry step */ - if (cv_mem->cv_q > 1) { - cv_mem->cv_eta = SUNMAX(ETAMIN, cv_mem->cv_hmin / SUNRabs(cv_mem->cv_h)); - cvAdjustOrder(cv_mem,-1); - cv_mem->cv_L = cv_mem->cv_q; - cv_mem->cv_q--; - cv_mem->cv_qwait = cv_mem->cv_L; - cvRescale(cv_mem); - return(TRY_AGAIN); + if ( cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS ) { + (void) N_VLinearSumVectorArray(cv_mem->cv_Ns, + -cquot, cv_mem->cv_znQS[cv_mem->cv_qmax], + ONE, cv_mem->cv_acorQS, + cv_mem->cv_tempvQS); + + dup = cvSensUpdateNorm(cv_mem, dup, cv_mem->cv_tempvQS, cv_mem->cv_ewtQS); + } + + dup = dup * cv_mem->cv_tq[3]; + cv_mem->cv_etaqp1 = ONE / (SUNRpowerR(BIAS3*dup, ONE/(cv_mem->cv_L+1)) + ADDON); } + return(cv_mem->cv_etaqp1); +} - /* If already at order 1, restart: reload zn, znQ, znS, znQS from scratch */ - cv_mem->cv_eta = SUNMAX(ETAMIN, cv_mem->cv_hmin / SUNRabs(cv_mem->cv_h)); - cv_mem->cv_h *= cv_mem->cv_eta; - cv_mem->cv_next_h = cv_mem->cv_h; - cv_mem->cv_hscale = cv_mem->cv_h; - cv_mem->cv_qwait = LONG_WAIT; - cv_mem->cv_nscon = 0; +/* + * cvChooseEta + * Given etaqm1, etaq, etaqp1 (the values of eta for qprime = + * q - 1, q, or q + 1, respectively), this routine chooses the + * maximum eta value, sets eta to that value, and sets qprime to the + * corresponding value of q. If there is a tie, the preference + * order is to (1) keep the same order, then (2) decrease the order, + * and finally (3) increase the order. If the maximum eta value + * is below the threshhold THRESH, the order is kept unchanged and + * eta is set to 1. + */ - retval = cv_mem->cv_f(cv_mem->cv_tn, cv_mem->cv_zn[0], - cv_mem->cv_tempv, cv_mem->cv_user_data); - cv_mem->cv_nfe++; - if (retval < 0) return(CV_RHSFUNC_FAIL); - if (retval > 0) return(CV_UNREC_RHSFUNC_ERR); +static void cvChooseEta(CVodeMem cv_mem) +{ + realtype etam; + int is; - N_VScale(cv_mem->cv_h, cv_mem->cv_tempv, cv_mem->cv_zn[1]); + etam = SUNMAX(cv_mem->cv_etaqm1, SUNMAX(cv_mem->cv_etaq, cv_mem->cv_etaqp1)); - if (cv_mem->cv_quadr) { + if (etam < THRESH) { + cv_mem->cv_eta = ONE; + cv_mem->cv_qprime = cv_mem->cv_q; + return; + } - retval = cv_mem->cv_fQ(cv_mem->cv_tn, cv_mem->cv_zn[0], - cv_mem->cv_tempvQ, cv_mem->cv_user_data); - cv_mem->cv_nfQe++; - if (retval < 0) return(CV_QRHSFUNC_FAIL); - if (retval > 0) return(CV_UNREC_QRHSFUNC_ERR); + if (etam == cv_mem->cv_etaq) { - N_VScale(cv_mem->cv_h, cv_mem->cv_tempvQ, cv_mem->cv_znQ[1]); + cv_mem->cv_eta = cv_mem->cv_etaq; + cv_mem->cv_qprime = cv_mem->cv_q; - } + } else if (etam == cv_mem->cv_etaqm1) { - if (cv_mem->cv_sensi) { + cv_mem->cv_eta = cv_mem->cv_etaqm1; + cv_mem->cv_qprime = cv_mem->cv_q - 1; - wrk1 = cv_mem->cv_ftemp; - wrk2 = cv_mem->cv_ftempS[0]; + } else { - retval = cvSensRhsWrapper(cv_mem, cv_mem->cv_tn, cv_mem->cv_zn[0], - cv_mem->cv_tempv, cv_mem->cv_znS[0], - cv_mem->cv_tempvS, wrk1, wrk2); - if (retval < 0) return(CV_SRHSFUNC_FAIL); - if (retval > 0) return(CV_UNREC_SRHSFUNC_ERR); + cv_mem->cv_eta = cv_mem->cv_etaqp1; + cv_mem->cv_qprime = cv_mem->cv_q + 1; - for (is=0; iscv_Ns; is++) - cv_mem->cv_cvals[is] = cv_mem->cv_h; - - retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, - cv_mem->cv_tempvS, cv_mem->cv_znS[1]); - if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); - } + if (cv_mem->cv_lmm == CV_BDF) { + /* + * Store Delta_n in zn[qmax] to be used in order increase + * + * This happens at the last step of order q before an increase + * to order q+1, so it represents Delta_n in the ELTE at q+1 + */ - if (cv_mem->cv_quadr_sensi) { + N_VScale(ONE, cv_mem->cv_acor, cv_mem->cv_zn[cv_mem->cv_qmax]); - wrk1 = cv_mem->cv_ftemp; - wrk2 = cv_mem->cv_ftempQ; + if (cv_mem->cv_quadr && cv_mem->cv_errconQ) + N_VScale(ONE, cv_mem->cv_acorQ, cv_mem->cv_znQ[cv_mem->cv_qmax]); - retval = cv_mem->cv_fQS(cv_mem->cv_Ns, cv_mem->cv_tn, - cv_mem->cv_zn[0], cv_mem->cv_znS[0], - cv_mem->cv_tempvQ, cv_mem->cv_tempvQS, - cv_mem->cv_fQS_data, wrk1, wrk2); - cv_mem->cv_nfQSe++; - if (retval < 0) return(CV_QSRHSFUNC_FAIL); - if (retval > 0) return(CV_UNREC_QSRHSFUNC_ERR); + if (cv_mem->cv_sensi && cv_mem->cv_errconS) { + for (is=0; iscv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; - for (is=0; iscv_Ns; is++) - cv_mem->cv_cvals[is] = cv_mem->cv_h; + (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_acorS, cv_mem->cv_znS[cv_mem->cv_qmax]); + } - retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, - cv_mem->cv_tempvQS, cv_mem->cv_znQS[1]); - if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + if (cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS) { + for (is=0; iscv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; + + (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_acorQS, cv_mem->cv_znQS[cv_mem->cv_qmax]); + } + } } - - return(TRY_AGAIN); } -/* +/* * ----------------------------------------------------------------- - * Functions called after a successful step + * Function to handle failures * ----------------------------------------------------------------- */ /* - * cvCompleteStep + * cvHandleFailure * - * This routine performs various update operations when the solution - * to the nonlinear system has passed the local error test. - * We increment the step counter nst, record the values hu and qu, - * update the tau array, and apply the corrections to the zn array. - * The tau[i] are the last q values of h, with tau[1] the most recent. - * The counter qwait is decremented, and if qwait == 1 (and q < qmax) - * we save acor and tq[5] for a possible order increase. + * This routine prints error messages for all cases of failure by + * cvHin and cvStep. + * It returns to CVode the value that CVode is to return to the user. */ -static void cvCompleteStep(CVodeMem cv_mem) +static int cvHandleFailure(CVodeMem cv_mem, int flag) { - int i; - int is; - - cv_mem->cv_nst++; - cv_mem->cv_nscon++; - cv_mem->cv_hu = cv_mem->cv_h; - cv_mem->cv_qu = cv_mem->cv_q; - - for (i=cv_mem->cv_q; i >= 2; i--) - cv_mem->cv_tau[i] = cv_mem->cv_tau[i-1]; - if ((cv_mem->cv_q==1) && (cv_mem->cv_nst > 1)) - cv_mem->cv_tau[2] = cv_mem->cv_tau[1]; - cv_mem->cv_tau[1] = cv_mem->cv_h; - - /* Apply correction to column j of zn: l_j * Delta_n */ - (void) N_VScaleAddMulti(cv_mem->cv_q+1, cv_mem->cv_l, cv_mem->cv_acor, - cv_mem->cv_zn, cv_mem->cv_zn); - - if (cv_mem->cv_quadr) - (void) N_VScaleAddMulti(cv_mem->cv_q+1, cv_mem->cv_l, cv_mem->cv_acorQ, - cv_mem->cv_znQ, cv_mem->cv_znQ); - - if (cv_mem->cv_sensi) - (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q+1, - cv_mem->cv_l, cv_mem->cv_acorS, - cv_mem->cv_znS, cv_mem->cv_znS); - - if (cv_mem->cv_quadr_sensi) - (void) N_VScaleAddMultiVectorArray(cv_mem->cv_Ns, cv_mem->cv_q+1, - cv_mem->cv_l, cv_mem->cv_acorQS, - cv_mem->cv_znQS, cv_mem->cv_znQS); - - /* If necessary, store Delta_n in zn[qmax] to be used in order increase. - * This actually will be Delta_{n-1} in the ELTE at q+1 since it happens at - * the next to last step of order q before a possible one at order q+1 - */ - - cv_mem->cv_qwait--; - if ((cv_mem->cv_qwait == 1) && (cv_mem->cv_q != cv_mem->cv_qmax)) { - - N_VScale(ONE, cv_mem->cv_acor, cv_mem->cv_zn[cv_mem->cv_qmax]); - - if (cv_mem->cv_quadr) - N_VScale(ONE, cv_mem->cv_acorQ, cv_mem->cv_znQ[cv_mem->cv_qmax]); - if (cv_mem->cv_sensi) { - for (is=0; iscv_Ns; is++) - cv_mem->cv_cvals[is] = ONE; - - (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, - cv_mem->cv_acorS, cv_mem->cv_znS[cv_mem->cv_qmax]); - } - - if (cv_mem->cv_quadr_sensi) { - for (is=0; iscv_Ns; is++) - cv_mem->cv_cvals[is] = ONE; - - (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, - cv_mem->cv_acorQS, cv_mem->cv_znQS[cv_mem->cv_qmax]); - } - - cv_mem->cv_saved_tq5 = cv_mem->cv_tq[5]; - cv_mem->cv_indx_acor = cv_mem->cv_qmax; - } - -} - -/* - * cvPrepareNextStep - * - * This routine handles the setting of stepsize and order for the - * next step -- hprime and qprime. Along with hprime, it sets the - * ratio eta = hprime/h. It also updates other state variables - * related to a change of step size or order. - */ - -static void cvPrepareNextStep(CVodeMem cv_mem, realtype dsm) -{ - /* If etamax = 1, defer step size or order changes */ - if (cv_mem->cv_etamax == ONE) { - cv_mem->cv_qwait = SUNMAX(cv_mem->cv_qwait, 2); - cv_mem->cv_qprime = cv_mem->cv_q; - cv_mem->cv_hprime = cv_mem->cv_h; - cv_mem->cv_eta = ONE; - return; - } - - /* etaq is the ratio of new to old h at the current order */ - cv_mem->cv_etaq = ONE /(SUNRpowerR(BIAS2*dsm,ONE/cv_mem->cv_L) + ADDON); - - /* If no order change, adjust eta and acor in cvSetEta and return */ - if (cv_mem->cv_qwait != 0) { - cv_mem->cv_eta = cv_mem->cv_etaq; - cv_mem->cv_qprime = cv_mem->cv_q; - cvSetEta(cv_mem); - return; - } - - /* If qwait = 0, consider an order change. etaqm1 and etaqp1 are - the ratios of new to old h at orders q-1 and q+1, respectively. - cvChooseEta selects the largest; cvSetEta adjusts eta and acor */ - cv_mem->cv_qwait = 2; - cv_mem->cv_etaqm1 = cvComputeEtaqm1(cv_mem); - cv_mem->cv_etaqp1 = cvComputeEtaqp1(cv_mem); - cvChooseEta(cv_mem); - cvSetEta(cv_mem); -} - -/* - * cvSetEta - * - * This routine adjusts the value of eta according to the various - * heuristic limits and the optional input hmax. - */ - -static void cvSetEta(CVodeMem cv_mem) -{ - - /* If eta below the threshhold THRESH, reject a change of step size */ - if (cv_mem->cv_eta < THRESH) { - cv_mem->cv_eta = ONE; - cv_mem->cv_hprime = cv_mem->cv_h; - } else { - /* Limit eta by etamax and hmax, then set hprime */ - cv_mem->cv_eta = SUNMIN(cv_mem->cv_eta, cv_mem->cv_etamax); - cv_mem->cv_eta /= SUNMAX(ONE, SUNRabs(cv_mem->cv_h) * - cv_mem->cv_hmax_inv*cv_mem->cv_eta); - cv_mem->cv_hprime = cv_mem->cv_h * cv_mem->cv_eta; - if (cv_mem->cv_qprime < cv_mem->cv_q) cv_mem->cv_nscon = 0; - } -} - -/* - * cvComputeEtaqm1 - * - * This routine computes and returns the value of etaqm1 for a - * possible decrease in order by 1. - */ - -static realtype cvComputeEtaqm1(CVodeMem cv_mem) -{ - realtype ddn; - - cv_mem->cv_etaqm1 = ZERO; - - if (cv_mem->cv_q > 1) { - - ddn = N_VWrmsNorm(cv_mem->cv_zn[cv_mem->cv_q], cv_mem->cv_ewt); - - if ( cv_mem->cv_quadr && cv_mem->cv_errconQ ) - ddn = cvQuadUpdateNorm(cv_mem, ddn, cv_mem->cv_znQ[cv_mem->cv_q], - cv_mem->cv_ewtQ); - - if ( cv_mem->cv_sensi && cv_mem->cv_errconS ) - ddn = cvSensUpdateNorm(cv_mem, ddn, cv_mem->cv_znS[cv_mem->cv_q], - cv_mem->cv_ewtS); - - if ( cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS ) - ddn = cvQuadSensUpdateNorm(cv_mem, ddn, cv_mem->cv_znQS[cv_mem->cv_q], - cv_mem->cv_ewtQS); - - ddn = ddn * cv_mem->cv_tq[1]; - cv_mem->cv_etaqm1 = ONE/(SUNRpowerR(BIAS1*ddn, ONE/cv_mem->cv_q) + ADDON); - } - - return(cv_mem->cv_etaqm1); -} - -/* - * cvComputeEtaqp1 - * - * This routine computes and returns the value of etaqp1 for a - * possible increase in order by 1. - */ - -static realtype cvComputeEtaqp1(CVodeMem cv_mem) -{ - realtype dup, cquot; - - cv_mem->cv_etaqp1 = ZERO; - - if (cv_mem->cv_q != cv_mem->cv_qmax) { - - if (cv_mem->cv_saved_tq5 == ZERO) return(cv_mem->cv_etaqp1); - - cquot = (cv_mem->cv_tq[5] / cv_mem->cv_saved_tq5) * - SUNRpowerI(cv_mem->cv_h/cv_mem->cv_tau[2], cv_mem->cv_L); - N_VLinearSum(-cquot, cv_mem->cv_zn[cv_mem->cv_qmax], ONE, - cv_mem->cv_acor, cv_mem->cv_tempv); - dup = N_VWrmsNorm(cv_mem->cv_tempv, cv_mem->cv_ewt); - - if ( cv_mem->cv_quadr && cv_mem->cv_errconQ ) { - N_VLinearSum(-cquot, cv_mem->cv_znQ[cv_mem->cv_qmax], ONE, - cv_mem->cv_acorQ, cv_mem->cv_tempvQ); - dup = cvQuadUpdateNorm(cv_mem, dup, cv_mem->cv_tempvQ, cv_mem->cv_ewtQ); - } - - if ( cv_mem->cv_sensi && cv_mem->cv_errconS ) { - (void) N_VLinearSumVectorArray(cv_mem->cv_Ns, - -cquot, cv_mem->cv_znS[cv_mem->cv_qmax], - ONE, cv_mem->cv_acorS, - cv_mem->cv_tempvS); - - dup = cvSensUpdateNorm(cv_mem, dup, cv_mem->cv_tempvS, cv_mem->cv_ewtS); - } - - if ( cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS ) { - (void) N_VLinearSumVectorArray(cv_mem->cv_Ns, - -cquot, cv_mem->cv_znQS[cv_mem->cv_qmax], - ONE, cv_mem->cv_acorQS, - cv_mem->cv_tempvQS); - - dup = cvSensUpdateNorm(cv_mem, dup, cv_mem->cv_tempvQS, cv_mem->cv_ewtQS); - } - - dup = dup * cv_mem->cv_tq[3]; - cv_mem->cv_etaqp1 = ONE / (SUNRpowerR(BIAS3*dup, ONE/(cv_mem->cv_L+1)) + ADDON); - } - - return(cv_mem->cv_etaqp1); -} - -/* - * cvChooseEta - * Given etaqm1, etaq, etaqp1 (the values of eta for qprime = - * q - 1, q, or q + 1, respectively), this routine chooses the - * maximum eta value, sets eta to that value, and sets qprime to the - * corresponding value of q. If there is a tie, the preference - * order is to (1) keep the same order, then (2) decrease the order, - * and finally (3) increase the order. If the maximum eta value - * is below the threshhold THRESH, the order is kept unchanged and - * eta is set to 1. - */ - -static void cvChooseEta(CVodeMem cv_mem) -{ - realtype etam; - int is; - - etam = SUNMAX(cv_mem->cv_etaqm1, SUNMAX(cv_mem->cv_etaq, cv_mem->cv_etaqp1)); - - if (etam < THRESH) { - cv_mem->cv_eta = ONE; - cv_mem->cv_qprime = cv_mem->cv_q; - return; - } - - if (etam == cv_mem->cv_etaq) { - - cv_mem->cv_eta = cv_mem->cv_etaq; - cv_mem->cv_qprime = cv_mem->cv_q; - - } else if (etam == cv_mem->cv_etaqm1) { - - cv_mem->cv_eta = cv_mem->cv_etaqm1; - cv_mem->cv_qprime = cv_mem->cv_q - 1; - - } else { - - cv_mem->cv_eta = cv_mem->cv_etaqp1; - cv_mem->cv_qprime = cv_mem->cv_q + 1; - - if (cv_mem->cv_lmm == CV_BDF) { - - /* - * Store Delta_n in zn[qmax] to be used in order increase - * - * This happens at the last step of order q before an increase - * to order q+1, so it represents Delta_n in the ELTE at q+1 - */ - - N_VScale(ONE, cv_mem->cv_acor, cv_mem->cv_zn[cv_mem->cv_qmax]); - - if (cv_mem->cv_quadr && cv_mem->cv_errconQ) - N_VScale(ONE, cv_mem->cv_acorQ, cv_mem->cv_znQ[cv_mem->cv_qmax]); - - if (cv_mem->cv_sensi && cv_mem->cv_errconS) { - for (is=0; iscv_Ns; is++) - cv_mem->cv_cvals[is] = ONE; - - (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, - cv_mem->cv_acorS, cv_mem->cv_znS[cv_mem->cv_qmax]); - } - - if (cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS) { - for (is=0; iscv_Ns; is++) - cv_mem->cv_cvals[is] = ONE; - - (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, - cv_mem->cv_acorQS, cv_mem->cv_znQS[cv_mem->cv_qmax]); - } - - } - } -} - -/* - * ----------------------------------------------------------------- - * Function to handle failures - * ----------------------------------------------------------------- - */ - -/* - * cvHandleFailure - * - * This routine prints error messages for all cases of failure by - * cvHin or cvStep. - * It returns to CVode the value that CVode is to return to the user. - */ - -static int cvHandleFailure(CVodeMem cv_mem, int flag) -{ - - /* Set vector of absolute weighted local errors */ - /* - N_VProd(acor, ewt, tempv); - N_VAbs(tempv, tempv); - */ + /* Set vector of absolute weighted local errors */ + /* + N_VProd(acor, ewt, tempv); + N_VAbs(tempv, tempv); + */ /* Depending on flag, print error message and return error flag */ switch (flag) { @@ -7383,29 +7133,38 @@ static int cvHandleFailure(CVodeMem cv_mem, int flag) MSGCV_TOO_CLOSE); break; case CV_MEM_NULL: - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVode", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVode", + MSGCV_NO_MEM); break; case SUN_NLS_MEM_NULL: - cvProcessError(cv_mem, CV_MEM_NULL, "CVODES", "CVode", MSGCV_NLS_INPUT_NULL, - cv_mem->cv_tn); + cvProcessError(cv_mem, CV_MEM_NULL, "CVODES", "CVode", + MSGCV_NLS_INPUT_NULL, cv_mem->cv_tn); break; case CV_NLS_SETUP_FAIL: - cvProcessError(cv_mem, CV_NLS_SETUP_FAIL, "CVODES", "CVode", MSGCV_NLS_SETUP_FAILED, - cv_mem->cv_tn); + cvProcessError(cv_mem, CV_NLS_SETUP_FAIL, "CVODES", "CVode", + MSGCV_NLS_SETUP_FAILED, cv_mem->cv_tn); break; case CV_CONSTR_FAIL: cvProcessError(cv_mem, CV_CONSTR_FAIL, "CVODES", "CVode", MSGCV_FAILED_CONSTR, cv_mem->cv_tn); + break; + case CV_NLS_FAIL: + cvProcessError(cv_mem, CV_NLS_FAIL, "CVODES", "CVode", + MSGCV_NLS_FAIL, cv_mem->cv_tn); + break; default: - return(CV_SUCCESS); + /* This return should never happen */ + cvProcessError(cv_mem, CV_UNRECOGNIZED_ERR, "CVODES", "CVode", + "CVODES encountered an unrecognized error. Please report this to the Sundials developers at sundials-users@llnl.gov"); + return (CV_UNRECOGNIZED_ERR); } return(flag); } -/* +/* * ----------------------------------------------------------------- - * Functions for BDF Stability Limit Detection + * Functions for BDF Stability Limit Detection * ----------------------------------------------------------------- */ @@ -7425,7 +7184,7 @@ static void cvBDFStab(CVodeMem cv_mem) { int i,k, ldflag, factorial; realtype sq, sqm1, sqm2; - + /* If order is 3 or greater, then save scaled derivative data, push old data down in i, then add current values to top. */ @@ -7444,7 +7203,7 @@ static void cvBDFStab(CVodeMem cv_mem) cv_mem->cv_ssdat[1][1] = sqm2*sqm2; cv_mem->cv_ssdat[1][2] = sqm1*sqm1; cv_mem->cv_ssdat[1][3] = sq*sq; - } + } if (cv_mem->cv_qprime >= cv_mem->cv_q) { @@ -7458,7 +7217,7 @@ static void cvBDFStab(CVodeMem cv_mem) a return flag of 4, 5, or 6. Reduce new order. */ cv_mem->cv_qprime = cv_mem->cv_q-1; - cv_mem->cv_eta = cv_mem->cv_etaqm1; + cv_mem->cv_eta = cv_mem->cv_etaqm1; cv_mem->cv_eta = SUNMIN(cv_mem->cv_eta,cv_mem->cv_etamax); cv_mem->cv_eta = cv_mem->cv_eta / SUNMAX(ONE,SUNRabs(cv_mem->cv_h)*cv_mem->cv_hmax_inv*cv_mem->cv_eta); @@ -7468,7 +7227,7 @@ static void cvBDFStab(CVodeMem cv_mem) } } else { - /* Otherwise, let order increase happen, and + /* Otherwise, let order increase happen, and reset stability limit counter, nscon. */ cv_mem->cv_nscon = 0; } @@ -7477,14 +7236,14 @@ static void cvBDFStab(CVodeMem cv_mem) /* * cvSLdet * - * This routine detects stability limitation using stored scaled + * This routine detects stability limitation using stored scaled * derivatives data. cvSLdet returns the magnitude of the * dominate characteristic root, rr. The presence of a stability - * limit is indicated by rr > "something a little less then 1.0", + * limit is indicated by rr > "something a little less then 1.0", * and a positive kflag. This routine should only be called if * order is greater than or equal to 3, and data has been collected - * for 5 time steps. - * + * for 5 time steps. + * * Returned values: * kflag = 1 -> Found stable characteristic root, normal matrix case * kflag = 2 -> Found stable characteristic root, quartic solution @@ -7495,14 +7254,14 @@ static void cvBDFStab(CVodeMem cv_mem) * kflag = 6 -> Found stability violation, quartic solution, * with Newton correction * - * kflag < 0 -> No stability limitation, + * kflag < 0 -> No stability limitation, * or could not compute limitation. * * kflag = -1 -> Min/max ratio of ssdat too small. * kflag = -2 -> For normal matrix case, vmax > vrrt2*vrrt2 * kflag = -3 -> For normal matrix case, The three ratios * are inconsistent. - * kflag = -4 -> Small coefficient prevents elimination of quartics. + * kflag = -4 -> Small coefficient prevents elimination of quartics. * kflag = -5 -> R value from quartics not consistent. * kflag = -6 -> No corrected root passes test on qk values * kflag = -7 -> Trouble solving for sigsq. @@ -7519,7 +7278,7 @@ static int cvSLdet(CVodeMem cv_mem) realtype smink, smaxk, sumrat, sumrsq, vmin, vmax, drrmax, adrr; realtype tem, sqmax, saqk, qp, s, sqmaxk, saqj, sqmin; realtype rsa, rsb, rsc, rsd, rd1a, rd1b, rd1c; - realtype rd2a, rd2b, rd3a, cest1, corr1; + realtype rd2a, rd2b, rd3a, cest1, corr1; realtype ratp, ratm, qfac1, qfac2, bb, rrb; /* The following are cutoffs and tolerances used by this routine */ @@ -7545,14 +7304,14 @@ static int cvSLdet(CVodeMem cv_mem) for (k=1; k<=3; k++) { smink = cv_mem->cv_ssdat[1][k]; smaxk = ZERO; - + for (i=1; i<=5; i++) { smink = SUNMIN(smink,cv_mem->cv_ssdat[i][k]); smaxk = SUNMAX(smaxk,cv_mem->cv_ssdat[i][k]); } - + if (smink < TINY*smaxk) { - kflag = -1; + kflag = -1; return(kflag); } smax[k] = smaxk; @@ -7564,7 +7323,7 @@ static int cvSLdet(CVodeMem cv_mem) rat[i][k] = cv_mem->cv_ssdat[i][k] / cv_mem->cv_ssdat[i+1][k]; sumrat = sumrat + rat[i][k]; sumrsq = sumrsq + rat[i][k]*rat[i][k]; - } + } rav[k] = FOURTH*sumrat; vrat[k] = SUNRabs(FOURTH*sumrsq - rav[k]*rav[k]); @@ -7578,23 +7337,23 @@ static int cvSLdet(CVodeMem cv_mem) qc[1][k] = cv_mem->cv_ssdat[4][k] * cv_mem->cv_ssdat[4][k] - cv_mem->cv_ssdat[3][k] * cv_mem->cv_ssdat[5][k]; - for (i=1; i<=5; i++) { + for (i=1; i<=5; i++) qco[i][k] = qc[i][k]; - } + } /* End of k loop */ - + /* Isolate normal or nearly-normal matrix case. The three quartics will have a common or nearly-common root in this case. Return a kflag = 1 if this procedure works. If the three roots differ more than vrrt2, return error kflag = -3. */ - + vmin = SUNMIN(vrat[1],SUNMIN(vrat[2],vrat[3])); vmax = SUNMAX(vrat[1],SUNMAX(vrat[2],vrat[3])); - + if (vmin < vrrtol*vrrtol) { if (vmax > vrrt2*vrrt2) { - kflag = -2; + kflag = -2; return(kflag); } else { rr = (rav[1] + rav[2] + rav[3])/THREE; @@ -7604,7 +7363,7 @@ static int cvSLdet(CVodeMem cv_mem) drrmax = SUNMAX(drrmax, adrr); } if (drrmax > vrrt2) { kflag = -3; return(kflag); } - + kflag = 1; /* can compute charactistic root, drop to next section */ @@ -7615,7 +7374,7 @@ static int cvSLdet(CVodeMem cv_mem) /* use the quartics to get rr. */ if (SUNRabs(qco[1][1]) < TINY*ssmax[1]) { - kflag = -4; + kflag = -4; return(kflag); } @@ -7632,7 +7391,7 @@ static int cvSLdet(CVodeMem cv_mem) qco[1][3] = ZERO; if (SUNRabs(qco[2][2]) < TINY*ssmax[2]) { - kflag = -4; + kflag = -4; return(kflag); } @@ -7642,14 +7401,14 @@ static int cvSLdet(CVodeMem cv_mem) } if (SUNRabs(qco[4][3]) < TINY*ssmax[3]) { - kflag = -4; + kflag = -4; return(kflag); } rr = -qco[5][3]/qco[4][3]; if (rr < TINY || rr > HUNDRED) { - kflag = -5; + kflag = -5; return(kflag); } @@ -7660,7 +7419,7 @@ static int cvSLdet(CVodeMem cv_mem) for (k=1; k<=3; k++) { saqk = SUNRabs(qkr[k])/ssmax[k]; if (saqk > sqmax) sqmax = saqk; - } + } if (sqmax < sqtol) { kflag = 2; @@ -7677,7 +7436,7 @@ static int cvSLdet(CVodeMem cv_mem) drr[k] = ZERO; if (SUNRabs(qp) > TINY*ssmax[k]) drr[k] = -qkr[k]/qp; rrc[k] = rr + drr[k]; - } + } for (k=1; k<=3; k++) { s = rrc[k]; @@ -7686,7 +7445,7 @@ static int cvSLdet(CVodeMem cv_mem) qjk[j][k] = qc[5][j] + s*(qc[4][j] + s*s*(qc[2][j] + s*qc[1][j])); saqj = SUNRabs(qjk[j][k])/ssmax[j]; if (saqj > sqmaxk) sqmaxk = saqj; - } + } sqmx[k] = sqmaxk; } @@ -7696,20 +7455,20 @@ static int cvSLdet(CVodeMem cv_mem) kmin = k; sqmin = sqmx[k]; } - } + } rr = rrc[kmin]; if (sqmin < sqtol) { kflag = 3; /* can compute charactistic root */ - /* break out of Newton correction loop and drop to "given rr,etc" */ + /* break out of Newton correction loop and drop to "given rr,etc" */ break; } else { for (j=1; j<=3; j++) { qkr[j] = qjk[j][kmin]; } - } - } /* end of Newton correction loop */ + } + } /* end of Newton correction loop */ if (sqmin > sqtol) { kflag = -6; @@ -7720,7 +7479,7 @@ static int cvSLdet(CVodeMem cv_mem) /* given rr, find sigsq[k] and verify rr. */ /* All positive kflag drop to this section */ - + for (k=1; k<=3; k++) { rsa = cv_mem->cv_ssdat[1][k]; rsb = cv_mem->cv_ssdat[2][k]*rr; @@ -7732,12 +7491,12 @@ static int cvSLdet(CVodeMem cv_mem) rd2a = rd1a - rd1b; rd2b = rd1b - rd1c; rd3a = rd2a - rd2b; - + if (SUNRabs(rd1b) < TINY*smax[k]) { kflag = -7; return(kflag); } - + cest1 = -rd3a/rd1b; if (cest1 < TINY || cest1 > FOUR) { kflag = -7; @@ -7746,51 +7505,51 @@ static int cvSLdet(CVodeMem cv_mem) corr1 = (rd2b/cest1)/(rr*rr); sigsq[k] = cv_mem->cv_ssdat[3][k] + corr1; } - + if (sigsq[2] < TINY) { kflag = -8; return(kflag); } - + ratp = sigsq[3]/sigsq[2]; ratm = sigsq[1]/sigsq[2]; qfac1 = FOURTH*(cv_mem->cv_q*cv_mem->cv_q - ONE); qfac2 = TWO/(cv_mem->cv_q - ONE); bb = ratp*ratm - ONE - qfac1*ratp; tem = ONE - qfac2*bb; - + if (SUNRabs(tem) < TINY) { kflag = -8; return(kflag); } - + rrb = ONE/tem; - + if (SUNRabs(rrb - rr) > rrtol) { kflag = -9; return(kflag); } - + /* Check to see if rr is above cutoff rrcut */ if (rr > rrcut) { if (kflag == 1) kflag = 4; if (kflag == 2) kflag = 5; if (kflag == 3) kflag = 6; } - + /* All positive kflag returned at this point */ - + return(kflag); - + } -/* +/* * ----------------------------------------------------------------- * Functions for rootfinding * ----------------------------------------------------------------- */ -/* +/* * cvRcheck1 * * This routine completes the initialization of rootfinding memory @@ -7808,8 +7567,7 @@ static int cvRcheck1(CVodeMem cv_mem) realtype smallh, hratio, tplus; booleantype zroot; - for (i = 0; i < cv_mem->cv_nrtfn; i++) - cv_mem->cv_iroots[i] = 0; + for (i = 0; i < cv_mem->cv_nrtfn; i++) cv_mem->cv_iroots[i] = 0; cv_mem->cv_tlo = cv_mem->cv_tn; cv_mem->cv_ttol = (SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_h)) * cv_mem->cv_uround*HUNDRED; @@ -7886,8 +7644,7 @@ static int cvRcheck2(CVodeMem cv_mem) if (retval != 0) return(CV_RTFUNC_FAIL); zroot = SUNFALSE; - for (i = 0; i < cv_mem->cv_nrtfn; i++) - cv_mem->cv_iroots[i] = 0; + for (i = 0; i < cv_mem->cv_nrtfn; i++) cv_mem->cv_iroots[i] = 0; for (i = 0; i < cv_mem->cv_nrtfn; i++) { if (!cv_mem->cv_gactive[i]) continue; if (SUNRabs(cv_mem->cv_glo[i]) == ZERO) { @@ -7899,7 +7656,7 @@ static int cvRcheck2(CVodeMem cv_mem) /* One or more g_i has a zero at tlo. Check g at tlo+smallh. */ cv_mem->cv_ttol = (SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_h)) * - cv_mem->cv_uround*HUNDRED; + cv_mem->cv_uround * HUNDRED; smallh = (cv_mem->cv_h > ZERO) ? cv_mem->cv_ttol : -cv_mem->cv_ttol; tplus = cv_mem->cv_tlo + smallh; if ( (tplus - cv_mem->cv_tn)*cv_mem->cv_h >= ZERO) { @@ -7955,7 +7712,7 @@ static int cvRcheck3(CVodeMem cv_mem) } if (cv_mem->cv_taskc == CV_NORMAL) { if ( (cv_mem->cv_toutc - cv_mem->cv_tn)*cv_mem->cv_h >= ZERO) { - cv_mem->cv_thi = cv_mem->cv_tn; + cv_mem->cv_thi = cv_mem->cv_tn; N_VScale(ONE, cv_mem->cv_zn[0], cv_mem->cv_y); } else { cv_mem->cv_thi = cv_mem->cv_toutc; @@ -7970,7 +7727,7 @@ static int cvRcheck3(CVodeMem cv_mem) if (retval != 0) return(CV_RTFUNC_FAIL); cv_mem->cv_ttol = (SUNRabs(cv_mem->cv_tn) + SUNRabs(cv_mem->cv_h)) * - cv_mem->cv_uround*HUNDRED; + cv_mem->cv_uround * HUNDRED; ier = cvRootfind(cv_mem); if (ier == CV_RTFUNC_FAIL) return(CV_RTFUNC_FAIL); for(i=0; icv_nrtfn; i++) { @@ -7981,7 +7738,7 @@ static int cvRcheck3(CVodeMem cv_mem) for (i = 0; i < cv_mem->cv_nrtfn; i++) cv_mem->cv_glo[i] = cv_mem->cv_grout[i]; - /* If no root found, return CV_SUCCESS. */ + /* If no root found, return CV_SUCCESS. */ if (ier == CV_SUCCESS) return(CV_SUCCESS); /* If a root was found, interpolate to get y(trout) and return. */ @@ -8022,7 +7779,7 @@ static int cvRcheck3(CVodeMem cv_mem) * set to SUNTRUE for all i=0,...,nrtfn-1, but it may be * reset to SUNFALSE if at the first step g[i] is 0.0 * both at the I.C. and at a small perturbation of them. - * gactive[i] is then set back on SUNTRUE only after the + * gactive[i] is then set back on SUNTRUE only after the * corresponding g function moves away from 0.0. * * nge = cumulative counter for gfun calls. @@ -8097,142 +7854,468 @@ static int cvRootfind(CVodeMem cv_mem) } } - /* If no sign change was found, reset trout and grout. Then return - CV_SUCCESS if no zero was found, or set iroots and return RTFOUND. */ - if (!sgnchg) { - cv_mem->cv_trout = cv_mem->cv_thi; - for (i = 0; i < cv_mem->cv_nrtfn; i++) - cv_mem->cv_grout[i] = cv_mem->cv_ghi[i]; - if (!zroot) return(CV_SUCCESS); - for (i = 0; i < cv_mem->cv_nrtfn; i++) { - cv_mem->cv_iroots[i] = 0; - if(!cv_mem->cv_gactive[i]) continue; - if ( (SUNRabs(cv_mem->cv_ghi[i]) == ZERO) && - (cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) ) - cv_mem->cv_iroots[i] = cv_mem->cv_glo[i] > 0 ? -1:1; + /* If no sign change was found, reset trout and grout. Then return + CV_SUCCESS if no zero was found, or set iroots and return RTFOUND. */ + if (!sgnchg) { + cv_mem->cv_trout = cv_mem->cv_thi; + for (i = 0; i < cv_mem->cv_nrtfn; i++) cv_mem->cv_grout[i] = cv_mem->cv_ghi[i]; + if (!zroot) return(CV_SUCCESS); + for (i = 0; i < cv_mem->cv_nrtfn; i++) { + cv_mem->cv_iroots[i] = 0; + if(!cv_mem->cv_gactive[i]) continue; + if ( (SUNRabs(cv_mem->cv_ghi[i]) == ZERO) && + (cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) ) + cv_mem->cv_iroots[i] = cv_mem->cv_glo[i] > 0 ? -1 : 1; + } + return(RTFOUND); + } + + /* Initialize alph to avoid compiler warning */ + alph = ONE; + + /* A sign change was found. Loop to locate nearest root. */ + + side = 0; sideprev = -1; + for(;;) { /* Looping point */ + + /* If interval size is already less than tolerance ttol, break. */ + if (SUNRabs(cv_mem->cv_thi - cv_mem->cv_tlo) <= cv_mem->cv_ttol) break; + + /* Set weight alph. + On the first two passes, set alph = 1. Thereafter, reset alph + according to the side (low vs high) of the subinterval in which + the sign change was found in the previous two passes. + If the sides were opposite, set alph = 1. + If the sides were the same, then double alph (if high side), + or halve alph (if low side). + The next guess tmid is the secant method value if alph = 1, but + is closer to tlo if alph < 1, and closer to thi if alph > 1. */ + + if (sideprev == side) { + alph = (side == 2) ? alph*TWO : alph*HALF; + } else { + alph = ONE; + } + + /* Set next root approximation tmid and get g(tmid). + If tmid is too close to tlo or thi, adjust it inward, + by a fractional distance that is between 0.1 and 0.5. */ + tmid = cv_mem->cv_thi - (cv_mem->cv_thi - cv_mem->cv_tlo) * + cv_mem->cv_ghi[imax] / (cv_mem->cv_ghi[imax] - alph*cv_mem->cv_glo[imax]); + if (SUNRabs(tmid - cv_mem->cv_tlo) < HALF*cv_mem->cv_ttol) { + fracint = SUNRabs(cv_mem->cv_thi - cv_mem->cv_tlo)/cv_mem->cv_ttol; + fracsub = (fracint > FIVE) ? PT1 : HALF/fracint; + tmid = cv_mem->cv_tlo + fracsub*(cv_mem->cv_thi - cv_mem->cv_tlo); + } + if (SUNRabs(cv_mem->cv_thi - tmid) < HALF*cv_mem->cv_ttol) { + fracint = SUNRabs(cv_mem->cv_thi - cv_mem->cv_tlo)/cv_mem->cv_ttol; + fracsub = (fracint > FIVE) ? PT1 : HALF/fracint; + tmid = cv_mem->cv_thi - fracsub*(cv_mem->cv_thi - cv_mem->cv_tlo); + } + + (void) CVodeGetDky(cv_mem, tmid, 0, cv_mem->cv_y); + retval = cv_mem->cv_gfun(tmid, cv_mem->cv_y, cv_mem->cv_grout, + cv_mem->cv_user_data); + cv_mem->cv_nge++; + if (retval != 0) return(CV_RTFUNC_FAIL); + + /* Check to see in which subinterval g changes sign, and reset imax. + Set side = 1 if sign change is on low side, or 2 if on high side. */ + maxfrac = ZERO; + zroot = SUNFALSE; + sgnchg = SUNFALSE; + sideprev = side; + for (i = 0; i < cv_mem->cv_nrtfn; i++) { + if(!cv_mem->cv_gactive[i]) continue; + if (SUNRabs(cv_mem->cv_grout[i]) == ZERO) { + if(cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) zroot = SUNTRUE; + } else { + if ( (cv_mem->cv_glo[i]*cv_mem->cv_grout[i] < ZERO) && + (cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) ) { + gfrac = SUNRabs(cv_mem->cv_grout[i] / + (cv_mem->cv_grout[i] - cv_mem->cv_glo[i])); + if (gfrac > maxfrac) { + sgnchg = SUNTRUE; + maxfrac = gfrac; + imax = i; + } + } + } + } + if (sgnchg) { + /* Sign change found in (tlo,tmid); replace thi with tmid. */ + cv_mem->cv_thi = tmid; + for (i = 0; i < cv_mem->cv_nrtfn; i++) + cv_mem->cv_ghi[i] = cv_mem->cv_grout[i]; + side = 1; + /* Stop at root thi if converged; otherwise loop. */ + if (SUNRabs(cv_mem->cv_thi - cv_mem->cv_tlo) <= cv_mem->cv_ttol) break; + continue; /* Return to looping point. */ + } + + if (zroot) { + /* No sign change in (tlo,tmid), but g = 0 at tmid; return root tmid. */ + cv_mem->cv_thi = tmid; + for (i = 0; i < cv_mem->cv_nrtfn; i++) + cv_mem->cv_ghi[i] = cv_mem->cv_grout[i]; + break; + } + + /* No sign change in (tlo,tmid), and no zero at tmid. + Sign change must be in (tmid,thi). Replace tlo with tmid. */ + cv_mem->cv_tlo = tmid; + for (i = 0; i < cv_mem->cv_nrtfn; i++) + cv_mem->cv_glo[i] = cv_mem->cv_grout[i]; + side = 2; + /* Stop at root thi if converged; otherwise loop back. */ + if (SUNRabs(cv_mem->cv_thi - cv_mem->cv_tlo) <= cv_mem->cv_ttol) break; + + } /* End of root-search loop */ + + /* Reset trout and grout, set iroots, and return RTFOUND. */ + cv_mem->cv_trout = cv_mem->cv_thi; + for (i = 0; i < cv_mem->cv_nrtfn; i++) { + cv_mem->cv_grout[i] = cv_mem->cv_ghi[i]; + cv_mem->cv_iroots[i] = 0; + if(!cv_mem->cv_gactive[i]) continue; + if ( (SUNRabs(cv_mem->cv_ghi[i]) == ZERO) && + (cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) ) + cv_mem->cv_iroots[i] = cv_mem->cv_glo[i] > 0 ? -1 : 1; + if ( (cv_mem->cv_glo[i]*cv_mem->cv_ghi[i] < ZERO) && + (cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) ) + cv_mem->cv_iroots[i] = cv_mem->cv_glo[i] > 0 ? -1 : 1; + } + return(RTFOUND); +} + +/* + * ================================================================= + * Internal EWT function + * ================================================================= + */ + +/* + * cvEwtSet + * + * This routine is responsible for setting the error weight vector ewt, + * according to tol_type, as follows: + * + * (1) ewt[i] = 1 / (reltol * SUNRabs(ycur[i]) + abstol), i=0,...,neq-1 + * if tol_type = CV_SS + * (2) ewt[i] = 1 / (reltol * SUNRabs(ycur[i]) + abstol[i]), i=0,...,neq-1 + * if tol_type = CV_SV + * + * cvEwtSet returns 0 if ewt is successfully set as above to a + * positive vector and -1 otherwise. In the latter case, ewt is + * considered undefined. + * + * All the real work is done in the routines cvEwtSetSS, cvEwtSetSV. + */ + +int cvEwtSet(N_Vector ycur, N_Vector weight, void *data) +{ + CVodeMem cv_mem; + int flag = 0; + + /* data points to cv_mem here */ + + cv_mem = (CVodeMem) data; + + switch(cv_mem->cv_itol) { + case CV_SS: + flag = cvEwtSetSS(cv_mem, ycur, weight); + break; + case CV_SV: + flag = cvEwtSetSV(cv_mem, ycur, weight); + break; + } + + return(flag); +} + +/* + * cvEwtSetSS + * + * This routine sets ewt as decribed above in the case tol_type = CV_SS. + * If the absolute tolerance is zero, it tests for non-positive components + * before inverting. cvEwtSetSS returns 0 if ewt is successfully set to a + * positive vector and -1 otherwise. In the latter case, ewt is considered + * undefined. + */ + +static int cvEwtSetSS(CVodeMem cv_mem, N_Vector ycur, N_Vector weight) +{ + N_VAbs(ycur, cv_mem->cv_tempv); + N_VScale(cv_mem->cv_reltol, cv_mem->cv_tempv, cv_mem->cv_tempv); + N_VAddConst(cv_mem->cv_tempv, cv_mem->cv_Sabstol, cv_mem->cv_tempv); + if (cv_mem->cv_atolmin0) { + if (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); + } + N_VInv(cv_mem->cv_tempv, weight); + return(0); +} + +/* + * cvEwtSetSV + * + * This routine sets ewt as decribed above in the case tol_type = CV_SV. + * If any absolute tolerance is zero, it tests for non-positive components + * before inverting. cvEwtSetSV returns 0 if ewt is successfully set to a + * positive vector and -1 otherwise. In the latter case, ewt is considered + * undefined. + */ + +static int cvEwtSetSV(CVodeMem cv_mem, N_Vector ycur, N_Vector weight) +{ + N_VAbs(ycur, cv_mem->cv_tempv); + N_VLinearSum(cv_mem->cv_reltol, cv_mem->cv_tempv, ONE, + cv_mem->cv_Vabstol, cv_mem->cv_tempv); + if (cv_mem->cv_atolmin0) { + if (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); + } + N_VInv(cv_mem->cv_tempv, weight); + return(0); +} + +/* + * cvQuadEwtSet + * + */ + +static int cvQuadEwtSet(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ) +{ + int flag=0; + + switch (cv_mem->cv_itolQ) { + case CV_SS: + flag = cvQuadEwtSetSS(cv_mem, qcur, weightQ); + break; + case CV_SV: + flag = cvQuadEwtSetSV(cv_mem, qcur, weightQ); + break; + } + + return(flag); + +} + +/* + * cvQuadEwtSetSS + * + */ + +static int cvQuadEwtSetSS(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ) +{ + N_VAbs(qcur, cv_mem->cv_tempvQ); + N_VScale(cv_mem->cv_reltolQ, cv_mem->cv_tempvQ, cv_mem->cv_tempvQ); + N_VAddConst(cv_mem->cv_tempvQ, cv_mem->cv_SabstolQ, cv_mem->cv_tempvQ); + if (cv_mem->cv_atolQmin0) { + if (N_VMin(cv_mem->cv_tempvQ) <= ZERO) return(-1); + } + N_VInv(cv_mem->cv_tempvQ, weightQ); + return(0); +} + +/* + * cvQuadEwtSetSV + * + */ + +static int cvQuadEwtSetSV(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ) +{ + N_VAbs(qcur, cv_mem->cv_tempvQ); + N_VLinearSum(cv_mem->cv_reltolQ, cv_mem->cv_tempvQ, ONE, + cv_mem->cv_VabstolQ, cv_mem->cv_tempvQ); + if (cv_mem->cv_atolQmin0) { + if (N_VMin(cv_mem->cv_tempvQ) <= ZERO) return(-1); + } + N_VInv(cv_mem->cv_tempvQ, weightQ); + return(0); +} + +/* + * cvSensEwtSet + * + */ + +static int cvSensEwtSet(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS) +{ + int flag=0; + + switch (cv_mem->cv_itolS) { + case CV_EE: + flag = cvSensEwtSetEE(cv_mem, yScur, weightS); + break; + case CV_SS: + flag = cvSensEwtSetSS(cv_mem, yScur, weightS); + break; + case CV_SV: + flag = cvSensEwtSetSV(cv_mem, yScur, weightS); + break; + } + + return(flag); +} + +/* + * cvSensEwtSetEE + * + * In this case, the error weight vector for the i-th sensitivity is set to + * + * ewtS_i = pbar_i * efun(pbar_i*yS_i) + * + * In other words, the scaled sensitivity pbar_i * yS_i has the same error + * weight vector calculation as the solution vector. + * + */ + +static int cvSensEwtSetEE(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS) +{ + int is; + N_Vector pyS; + int flag; + + /* Use tempvS[0] as temporary storage for the scaled sensitivity */ + pyS = cv_mem->cv_tempvS[0]; + + for (is=0; iscv_Ns; is++) { + N_VScale(cv_mem->cv_pbar[is], yScur[is], pyS); + flag = cv_mem->cv_efun(pyS, weightS[is], cv_mem->cv_e_data); + if (flag != 0) return(-1); + N_VScale(cv_mem->cv_pbar[is], weightS[is], weightS[is]); + } + return(0); +} + +/* + * cvSensEwtSetSS + * + */ + +static int cvSensEwtSetSS(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS) +{ + int is; + + for (is=0; iscv_Ns; is++) { + N_VAbs(yScur[is], cv_mem->cv_tempv); + N_VScale(cv_mem->cv_reltolS, cv_mem->cv_tempv, cv_mem->cv_tempv); + N_VAddConst(cv_mem->cv_tempv, cv_mem->cv_SabstolS[is], cv_mem->cv_tempv); + if (cv_mem->cv_atolSmin0[is]) { + if (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); + } + N_VInv(cv_mem->cv_tempv, weightS[is]); + } + return(0); +} + +/* + * cvSensEwtSetSV + * + */ + +static int cvSensEwtSetSV(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS) +{ + int is; + + for (is=0; iscv_Ns; is++) { + N_VAbs(yScur[is], cv_mem->cv_tempv); + N_VLinearSum(cv_mem->cv_reltolS, cv_mem->cv_tempv, ONE, + cv_mem->cv_VabstolS[is], cv_mem->cv_tempv); + if (cv_mem->cv_atolSmin0[is]) { + if (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); } - return(RTFOUND); + N_VInv(cv_mem->cv_tempv, weightS[is]); } + return(0); +} - /* Initialize alph to avoid compiler warning */ - alph = ONE; - - /* A sign change was found. Loop to locate nearest root. */ +/* + * cvQuadSensEwtSet + * + */ - side = 0; sideprev = -1; - for(;;) { /* Looping point */ +static int cvQuadSensEwtSet(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS) +{ + int flag=0; - /* If interval size is already less than tolerance ttol, break. */ - if (SUNRabs(cv_mem->cv_thi - cv_mem->cv_tlo) <= cv_mem->cv_ttol) break; + switch (cv_mem->cv_itolQS) { + case CV_EE: + flag = cvQuadSensEwtSetEE(cv_mem, yQScur, weightQS); + break; + case CV_SS: + flag = cvQuadSensEwtSetSS(cv_mem, yQScur, weightQS); + break; + case CV_SV: + flag = cvQuadSensEwtSetSV(cv_mem, yQScur, weightQS); + break; + } - /* Set weight alph. - On the first two passes, set alph = 1. Thereafter, reset alph - according to the side (low vs high) of the subinterval in which - the sign change was found in the previous two passes. - If the sides were opposite, set alph = 1. - If the sides were the same, then double alph (if high side), - or halve alph (if low side). - The next guess tmid is the secant method value if alph = 1, but - is closer to cv_mem->cv_tlo if alph < 1, and closer to thi if alph > 1. */ + return(flag); +} - if (sideprev == side) { - alph = (side == 2) ? alph*TWO : alph*HALF; - } else { - alph = ONE; - } +/* + * cvQuadSensEwtSetEE + * + * In this case, the error weight vector for the i-th quadrature sensitivity + * is set to + * + * ewtQS_i = pbar_i * cvQuadEwtSet(pbar_i*yQS_i) + * + * In other words, the scaled sensitivity pbar_i * yQS_i has the same error + * weight vector calculation as the quadrature vector. + * + */ +static int cvQuadSensEwtSetEE(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS) +{ + int is; + N_Vector pyS; + int flag; - /* Set next root approximation tmid and get g(tmid). - If tmid is too close to tlo or thi, adjust it inward, - by a fractional distance that is between 0.1 and 0.5. */ - tmid = cv_mem->cv_thi - (cv_mem->cv_thi - cv_mem->cv_tlo) * - cv_mem->cv_ghi[imax] / (cv_mem->cv_ghi[imax] - alph*cv_mem->cv_glo[imax]); - if (SUNRabs(tmid - cv_mem->cv_tlo) < HALF*cv_mem->cv_ttol) { - fracint = SUNRabs(cv_mem->cv_thi - cv_mem->cv_tlo)/cv_mem->cv_ttol; - fracsub = (fracint > FIVE) ? PT1 : HALF/fracint; - tmid = cv_mem->cv_tlo + fracsub*(cv_mem->cv_thi - cv_mem->cv_tlo); - } - if (SUNRabs(cv_mem->cv_thi - tmid) < HALF*cv_mem->cv_ttol) { - fracint = SUNRabs(cv_mem->cv_thi - cv_mem->cv_tlo)/cv_mem->cv_ttol; - fracsub = (fracint > FIVE) ? PT1 : HALF/fracint; - tmid = cv_mem->cv_thi - fracsub*(cv_mem->cv_thi - cv_mem->cv_tlo); - } + /* Use tempvQS[0] as temporary storage for the scaled sensitivity */ + pyS = cv_mem->cv_tempvQS[0]; - (void) CVodeGetDky(cv_mem, tmid, 0, cv_mem->cv_y); - retval = cv_mem->cv_gfun(tmid, cv_mem->cv_y, cv_mem->cv_grout, - cv_mem->cv_user_data); - cv_mem->cv_nge++; - if (retval != 0) return(CV_RTFUNC_FAIL); + for (is=0; iscv_Ns; is++) { + N_VScale(cv_mem->cv_pbar[is], yQScur[is], pyS); + flag = cvQuadEwtSet(cv_mem, pyS, weightQS[is]); + if (flag != 0) return(-1); + N_VScale(cv_mem->cv_pbar[is], weightQS[is], weightQS[is]); + } + return(0); +} - /* Check to see in which subinterval g changes sign, and reset imax. - Set side = 1 if sign change is on low side, or 2 if on high side. */ - maxfrac = ZERO; - zroot = SUNFALSE; - sgnchg = SUNFALSE; - sideprev = side; - for (i = 0; i < cv_mem->cv_nrtfn; i++) { - if(!cv_mem->cv_gactive[i]) continue; - if (SUNRabs(cv_mem->cv_grout[i]) == ZERO) { - if(cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) zroot = SUNTRUE; - } else { - if ( (cv_mem->cv_glo[i]*cv_mem->cv_grout[i] < ZERO) && - (cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) ) { - gfrac = SUNRabs(cv_mem->cv_grout[i] / - (cv_mem->cv_grout[i] - cv_mem->cv_glo[i])); - if (gfrac > maxfrac) { - sgnchg = SUNTRUE; - maxfrac = gfrac; - imax = i; - } - } - } - } - if (sgnchg) { - /* Sign change found in (tlo,tmid); replace thi with tmid. */ - cv_mem->cv_thi = tmid; - for (i = 0; i < cv_mem->cv_nrtfn; i++) - cv_mem->cv_ghi[i] = cv_mem->cv_grout[i]; - side = 1; - /* Stop at root thi if converged; otherwise loop. */ - if (SUNRabs(cv_mem->cv_thi - cv_mem->cv_tlo) <= cv_mem->cv_ttol) break; - continue; /* Return to looping point. */ - } +static int cvQuadSensEwtSetSS(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS) +{ + int is; - if (zroot) { - /* No sign change in (tlo,tmid), but g = 0 at tmid; return root tmid. */ - cv_mem->cv_thi = tmid; - for (i = 0; i < cv_mem->cv_nrtfn; i++) - cv_mem->cv_ghi[i] = cv_mem->cv_grout[i]; - break; + for (is=0; iscv_Ns; is++) { + N_VAbs(yQScur[is], cv_mem->cv_tempvQ); + N_VScale(cv_mem->cv_reltolQS, cv_mem->cv_tempvQ, cv_mem->cv_tempvQ); + N_VAddConst(cv_mem->cv_tempvQ, cv_mem->cv_SabstolQS[is], cv_mem->cv_tempvQ); + if (cv_mem->cv_atolQSmin0[is]) { + if (N_VMin(cv_mem->cv_tempvQ) <= ZERO) return(-1); } + N_VInv(cv_mem->cv_tempvQ, weightQS[is]); + } + return(0); +} - /* No sign change in (tlo,tmid), and no zero at tmid. - Sign change must be in (tmid,thi). Replace tlo with tmid. */ - cv_mem->cv_tlo = tmid; - for (i = 0; i < cv_mem->cv_nrtfn; i++) - cv_mem->cv_glo[i] = cv_mem->cv_grout[i]; - side = 2; - /* Stop at root thi if converged; otherwise loop back. */ - if (SUNRabs(cv_mem->cv_thi - cv_mem->cv_tlo) <= cv_mem->cv_ttol) break; - - } /* End of root-search loop */ +static int cvQuadSensEwtSetSV(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS) +{ + int is; - /* Reset trout and grout, set iroots, and return RTFOUND. */ - cv_mem->cv_trout = cv_mem->cv_thi; - for (i = 0; i < cv_mem->cv_nrtfn; i++) { - cv_mem->cv_grout[i] = cv_mem->cv_ghi[i]; - cv_mem->cv_iroots[i] = 0; - if(!cv_mem->cv_gactive[i]) continue; - if ( (SUNRabs(cv_mem->cv_ghi[i]) == ZERO) && - (cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) ) - cv_mem->cv_iroots[i] = cv_mem->cv_glo[i] > 0 ? -1:1; - if ( (cv_mem->cv_glo[i]*cv_mem->cv_ghi[i] < ZERO) && - (cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) ) - cv_mem->cv_iroots[i] = cv_mem->cv_glo[i] > 0 ? -1:1; + for (is=0; iscv_Ns; is++) { + N_VAbs(yQScur[is], cv_mem->cv_tempvQ); + N_VLinearSum(cv_mem->cv_reltolQS, cv_mem->cv_tempvQ, ONE, + cv_mem->cv_VabstolQS[is], cv_mem->cv_tempvQ); + if (cv_mem->cv_atolQSmin0[is]) { + if (N_VMin(cv_mem->cv_tempvQ) <= ZERO) return(-1); + } + N_VInv(cv_mem->cv_tempvQ, weightQS[is]); } - return(RTFOUND); + return(0); } -/* +/* * ----------------------------------------------------------------- * Functions for combined norms * ----------------------------------------------------------------- @@ -8257,12 +8340,12 @@ static realtype cvQuadUpdateNorm(CVodeMem cv_mem, realtype old_nrm, /* * cvSensNorm * - * This routine returns the maximum over the weighted root mean + * This routine returns the maximum over the weighted root mean * square norm of xS with weight vectors wS: * - * max { wrms(xS[0],wS[0]) ... wrms(xS[Ns-1],wS[Ns-1]) } + * max { wrms(xS[0],wS[0]) ... wrms(xS[Ns-1],wS[Ns-1]) } * - * Called by cvSensUpdateNorm or directly in the CV_STAGGERED approach + * Called by cvSensUpdateNorm or directly in the CV_STAGGERED approach * during the NLS solution and before the error test. */ @@ -8272,7 +8355,7 @@ realtype cvSensNorm(CVodeMem cv_mem, N_Vector *xS, N_Vector *wS) realtype nrm; (void) N_VWrmsNormVectorArray(cv_mem->cv_Ns, xS, wS, cv_mem->cv_cvals); - + nrm = cv_mem->cv_cvals[0]; for (is=1; iscv_Ns; is++) if ( cv_mem->cv_cvals[is] > nrm ) nrm = cv_mem->cv_cvals[is]; @@ -8290,7 +8373,7 @@ realtype cvSensUpdateNorm(CVodeMem cv_mem, realtype old_nrm, N_Vector *xS, N_Vector *wS) { realtype snrm; - + snrm = cvSensNorm(cv_mem, xS, wS); if (old_nrm > snrm) return(old_nrm); else return(snrm); @@ -8299,10 +8382,10 @@ realtype cvSensUpdateNorm(CVodeMem cv_mem, realtype old_nrm, /* * cvQuadSensNorm * - * This routine returns the maximum over the weighted root mean + * This routine returns the maximum over the weighted root mean * square norm of xQS with weight vectors wQS: * - * max { wrms(xQS[0],wS[0]) ... wrms(xQS[Ns-1],wS[Ns-1]) } + * max { wrms(xQS[0],wS[0]) ... wrms(xQS[Ns-1],wS[Ns-1]) } * * Called by cvQuadSensUpdateNorm. */ @@ -8313,7 +8396,7 @@ static realtype cvQuadSensNorm(CVodeMem cv_mem, N_Vector *xQS, N_Vector *wQS) realtype nrm; (void) N_VWrmsNormVectorArray(cv_mem->cv_Ns, xQS, wQS, cv_mem->cv_cvals); - + nrm = cv_mem->cv_cvals[0]; for (is=1; iscv_Ns; is++) if ( cv_mem->cv_cvals[is] > nrm ) nrm = cv_mem->cv_cvals[is]; @@ -8331,13 +8414,13 @@ static realtype cvQuadSensUpdateNorm(CVodeMem cv_mem, realtype old_nrm, N_Vector *xQS, N_Vector *wQS) { realtype snrm; - + snrm = cvQuadSensNorm(cv_mem, xQS, wQS); if (old_nrm > snrm) return(old_nrm); else return(snrm); } -/* +/* * ----------------------------------------------------------------- * Wrappers for sensitivity RHS * ----------------------------------------------------------------- @@ -8346,9 +8429,9 @@ static realtype cvQuadSensUpdateNorm(CVodeMem cv_mem, realtype old_nrm, /* * cvSensRhsWrapper * - * CVSensRhs is a high level routine that returns right hand side - * of sensitivity equations. Depending on the 'ifS' flag, it either - * calls directly the fS routine (ifS=CV_ALLSENS) or (if ifS=CV_ONESENS) + * CVSensRhs is a high level routine that returns right hand side + * of sensitivity equations. Depending on the 'ifS' flag, it either + * calls directly the fS routine (ifS=CV_ALLSENS) or (if ifS=CV_ONESENS) * calls the fS1 routine in a loop over all sensitivities. * * CVSensRhs is called: @@ -8357,26 +8440,26 @@ static realtype cvQuadSensUpdateNorm(CVodeMem cv_mem, realtype old_nrm, * (*) by the nonlinear solver if ism=CV_SIMULTANEOUS * (*) by cvDoErrorTest when restarting from scratch * (*) in the corrector loop if ism=CV_STAGGERED - * (*) by cvStgrDoErrorTest when restarting from scratch + * (*) by cvStgrDoErrorTest when restarting from scratch * * The return value is that of the sensitivity RHS function fS, * */ -int cvSensRhsWrapper(CVodeMem cv_mem, realtype time, - N_Vector ycur, N_Vector fcur, +int cvSensRhsWrapper(CVodeMem cv_mem, realtype time, + N_Vector ycur, N_Vector fcur, N_Vector *yScur, N_Vector *fScur, N_Vector temp1, N_Vector temp2) { int retval=0, is; if (cv_mem->cv_ifS==CV_ALLSENS) { - retval = cv_mem->cv_fS(cv_mem->cv_Ns, time, ycur, fcur, yScur, + retval = cv_mem->cv_fS(cv_mem->cv_Ns, time, ycur, fcur, yScur, fScur, cv_mem->cv_fS_data, temp1, temp2); cv_mem->cv_nfSe++; } else { for (is=0; iscv_Ns; is++) { - retval = cv_mem->cv_fS1(cv_mem->cv_Ns, time, ycur, fcur, is, yScur[is], + retval = cv_mem->cv_fS1(cv_mem->cv_Ns, time, ycur, fcur, is, yScur[is], fScur[is], cv_mem->cv_fS_data, temp1, temp2); cv_mem->cv_nfSe++; if (retval != 0) break; @@ -8390,30 +8473,30 @@ int cvSensRhsWrapper(CVodeMem cv_mem, realtype time, * cvSensRhs1Wrapper * * cvSensRhs1Wrapper is a high level routine that returns right-hand - * side of the is-th sensitivity equation. + * side of the is-th sensitivity equation. * * cvSensRhs1Wrapper is called only during the CV_STAGGERED1 corrector loop - * (ifS must be CV_ONESENS, otherwise CVodeSensInit would have + * (ifS must be CV_ONESENS, otherwise CVodeSensInit would have * issued an error message). * * The return value is that of the sensitivity RHS function fS1, */ -int cvSensRhs1Wrapper(CVodeMem cv_mem, realtype time, - N_Vector ycur, N_Vector fcur, +int cvSensRhs1Wrapper(CVodeMem cv_mem, realtype time, + N_Vector ycur, N_Vector fcur, int is, N_Vector yScur, N_Vector fScur, N_Vector temp1, N_Vector temp2) { int retval; - retval = cv_mem->cv_fS1(cv_mem->cv_Ns, time, ycur, fcur, is, yScur, + retval = cv_mem->cv_fS1(cv_mem->cv_Ns, time, ycur, fcur, is, yScur, fScur, cv_mem->cv_fS_data, temp1, temp2); cv_mem->cv_nfSe++; return(retval); } -/* +/* * ----------------------------------------------------------------- * Internal DQ approximations for sensitivity RHS * ----------------------------------------------------------------- @@ -8430,16 +8513,16 @@ int cvSensRhs1Wrapper(CVodeMem cv_mem, realtype time, * by finite differences */ -int cvSensRhsInternalDQ(int Ns, realtype t, - N_Vector y, N_Vector ydot, - N_Vector *yS, N_Vector *ySdot, - void *cvode_mem, +int cvSensRhsInternalDQ(int Ns, realtype t, + N_Vector y, N_Vector ydot, + N_Vector *yS, N_Vector *ySdot, + void *cvode_mem, N_Vector ytemp, N_Vector ftemp) { int is, retval; - + for (is=0; iscv_reltol, cv_mem->cv_uround)); rdelta = ONE/delta; - + pbari = cv_mem->cv_pbar[is]; which = cv_mem->cv_plist[is]; psave = cv_mem->cv_p[which]; - + Deltap = pbari * delta; rDeltap = ONE/Deltap; norms = N_VWrmsNorm(yS, cv_mem->cv_ewt) * pbari; rDeltay = SUNMAX(norms, rdelta) / pbari; Deltay = ONE/rDeltay; - + if (cv_mem->cv_DQrhomax == ZERO) { /* No switching */ method = (cv_mem->cv_DQtype==CV_CENTERED) ? CENTERED1 : FORWARD1; @@ -8508,19 +8591,19 @@ int cvSensRhs1InternalDQ(int Ns, realtype t, } switch(method) { - + case CENTERED1: - + Delta = SUNMIN(Deltay, Deltap); r2Delta = HALF/Delta; - + N_VLinearSum(ONE,y,Delta,yS,ytemp); cv_mem->cv_p[which] = psave + Delta; retval = cv_mem->cv_f(t, ytemp, ySdot, cv_mem->cv_user_data); nfel++; if (retval != 0) return(retval); - + N_VLinearSum(ONE,y,-Delta,yS,ytemp); cv_mem->cv_p[which] = psave - Delta; @@ -8529,14 +8612,14 @@ int cvSensRhs1InternalDQ(int Ns, realtype t, if (retval != 0) return(retval); N_VLinearSum(r2Delta,ySdot,-r2Delta,ftemp,ySdot); - + break; - + case CENTERED2: - + r2Deltap = HALF/Deltap; r2Deltay = HALF/Deltay; - + N_VLinearSum(ONE,y,Deltay,yS,ytemp); retval = cv_mem->cv_f(t, ytemp, ySdot, cv_mem->cv_user_data); @@ -8550,7 +8633,7 @@ int cvSensRhs1InternalDQ(int Ns, realtype t, if (retval != 0) return(retval); N_VLinearSum(r2Deltay, ySdot, -r2Deltay, ftemp, ySdot); - + cv_mem->cv_p[which] = psave + Deltap; retval = cv_mem->cv_f(t, y, ytemp, cv_mem->cv_user_data); nfel++; @@ -8560,7 +8643,7 @@ int cvSensRhs1InternalDQ(int Ns, realtype t, retval = cv_mem->cv_f(t, y, ftemp, cv_mem->cv_user_data); nfel++; if (retval != 0) return(retval); - + /* ySdot = ySdot + r2Deltap * ytemp - r2Deltap * ftemp */ cvals[0] = ONE; Xvecs[0] = ySdot; cvals[1] = r2Deltap; Xvecs[1] = ytemp; @@ -8572,23 +8655,23 @@ int cvSensRhs1InternalDQ(int Ns, realtype t, break; case FORWARD1: - + Delta = SUNMIN(Deltay, Deltap); rDelta = ONE/Delta; - + N_VLinearSum(ONE,y,Delta,yS,ytemp); cv_mem->cv_p[which] = psave + Delta; retval = cv_mem->cv_f(t, ytemp, ySdot, cv_mem->cv_user_data); nfel++; if (retval != 0) return(retval); - + N_VLinearSum(rDelta,ySdot,-rDelta,ydot,ySdot); - + break; - + case FORWARD2: - + N_VLinearSum(ONE,y,Deltay,yS,ytemp); retval = cv_mem->cv_f(t, ytemp, ySdot, cv_mem->cv_user_data); @@ -8596,7 +8679,7 @@ int cvSensRhs1InternalDQ(int Ns, realtype t, if (retval != 0) return(retval); N_VLinearSum(rDeltay, ySdot, -rDeltay, ydot, ySdot); - + cv_mem->cv_p[which] = psave + Deltap; retval = cv_mem->cv_f(t, y, ytemp, cv_mem->cv_user_data); nfel++; @@ -8613,12 +8696,12 @@ int cvSensRhs1InternalDQ(int Ns, realtype t, break; } - + cv_mem->cv_p[which] = psave; - + /* Increment counter nfeS */ cv_mem->cv_nfeS += nfel; - + return(0); } @@ -8631,21 +8714,21 @@ int cvSensRhs1InternalDQ(int Ns, realtype t, * done in cvQuadSensRhs1InternalDQ. */ -static int cvQuadSensRhsInternalDQ(int Ns, realtype t, +static int cvQuadSensRhsInternalDQ(int Ns, realtype t, N_Vector y, N_Vector *yS, N_Vector yQdot, N_Vector *yQSdot, - void *cvode_mem, + void *cvode_mem, N_Vector tmp, N_Vector tmpQ) { CVodeMem cv_mem; int is, retval; - + /* cvode_mem is passed here as user data */ cv_mem = (CVodeMem) cvode_mem; for (is=0; iscv_reltol, cv_mem->cv_uround)); rdelta = ONE/delta; - + pbari = cv_mem->cv_pbar[is]; which = cv_mem->cv_plist[is]; psave = cv_mem->cv_p[which]; - + Deltap = pbari * delta; norms = N_VWrmsNorm(yS, cv_mem->cv_ewt) * pbari; rDeltay = SUNMAX(norms, rdelta) / pbari; Deltay = ONE/rDeltay; - + method = (cv_mem->cv_DQtype==CV_CENTERED) ? CENTERED1 : FORWARD1; switch(method) { case CENTERED1: - + Delta = SUNMIN(Deltay, Deltap); r2Delta = HALF/Delta; - + N_VLinearSum(ONE, y, Delta, yS, tmp); cv_mem->cv_p[which] = psave + Delta; retval = cv_mem->cv_fQ(t, tmp, yQSdot, cv_mem->cv_user_data); nfel++; if (retval != 0) return(retval); - + N_VLinearSum(ONE, y, -Delta, yS, tmp); cv_mem->cv_p[which] = psave - Delta; @@ -8706,38 +8789,38 @@ static int cvQuadSensRhs1InternalDQ(CVodeMem cv_mem, int is, realtype t, if (retval != 0) return(retval); N_VLinearSum(r2Delta, yQSdot, -r2Delta, tmpQ, yQSdot); - + break; case FORWARD1: - + Delta = SUNMIN(Deltay, Deltap); rDelta = ONE/Delta; - + N_VLinearSum(ONE, y, Delta, yS, tmp); cv_mem->cv_p[which] = psave + Delta; retval = cv_mem->cv_fQ(t, tmp, yQSdot, cv_mem->cv_user_data); nfel++; if (retval != 0) return(retval); - + N_VLinearSum(rDelta, yQSdot, -rDelta, yQdot, yQSdot); - + break; } cv_mem->cv_p[which] = psave; - + /* Increment counter nfQeS */ cv_mem->cv_nfQeS += nfel; - + return(0); } -/* +/* * ----------------------------------------------------------------- * Error message handling functions * ----------------------------------------------------------------- @@ -8746,18 +8829,18 @@ static int cvQuadSensRhs1InternalDQ(CVodeMem cv_mem, int is, realtype t, /* * cvProcessError is a high level error handling function. * - If cv_mem==NULL it prints the error message to stderr. - * - Otherwise, it sets up and calls the error handling function + * - Otherwise, it sets up and calls the error handling function * pointed to by cv_ehfun. */ -void cvProcessError(CVodeMem cv_mem, - int error_code, const char *module, const char *fname, +void cvProcessError(CVodeMem cv_mem, + int error_code, const char *module, const char *fname, const char *msgfmt, ...) { va_list ap; char msg[256]; - /* Initialize the argument pointer variable + /* Initialize the argument pointer variable (msgfmt is the last required argument to cvProcessError) */ va_start(ap, msgfmt); @@ -8782,7 +8865,7 @@ void cvProcessError(CVodeMem cv_mem, return; } -/* +/* * cvErrHandler is the default error handling function. * It sends the error message to the stream pointed to by cv_errfp. */ diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bandpre.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bandpre.c index 844754cf8..4f97ee56e 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bandpre.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bandpre.c @@ -1,10 +1,10 @@ /* - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Programmer(s): Daniel R. Reynolds @ SMU * Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -33,11 +33,11 @@ #define TWO RCONST(2.0) /* Prototypes of cvBandPrecSetup and cvBandPrecSolve */ -static int cvBandPrecSetup(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, +static int cvBandPrecSetup(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, realtype gamma, void *bp_data); -static int cvBandPrecSolve(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, +static int cvBandPrecSolve(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, realtype delta, int lr, void *bp_data); @@ -45,7 +45,7 @@ static int cvBandPrecSolve(realtype t, N_Vector y, N_Vector fy, static int cvBandPrecFree(CVodeMem cv_mem); /* Prototype for difference quotient Jacobian calculation routine */ -static int cvBandPrecDQJac(CVBandPrecData pdata, realtype t, N_Vector y, +static int cvBandPrecDQJac(CVBandPrecData pdata, realtype t, N_Vector y, N_Vector fy, N_Vector ftemp, N_Vector ytemp); @@ -55,10 +55,10 @@ static int cvBandPrecDQJac(CVBandPrecData pdata, realtype t, N_Vector y, /*----------------------------------------------------------------- Initialization, Free, and Get Functions - NOTE: The band linear solver assumes a serial/OpenMP/Pthreads - implementation of the NVECTOR package. Therefore, - CVBandPrecInit will first test for a compatible N_Vector - internal representation by checking that the function + NOTE: The band linear solver assumes a serial/OpenMP/Pthreads + implementation of the NVECTOR package. Therefore, + CVBandPrecInit will first test for a compatible N_Vector + internal representation by checking that the function N_VGetArrayPointer exists. -----------------------------------------------------------------*/ int CVBandPrecInit(void *cvode_mem, sunindextype N, @@ -152,7 +152,7 @@ int CVBandPrecInit(void *cvode_mem, sunindextype N, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBANDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBANDPRE", "CVBandPrecInit", MSGBP_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -164,7 +164,7 @@ int CVBandPrecInit(void *cvode_mem, sunindextype N, SUNMatDestroy(pdata->savedJ); N_VDestroy(pdata->tmp1); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBANDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBANDPRE", "CVBandPrecInit", MSGBP_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -178,11 +178,11 @@ int CVBandPrecInit(void *cvode_mem, sunindextype N, N_VDestroy(pdata->tmp1); N_VDestroy(pdata->tmp2); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVSBANDPRE", + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVSBANDPRE", "CVBandPrecInit", MSGBP_SUNLS_FAIL); return(CVLS_SUNLS_FAIL); } - + /* make sure P_data is free from any previous allocations */ if (cvls_mem->pfree) cvls_mem->pfree(cv_mem); @@ -209,7 +209,7 @@ int CVBandPrecGetWorkSpace(void *cvode_mem, long int *lenrwBP, sunindextype lrw1, liw1; long int lrw, liw; int flag; - + if (cvode_mem == NULL) { cvProcessError(NULL, CVLS_MEM_NULL, "CVSBANDPRE", "CVBandPrecGetWorkSpace", MSGBP_MEM_NULL); @@ -228,7 +228,7 @@ int CVBandPrecGetWorkSpace(void *cvode_mem, long int *lenrwBP, cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVSBANDPRE", "CVBandPrecGetWorkSpace", MSGBP_PMEM_NULL); return(CVLS_PMEM_NULL); - } + } pdata = (CVBandPrecData) cvls_mem->P_data; /* sum space requirements for all objects in pdata */ @@ -286,7 +286,7 @@ int CVBandPrecGetNumRhsEvals(void *cvode_mem, long int *nfevalsBP) cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVSBANDPRE", "CVBandPrecGetNumRhsEvals", MSGBP_PMEM_NULL); return(CVLS_PMEM_NULL); - } + } pdata = (CVBandPrecData) cvls_mem->P_data; *nfevalsBP = pdata->nfeBP; @@ -302,16 +302,16 @@ int CVBandPrecGetNumRhsEvals(void *cvode_mem, long int *nfevalsBP) difference quotient Jacobian to create a preconditioner. cvBandPrecSetup calculates a new J, if necessary, then calculates P = I - gamma*J, and does an LU factorization of P. - + The parameters of cvBandPrecSetup are as follows: - + t is the current value of the independent variable. - + y is the current value of the dependent variable vector, namely the predicted value of y(t). - + fy is the vector f(t,y). - + jok is an input flag indicating whether Jacobian-related data needs to be recomputed, as follows: jok == SUNFALSE means recompute Jacobian-related data @@ -321,29 +321,28 @@ int CVBandPrecGetNumRhsEvals(void *cvode_mem, long int *nfevalsBP) (with the current value of gamma). A cvBandPrecSetup call with jok == SUNTRUE should only occur after a call with jok == SUNFALSE. - + *jcurPtr is a pointer to an output integer flag which is set by cvBandPrecSetup as follows: *jcurPtr = SUNTRUE if Jacobian data was recomputed. *jcurPtr = SUNFALSE if Jacobian data was not recomputed, but saved data was reused. - + gamma is the scalar appearing in the Newton matrix. - + bp_data is a pointer to preconditoner data (set by cvBandPrecInit) - + The value to be returned by the cvBandPrecSetup function is 0 if successful, or 1 if the band factorization failed. -----------------------------------------------------------------*/ -static int cvBandPrecSetup(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, +static int cvBandPrecSetup(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, realtype gamma, void *bp_data) { CVBandPrecData pdata; CVodeMem cv_mem; int retval; - sunindextype ier; /* Assume matrix and lpivots have already been allocated. */ pdata = (CVBandPrecData) bp_data; @@ -355,7 +354,7 @@ static int cvBandPrecSetup(realtype t, N_Vector y, N_Vector fy, *jcurPtr = SUNFALSE; retval = SUNMatCopy(pdata->savedJ, pdata->savedP); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBANDPRE", + cvProcessError(cv_mem, -1, "CVBANDPRE", "cvBandPrecSetup", MSGBP_SUNMAT_FAIL); return(-1); } @@ -369,7 +368,7 @@ static int cvBandPrecSetup(realtype t, N_Vector y, N_Vector fy, *jcurPtr = SUNTRUE; retval = SUNMatZero(pdata->savedJ); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBANDPRE", + cvProcessError(cv_mem, -1, "CVBANDPRE", "cvBandPrecSetup", MSGBP_SUNMAT_FAIL); return(-1); } @@ -377,10 +376,10 @@ static int cvBandPrecSetup(realtype t, N_Vector y, N_Vector fy, return(1); } - retval = cvBandPrecDQJac(pdata, t, y, fy, + retval = cvBandPrecDQJac(pdata, t, y, fy, pdata->tmp1, pdata->tmp2); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBANDPRE", + cvProcessError(cv_mem, -1, "CVBANDPRE", "cvBandPrecSetup", MSGBP_RHSFUNC_FAILED); return(-1); } @@ -390,7 +389,7 @@ static int cvBandPrecSetup(realtype t, N_Vector y, N_Vector fy, retval = SUNMatCopy(pdata->savedJ, pdata->savedP); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBANDPRE", + cvProcessError(cv_mem, -1, "CVBANDPRE", "cvBandPrecSetup", MSGBP_SUNMAT_FAIL); return(-1); } @@ -399,18 +398,18 @@ static int cvBandPrecSetup(realtype t, N_Vector y, N_Vector fy, } } - + /* Scale and add identity to get savedP = I - gamma*J. */ retval = SUNMatScaleAddI(-gamma, pdata->savedP); if (retval) { - cvProcessError(cv_mem, -1, "CVBANDPRE", + cvProcessError(cv_mem, -1, "CVBANDPRE", "cvBandPrecSetup", MSGBP_SUNMAT_FAIL); return(-1); } /* Do LU factorization of matrix and return error flag */ - ier = SUNLinSolSetup_Band(pdata->LS, pdata->savedP); - return(ier); + retval = SUNLinSolSetup_Band(pdata->LS, pdata->savedP); + return(retval); } @@ -419,20 +418,20 @@ static int cvBandPrecSetup(realtype t, N_Vector y, N_Vector fy, ----------------------------------------------------------------- cvBandPrecSolve solves a linear system P z = r, where P is the matrix computed by cvBandPrecond. - + The parameters of cvBandPrecSolve used here are as follows: - + r is the right-hand side vector of the linear system. - + bp_data is a pointer to preconditoner data (set by CVBandPrecInit) - + z is the output vector computed by cvBandPrecSolve. - + The value returned by the cvBandPrecSolve function is always 0, indicating success. - -----------------------------------------------------------------*/ -static int cvBandPrecSolve(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, realtype gamma, + -----------------------------------------------------------------*/ +static int cvBandPrecSolve(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, realtype delta, int lr, void *bp_data) { CVBandPrecData pdata; @@ -454,7 +453,7 @@ static int cvBandPrecFree(CVodeMem cv_mem) if (cv_mem->cv_lmem == NULL) return(0); cvls_mem = (CVLsMem) cv_mem->cv_lmem; - + if (cvls_mem->P_data == NULL) return(0); pdata = (CVBandPrecData) cvls_mem->P_data; @@ -474,12 +473,12 @@ static int cvBandPrecFree(CVodeMem cv_mem) /*----------------------------------------------------------------- cvBandPrecDQJac ----------------------------------------------------------------- - This routine generates a banded difference quotient approximation - to the Jacobian of f(t,y). It assumes that a band SUNMatrix is - stored column-wise, and that elements within each column are + This routine generates a banded difference quotient approximation + to the Jacobian of f(t,y). It assumes that a band SUNMatrix is + stored column-wise, and that elements within each column are contiguous. This makes it possible to get the address of a column - of J via the accessor function SUNBandMatrix_Column() and to - write a simple for loop to set each of the elements of a column + of J via the accessor function SUNBandMatrix_Column() and to + write a simple for loop to set each of the elements of a column in succession. -----------------------------------------------------------------*/ static int cvBandPrecDQJac(CVBandPrecData pdata, realtype t, N_Vector y, @@ -492,6 +491,9 @@ static int cvBandPrecDQJac(CVBandPrecData pdata, realtype t, N_Vector y, realtype *y_data, *ytemp_data, *cns_data; int retval; + /* initialize cns_data to avoid compiler warning */ + cns_data = NULL; + cv_mem = (CVodeMem) pdata->cvode_mem; /* Obtain pointers to the data for ewt, fy, ftemp, y, ytemp. */ @@ -500,7 +502,7 @@ static int cvBandPrecDQJac(CVBandPrecData pdata, realtype t, N_Vector y, ftemp_data = N_VGetArrayPointer(ftemp); y_data = N_VGetArrayPointer(y); ytemp_data = N_VGetArrayPointer(ytemp); - if (cv_mem->cv_constraints != NULL) + if (cv_mem->cv_constraintsSet) cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); /* Load ytemp with y = predicted y vector. */ @@ -515,16 +517,16 @@ static int cvBandPrecDQJac(CVBandPrecData pdata, realtype t, N_Vector y, /* Set bandwidth and number of column groups for band differencing. */ width = pdata->ml + pdata->mu + 1; ngroups = SUNMIN(width, pdata->N); - + for (group = 1; group <= ngroups; group++) { - + /* Increment all y_j in group. */ for(j = group-1; j < pdata->N; j += width) { inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); yj = y_data[j]; /* Adjust sign(inc) again if yj has an inequality constraint. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} @@ -546,7 +548,7 @@ static int cvBandPrecDQJac(CVBandPrecData pdata, realtype t, N_Vector y, inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); /* Adjust sign(inc) as before. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} @@ -594,7 +596,7 @@ int CVBandPrecInitB(void *cvode_mem, int which, sunindextype nB, cvProcessError(cv_mem, CVLS_NO_ADJ, "CVSBANDPRE", "CVBandPrecInitB", MSGBP_NO_ADJ); return(CVLS_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; /* Check which */ @@ -616,7 +618,7 @@ int CVBandPrecInitB(void *cvode_mem, int which, sunindextype nB, /* Set pfree */ cvB_mem->cv_pfree = NULL; - + /* Initialize the band preconditioner for this backward problem. */ flag = CVBandPrecInit(cvodeB_mem, nB, muB, mlB); return(flag); diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bandpre_impl.h b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bandpre_impl.h index de1b147f4..d4f79a3ef 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bandpre_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bandpre_impl.h @@ -4,7 +4,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bbdpre.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bbdpre.c index 65ac4fee6..ff79ec5f9 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bbdpre.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bbdpre.c @@ -1,10 +1,10 @@ /* - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Programmer(s): Daniel R. Reynolds @ SMU * Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -35,11 +35,11 @@ #define TWO RCONST(2.0) /* Prototypes of functions cvBBDPrecSetup and cvBBDPrecSolve */ -static int cvBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, +static int cvBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, realtype gamma, void *bbd_data); -static int cvBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, +static int cvBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, realtype delta, int lr, void *bbd_data); @@ -48,14 +48,14 @@ static int cvBBDPrecFree(CVodeMem cv_mem); /* Wrapper functions for adjoint code */ static int cvGlocWrapper(sunindextype NlocalB, realtype t, - N_Vector yB, N_Vector gB, + N_Vector yB, N_Vector gB, void *cvadj_mem); static int cvCfnWrapper(sunindextype NlocalB, realtype t, N_Vector yB, void *cvadj_mem); /* Prototype for difference quotient Jacobian calculation routine */ -static int cvBBDDQJac(CVBBDPrecData pdata, realtype t, - N_Vector y, N_Vector gy, +static int cvBBDDQJac(CVBBDPrecData pdata, realtype t, + N_Vector y, N_Vector gy, N_Vector ytemp, N_Vector gtemp); /* Prototype for the backward pfree routine */ @@ -69,9 +69,9 @@ static int CVBBDPrecFreeB(CVodeBMem cvB_mem); /*----------------------------------------------------------------- User-Callable Functions: initialization, reinit and free -----------------------------------------------------------------*/ -int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, +int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, sunindextype mudq, sunindextype mldq, - sunindextype mukeep, sunindextype mlkeep, + sunindextype mukeep, sunindextype mlkeep, realtype dqrely, CVLocalFn gloc, CVCommFn cfn) { CVodeMem cv_mem; @@ -105,7 +105,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, /* Allocate data memory */ pdata = NULL; - pdata = (CVBBDPrecData) malloc(sizeof *pdata); + pdata = (CVBBDPrecData) malloc(sizeof *pdata); if (pdata == NULL) { cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); @@ -125,11 +125,11 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, /* Allocate memory for saved Jacobian */ pdata->savedJ = SUNBandMatrixStorage(Nlocal, muk, mlk, muk); - if (pdata->savedJ == NULL) { - free(pdata); pdata = NULL; + if (pdata->savedJ == NULL) { + free(pdata); pdata = NULL; cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); - return(CVLS_MEM_FAIL); + return(CVLS_MEM_FAIL); } /* Allocate memory for preconditioner matrix */ @@ -143,7 +143,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } - + /* Allocate memory for temporary N_Vectors */ pdata->zlocal = NULL; pdata->zlocal = N_VNewEmpty_Serial(Nlocal); @@ -151,7 +151,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -162,7 +162,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -174,7 +174,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -187,7 +187,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -201,7 +201,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -218,7 +218,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedP); SUNMatDestroy(pdata->savedJ); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", "CVBBDPrecInit", MSGBBD_MEM_FAIL); return(CVLS_MEM_FAIL); } @@ -235,7 +235,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, SUNMatDestroy(pdata->savedJ); SUNLinSolFree(pdata->LS); free(pdata); pdata = NULL; - cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVSBBDPRE", + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVSBBDPRE", "CVBBDPrecInit", MSGBBD_SUNLS_FAIL); return(CVLS_SUNLS_FAIL); } @@ -294,7 +294,7 @@ int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, } -int CVBBDPrecReInit(void *cvode_mem, sunindextype mudq, +int CVBBDPrecReInit(void *cvode_mem, sunindextype mudq, sunindextype mldq, realtype dqrely) { CVodeMem cv_mem; @@ -322,7 +322,7 @@ int CVBBDPrecReInit(void *cvode_mem, sunindextype mudq, cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVSBBDPRE", "CVBBDPrecReInit", MSGBBD_PMEM_NULL); return(CVLS_PMEM_NULL); - } + } pdata = (CVBBDPrecData) cvls_mem->P_data; /* Load half-bandwidths */ @@ -367,7 +367,7 @@ int CVBBDPrecGetWorkSpace(void *cvode_mem, cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVSBBDPRE", "CVBBDPrecGetWorkSpace", MSGBBD_PMEM_NULL); return(CVLS_PMEM_NULL); - } + } pdata = (CVBBDPrecData) cvls_mem->P_data; *lenrwBBDP = pdata->rpwsize; @@ -402,7 +402,7 @@ int CVBBDPrecGetNumGfnEvals(void *cvode_mem, cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVSBBDPRE", "CVBBDPrecGetNumGfnEvals", MSGBBD_PMEM_NULL); return(CVLS_PMEM_NULL); - } + } pdata = (CVBBDPrecData) cvls_mem->P_data; *ngevalsBBDP = pdata->nge; @@ -412,25 +412,25 @@ int CVBBDPrecGetNumGfnEvals(void *cvode_mem, /*----------------------------------------------------------------- - Function : cvBBDPrecSetup + Function : cvBBDPrecSetup ----------------------------------------------------------------- cvBBDPrecSetup generates and factors a banded block of the preconditioner matrix on each processor, via calls to the user-supplied gloc and cfn functions. It uses difference quotient approximations to the Jacobian elements. - + cvBBDPrecSetup calculates a new J,if necessary, then calculates P = I - gamma*J, and does an LU factorization of P. - + The parameters of cvBBDPrecSetup used here are as follows: - + t is the current value of the independent variable. - + y is the current value of the dependent variable vector, namely the predicted value of y(t). - + fy is the vector f(t,y). - + jok is an input flag indicating whether Jacobian-related data needs to be recomputed, as follows: jok == SUNFALSE means recompute Jacobian-related data @@ -440,28 +440,27 @@ int CVBBDPrecGetNumGfnEvals(void *cvode_mem, (with the current value of gamma). A cvBBDPrecSetup call with jok == SUNTRUE should only occur after a call with jok == SUNFALSE. - + jcurPtr is a pointer to an output integer flag which is set by cvBBDPrecSetup as follows: *jcurPtr = SUNTRUE if Jacobian data was recomputed. *jcurPtr = SUNFALSE if Jacobian data was not recomputed, but saved data was reused. - + gamma is the scalar appearing in the Newton matrix. - + bbd_data is a pointer to the preconditioner data set by CVBBDPrecInit - + Return value: The value returned by this cvBBDPrecSetup function is the int 0 if successful, 1 for a recoverable error (step will be retried). -----------------------------------------------------------------*/ -static int cvBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, - booleantype jok, booleantype *jcurPtr, +static int cvBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, realtype gamma, void *bbd_data) { - sunindextype ier; CVBBDPrecData pdata; CVodeMem cv_mem; int retval; @@ -474,7 +473,7 @@ static int cvBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, *jcurPtr = SUNFALSE; retval = SUNMatCopy(pdata->savedJ, pdata->savedP); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBBDPRE", + cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); return(-1); } @@ -488,7 +487,7 @@ static int cvBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, *jcurPtr = SUNTRUE; retval = SUNMatZero(pdata->savedJ); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBBDPRE", + cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); return(-1); } @@ -496,10 +495,10 @@ static int cvBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, return(1); } - retval = cvBBDDQJac(pdata, t, y, pdata->tmp1, + retval = cvBBDDQJac(pdata, t, y, pdata->tmp1, pdata->tmp2, pdata->tmp3); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", + cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", MSGBBD_FUNC_FAILED); return(-1); } @@ -509,7 +508,7 @@ static int cvBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, retval = SUNMatCopy(pdata->savedJ, pdata->savedP); if (retval < 0) { - cvProcessError(cv_mem, -1, "CVBBDPRE", + cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); return(-1); } @@ -518,18 +517,18 @@ static int cvBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, } } - + /* Scale and add I to get P = I - gamma*J */ retval = SUNMatScaleAddI(-gamma, pdata->savedP); if (retval) { - cvProcessError(cv_mem, -1, "CVBBDPRE", + cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); return(-1); } - + /* Do LU factorization of matrix and return error flag */ - ier = SUNLinSolSetup_Band(pdata->LS, pdata->savedP); - return(ier); + retval = SUNLinSolSetup_Band(pdata->LS, pdata->savedP); + return(retval); } @@ -539,21 +538,21 @@ static int cvBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, cvBBDPrecSolve solves a linear system P z = r, with the band-block-diagonal preconditioner matrix P generated and factored by cvBBDPrecSetup. - + The parameters of cvBBDPrecSolve used here are as follows: - + r is the right-hand side vector of the linear system. - + bbd_data is a pointer to the preconditioner data set by CVBBDPrecInit. - + z is the output vector computed by cvBBDPrecSolve. - + The value returned by the cvBBDPrecSolve function is always 0, indicating success. -----------------------------------------------------------------*/ -static int cvBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, - N_Vector r, N_Vector z, +static int cvBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, realtype delta, int lr, void *bbd_data) { @@ -565,9 +564,9 @@ static int cvBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, /* Attach local data arrays for r and z to rlocal and zlocal */ N_VSetArrayPointer(N_VGetArrayPointer(r), pdata->rlocal); N_VSetArrayPointer(N_VGetArrayPointer(z), pdata->zlocal); - + /* Call banded solver object to do the work */ - retval = SUNLinSolSolve(pdata->LS, pdata->savedP, pdata->zlocal, + retval = SUNLinSolSolve(pdata->LS, pdata->savedP, pdata->zlocal, pdata->rlocal, ZERO); /* Detach local data arrays from rlocal and zlocal */ @@ -582,10 +581,10 @@ static int cvBBDPrecFree(CVodeMem cv_mem) { CVLsMem cvls_mem; CVBBDPrecData pdata; - + if (cv_mem->cv_lmem == NULL) return(0); cvls_mem = (CVLsMem) cv_mem->cv_lmem; - + if (cvls_mem->P_data == NULL) return(0); pdata = (CVBBDPrecData) cvls_mem->P_data; @@ -600,7 +599,7 @@ static int cvBBDPrecFree(CVodeMem cv_mem) free(pdata); pdata = NULL; - + return(0); } @@ -610,8 +609,8 @@ static int cvBBDPrecFree(CVodeMem cv_mem) ----------------------------------------------------------------- This routine generates a banded difference quotient approximation to the local block of the Jacobian of g(t,y). It assumes that a - band SUNMatrix is stored columnwise, and that elements within each - column are contiguous. All matrix elements are generated as + band SUNMatrix is stored columnwise, and that elements within each + column are contiguous. All matrix elements are generated as difference quotients, by way of calls to the user routine gloc. By virtue of the band structure, the number of these calls is bandwidth + 1, where bandwidth = mldq + mudq + 1. @@ -619,7 +618,7 @@ static int cvBBDPrecFree(CVodeMem cv_mem) This routine also assumes that the local elements of a vector are stored contiguously. -----------------------------------------------------------------*/ -static int cvBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, +static int cvBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, N_Vector gy, N_Vector ytemp, N_Vector gtemp) { CVodeMem cv_mem; @@ -629,6 +628,9 @@ static int cvBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, realtype *ytemp_data, *col_j, *cns_data; int retval; + /* initialize cns_data to avoid compiler warning */ + cns_data = NULL; + cv_mem = (CVodeMem) pdata->cvode_mem; /* Load ytemp with y = predicted solution vector */ @@ -651,7 +653,7 @@ static int cvBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, ewt_data = N_VGetArrayPointer(cv_mem->cv_ewt); ytemp_data = N_VGetArrayPointer(ytemp); gtemp_data = N_VGetArrayPointer(gtemp); - if (cv_mem->cv_constraints != NULL) + if (cv_mem->cv_constraintsSet) cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); /* Set minimum increment based on uround and norm of g */ @@ -664,16 +666,16 @@ static int cvBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, width = pdata->mldq + pdata->mudq + 1; ngroups = SUNMIN(width, pdata->n_local); - /* Loop over groups */ + /* Loop over groups */ for (group=1; group <= ngroups; group++) { - + /* Increment all y_j in group */ for(j=group-1; j < pdata->n_local; j+=width) { inc = SUNMAX(pdata->dqrely * SUNRabs(y_data[j]), minInc/ewt_data[j]); yj = y_data[j]; /* Adjust sign(inc) again if yj has an inequality constraint. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} @@ -695,7 +697,7 @@ static int cvBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, inc = SUNMAX(pdata->dqrely * SUNRabs(y_data[j]), minInc/ewt_data[j]); /* Adjust sign(inc) as before. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} @@ -721,9 +723,9 @@ static int cvBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, /*--------------------------------------------------------------- User-Callable Functions: initialization, reinit and free ---------------------------------------------------------------*/ -int CVBBDPrecInitB(void *cvode_mem, int which, sunindextype NlocalB, +int CVBBDPrecInitB(void *cvode_mem, int which, sunindextype NlocalB, sunindextype mudqB, sunindextype mldqB, - sunindextype mukeepB, sunindextype mlkeepB, + sunindextype mukeepB, sunindextype mlkeepB, realtype dqrelyB, CVLocalFnB glocB, CVCommFnB cfnB) { CVodeMem cv_mem; @@ -746,7 +748,7 @@ int CVBBDPrecInitB(void *cvode_mem, int which, sunindextype NlocalB, cvProcessError(cv_mem, CVLS_NO_ADJ, "CVSBBDPRE", "CVBBDPrecInitB", MSGBBD_NO_ADJ); return(CVLS_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; /* Check which */ @@ -767,7 +769,7 @@ int CVBBDPrecInitB(void *cvode_mem, int which, sunindextype NlocalB, cvodeB_mem = (void *) (cvB_mem->cv_mem); /* Initialize the BBD preconditioner for this backward problem. */ - flag = CVBBDPrecInit(cvodeB_mem, NlocalB, mudqB, mldqB, mukeepB, + flag = CVBBDPrecInit(cvodeB_mem, NlocalB, mudqB, mldqB, mukeepB, mlkeepB, dqrelyB, cvGlocWrapper, cvCfnWrapper); if (flag != CV_SUCCESS) return(flag); @@ -793,7 +795,7 @@ int CVBBDPrecInitB(void *cvode_mem, int which, sunindextype NlocalB, } -int CVBBDPrecReInitB(void *cvode_mem, int which, sunindextype mudqB, +int CVBBDPrecReInitB(void *cvode_mem, int which, sunindextype mudqB, sunindextype mldqB, realtype dqrelyB) { CVodeMem cv_mem; @@ -815,7 +817,7 @@ int CVBBDPrecReInitB(void *cvode_mem, int which, sunindextype mudqB, cvProcessError(cv_mem, CVLS_NO_ADJ, "CVSBBDPRE", "CVBBDPrecReInitB", MSGBBD_NO_ADJ); return(CVLS_NO_ADJ); - } + } ca_mem = cv_mem->cv_adj_mem; /* Check which */ @@ -834,7 +836,7 @@ int CVBBDPrecReInitB(void *cvode_mem, int which, sunindextype mudqB, } /* cv_mem corresponding to 'which' backward problem. */ cvodeB_mem = (void *) (cvB_mem->cv_mem); - + /* ReInitialize the BBD preconditioner for this backward problem. */ flag = CVBBDPrecReInit(cvodeB_mem, mudqB, mldqB, dqrelyB); return(flag); @@ -843,7 +845,7 @@ int CVBBDPrecReInitB(void *cvode_mem, int which, sunindextype mudqB, static int CVBBDPrecFreeB(CVodeBMem cvB_mem) { - free(cvB_mem->cv_pmem); + free(cvB_mem->cv_pmem); cvB_mem->cv_pmem = NULL; return(0); } @@ -874,7 +876,7 @@ static int cvGlocWrapper(sunindextype NlocalB, realtype t, N_Vector yB, cvProcessError(cv_mem, -1, "CVSBBDPRE", "cvGlocWrapper", MSGBBD_BAD_TINTERP); return(-1); - } + } /* Call user's adjoint glocB routine */ return cvbbdB_mem->glocB(NlocalB, t, ca_mem->ca_ytmp, yB, @@ -904,7 +906,7 @@ static int cvCfnWrapper(sunindextype NlocalB, realtype t, cvProcessError(cv_mem, -1, "CVSBBDPRE", "cvCfnWrapper", MSGBBD_BAD_TINTERP); return(-1); - } + } /* Call user's adjoint cfnB routine */ return cvbbdB_mem->cfnB(NlocalB, t, ca_mem->ca_ytmp, diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bbdpre_impl.h b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bbdpre_impl.h index e6ad58932..362c3e238 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bbdpre_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_bbdpre_impl.h @@ -4,7 +4,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_diag.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_diag.c index cc3ca62b5..0a3c43766 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_diag.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_diag.c @@ -3,7 +3,7 @@ * Programmer(s): Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_diag_impl.h b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_diag_impl.h index 799f7cb53..79450c99c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_diag_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_diag_impl.h @@ -3,7 +3,7 @@ * Programmer(s): Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_direct.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_direct.c index 3f172ac91..5b9e56711 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_direct.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_direct.c @@ -1,8 +1,8 @@ -/* ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -11,7 +11,7 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * Header file for the deprecated direct linear solver interface in + * Header file for the deprecated direct linear solver interface in * CVODES; these routines now just wrap the updated CVODE generic * linear solver interface in cvodes_ls.h. * -----------------------------------------------------------------*/ @@ -63,4 +63,3 @@ int CVDlsSetJacFnBS(void *cvode_mem, int which, CVDlsJacFnBS jacBS) #ifdef __cplusplus } #endif - diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_impl.h b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_impl.h index 233ab038e..07a0c2067 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_impl.h @@ -1,12 +1,8 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -16,8 +12,7 @@ * SUNDIALS Copyright End * ----------------------------------------------------------------- * Implementation header file for the main CVODES integrator. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #ifndef _CVODES_IMPL_H #define _CVODES_IMPL_H @@ -32,7 +27,7 @@ extern "C" { #endif -/* +/* * ================================================================= * I N T E R N A L C V O D E S C O N S T A N T S * ================================================================= @@ -67,7 +62,7 @@ extern "C" { #define CRDOWN RCONST(0.3) #define RDIV RCONST(2.0) -/* +/* * ================================================================= * F O R W A R D P O I N T E R R E F E R E N C E S * ================================================================= @@ -78,7 +73,7 @@ typedef struct CkpntMemRec *CkpntMem; typedef struct DtpntMemRec *DtpntMem; typedef struct CVodeBMemRec *CVodeBMem; -/* +/* * ================================================================= * M A I N I N T E G R A T O R M E M O R Y B L O C K * ================================================================= @@ -93,13 +88,13 @@ typedef struct CVodeBMemRec *CVodeBMem; * This structure contains fields to keep track of problem state. * ----------------------------------------------------------------- */ - + typedef struct CVodeMemRec { - - realtype cv_uround; /* machine unit roundoff */ - /*-------------------------- - Problem Specification Data + realtype cv_uround; /* machine unit roundoff */ + + /*-------------------------- + Problem Specification Data --------------------------*/ CVRhsFn cv_f; /* y' = f(t,y(t)) */ @@ -111,6 +106,7 @@ typedef struct CVodeMemRec { realtype cv_reltol; /* relative tolerance */ realtype cv_Sabstol; /* scalar absolute tolerance */ N_Vector cv_Vabstol; /* vector absolute tolerance */ + booleantype cv_atolmin0; /* flag indicating that min(abstol) = 0 */ booleantype cv_user_efun; /* SUNTRUE if user sets efun */ CVEwtFn cv_efun; /* function to set ewt */ void *cv_e_data; /* user pointer passed to efun */ @@ -119,7 +115,7 @@ typedef struct CVodeMemRec { do constraints calc */ /*----------------------- - Quadrature Related Data + Quadrature Related Data -----------------------*/ booleantype cv_quadr; /* SUNTRUE if integrating quadratures */ @@ -132,9 +128,10 @@ typedef struct CVodeMemRec { realtype cv_reltolQ; /* relative tolerance for quadratures */ realtype cv_SabstolQ; /* scalar absolute tolerance for quadratures */ N_Vector cv_VabstolQ; /* vector absolute tolerance for quadratures */ + booleantype cv_atolQmin0; /* flag indicating that min(abstolQ) = 0 */ /*------------------------ - Sensitivity Related Data + Sensitivity Related Data ------------------------*/ booleantype cv_sensi; /* SUNTRUE if computing sensitivities */ @@ -161,9 +158,10 @@ typedef struct CVodeMemRec { realtype cv_reltolS; /* relative tolerance for sensitivities */ realtype *cv_SabstolS; /* scalar absolute tolerances for sensi. */ N_Vector *cv_VabstolS; /* vector absolute tolerances for sensi. */ + booleantype *cv_atolSmin0; /* flags indicating that min(abstolS[i]) = 0 */ /*----------------------------------- - Quadrature Sensitivity Related Data + Quadrature Sensitivity Related Data -----------------------------------*/ booleantype cv_quadr_sensi; /* SUNTRUE if computing sensitivties of quadrs. */ @@ -178,23 +176,24 @@ typedef struct CVodeMemRec { realtype cv_reltolQS; /* relative tolerance for yQS */ realtype *cv_SabstolQS; /* scalar absolute tolerances for yQS */ N_Vector *cv_VabstolQS; /* vector absolute tolerances for yQS */ + booleantype *cv_atolQSmin0; /* flags indicating that min(abstolQS[i]) = 0 */ /*----------------------- - Nordsieck History Array + Nordsieck History Array -----------------------*/ N_Vector cv_zn[L_MAX]; /* Nordsieck array, of size N x (q+1). zn[j] is a vector of length N (j=0,...,q) - zn[j] = [1/factorial(j)] * h^j * + zn[j] = [1/factorial(j)] * h^j * (jth derivative of the interpolating poly.) */ /*------------------- - Vectors of length N + Vectors of length N -------------------*/ N_Vector cv_ewt; /* error weight vector */ N_Vector cv_y; /* y is used as temporary storage by the solver. - The memory is provided by the user to CVode + The memory is provided by the user to CVode where the vector is named yout. */ N_Vector cv_acor; /* In the context of the solution of the nonlinear equation, acor = y_n(m) - y_n(0). @@ -206,11 +205,10 @@ typedef struct CVodeMemRec { N_Vector cv_vtemp2; /* temporary storage vector */ N_Vector cv_vtemp3; /* temporary storage vector */ - N_Vector cv_mm; /* mask vector in constraints tests */ N_Vector cv_constraints; /* vector of inequality constraint options */ /*-------------------------- - Quadrature Related Vectors + Quadrature Related Vectors --------------------------*/ N_Vector cv_znQ[L_MAX]; /* Nordsieck arrays for quadratures */ @@ -220,7 +218,7 @@ typedef struct CVodeMemRec { N_Vector cv_tempvQ; /* temporary storage vector (~ tempv) */ /*--------------------------- - Sensitivity Related Vectors + Sensitivity Related Vectors ---------------------------*/ N_Vector *cv_znS[L_MAX]; /* Nordsieck arrays for sensitivities */ @@ -233,7 +231,7 @@ typedef struct CVodeMemRec { booleantype cv_stgr1alloc; /* Did we allocate ncfS1, ncfnS1, and nniS1? */ /*-------------------------------------- - Quadrature Sensitivity Related Vectors + Quadrature Sensitivity Related Vectors --------------------------------------*/ N_Vector *cv_znQS[L_MAX]; /* Nordsieck arrays for quadr. sensitivities */ @@ -242,7 +240,7 @@ typedef struct CVodeMemRec { N_Vector *cv_acorQS; /* acorQS = yQS_n(m) - yQS_n(0) */ N_Vector *cv_tempvQS; /* temporary storage vector (~ tempv) */ N_Vector cv_ftempQ; /* temporary storage vector (~ ftemp) */ - + /*----------------- Tstop information -----------------*/ @@ -251,7 +249,7 @@ typedef struct CVodeMemRec { realtype cv_tstop; /*--------- - Step Data + Step Data ---------*/ int cv_q; /* current order */ @@ -264,8 +262,8 @@ typedef struct CVodeMemRec { realtype cv_hin; realtype cv_h; /* current step size */ - realtype cv_hprime; /* step size to be used on the next step */ - realtype cv_next_h; /* step size to be used on the next step */ + realtype cv_hprime; /* step size to be used on the next step */ + realtype cv_next_h; /* step size to be used on the next step */ realtype cv_eta; /* eta = hprime / h */ realtype cv_hscale; /* value of h used in zn */ realtype cv_tn; /* current internal value of t */ @@ -286,31 +284,33 @@ typedef struct CVodeMemRec { realtype cv_crateS; /* est. corrector conv. rate in NlsStgr */ realtype cv_delp; /* norm of previous nonlinear solver update */ realtype cv_acnrm; /* | acor | */ + booleantype cv_acnrmcur; /* is | acor | current? */ realtype cv_acnrmQ; /* | acorQ | */ realtype cv_acnrmS; /* | acorS | */ + booleantype cv_acnrmScur; /* is | acorS | current? */ realtype cv_acnrmQS; /* | acorQS | */ realtype cv_nlscoef; /* coeficient in nonlinear convergence test */ - int *cv_ncfS1; /* Array of Ns local counters for conv. + int *cv_ncfS1; /* Array of Ns local counters for conv. * failures (used in CVStep for STAGGERED1) */ /*------ - Limits + Limits ------*/ int cv_qmax; /* q <= qmax */ - long int cv_mxstep; /* maximum number of internal steps for one + long int cv_mxstep; /* maximum number of internal steps for one user call */ int cv_mxhnil; /* max. number of warning messages issued to the user that t + h == t for the next internal step */ int cv_maxnef; /* maximum number of error test failures */ int cv_maxncf; /* maximum number of nonlinear conv. failures */ - + realtype cv_hmin; /* |h| >= hmin */ realtype cv_hmax_inv; /* |h| <= 1/hmax_inv */ realtype cv_etamax; /* eta <= etamax */ /*---------- - Counters + Counters ----------*/ long int cv_nst; /* number of internal steps taken */ @@ -343,13 +343,13 @@ typedef struct CVodeMemRec { t + h == t for the next iternal step */ /*----------------------------- - Space requirements for CVODES + Space requirements for CVODES -----------------------------*/ - sunindextype cv_lrw1; /* no. of realtype words in 1 N_Vector y */ - sunindextype cv_liw1; /* no. of integer words in 1 N_Vector y */ - sunindextype cv_lrw1Q; /* no. of realtype words in 1 N_Vector yQ */ - sunindextype cv_liw1Q; /* no. of integer words in 1 N_Vector yQ */ + sunindextype cv_lrw1; /* no. of realtype words in 1 N_Vector y */ + sunindextype cv_liw1; /* no. of integer words in 1 N_Vector y */ + sunindextype cv_lrw1Q; /* no. of realtype words in 1 N_Vector yQ */ + sunindextype cv_liw1Q; /* no. of integer words in 1 N_Vector yQ */ long int cv_lrw; /* no. of realtype words in CVODES work vectors */ long int cv_liw; /* no. of integer words in CVODES work vectors */ @@ -387,16 +387,16 @@ typedef struct CVodeMemRec { /* The following vectors are NVector wrappers for use with the simultaneous and staggered corrector methods: - Simultaneous: ycor0Sim = [ida_delta, ida_deltaS] - ycorSim = [ida_ee, ida_eeS] - ewtSim = [ida_ewt, ida_ewtS] + Simultaneous: zn0Sim = [cv_zn[0], cv_znS[0]] + ycorSim = [cv_acor, cv_acorS] + ewtSim = [cv_ewt, cv_ewtS] - Staggered: ycor0Stg = ida_deltaS - ycorStg = ida_eeS - ewtStg = ida_ewtS + Staggered: zn0Stg = cv_znS[0] + ycorStg = cv_acorS + ewtStg = cv_ewtS */ - N_Vector ycor0Sim, ycorSim, ewtSim; - N_Vector ycor0Stg, ycorStg, ewtStg; + N_Vector zn0Sim, ycorSim, ewtSim; + N_Vector zn0Stg, ycorStg, ewtStg; /* flags indicating if vector wrappers for the simultaneous and staggered correctors have been allocated */ @@ -412,9 +412,9 @@ typedef struct CVodeMemRec { int (*cv_linit)(struct CVodeMemRec *cv_mem); - int (*cv_lsetup)(struct CVodeMemRec *cv_mem, int convfail, - N_Vector ypred, N_Vector fpred, booleantype *jcurPtr, - N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); + int (*cv_lsetup)(struct CVodeMemRec *cv_mem, int convfail, + N_Vector ypred, N_Vector fpred, booleantype *jcurPtr, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); int (*cv_lsolve)(struct CVodeMemRec *cv_mem, N_Vector b, N_Vector weight, N_Vector ycur, N_Vector fcur); @@ -423,7 +423,7 @@ typedef struct CVodeMemRec { /* Linear Solver specific memory */ - void *cv_lmem; + void *cv_lmem; /* Flag to request a call to the setup routine */ @@ -448,7 +448,7 @@ typedef struct CVodeMemRec { int cv_indx_acor; /* index of zn vector in which acor is saved */ /*-------------------------------------------------------------------- - Flags turned ON by CVodeInit, CVodeSensMalloc, and CVodeQuadMalloc + Flags turned ON by CVodeInit, CVodeSensMalloc, and CVodeQuadMalloc and read by CVodeReInit, CVodeSensReInit, and CVodeQuadReInit --------------------------------------------------------------------*/ @@ -468,12 +468,12 @@ typedef struct CVodeMemRec { booleantype cv_QuadSensMallocDone; /*------------------------------------------- - Error handler function and error ouput file + Error handler function and error ouput file -------------------------------------------*/ CVErrHandlerFn cv_ehfun; /* Error messages are handled by ehfun */ void *cv_eh_data; /* dats pointer passed to ehfun */ - FILE *cv_errfp; /* CVODES error messages are sent to errfp */ + FILE *cv_errfp; /* CVODES error messages are sent to errfp */ /*------------------------- Stability Limit Detection @@ -527,7 +527,7 @@ typedef struct CVodeMemRec { } *CVodeMem; -/* +/* * ================================================================= * A D J O I N T M O D U L E M E M O R Y B L O C K * ================================================================= @@ -548,16 +548,16 @@ struct CkpntMemRec { /* Integration limits */ realtype ck_t0; realtype ck_t1; - + /* Nordsieck History Array */ N_Vector ck_zn[L_MAX]; - + /* Do we need to carry quadratures? */ booleantype ck_quadr; - + /* Nordsieck History Array for quadratures */ N_Vector ck_znQ[L_MAX]; - + /* Do we need to carry sensitivities? */ booleantype ck_sensi; @@ -572,12 +572,12 @@ struct CkpntMemRec { /* Nordsieck History Array for quadrature sensitivities */ N_Vector *ck_znQS[L_MAX]; - + /* Was ck_zn[qmax] allocated? ck_zqm = 0 - no ck_zqm = qmax - yes */ int ck_zqm; - + /* Step data */ long int ck_nst; realtype ck_tretlast; @@ -594,15 +594,15 @@ struct CkpntMemRec { realtype ck_tau[L_MAX+1]; realtype ck_tq[NUM_TESTS+1]; realtype ck_l[L_MAX]; - + /* Saved values */ realtype ck_saved_tq5; - + /* Pointer to next structure in list */ struct CkpntMemRec *ck_next; - + }; - + /* * ----------------------------------------------------------------- * Types for functions provided by an interpolation module @@ -611,7 +611,7 @@ struct CkpntMemRec { * field of the structures in the dt array * cvaIMFreeFn: Type for a function that deallocates the content * field of the structures in the dt array - * cvaIMGetYFn: Type for a function that returns the + * cvaIMGetYFn: Type for a function that returns the * interpolated forward solution. * cvaIMStorePnt: Type for a function that stores a new * point in the structure d @@ -632,7 +632,7 @@ typedef int (*cvaIMStorePntFn)(CVodeMem cv_mem, DtpntMem d); * simulations. Its content field depends on IMtype. * ----------------------------------------------------------------- */ - + struct DtpntMemRec { realtype t; /* time */ void *content; /* IMtype-dependent content */ @@ -671,7 +671,7 @@ struct CVodeBMemRec { /* Time at which the backward problem is initialized */ realtype cv_t0; - + /* CVODES memory for this backward problem */ CVodeMem cv_mem; @@ -690,14 +690,14 @@ struct CVodeBMemRec { /* User user_data */ void *cv_user_data; - + /* Memory block for a linear solver's interface to CVODEA */ void *cv_lmem; /* Function to free any memory allocated by the linear solver */ int (*cv_lfree)(CVodeBMem cvB_mem); - /* Memory block for a preconditioner's module interface to CVODEA */ + /* Memory block for a preconditioner's module interface to CVODEA */ void *cv_pmem; /* Function to free any memory allocated by the preconditioner module */ @@ -705,7 +705,7 @@ struct CVodeBMemRec { /* Time at which to extract solution / quadratures */ realtype cv_tout; - + /* Workspace Nvector */ N_Vector cv_y; @@ -725,7 +725,7 @@ struct CVodeBMemRec { */ struct CVadjMemRec { - + /* -------------------- * Forward problem data * -------------------- */ @@ -739,7 +739,12 @@ struct CVadjMemRec { /* Flag if CVodeF was called with TSTOP */ booleantype ca_tstopCVodeFcall; realtype ca_tstopCVodeF; - + + /* Flag if CVodeF was called in CV_NORMAL_MODE and encountered a + root after tout */ + booleantype ca_rootret; + realtype ca_troot; + /* ---------------------- * Backward problems data * ---------------------- */ @@ -755,7 +760,7 @@ struct CVadjMemRec { /* Flag for first call to CVodeB */ booleantype ca_firstCVodeBcall; - + /* ---------------- * Check point data * ---------------- */ @@ -768,7 +773,7 @@ struct CVadjMemRec { /* address of the check point structure for which data is available */ struct CkpntMemRec *ca_ckpntData; - + /* ------------------ * Interpolation data * ------------------ */ @@ -778,18 +783,18 @@ struct CVadjMemRec { /* Last index used in CVAfindIndex */ long int ca_ilast; - + /* Storage for data from forward runs */ struct DtpntMemRec **dt_mem; /* Actual number of data points in dt_mem (typically np=nsteps+1) */ long int ca_np; - + /* Interpolation type */ int ca_IMtype; /* Functions set by the interpolation module */ - cvaIMMallocFn ca_IMmalloc; + cvaIMMallocFn ca_IMmalloc; cvaIMFreeFn ca_IMfree; cvaIMStorePntFn ca_IMstore; /* store a new interpolation point */ cvaIMGetYFn ca_IMget; /* interpolate forward solution */ @@ -812,9 +817,9 @@ struct CVadjMemRec { N_Vector ca_ytmp; N_Vector *ca_yStmp; - + }; - + /* * ================================================================= @@ -943,7 +948,7 @@ struct CVadjMemRec { * ----------------------------------------------------------------- * cv_lfree should free up any memory allocated by the linear * solver. This routine is called once a problem has been - * completed and the linear solver is no longer needed. It should + * completed and the linear solver is no longer needed. It should * return 0 upon success, nonzero on failure. * ----------------------------------------------------------------- */ @@ -968,38 +973,38 @@ int cvEwtSet(N_Vector ycur, N_Vector weight, void *data); /* High level error handler */ -void cvProcessError(CVodeMem cv_mem, - int error_code, const char *module, const char *fname, +void cvProcessError(CVodeMem cv_mem, + int error_code, const char *module, const char *fname, const char *msgfmt, ...); /* Prototype of internal errHandler function */ -void cvErrHandler(int error_code, const char *module, const char *function, +void cvErrHandler(int error_code, const char *module, const char *function, char *msg, void *data); /* Prototypes for internal sensitivity rhs wrappers */ -int cvSensRhsWrapper(CVodeMem cv_mem, realtype time, - N_Vector ycur, N_Vector fcur, +int cvSensRhsWrapper(CVodeMem cv_mem, realtype time, + N_Vector ycur, N_Vector fcur, N_Vector *yScur, N_Vector *fScur, N_Vector temp1, N_Vector temp2); -int cvSensRhs1Wrapper(CVodeMem cv_mem, realtype time, - N_Vector ycur, N_Vector fcur, +int cvSensRhs1Wrapper(CVodeMem cv_mem, realtype time, + N_Vector ycur, N_Vector fcur, int is, N_Vector yScur, N_Vector fScur, N_Vector temp1, N_Vector temp2); /* Prototypes for internal sensitivity rhs DQ functions */ -int cvSensRhsInternalDQ(int Ns, realtype t, - N_Vector y, N_Vector ydot, - N_Vector *yS, N_Vector *ySdot, - void *fS_data, +int cvSensRhsInternalDQ(int Ns, realtype t, + N_Vector y, N_Vector ydot, + N_Vector *yS, N_Vector *ySdot, + void *fS_data, N_Vector tempv, N_Vector ftemp); -int cvSensRhs1InternalDQ(int Ns, realtype t, - N_Vector y, N_Vector ydot, - int is, N_Vector yS, N_Vector ySdot, +int cvSensRhs1InternalDQ(int Ns, realtype t, + N_Vector y, N_Vector ydot, + int is, N_Vector yS, N_Vector ySdot, void *fS_data, N_Vector tempv, N_Vector ftemp); @@ -1009,7 +1014,7 @@ int cvNlsInitSensSim(CVodeMem cv_mem); int cvNlsInitSensStg(CVodeMem cv_mem); int cvNlsInitSensStg1(CVodeMem cv_mem); -/* +/* * ================================================================= * C V O D E S E R R O R M E S S A G E S * ================================================================= @@ -1075,14 +1080,14 @@ int cvNlsInitSensStg1(CVodeMem cv_mem); #define MSGCV_BAD_ITOLQ "Illegal value for itolQ. The legal values are CV_SS and CV_SV." #define MSGCV_NULL_ABSTOLQ "abstolQ = NULL illegal." #define MSGCV_BAD_RELTOLQ "reltolQ < 0 illegal." -#define MSGCV_BAD_ABSTOLQ "abstolQ has negative component(s) (illegal)." +#define MSGCV_BAD_ABSTOLQ "abstolQ has negative component(s) (illegal)." #define MSGCV_SENSINIT_2 "Sensitivity analysis already initialized." #define MSGCV_NO_SENSI "Forward sensitivity analysis not activated." #define MSGCV_BAD_ITOLS "Illegal value for itolS. The legal values are CV_SS, CV_SV, and CV_EE." #define MSGCV_NULL_ABSTOLS "abstolS = NULL illegal." #define MSGCV_BAD_RELTOLS "reltolS < 0 illegal." -#define MSGCV_BAD_ABSTOLS "abstolS has negative component(s) (illegal)." +#define MSGCV_BAD_ABSTOLS "abstolS has negative component(s) (illegal)." #define MSGCV_BAD_PBAR "pbar has zero component(s) (illegal)." #define MSGCV_BAD_PLIST "plist has negative component(s) (illegal)." #define MSGCV_BAD_NS "NS <= 0 illegal." @@ -1098,7 +1103,7 @@ int cvNlsInitSensStg1(CVodeMem cv_mem); #define MSGCV_BAD_ITOLQS "Illegal value for itolQS. The legal values are CV_SS, CV_SV, and CV_EE." #define MSGCV_NULL_ABSTOLQS "abstolQS = NULL illegal." #define MSGCV_BAD_RELTOLQS "reltolQS < 0 illegal." -#define MSGCV_BAD_ABSTOLQS "abstolQS has negative component(s) (illegal)." +#define MSGCV_BAD_ABSTOLQS "abstolQS has negative component(s) (illegal)." #define MSGCV_NO_QUADSENSI "Forward sensitivity analysis for quadrature variables not activated." #define MSGCV_NULL_YQS0 "yQS0 = NULL illegal." @@ -1134,9 +1139,9 @@ int cvNlsInitSensStg1(CVodeMem cv_mem); #define MSGCV_CLOSE_ROOTS "Root found at and very near " MSG_TIME "." #define MSGCV_BAD_TSTOP "The value " MSG_TIME_TSTOP " is behind current " MSG_TIME " in the direction of integration." #define MSGCV_INACTIVE_ROOTS "At the end of the first step, there are still some root functions identically 0. This warning will not be issued again." -#define MSGCV_NLS_SETUP_FAILED "At " MSG_TIME "the nonlinear solver setup failed unrecoverably." -#define MSGCV_NLS_INPUT_NULL "At " MSG_TIME "the nonlinear solver was passed a NULL input." - +#define MSGCV_NLS_SETUP_FAILED "At " MSG_TIME ", the nonlinear solver setup failed unrecoverably." +#define MSGCV_NLS_INPUT_NULL "At " MSG_TIME ", the nonlinear solver was passed a NULL input." +#define MSGCV_NLS_FAIL "At " MSG_TIME ", the nonlinear solver failed in an unrecoverable manner." #define MSGCV_NO_TOLQ "No integration tolerances for quadrature variables have been specified." #define MSGCV_BAD_EWTQ "Initial ewtQ has component(s) equal to zero (illegal)." @@ -1164,7 +1169,7 @@ int cvNlsInitSensStg1(CVodeMem cv_mem); #define MSGCV_QSRHSFUNC_REPTD "At " MSG_TIME " repeated recoverable quadrature sensitivity right-hand side function errors." #define MSGCV_QSRHSFUNC_FIRST "The quadrature sensitivity right-hand side routine failed at the first call." -/* +/* * ================================================================= * C V O D E A E R R O R M E S S A G E S * ================================================================= @@ -1180,7 +1185,7 @@ int cvNlsInitSensStg1(CVodeMem cv_mem); #define MSGCV_BAD_SENSI "At least one backward problem requires sensitivities, but they were not stored for interpolation." #define MSGCV_BAD_ITASKB "Illegal value for itaskB. Legal values are CV_NORMAL and CV_ONE_STEP." #define MSGCV_BAD_TBOUT "The final time tBout is outside the interval over which the forward problem was solved." -#define MSGCV_BACK_ERROR "Error occured while integrating backward problem # %d" +#define MSGCV_BACK_ERROR "Error occured while integrating backward problem # %d" #define MSGCV_BAD_TINTERP "Bad t = %g for interpolation." #define MSGCV_WRONG_INTERP "This function cannot be called for the specified interp type." diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_io.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_io.c index cb40f8ebf..9499fea6e 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_io.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_io.c @@ -6,7 +6,7 @@ * Programmer(s): Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -33,13 +33,13 @@ #define ONE RCONST(1.0) #define TWOPT5 RCONST(2.5) -/* +/* * ================================================================= * CVODES optional input functions * ================================================================= */ -/* +/* * CVodeSetErrHandlerFn * * Specifies the error handler function @@ -62,7 +62,7 @@ int CVodeSetErrHandlerFn(void *cvode_mem, CVErrHandlerFn ehfun, void *eh_data) return(CV_SUCCESS); } -/* +/* * CVodeSetErrFile * * Specifies the FILE pointer for output (NULL means no messages) @@ -84,7 +84,7 @@ int CVodeSetErrFile(void *cvode_mem, FILE *errfp) return(CV_SUCCESS); } -/* +/* * CVodeSetUserData * * Specifies the user data pointer for f @@ -106,7 +106,7 @@ int CVodeSetUserData(void *cvode_mem, void *user_data) return(CV_SUCCESS); } -/* +/* * CVodeSetMaxOrd * * Specifies the maximum method order @@ -128,7 +128,7 @@ int CVodeSetMaxOrd(void *cvode_mem, int maxord) cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMaxOrd", MSGCV_NEG_MAXORD); return(CV_ILL_INPUT); } - + /* Cannot increase maximum order beyond the value that was used when allocating memory */ qmax_alloc = cv_mem->cv_qmax_alloc; @@ -145,7 +145,7 @@ int CVodeSetMaxOrd(void *cvode_mem, int maxord) return(CV_SUCCESS); } -/* +/* * CVodeSetMaxNumSteps * * Specifies the maximum number of integration steps @@ -171,7 +171,7 @@ int CVodeSetMaxNumSteps(void *cvode_mem, long int mxsteps) return(CV_SUCCESS); } -/* +/* * CVodeSetMaxHnilWarns * * Specifies the maximum number of warnings for small h @@ -193,7 +193,7 @@ int CVodeSetMaxHnilWarns(void *cvode_mem, int mxhnil) return(CV_SUCCESS); } -/* +/* *CVodeSetStabLimDet * * Turns on/off the stability limit detection algorithm @@ -220,7 +220,7 @@ int CVodeSetStabLimDet(void *cvode_mem, booleantype sldet) return(CV_SUCCESS); } -/* +/* * CVodeSetInitStep * * Specifies the initial step size @@ -242,7 +242,7 @@ int CVodeSetInitStep(void *cvode_mem, realtype hin) return(CV_SUCCESS); } -/* +/* * CVodeSetMinStep * * Specifies the minimum step size @@ -280,7 +280,7 @@ int CVodeSetMinStep(void *cvode_mem, realtype hmin) return(CV_SUCCESS); } -/* +/* * CVodeSetMaxStep * * Specifies the maximum step size @@ -320,7 +320,7 @@ int CVodeSetMaxStep(void *cvode_mem, realtype hmax) return(CV_SUCCESS); } -/* +/* * CVodeSetStopTime * * Specifies the time beyond which the integration is not to proceed. @@ -355,7 +355,7 @@ int CVodeSetStopTime(void *cvode_mem, realtype tstop) return(CV_SUCCESS); } -/* +/* * CVodeSetMaxErrTestFails * * Specifies the maximum number of error test failures during one @@ -378,10 +378,10 @@ int CVodeSetMaxErrTestFails(void *cvode_mem, int maxnef) return(CV_SUCCESS); } -/* +/* * CVodeSetMaxConvFails * - * Specifies the maximum number of nonlinear convergence failures + * Specifies the maximum number of nonlinear convergence failures * during one step try. */ @@ -450,7 +450,7 @@ int CVodeSetMaxNonlinIters(void *cvode_mem, int maxcor) return(CV_SUCCESS); } -/* +/* * CVodeSetNonlinConvCoef * * Specifies the coeficient in the nonlinear solver convergence @@ -473,7 +473,7 @@ int CVodeSetNonlinConvCoef(void *cvode_mem, realtype nlscoef) return(CV_SUCCESS); } -/* +/* * CVodeSetRootDirection * * Specifies the direction of zero-crossings to be monitored. @@ -495,7 +495,7 @@ int CVodeSetRootDirection(void *cvode_mem, int *rootdir) nrt = cv_mem->cv_nrtfn; if (nrt==0) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetRootDirection", MSGCV_NO_ROOT); - return(CV_ILL_INPUT); + return(CV_ILL_INPUT); } for(i=0; icv_rootdir[i] = rootdir[i]; @@ -523,7 +523,7 @@ int CVodeSetNoInactiveRootWarn(void *cvode_mem) cv_mem = (CVodeMem) cvode_mem; cv_mem->cv_mxgnull = 0; - + return(CV_SUCCESS); } @@ -590,7 +590,7 @@ int CVodeSetConstraints(void *cvode_mem, N_Vector constraints) return(CV_SUCCESS); } -/* +/* * ================================================================= * Quadrature optional input functions * ================================================================= @@ -601,7 +601,7 @@ int CVodeSetQuadErrCon(void *cvode_mem, booleantype errconQ) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetQuadErrCon", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetQuadErrCon", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -611,7 +611,7 @@ int CVodeSetQuadErrCon(void *cvode_mem, booleantype errconQ) return(CV_SUCCESS); } -/* +/* * ================================================================= * FSA optional input functions * ================================================================= @@ -622,19 +622,19 @@ int CVodeSetSensDQMethod(void *cvode_mem, int DQtype, realtype DQrhomax) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensDQMethod", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensDQMethod", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if ( (DQtype != CV_CENTERED) && (DQtype != CV_FORWARD) ) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensDQMethod", MSGCV_BAD_DQTYPE); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensDQMethod", MSGCV_BAD_DQTYPE); return(CV_ILL_INPUT); } if (DQrhomax < ZERO ) { - cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensDQMethod", MSGCV_BAD_DQRHO); + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensDQMethod", MSGCV_BAD_DQRHO); return(CV_ILL_INPUT); } @@ -651,7 +651,7 @@ int CVodeSetSensErrCon(void *cvode_mem, booleantype errconS) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensErrCon", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensErrCon", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; @@ -713,7 +713,7 @@ int CVodeSetSensParams(void *cvode_mem, realtype *p, realtype *pbar, int *plist) int is, Ns; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensParams", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensParams", MSGCV_NO_MEM); return(CV_MEM_NULL); } @@ -772,7 +772,7 @@ int CVodeSetQuadSensErrCon(void *cvode_mem, booleantype errconQS) if (cvode_mem==NULL) { cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetQuadSensErrCon", MSGCV_NO_MEM); return(CV_MEM_NULL); - } + } cv_mem = (CVodeMem) cvode_mem; /* Was sensitivity initialized? */ @@ -780,12 +780,12 @@ int CVodeSetQuadSensErrCon(void *cvode_mem, booleantype errconQS) if (cv_mem->cv_SensMallocDone == SUNFALSE) { cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeSetQuadSensTolerances", MSGCV_NO_SENSI); return(CV_NO_SENS); - } + } /* Ckeck if quadrature sensitivity was initialized? */ if (cv_mem->cv_QuadSensMallocDone == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeSetQuadSensErrCon", MSGCV_NO_QUADSENSI); + cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeSetQuadSensErrCon", MSGCV_NO_QUADSENSI); return(CV_NO_QUAD); } @@ -794,7 +794,7 @@ int CVodeSetQuadSensErrCon(void *cvode_mem, booleantype errconQS) return(CV_SUCCESS); } -/* +/* * ================================================================= * CVODES optional output functions * ================================================================= @@ -822,7 +822,7 @@ int CVodeGetNumSteps(void *cvode_mem, long int *nsteps) return(CV_SUCCESS); } -/* +/* * CVodeGetNumRhsEvals * * Returns the current number of calls to f @@ -844,7 +844,7 @@ int CVodeGetNumRhsEvals(void *cvode_mem, long int *nfevals) return(CV_SUCCESS); } -/* +/* * CVodeGetNumLinSolvSetups * * Returns the current number of calls to the linear solver setup routine @@ -888,7 +888,7 @@ int CVodeGetNumErrTestFails(void *cvode_mem, long int *netfails) return(CV_SUCCESS); } -/* +/* * CVodeGetLastOrder * * Returns the order on the last succesful step @@ -910,7 +910,7 @@ int CVodeGetLastOrder(void *cvode_mem, int *qlast) return(CV_SUCCESS); } -/* +/* * CVodeGetCurrentOrder * * Returns the order to be attempted on the next step @@ -932,7 +932,29 @@ int CVodeGetCurrentOrder(void *cvode_mem, int *qcur) return(CV_SUCCESS); } -/* +/* + * CVodeGetCurrentGamma + * + * Returns the value of gamma for the current step. + */ + +int CVodeGetCurrentGamma(void *cvode_mem, realtype *gamma) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetCurrentGamma", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *gamma = cv_mem->cv_gamma; + + return(CV_SUCCESS); +} + +/* * CVodeGetNumStabLimOrderReds * * Returns the number of order reductions triggered by the stability @@ -958,7 +980,7 @@ int CVodeGetNumStabLimOrderReds(void *cvode_mem, long int *nslred) return(CV_SUCCESS); } -/* +/* * CVodeGetActualInitStep * * Returns the step size used on the first step @@ -1002,7 +1024,7 @@ int CVodeGetLastStep(void *cvode_mem, realtype *hlast) return(CV_SUCCESS); } -/* +/* * CVodeGetCurrentStep * * Returns the step size to be attempted on the next step @@ -1018,13 +1040,80 @@ int CVodeGetCurrentStep(void *cvode_mem, realtype *hcur) } cv_mem = (CVodeMem) cvode_mem; - + *hcur = cv_mem->cv_next_h; return(CV_SUCCESS); } -/* +/* + * CVodeGetCurrentState + * + * Returns the current state vector + */ + +int CVodeGetCurrentState(void *cvode_mem, N_Vector *y) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetCurrentState", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *y = cv_mem->cv_y; + + return(CV_SUCCESS); +} + +/* + * CVodeGetCurrentStateSens + * + * Returns the current sensitivity state vector array + */ + +int CVodeGetCurrentStateSens(void *cvode_mem, N_Vector **yS) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetCurrentStateSens", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *yS = cv_mem->cv_yS; + + return(CV_SUCCESS); +} + +/* + * CVodeGetCurrentSensSolveIndex + * + * Returns the current index of the sensitivity solve when using + * the staggered1 nonlinear solver. + */ + +int CVodeGetCurrentSensSolveIndex(void *cvode_mem, int *index) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetCurrentSensSolveIndex", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *index = cv_mem->sens_solve_idx; + + return(CV_SUCCESS); +} + +/* * CVodeGetCurrentTime * * Returns the current value of the independent variable @@ -1046,7 +1135,7 @@ int CVodeGetCurrentTime(void *cvode_mem, realtype *tcur) return(CV_SUCCESS); } -/* +/* * CVodeGetTolScaleFactor * * Returns a suggested factor for scaling tolerances @@ -1068,7 +1157,7 @@ int CVodeGetTolScaleFactor(void *cvode_mem, realtype *tolsfact) return(CV_SUCCESS); } -/* +/* * CVodeGetErrWeights * * This routine returns the current weight vector. @@ -1112,7 +1201,7 @@ int CVodeGetEstLocalErrors(void *cvode_mem, N_Vector ele) return(CV_SUCCESS); } -/* +/* * CVodeGetWorkSpace * * Returns integrator work space requirements @@ -1135,15 +1224,15 @@ int CVodeGetWorkSpace(void *cvode_mem, long int *lenrw, long int *leniw) return(CV_SUCCESS); } -/* +/* * CVodeGetIntegratorStats * * Returns integrator statistics */ -int CVodeGetIntegratorStats(void *cvode_mem, long int *nsteps, long int *nfevals, - long int *nlinsetups, long int *netfails, int *qlast, - int *qcur, realtype *hinused, realtype *hlast, +int CVodeGetIntegratorStats(void *cvode_mem, long int *nsteps, long int *nfevals, + long int *nlinsetups, long int *netfails, int *qlast, + int *qcur, realtype *hinused, realtype *hlast, realtype *hcur, realtype *tcur) { CVodeMem cv_mem; @@ -1169,7 +1258,7 @@ int CVodeGetIntegratorStats(void *cvode_mem, long int *nsteps, long int *nfevals return(CV_SUCCESS); } -/* +/* * CVodeGetNumGEvals * * Returns the current number of calls to g (for rootfinding) @@ -1191,7 +1280,7 @@ int CVodeGetNumGEvals(void *cvode_mem, long int *ngevals) return(CV_SUCCESS); } -/* +/* * CVodeGetRootInfo * * Returns pointer to array rootsfound showing roots found @@ -1266,7 +1355,7 @@ int CVodeGetNumNonlinSolvIters(void *cvode_mem, long int *nniters) return(CV_SUCCESS); } -/* +/* * CVodeGetNumNonlinSolvConvFails * * Returns the current number of convergence failures in the @@ -1342,7 +1431,7 @@ int CVodeGetNonlinSolvStats(void *cvode_mem, long int *nniters, } -/* +/* * ================================================================= * Quadrature optional output functions * ================================================================= @@ -1355,14 +1444,14 @@ int CVodeGetQuadNumRhsEvals(void *cvode_mem, long int *nfQevals) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadNumRhsEvals", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadNumRhsEvals", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_quadr==SUNFALSE) { - cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadNumRhsEvals", MSGCV_NO_QUAD); + cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadNumRhsEvals", MSGCV_NO_QUAD); return(CV_NO_QUAD); } @@ -1378,14 +1467,14 @@ int CVodeGetQuadNumErrTestFails(void *cvode_mem, long int *nQetfails) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadNumErrTestFails", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadNumErrTestFails", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_quadr==SUNFALSE) { - cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadNumErrTestFails", MSGCV_NO_QUAD); + cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadNumErrTestFails", MSGCV_NO_QUAD); return(CV_NO_QUAD); } @@ -1401,14 +1490,14 @@ int CVodeGetQuadErrWeights(void *cvode_mem, N_Vector eQweight) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadErrWeights", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadErrWeights", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_quadr==SUNFALSE) { - cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadErrWeights", MSGCV_NO_QUAD); + cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadErrWeights", MSGCV_NO_QUAD); return(CV_NO_QUAD); } @@ -1424,14 +1513,14 @@ int CVodeGetQuadStats(void *cvode_mem, long int *nfQevals, long int *nQetfails) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadStats", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadStats", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_quadr==SUNFALSE) { - cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadStats", MSGCV_NO_QUAD); + cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadStats", MSGCV_NO_QUAD); return(CV_NO_QUAD); } @@ -1441,7 +1530,7 @@ int CVodeGetQuadStats(void *cvode_mem, long int *nfQevals, long int *nQetfails) return(CV_SUCCESS); } -/* +/* * ================================================================= * Quadrature FSA optional output functions * ================================================================= @@ -1454,14 +1543,14 @@ int CVodeGetQuadSensNumRhsEvals(void *cvode_mem, long int *nfQSevals) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadSensNumRhsEvals", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadSensNumRhsEvals", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_quadr_sensi == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeGetQuadSensNumRhsEvals", MSGCV_NO_QUADSENSI); + cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeGetQuadSensNumRhsEvals", MSGCV_NO_QUADSENSI); return(CV_NO_QUADSENS); } @@ -1477,14 +1566,14 @@ int CVodeGetQuadSensNumErrTestFails(void *cvode_mem, long int *nQSetfails) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadSensNumErrTestFails", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadSensNumErrTestFails", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_quadr_sensi == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeGetQuadSensNumErrTestFails", MSGCV_NO_QUADSENSI); + cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeGetQuadSensNumErrTestFails", MSGCV_NO_QUADSENSI); return(CV_NO_QUADSENS); } @@ -1501,14 +1590,14 @@ int CVodeGetQuadSensErrWeights(void *cvode_mem, N_Vector *eQSweight) int is, Ns; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadSensErrWeights", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadSensErrWeights", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_quadr_sensi == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeGetQuadSensErrWeights", MSGCV_NO_QUADSENSI); + cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeGetQuadSensErrWeights", MSGCV_NO_QUADSENSI); return(CV_NO_QUADSENS); } Ns = cv_mem->cv_Ns; @@ -1527,14 +1616,14 @@ int CVodeGetQuadSensStats(void *cvode_mem, long int *nfQSevals, long int *nQSetf CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadSensStats", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadSensStats", MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; if (cv_mem->cv_quadr_sensi == SUNFALSE) { - cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeGetQuadSensStats", MSGCV_NO_QUADSENSI); + cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeGetQuadSensStats", MSGCV_NO_QUADSENSI); return(CV_NO_QUADSENS); } @@ -1545,7 +1634,7 @@ int CVodeGetQuadSensStats(void *cvode_mem, long int *nfQSevals, long int *nQSetf } -/* +/* * ================================================================= * FSA optional output functions * ================================================================= @@ -1558,7 +1647,7 @@ int CVodeGetSensNumRhsEvals(void *cvode_mem, long int *nfSevals) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensNumRhsEvals", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensNumRhsEvals", MSGCV_NO_MEM); return(CV_MEM_NULL); } @@ -1581,7 +1670,7 @@ int CVodeGetNumRhsEvalsSens(void *cvode_mem, long int *nfevalsS) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumRhsEvalsSens", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumRhsEvalsSens", MSGCV_NO_MEM); return(CV_MEM_NULL); } @@ -1604,7 +1693,7 @@ int CVodeGetSensNumErrTestFails(void *cvode_mem, long int *nSetfails) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensNumErrTestFails", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensNumErrTestFails", MSGCV_NO_MEM); return(CV_MEM_NULL); } @@ -1627,7 +1716,7 @@ int CVodeGetSensNumLinSolvSetups(void *cvode_mem, long int *nlinsetupsS) CVodeMem cv_mem; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensNumLinSolvSetups", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensNumLinSolvSetups", MSGCV_NO_MEM); return(CV_MEM_NULL); } @@ -1651,7 +1740,7 @@ int CVodeGetSensErrWeights(void *cvode_mem, N_Vector *eSweight) int is, Ns; if (cvode_mem==NULL) { - cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensErrWeights", MSGCV_NO_MEM); + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensErrWeights", MSGCV_NO_MEM); return(CV_MEM_NULL); } @@ -1672,7 +1761,7 @@ int CVodeGetSensErrWeights(void *cvode_mem, N_Vector *eSweight) /*-----------------------------------------------------------------*/ -int CVodeGetSensStats(void *cvode_mem, long int *nfSevals, long int *nfevalsS, +int CVodeGetSensStats(void *cvode_mem, long int *nfSevals, long int *nfevalsS, long int *nSetfails, long int *nlinsetupsS) { CVodeMem cv_mem; @@ -1790,7 +1879,7 @@ int CVodeGetStgrSensNumNonlinSolvIters(void *cvode_mem, long int *nSTGR1niters) return(CV_NO_SENS); } - if(cv_mem->cv_ism==CV_STAGGERED1) + if(cv_mem->cv_ism==CV_STAGGERED1) for(is=0; iscv_nniS1[is]; return(CV_SUCCESS); @@ -1817,7 +1906,7 @@ int CVodeGetStgrSensNumNonlinSolvConvFails(void *cvode_mem, long int *nSTGR1ncfa return(CV_NO_SENS); } - if(cv_mem->cv_ism==CV_STAGGERED1) + if(cv_mem->cv_ism==CV_STAGGERED1) for(is=0; iscv_ncfnS1[is]; return(CV_SUCCESS); @@ -1825,7 +1914,7 @@ int CVodeGetStgrSensNumNonlinSolvConvFails(void *cvode_mem, long int *nSTGR1ncfa /*-----------------------------------------------------------------*/ -int CVodeGetSensNonlinSolvStats(void *cvode_mem, long int *nSniters, +int CVodeGetSensNonlinSolvStats(void *cvode_mem, long int *nSniters, long int *nSncfails) { CVodeMem cv_mem; @@ -1986,7 +2075,7 @@ char *CVodeGetReturnFlagName(long int flag) break; case CV_TOO_CLOSE: sprintf(name,"CV_TOO_CLOSE"); - break; + break; case CV_NO_ADJ: sprintf(name,"CV_NO_ADJ"); break; @@ -2007,11 +2096,13 @@ char *CVodeGetReturnFlagName(long int flag) break; case CV_GETY_BADT: sprintf(name,"CV_GETY_BADT"); - break; + break; + case CV_NLS_FAIL: + sprintf(name,"CV_NLS_FAIL"); + break; default: sprintf(name,"NONE"); } return(name); } - diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_ls.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_ls.c index 0a5c9aca8..ebf38fbe4 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_ls.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_ls.c @@ -3,7 +3,7 @@ * Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -40,7 +40,16 @@ #define TWO RCONST(2.0) /*================================================================= - PRIVATE FUNCTION PROTOTYPES + PRIVATE FUNCTION PROTOTYPES - forward problems + =================================================================*/ + +static int cvLsLinSys(realtype t, N_Vector y, N_Vector fy, SUNMatrix A, + booleantype jok, booleantype *jcur, realtype gamma, + void *user_data, N_Vector tmp1, N_Vector tmp2, + N_Vector tmp3); + +/*================================================================= + PRIVATE FUNCTION PROTOTYPES - backward problems =================================================================*/ /* cvLsJacBWrapper and cvLsJacBSWrapper have type CVLsJacFn, and @@ -96,14 +105,28 @@ static int cvLsJacTimesVecBSWrapper(N_Vector vB, N_Vector JvB, realtype t, N_Vector yB, N_Vector fyB, void *cvode_mem, N_Vector tmpB); +/* cvLsLinSysFnBWrapper and cvLsLinSysFnBSWrapper have type CVLsLinSysFn, and + wrap around user-provided functions of type CVLsLinSysFnB and CVLsLinSysFnBS, + respectively */ +static int cvLsLinSysBWrapper(realtype t, N_Vector yB, N_Vector fyB, + SUNMatrix AB, booleantype jokB, + booleantype *jcurB, realtype gammaB, + void *user_dataB, N_Vector tmp1B, N_Vector tmp2B, + N_Vector tmp3B); +static int cvLsLinSysBSWrapper(realtype t, N_Vector yB, N_Vector fyB, + SUNMatrix AB, booleantype jokB, + booleantype *jcurB, realtype gammaB, + void *user_dataB, N_Vector tmp1B, N_Vector tmp2B, + N_Vector tmp3); + /*================================================================ PART I - forward problems ================================================================*/ -/*----------------------------------------------------------------- +/*=============================================================== CVSLS Exported functions -- Required - -----------------------------------------------------------------*/ + ===============================================================*/ /*--------------------------------------------------------------- CVodeSetLinearSolver specifies the linear solver @@ -111,9 +134,11 @@ static int cvLsJacTimesVecBSWrapper(N_Vector vB, N_Vector JvB, realtype t, int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, SUNMatrix A) { - CVodeMem cv_mem; - CVLsMem cvls_mem; - int retval, LSType; + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval, LSType; + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ /* Return immediately if either cvode_mem or LS inputs are NULL */ if (cvode_mem == NULL) { @@ -130,42 +155,55 @@ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, cv_mem = (CVodeMem) cvode_mem; /* Test if solver is compatible with LS interface */ - if ( (LS->ops->gettype == NULL) || - (LS->ops->initialize == NULL) || - (LS->ops->setup == NULL) || - (LS->ops->solve == NULL) ) { + if ( (LS->ops->gettype == NULL) || (LS->ops->solve == NULL) ) { cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", "CVodeSetLinearSolver", "LS object is missing a required operation"); return(CVLS_ILL_INPUT); } + /* Retrieve the LS type */ + LSType = SUNLinSolGetType(LS); + + /* Set flags based on LS type */ + iterative = (LSType != SUNLINEARSOLVER_DIRECT); + matrixbased = (LSType != SUNLINEARSOLVER_ITERATIVE); + /* Test if vector is compatible with LS interface */ if ( (cv_mem->cv_tempv->ops->nvconst == NULL) || - (cv_mem->cv_tempv->ops->nvdotprod == NULL) ) { + (cv_mem->cv_tempv->ops->nvwrmsnorm == NULL) ) { cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", "CVodeSetLinearSolver", MSG_LS_BAD_NVECTOR); return(CVLS_ILL_INPUT); } - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(LS); - /* Check for compatible LS type, matrix and "atimes" support */ - if ((LSType == SUNLINEARSOLVER_ITERATIVE) && (LS->ops->setatimes == NULL)) { - cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", - "Incompatible inputs: iterative LS must support ATimes routine"); - return(CVLS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_DIRECT) && (A == NULL)) { - cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", - "Incompatible inputs: direct LS requires non-NULL matrix"); - return(CVLS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) && (A == NULL)) { - cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", - "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); + if (iterative) { + + if (cv_mem->cv_tempv->ops->nvgetlength == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", + "CVodeSetLinearSolver", MSG_LS_BAD_NVECTOR); + return(CVLS_ILL_INPUT); + } + + if (!matrixbased && LS->ops->setatimes == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", "CVodeSetLinearSolver", + "Incompatible inputs: iterative LS must support ATimes routine"); + return(CVLS_ILL_INPUT); + } + + if (matrixbased && A == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", "CVodeSetLinearSolver", + "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); + return(CVLS_ILL_INPUT); + } + + } else if (A == NULL) { + + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", "CVodeSetLinearSolver", + "Incompatible inputs: direct LS requires non-NULL matrix"); return(CVLS_ILL_INPUT); + } /* free any existing system solver attached to CVode */ @@ -190,6 +228,10 @@ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, /* set SUNLinearSolver pointer */ cvls_mem->LS = LS; + /* Linear solver type information */ + cvls_mem->iterative = iterative; + cvls_mem->matrixbased = matrixbased; + /* Set defaults for Jacobian-related fields */ if (A != NULL) { cvls_mem->jacDQ = SUNTRUE; @@ -200,11 +242,16 @@ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, cvls_mem->jac = NULL; cvls_mem->J_data = NULL; } + cvls_mem->jtimesDQ = SUNTRUE; cvls_mem->jtsetup = NULL; cvls_mem->jtimes = cvLsDQJtimes; cvls_mem->jt_data = cv_mem; + cvls_mem->user_linsys = SUNFALSE; + cvls_mem->linsys = cvLsLinSys; + cvls_mem->A_data = cv_mem; + /* Set defaults for preconditioner-related fields */ cvls_mem->pset = NULL; cvls_mem->psolve = NULL; @@ -244,23 +291,17 @@ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, } } - /* When using a non-NULL SUNMatrix object, store pointer to A and create saved_J */ + /* When using a SUNMatrix object, store pointer to A and initialize savedJ */ if (A != NULL) { cvls_mem->A = A; - cvls_mem->savedJ = SUNMatClone(A); - if (cvls_mem->savedJ == NULL) { - cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSLS", - "CVodeSetLinearSolver", MSG_LS_MEM_FAIL); - free(cvls_mem); cvls_mem = NULL; - return(CVLS_MEM_FAIL); - } + cvls_mem->savedJ = NULL; /* allocated in cvLsInitialize */ } + /* Allocate memory for ytemp and x */ cvls_mem->ytemp = N_VClone(cv_mem->cv_tempv); if (cvls_mem->ytemp == NULL) { cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSLS", "CVodeSetLinearSolver", MSG_LS_MEM_FAIL); - SUNMatDestroy(cvls_mem->savedJ); free(cvls_mem); cvls_mem = NULL; return(CVLS_MEM_FAIL); } @@ -269,19 +310,20 @@ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, if (cvls_mem->x == NULL) { cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSLS", "CVodeSetLinearSolver", MSG_LS_MEM_FAIL); - SUNMatDestroy(cvls_mem->savedJ); N_VDestroy(cvls_mem->ytemp); free(cvls_mem); cvls_mem = NULL; return(CVLS_MEM_FAIL); } - /* For iterative LS, compute sqrtN from a dot product */ - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { - N_VConst(ONE, cvls_mem->ytemp); - cvls_mem->sqrtN = SUNRsqrt( N_VDotProd(cvls_mem->ytemp, - cvls_mem->ytemp) ); - } + /* For iterative LS, compute sqrtN */ + if (iterative) + cvls_mem->sqrtN = SUNRsqrt( N_VGetLength(cvls_mem->ytemp) ); + + /* Check if soltuion scaling should be enabled */ + if (matrixbased && cv_mem->cv_lmm == CV_BDF) + cvls_mem->scalesol = SUNTRUE; + else + cvls_mem->scalesol = SUNFALSE; /* Attach linear solver memory to integrator memory */ cv_mem->cv_lmem = cvls_mem; @@ -290,9 +332,9 @@ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, } -/*----------------------------------------------------------------- - CVSLS Exported functions -- Optional input/output - -----------------------------------------------------------------*/ +/*=============================================================== + Optional input/output routines + ===============================================================*/ /* CVodeSetJacFn specifies the Jacobian function. */ @@ -314,7 +356,7 @@ int CVodeSetJacFn(void *cvode_mem, CVLsJacFn jac) return(CVLS_ILL_INPUT); } - /* set Jacobian routine pointer, and update relevant flags */ + /* set the Jacobian routine pointer, and update relevant flags */ if (jac != NULL) { cvls_mem->jacDQ = SUNFALSE; cvls_mem->jac = jac; @@ -325,6 +367,11 @@ int CVodeSetJacFn(void *cvode_mem, CVLsJacFn jac) cvls_mem->J_data = cv_mem; } + /* ensure the internal linear system function is used */ + cvls_mem->user_linsys = SUNFALSE; + cvls_mem->linsys = cvLsLinSys; + cvls_mem->A_data = cv_mem; + return(CVLS_SUCCESS); } @@ -373,6 +420,30 @@ int CVodeSetMaxStepsBetweenJac(void *cvode_mem, long int msbj) } +/* CVodeSetLinearSolutionScaling enables or disables scaling the + linear solver solution to account for changes in gamma. */ +int CVodeSetLinearSolutionScaling(void *cvode_mem, booleantype onoff) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; store input and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetLinearSolutionScaling", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* check for valid solver and method type */ + if (!(cvls_mem->matrixbased) || cv_mem->cv_lmm != CV_BDF) + return(CVLS_ILL_INPUT); + + /* set solution scaling flag */ + cvls_mem->scalesol = onoff; + + return(CVLS_SUCCESS); +} + + /* CVodeSetPreconditioner specifies the user-supplied preconditioner setup and solve routines */ int CVodeSetPreconditioner(void *cvode_mem, CVLsPrecSetupFn psetup, @@ -457,6 +528,40 @@ int CVodeSetJacTimes(void *cvode_mem, CVLsJacTimesSetupFn jtsetup, } +/* CVodeSetLinSysFn specifies the linear system setup function. */ +int CVodeSetLinSysFn(void *cvode_mem, CVLsLinSysFn linsys) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetLinSysFn", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* return with failure if linsys cannot be used */ + if ((linsys != NULL) && (cvls_mem->A == NULL)) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", "CVodeSetLinSysFn", + "Linear system setup routine cannot be supplied for NULL SUNMatrix"); + return(CVLS_ILL_INPUT); + } + + /* set the linear system routine pointer, and update relevant flags */ + if (linsys != NULL) { + cvls_mem->user_linsys = SUNTRUE; + cvls_mem->linsys = linsys; + cvls_mem->A_data = cv_mem->cv_user_data; + } else { + cvls_mem->user_linsys = SUNFALSE; + cvls_mem->linsys = cvLsLinSys; + cvls_mem->A_data = cv_mem; + } + + return(CVLS_SUCCESS); +} + + /* CVodeGetLinWorkSpace returns the length of workspace allocated for the CVLS linear solver interface */ int CVodeGetLinWorkSpace(void *cvode_mem, long int *lenrwLS, @@ -711,9 +816,9 @@ char *CVodeGetLinReturnFlagName(long int flag) } -/*----------------------------------------------------------------- +/*================================================================= CVSLS private functions - -----------------------------------------------------------------*/ + =================================================================*/ /*----------------------------------------------------------------- cvLsATimes @@ -894,6 +999,9 @@ int cvLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, CVLsMem cvls_mem; int retval = 0; + /* initialize cns_data to avoid compiler warning */ + cns_data = NULL; + /* access LsMem interface structure */ cvls_mem = (CVLsMem) cv_mem->cv_lmem; @@ -909,7 +1017,7 @@ int cvLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, /* Obtain pointers to the data for ewt, y */ ewt_data = N_VGetArrayPointer(cv_mem->cv_ewt); y_data = N_VGetArrayPointer(y); - if (cv_mem->cv_constraints != NULL) + if (cv_mem->cv_constraintsSet) cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); /* Set minimum increment based on uround and norm of f */ @@ -927,7 +1035,7 @@ int cvLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, inc = SUNMAX(srur*SUNRabs(yjsaved), minInc/ewt_data[j]); /* Adjust sign(inc) if y_j has an inequality constraint. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((yjsaved+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yjsaved+inc)*conj <= ZERO) inc = -inc;} @@ -977,6 +1085,9 @@ int cvLsBandDQJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix Jac, CVLsMem cvls_mem; int retval = 0; + /* initialize cns_data to avoid compiler warning */ + cns_data = NULL; + /* access LsMem interface structure */ cvls_mem = (CVLsMem) cv_mem->cv_lmem; @@ -995,7 +1106,7 @@ int cvLsBandDQJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix Jac, ftemp_data = N_VGetArrayPointer(ftemp); y_data = N_VGetArrayPointer(y); ytemp_data = N_VGetArrayPointer(ytemp); - if (cv_mem->cv_constraints != NULL) + if (cv_mem->cv_constraintsSet) cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); /* Load ytemp with y = predicted y vector */ @@ -1019,7 +1130,7 @@ int cvLsBandDQJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix Jac, inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); /* Adjust sign(inc) if yj has an inequality constraint. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((ytemp_data[j]+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((ytemp_data[j]+inc)*conj <= ZERO) inc = -inc;} @@ -1040,7 +1151,7 @@ int cvLsBandDQJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix Jac, inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); /* Adjust sign(inc) as before. */ - if (cv_mem->cv_constraints != NULL) { + if (cv_mem->cv_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if ((ytemp_data[j]+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((ytemp_data[j]+inc)*conj <= ZERO) inc = -inc;} @@ -1109,6 +1220,94 @@ int cvLsDQJtimes(N_Vector v, N_Vector Jv, realtype t, } +/*----------------------------------------------------------------- + cvLsLinSys + + Setup the linear system A = I - gamma J + -----------------------------------------------------------------*/ +static int cvLsLinSys(realtype t, N_Vector y, N_Vector fy, SUNMatrix A, + booleantype jok, booleantype *jcur, realtype gamma, + void *cvode_mem, N_Vector vtemp1, N_Vector vtemp2, + N_Vector vtemp3) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "cvLsLinSys", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Check if Jacobian needs to be updated */ + if (jok) { + + /* Use saved copy of J */ + *jcur = SUNFALSE; + + /* Overwrite linear system matrix with saved J */ + retval = SUNMatCopy(cvls_mem->savedJ, A); + if (retval) { + cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVSLS", + "cvLsSetup", MSG_LS_SUNMAT_FAILED); + cvls_mem->last_flag = CVLS_SUNMAT_FAIL; + return(cvls_mem->last_flag); + } + + } else { + + /* Call jac() routine to update J */ + *jcur = SUNTRUE; + + /* Clear the linear system matrix if necessary */ + if (SUNLinSolGetType(cvls_mem->LS) == SUNLINEARSOLVER_DIRECT) { + retval = SUNMatZero(A); + if (retval) { + cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVSLS", + "cvLsSetup", MSG_LS_SUNMAT_FAILED); + cvls_mem->last_flag = CVLS_SUNMAT_FAIL; + return(cvls_mem->last_flag); + } + } + + /* Compute new Jacobian matrix */ + retval = cvls_mem->jac(t, y, fy, A, cvls_mem->J_data, + vtemp1, vtemp2, vtemp3); + if (retval < 0) { + cvProcessError(cv_mem, CVLS_JACFUNC_UNRECVR, "CVSLS", + "cvLsSetup", MSG_LS_JACFUNC_FAILED); + cvls_mem->last_flag = CVLS_JACFUNC_UNRECVR; + return(-1); + } + if (retval > 0) { + cvls_mem->last_flag = CVLS_JACFUNC_RECVR; + return(1); + } + + /* Update saved copy of the Jacobian matrix */ + retval = SUNMatCopy(A, cvls_mem->savedJ); + if (retval) { + cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVSLS", + "cvLsSetup", MSG_LS_SUNMAT_FAILED); + cvls_mem->last_flag = CVLS_SUNMAT_FAIL; + return(cvls_mem->last_flag); + } + + } + + /* Perform linear combination A = I - gamma*J */ + retval = SUNMatScaleAddI(-gamma, A); + if (retval) { + cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVSLS", + "cvLsSetup", MSG_LS_SUNMAT_FAILED); + cvls_mem->last_flag = CVLS_SUNMAT_FAIL; + return(cvls_mem->last_flag); + } + + return(CVLS_SUCCESS); +} + + /*----------------------------------------------------------------- cvLsInitialize @@ -1129,50 +1328,84 @@ int cvLsInitialize(CVodeMem cv_mem) cvls_mem = (CVLsMem) cv_mem->cv_lmem; /* Test for valid combinations of matrix & Jacobian routines: */ - if (cvls_mem->A == NULL) { + if (cvls_mem->A != NULL) { - /* If SUNMatrix A is NULL: ensure 'jac' function pointer is NULL */ - cvls_mem->jacDQ = SUNFALSE; - cvls_mem->jac = NULL; - cvls_mem->J_data = NULL; + /* Matrix-based case */ + + if (cvls_mem->user_linsys) { + + /* User-supplied linear system function, reset A_data (just in case) */ + cvls_mem->A_data = cv_mem->cv_user_data; - } else if (cvls_mem->jacDQ) { + } else { - /* If A is non-NULL, and 'jac' is not user-supplied: - - if A is dense or band, ensure that our DQ approx. is used - - otherwise => error */ - retval = 0; - if (cvls_mem->A->ops->getid) { + /* Internal linear system function, reset pointers (just in case) */ + cvls_mem->linsys = cvLsLinSys; + cvls_mem->A_data = cv_mem; + + /* Check if an internal or user-supplied Jacobian function is used */ + if (cvls_mem->jacDQ) { + + /* Internal difference quotient Jacobian. Check that A is dense or band, + otherwise return an error */ + retval = 0; + if (cvls_mem->A->ops->getid) { + + if ( (SUNMatGetID(cvls_mem->A) == SUNMATRIX_DENSE) || + (SUNMatGetID(cvls_mem->A) == SUNMATRIX_BAND) ) { + cvls_mem->jac = cvLsDQJac; + cvls_mem->J_data = cv_mem; + } else { + retval++; + } + + } else { + retval++; + } + if (retval) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", "cvLsInitialize", + "No Jacobian constructor available for SUNMatrix type"); + cvls_mem->last_flag = CVLS_ILL_INPUT; + return(CVLS_ILL_INPUT); + } - if ( (SUNMatGetID(cvls_mem->A) == SUNMATRIX_DENSE) || - (SUNMatGetID(cvls_mem->A) == SUNMATRIX_BAND) ) { - cvls_mem->jac = cvLsDQJac; - cvls_mem->J_data = cv_mem; } else { - retval++; + + /* User-supplied Jacobian, reset J_data pointer (just in case) */ + cvls_mem->J_data = cv_mem->cv_user_data; + } - } else { - retval++; - } - if (retval) { - cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", "cvLsInitialize", - "No Jacobian constructor available for SUNMatrix type"); - cvls_mem->last_flag = CVLS_ILL_INPUT; - return(CVLS_ILL_INPUT); - } + /* Allocate internally saved Jacobian if not already done */ + if (cvls_mem->savedJ == NULL) { + cvls_mem->savedJ = SUNMatClone(cvls_mem->A); + if (cvls_mem->savedJ == NULL) { + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSLS", "cvLsInitialize", + MSG_LS_MEM_FAIL); + cvls_mem->last_flag = CVLS_MEM_FAIL; + return(CVLS_MEM_FAIL); + } + } + + } /* end matrix-based case */ } else { - /* If A is non-NULL, and 'jac' is user-supplied, - reset J_data pointer (just in case) */ - cvls_mem->J_data = cv_mem->cv_user_data; + /* Matrix-free case: ensure 'jac' and `linsys` function pointers are NULL */ + cvls_mem->jacDQ = SUNFALSE; + cvls_mem->jac = NULL; + cvls_mem->J_data = NULL; + + cvls_mem->user_linsys = SUNFALSE; + cvls_mem->linsys = NULL; + cvls_mem->A_data = NULL; + } /* reset counters */ cvLsInitializeCounters(cvls_mem); - /* Set Jacobian-related fields, based on jtimesDQ */ + /* Set Jacobian-vector product related fields, based on jtimesDQ */ if (cvls_mem->jtimesDQ) { cvls_mem->jtsetup = NULL; cvls_mem->jtimes = cvLsDQJtimes; @@ -1233,70 +1466,41 @@ int cvLsSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, ((convfail == CV_FAIL_BAD_J) && (dgamma < CVLS_DGMAX)) || (convfail == CV_FAIL_OTHER); - /* If using a NULL SUNMatrix, set jcur to jbad; otherwise update J as appropriate */ - if (cvls_mem->A == NULL) { - - *jcurPtr = cvls_mem->jbad; - - } else { - - /* If jbad = SUNFALSE, use saved copy of J */ - if (!cvls_mem->jbad) { - - *jcurPtr = SUNFALSE; - retval = SUNMatCopy(cvls_mem->savedJ, cvls_mem->A); - if (retval) { - cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVSLS", - "cvLsSetup", MSG_LS_SUNMAT_FAILED); - cvls_mem->last_flag = CVLS_SUNMAT_FAIL; - return(cvls_mem->last_flag); - } + /* Setup the linear system if necessary */ + if (cvls_mem->A != NULL) { - /* If jbad = SUNTRUE, call jac routine for new J value */ - } else { + /* Update J if appropriate and evaluate A = I - gamma J */ + retval = cvls_mem->linsys(cv_mem->cv_tn, ypred, fpred, cvls_mem->A, + !(cvls_mem->jbad), jcurPtr, cv_mem->cv_gamma, + cvls_mem->A_data, vtemp1, vtemp2, vtemp3); + /* Update J eval count and step when J was last updated */ + if (*jcurPtr) { cvls_mem->nje++; cvls_mem->nstlj = cv_mem->cv_nst; - *jcurPtr = SUNTRUE; - retval = SUNMatZero(cvls_mem->A); - if (retval) { - cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVSLS", - "cvLsSetup", MSG_LS_SUNMAT_FAILED); - cvls_mem->last_flag = CVLS_SUNMAT_FAIL; - return(cvls_mem->last_flag); - } - - retval = cvls_mem->jac(cv_mem->cv_tn, ypred, fpred, cvls_mem->A, - cvls_mem->J_data, vtemp1, vtemp2, vtemp3); - if (retval < 0) { - cvProcessError(cv_mem, CVLS_JACFUNC_UNRECVR, "CVSLS", - "cvLsSetup", MSG_LS_JACFUNC_FAILED); - cvls_mem->last_flag = CVLS_JACFUNC_UNRECVR; - return(-1); - } - if (retval > 0) { - cvls_mem->last_flag = CVLS_JACFUNC_RECVR; - return(1); - } + } - retval = SUNMatCopy(cvls_mem->A, cvls_mem->savedJ); - if (retval) { - cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVSLS", - "cvLsSetup", MSG_LS_SUNMAT_FAILED); - cvls_mem->last_flag = CVLS_SUNMAT_FAIL; - return(cvls_mem->last_flag); + /* Check linsys() return value and return if necessary */ + if (retval != CVLS_SUCCESS) { + if (cvls_mem->user_linsys) { + if (retval < 0) { + cvProcessError(cv_mem, CVLS_JACFUNC_UNRECVR, "CVSLS", + "cvLsSetup", MSG_LS_JACFUNC_FAILED); + cvls_mem->last_flag = CVLS_JACFUNC_UNRECVR; + return(-1); + } else { + cvls_mem->last_flag = CVLS_JACFUNC_RECVR; + return(1); + } + } else { + return(retval); } - } - /* Scale and add I to get A = I - gamma*J */ - retval = SUNMatScaleAddI(-cv_mem->cv_gamma, cvls_mem->A); - if (retval) { - cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVSLS", - "cvLsSetup", MSG_LS_SUNMAT_FAILED); - cvls_mem->last_flag = CVLS_SUNMAT_FAIL; - return(cvls_mem->last_flag); - } + } else { + + /* Matrix-free case, set jcur to jbad */ + *jcurPtr = cvls_mem->jbad; } @@ -1304,7 +1508,7 @@ int cvLsSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, pass the heuristic suggestions above to the user code(s) */ cvls_mem->last_flag = SUNLinSolSetup(cvls_mem->LS, cvls_mem->A); - /* If the SUNMatrix was NULL, update heuristics flags */ + /* If Matrix-free, update heuristics flags */ if (cvls_mem->A == NULL) { /* If user set jcur to SUNTRUE, increment npe and save nst value */ @@ -1334,7 +1538,7 @@ int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, { CVLsMem cvls_mem; realtype bnorm, deltar, delta, w_mean; - int curiter, nli_inc, retval, LSType; + int curiter, nli_inc, retval; booleantype do_sensi_sim, do_sensi_stg, do_sensi_stg1; /* access CVLsMem structure */ @@ -1345,9 +1549,6 @@ int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, } cvls_mem = (CVLsMem) cv_mem->cv_lmem; - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(cvls_mem->LS); - /* are we computing sensitivities and with which approach? */ do_sensi_sim = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_SIMULTANEOUS)); do_sensi_stg = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_STAGGERED)); @@ -1366,8 +1567,7 @@ int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, /* If the linear solver is iterative: test norm(b), if small, return x = 0 or x = b; set linear solver tolerance (in left/right scaled 2-norm) */ - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (cvls_mem->iterative) { deltar = cvls_mem->eplifac * cv_mem->cv_tq[4]; bnorm = N_VWrmsNorm(b, weight); if (bnorm <= deltar) { @@ -1385,9 +1585,6 @@ int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, cvls_mem->ycur = ynow; cvls_mem->fcur = fnow; - /* Set initial guess x = 0 to LS */ - N_VConst(ZERO, cvls_mem->x); - /* Set scaling vectors for LS to use (if applicable) */ if (cvls_mem->LS->ops->setscalingvectors) { retval = SUNLinSolSetScalingVectors(cvls_mem->LS, @@ -1413,16 +1610,18 @@ int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, <=> w_mean^2 \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 <=> \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 / w_mean^2 <=> || b - A x ||_2 < tol / w_mean - So we compute w_mean = ||w||_RMS = ||w||_2 / sqrt(n), and scale - the desired tolerance accordingly. */ - } else if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + So we compute w_mean = ||w||_RMS = ||w||_2 and scale the desired tolerance accordingly. */ + } else if (cvls_mem->iterative) { - w_mean = SUNRsqrt( N_VDotProd(weight, weight) ) / cvls_mem->sqrtN; + N_VConst(ONE, cvls_mem->x); + w_mean = N_VWrmsNorm(weight, cvls_mem->x); delta /= w_mean; } + /* Set initial guess x = 0 to LS */ + N_VConst(ZERO, cvls_mem->x); + /* If a user-provided jtsetup routine is supplied, call that here */ if (cvls_mem->jtsetup) { cvls_mem->last_flag = cvls_mem->jtsetup(cv_mem->cv_tn, ynow, fnow, @@ -1441,17 +1640,12 @@ int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, /* If using a direct or matrix-iterative solver, BDF method, and gamma has changed, scale the correction to account for change in gamma */ - if ( ((LSType == SUNLINEARSOLVER_DIRECT) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE)) && - (cv_mem->cv_lmm == CV_BDF) && - (cv_mem->cv_gamrat != ONE) ) + if (cvls_mem->scalesol && cv_mem->cv_gamrat != ONE) N_VScale(TWO/(ONE + cv_mem->cv_gamrat), b, b); /* Retrieve statistics from iterative linear solvers */ nli_inc = 0; - if ( ((LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE)) && - (cvls_mem->LS->ops->numiters) ) + if (cvls_mem->iterative && cvls_mem->LS->ops->numiters) nli_inc = SUNLinSolNumIters(cvls_mem->LS); /* Increment counters nli and ncfl */ @@ -1611,8 +1805,8 @@ int cvLs_AccessLMem(void* cvode_mem, const char *fname, CVSLS Exported functions -- Required ---------------------------------------------------------------*/ -/* CVodeSetLinearSolverB specifies the iterative linear solver - for backward integration */ +/* CVodeSetLinearSolverB specifies the linear solver for backward + integration */ int CVodeSetLinearSolverB(void *cvode_mem, int which, SUNLinearSolver LS, SUNMatrix A) { @@ -1776,6 +1970,27 @@ int CVodeSetEpsLinB(void *cvode_mem, int which, realtype eplifacB) } +int CVodeSetLinearSolutionScalingB(void *cvode_mem, int which, + booleantype onoffB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + void *cvodeB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemB(cvode_mem, which, "CVodeSetLinearSolutionScalingB", + &cv_mem, &ca_mem, &cvB_mem, &cvlsB_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* call corresponding routine for cvodeB_mem structure */ + cvodeB_mem = (void *) (cvB_mem->cv_mem); + return(CVodeSetLinearSolutionScaling(cvodeB_mem, onoffB)); +} + + int CVodeSetPreconditionerB(void *cvode_mem, int which, CVLsPrecSetupFnB psetupB, CVLsPrecSolveFnB psolveB) @@ -1896,6 +2111,63 @@ int CVodeSetJacTimesBS(void *cvode_mem, int which, } +int CVodeSetLinSysFnB(void *cvode_mem, int which, CVLsLinSysFnB linsysB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + void *cvodeB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemB(cvode_mem, which, "CVodeSetLinSysFnB", + &cv_mem, &ca_mem, &cvB_mem, &cvlsB_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* set linsysB function pointer */ + cvlsB_mem->linsysB = linsysB; + + /* call corresponding routine for cvodeB_mem structure */ + cvodeB_mem = (void *) (cvB_mem->cv_mem); + if (linsysB != NULL) { + retval = CVodeSetLinSysFn(cvodeB_mem, cvLsLinSysBWrapper); + } else { + retval = CVodeSetLinSysFn(cvodeB_mem, NULL); + } + + return(retval); +} + + +int CVodeSetLinSysFnBS(void *cvode_mem, int which, CVLsLinSysFnBS linsysBS) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + void *cvodeB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemB(cvode_mem, which, "CVodeSetLinSysFnBS", + &cv_mem, &ca_mem, &cvB_mem, &cvlsB_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* set linsysB function pointer */ + cvlsB_mem->linsysBS = linsysBS; + + /* call corresponding routine for cvodeB_mem structure */ + cvodeB_mem = (void *) (cvB_mem->cv_mem); + if (linsysBS != NULL) { + retval = CVodeSetLinSysFn(cvodeB_mem, cvLsLinSysBSWrapper); + } else { + retval = CVodeSetLinSysFn(cvodeB_mem, NULL); + } + + return(retval); +} + /*----------------------------------------------------------------- CVSLS private functions for backwards problems @@ -2228,6 +2500,77 @@ static int cvLsJacTimesVecBSWrapper(N_Vector vB, N_Vector JvB, realtype t, } +/* cvLsLinSysBWrapper interfaces to the CVLsLinSysFnB routine provided + by the user. cvLsLinSysBWrapper is of type CVLsLinSysFn. */ +static int cvLsLinSysBWrapper(realtype t, N_Vector yB, N_Vector fyB, + SUNMatrix AB, booleantype jokB, + booleantype *jcurB, realtype gammaB, + void *cvode_mem, N_Vector tmp1B, N_Vector tmp2B, + N_Vector tmp3B) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemBCur(cvode_mem, "cvLsLinSysBWrapper", + &cv_mem, &ca_mem, &cvB_mem, &cvlsB_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Forward solution from interpolation */ + retval = ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, NULL); + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, -1, "CVSLS", "cvLsLinSysBWrapper", + MSG_LS_BAD_TINTERP); + return(-1); + } + + /* Call user's adjoint linsysB routine (of type CVLsLinSysFnB) */ + return(cvlsB_mem->linsysB(t, ca_mem->ca_ytmp, yB, fyB, AB, jokB, jcurB, + gammaB, cvB_mem->cv_user_data, tmp1B, tmp2B, + tmp3B)); +} + + +/* cvLsLinSysBSWrapper interfaces to the CVLsLinSysFnBS routine provided + by the user. cvLsLinSysBSWrapper is of type CVLsLinSysFn. */ +static int cvLsLinSysBSWrapper(realtype t, N_Vector yB, N_Vector fyB, + SUNMatrix AB, booleantype jokB, + booleantype *jcurB, realtype gammaB, + void *cvode_mem, N_Vector tmp1B, N_Vector tmp2B, + N_Vector tmp3B) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemBCur(cvode_mem, "cvLsLinSysBSWrapper", + &cv_mem, &ca_mem, &cvB_mem, &cvlsB_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Forward solution from interpolation */ + if (ca_mem->ca_IMinterpSensi) + retval = ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, ca_mem->ca_yStmp); + else + retval = ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, NULL); + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, -1, "CVSLS", "cvLsLinSysBSWrapper", + MSG_LS_BAD_TINTERP); + return(-1); + } + + /* Call user's adjoint dense djacBS routine (of type CVLsDenseJacFnBS) */ + return(cvlsB_mem->linsysBS(t, ca_mem->ca_ytmp, ca_mem->ca_yStmp, yB, fyB, + AB, jokB, jcurB, gammaB, cvB_mem->cv_user_data, + tmp1B, tmp2B, tmp3B)); +} + + /* cvLsFreeB frees memory associated with the CVSLS wrapper */ int cvLsFreeB(CVodeBMem cvB_mem) { diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_ls_impl.h b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_ls_impl.h index 14a92278b..18c5366d4 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_ls_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_ls_impl.h @@ -3,7 +3,7 @@ * Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -12,8 +12,7 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End *----------------------------------------------------------------- - * Implementation header file for the scaled, preconditioned - * linear solver interface. + * Implementation header file for CVODES' linear solver interface. *-----------------------------------------------------------------*/ #ifndef _CVSLS_IMPL_H @@ -26,6 +25,7 @@ extern "C" { #endif + /*----------------------------------------------------------------- CVSLS solver constants @@ -53,12 +53,19 @@ extern "C" { -----------------------------------------------------------------*/ typedef struct CVLsMemRec { + /* Linear solver type information */ + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ + /* Jacobian construction & storage */ booleantype jacDQ; /* SUNTRUE if using internal DQ Jac approx. */ CVLsJacFn jac; /* Jacobian routine to be called */ void *J_data; /* user data is passed to jac */ booleantype jbad; /* heuristic suggestion for pset */ + /* Matrix-based solver, scale solution to account for change in gamma */ + booleantype scalesol; + /* Iterative solver tolerance */ realtype sqrtN; /* sqrt(N) */ realtype eplifac; /* eplifac = user specified or EPLIN_DEFAULT */ @@ -109,7 +116,18 @@ typedef struct CVLsMemRec { CVLsJacTimesVecFn jtimes; void *jt_data; - long int last_flag; /* last error flag returned by any function */ + /* Linear system setup function + * (a) user-provided linsys function: + * - user_linsys = SUNTRUE + * - A_data = user_data + * (b) internal linsys function: + * - user_linsys = SUNFALSE + * - A_data = cvode_mem */ + booleantype user_linsys; + CVLsLinSysFn linsys; + void* A_data; + + int last_flag; /* last error flag returned by any function */ } *CVLsMem; @@ -169,6 +187,8 @@ typedef struct CVLsMemRecB { CVLsJacTimesSetupFnBS jtsetupBS; CVLsJacTimesVecFnB jtimesB; CVLsJacTimesVecFnBS jtimesBS; + CVLsLinSysFnB linsysB; + CVLsLinSysFnBS linsysBS; CVLsPrecSetupFnB psetB; CVLsPrecSetupFnBS psetBS; CVLsPrecSolveFnB psolveB; @@ -198,13 +218,13 @@ int cvLs_AccessLMemBCur(void *cvode_mem, const char *fname, #define MSG_LS_CVMEM_NULL "Integrator memory is NULL." #define MSG_LS_MEM_FAIL "A memory request failed." #define MSG_LS_BAD_NVECTOR "A required vector operation is not implemented." -#define MSG_LS_BAD_SIZES "Illegal bandwidth parameter(s). Must have 0 <= ml, mu <= N-1." #define MSG_LS_BAD_LSTYPE "Incompatible linear solver type." +#define MSG_LS_LMEM_NULL "Linear solver memory is NULL." +#define MSG_LS_BAD_SIZES "Illegal bandwidth parameter(s). Must have 0 <= ml, mu <= N-1." +#define MSG_LS_BAD_EPLIN "eplifac < 0 illegal." #define MSG_LS_BAD_PRETYPE "Illegal value for pretype. Legal values are PREC_NONE, PREC_LEFT, PREC_RIGHT, and PREC_BOTH." #define MSG_LS_PSOLVE_REQ "pretype != PREC_NONE, but PSOLVE = NULL is illegal." -#define MSG_LS_LMEM_NULL "Linear solver memory is NULL." #define MSG_LS_BAD_GSTYPE "Illegal value for gstype. Legal values are MODIFIED_GS and CLASSICAL_GS." -#define MSG_LS_BAD_EPLIN "eplifac < 0 illegal." #define MSG_LS_PSET_FAILED "The preconditioner setup routine failed in an unrecoverable manner." #define MSG_LS_PSOLVE_FAILED "The preconditioner solve routine failed in an unrecoverable manner." diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls.c index 627553065..257c91832 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -16,6 +16,7 @@ #include "cvodes_impl.h" #include "sundials/sundials_math.h" +#include "sundials/sundials_nvector_senswrapper.h" /* constant macros */ #define ONE RCONST(1.0) @@ -24,9 +25,8 @@ static int cvNlsResidual(N_Vector ycor, N_Vector res, void* cvode_mem); static int cvNlsFPFunction(N_Vector ycor, N_Vector res, void* cvode_mem); -static int cvNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, - booleantype* jcur, void* cvode_mem); -static int cvNlsLSolve(N_Vector ycor, N_Vector delta, void* cvode_mem); +static int cvNlsLSetup(booleantype jbad, booleantype* jcur, void* cvode_mem); +static int cvNlsLSolve(N_Vector delta, void* cvode_mem); static int cvNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, realtype tol, N_Vector ewt, void* cvode_mem); @@ -55,9 +55,7 @@ int CVodeSetNonlinearSolver(void *cvode_mem, SUNNonlinearSolver NLS) /* check for required nonlinear solver functions */ if ( NLS->ops->gettype == NULL || - NLS->ops->initialize == NULL || NLS->ops->solve == NULL || - NLS->ops->free == NULL || NLS->ops->setsysfn == NULL ) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolver", "NLS does not support required operations"); @@ -93,7 +91,7 @@ int CVodeSetNonlinearSolver(void *cvode_mem, SUNNonlinearSolver NLS) } /* set convergence test function */ - retval = SUNNonlinSolSetConvTestFn(cv_mem->NLS, cvNlsConvTest); + retval = SUNNonlinSolSetConvTestFn(cv_mem->NLS, cvNlsConvTest, cvode_mem); if (retval != CV_SUCCESS) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolver", "Setting convergence test function failed"); @@ -108,6 +106,9 @@ int CVodeSetNonlinearSolver(void *cvode_mem, SUNNonlinearSolver NLS) return(CV_ILL_INPUT); } + /* Reset the acnrmcur flag to SUNFALSE */ + cv_mem->cv_acnrmcur = SUNFALSE; + return(CV_SUCCESS); } @@ -158,8 +159,7 @@ int cvNlsInit(CVodeMem cvode_mem) } -static int cvNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, - booleantype* jcur, void* cvode_mem) +static int cvNlsLSetup(booleantype jbad, booleantype* jcur, void* cvode_mem) { CVodeMem cv_mem; int retval; @@ -197,7 +197,7 @@ static int cvNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, } -static int cvNlsLSolve(N_Vector ycor, N_Vector delta, void* cvode_mem) +static int cvNlsLSolve(N_Vector delta, void* cvode_mem) { CVodeMem cv_mem; int retval; @@ -247,6 +247,7 @@ static int cvNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector delta, if (dcon <= ONE) { cv_mem->cv_acnrm = (m==0) ? del : N_VWrmsNorm(ycor, cv_mem->cv_ewt); + cv_mem->cv_acnrmcur = SUNTRUE; return(CV_SUCCESS); /* Nonlinear system was solved successfully */ } diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls_sim.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls_sim.c index 54437f947..9ca13824c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls_sim.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls_sim.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -36,11 +36,9 @@ static int cvNlsResidualSensSim(N_Vector ycorSim, N_Vector resSim, static int cvNlsFPFunctionSensSim(N_Vector ycorSim, N_Vector resSim, void* cvode_mem); -static int cvNlsLSetupSensSim(N_Vector ycorSim, N_Vector resSim, - booleantype jbad, booleantype* jcur, - void* cvode_mem); -static int cvNlsLSolveSensSim(N_Vector ycorSim, N_Vector deltaSim, +static int cvNlsLSetupSensSim(booleantype jbad, booleantype* jcur, void* cvode_mem); +static int cvNlsLSolveSensSim(N_Vector deltaSim, void* cvode_mem); static int cvNlsConvTestSensSim(SUNNonlinearSolver NLS, N_Vector ycorSim, N_Vector delSim, realtype tol, N_Vector ewtSim, void* cvode_mem); @@ -72,9 +70,7 @@ int CVodeSetNonlinearSolverSensSim(void *cvode_mem, SUNNonlinearSolver NLS) /* check for required nonlinear solver functions */ if ( NLS->ops->gettype == NULL || - NLS->ops->initialize == NULL || NLS->ops->solve == NULL || - NLS->ops->free == NULL || NLS->ops->setsysfn == NULL ) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolverSensSim", @@ -129,7 +125,8 @@ int CVodeSetNonlinearSolverSensSim(void *cvode_mem, SUNNonlinearSolver NLS) } /* set convergence test function */ - retval = SUNNonlinSolSetConvTestFn(cv_mem->NLSsim, cvNlsConvTestSensSim); + retval = SUNNonlinSolSetConvTestFn(cv_mem->NLSsim, cvNlsConvTestSensSim, + cvode_mem); if (retval != CV_SUCCESS) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolverSensSim", @@ -149,8 +146,8 @@ int CVodeSetNonlinearSolverSensSim(void *cvode_mem, SUNNonlinearSolver NLS) /* create vector wrappers if necessary */ if (cv_mem->simMallocDone == SUNFALSE) { - cv_mem->ycor0Sim = N_VNewEmpty_SensWrapper(cv_mem->cv_Ns+1); - if (cv_mem->ycor0Sim == NULL) { + cv_mem->zn0Sim = N_VNewEmpty_SensWrapper(cv_mem->cv_Ns+1); + if (cv_mem->zn0Sim == NULL) { cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSetNonlinearSolverSensSim", MSGCV_MEM_FAIL); return(CV_MEM_FAIL); @@ -158,7 +155,7 @@ int CVodeSetNonlinearSolverSensSim(void *cvode_mem, SUNNonlinearSolver NLS) cv_mem->ycorSim = N_VNewEmpty_SensWrapper(cv_mem->cv_Ns+1); if (cv_mem->ycorSim == NULL) { - N_VDestroy(cv_mem->ycor0Sim); + N_VDestroy(cv_mem->zn0Sim); cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSetNonlinearSolverSensSim", MSGCV_MEM_FAIL); return(CV_MEM_FAIL); @@ -166,7 +163,7 @@ int CVodeSetNonlinearSolverSensSim(void *cvode_mem, SUNNonlinearSolver NLS) cv_mem->ewtSim = N_VNewEmpty_SensWrapper(cv_mem->cv_Ns+1); if (cv_mem->ewtSim == NULL) { - N_VDestroy(cv_mem->ycor0Sim); + N_VDestroy(cv_mem->zn0Sim); N_VDestroy(cv_mem->ycorSim); cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSetNonlinearSolverSensSim", MSGCV_MEM_FAIL); @@ -177,16 +174,19 @@ int CVodeSetNonlinearSolverSensSim(void *cvode_mem, SUNNonlinearSolver NLS) } /* attach vectors to vector wrappers */ - NV_VEC_SW(cv_mem->ycor0Sim, 0) = cv_mem->cv_tempv; - NV_VEC_SW(cv_mem->ycorSim, 0) = cv_mem->cv_acor; - NV_VEC_SW(cv_mem->ewtSim, 0) = cv_mem->cv_ewt; + NV_VEC_SW(cv_mem->zn0Sim, 0) = cv_mem->cv_zn[0]; + NV_VEC_SW(cv_mem->ycorSim, 0) = cv_mem->cv_acor; + NV_VEC_SW(cv_mem->ewtSim, 0) = cv_mem->cv_ewt; for (is=0; is < cv_mem->cv_Ns; is++) { - NV_VEC_SW(cv_mem->ycor0Sim, is+1) = cv_mem->cv_tempvS[is]; - NV_VEC_SW(cv_mem->ycorSim, is+1) = cv_mem->cv_acorS[is]; - NV_VEC_SW(cv_mem->ewtSim, is+1) = cv_mem->cv_ewtS[is]; + NV_VEC_SW(cv_mem->zn0Sim, is+1) = cv_mem->cv_znS[0][is]; + NV_VEC_SW(cv_mem->ycorSim, is+1) = cv_mem->cv_acorS[is]; + NV_VEC_SW(cv_mem->ewtSim, is+1) = cv_mem->cv_ewtS[is]; } + /* Reset the acnrmcur flag to SUNFALSE */ + cv_mem->cv_acnrmcur = SUNFALSE; + return(CV_SUCCESS); } @@ -237,8 +237,7 @@ int cvNlsInitSensSim(CVodeMem cvode_mem) } -static int cvNlsLSetupSensSim(N_Vector ycorSim, N_Vector resSim, - booleantype jbad, booleantype* jcur, +static int cvNlsLSetupSensSim(booleantype jbad, booleantype* jcur, void* cvode_mem) { CVodeMem cv_mem; @@ -279,7 +278,7 @@ static int cvNlsLSetupSensSim(N_Vector ycorSim, N_Vector resSim, } -static int cvNlsLSolveSensSim(N_Vector ycorSim, N_Vector deltaSim, void* cvode_mem) +static int cvNlsLSolveSensSim(N_Vector deltaSim, void* cvode_mem) { CVodeMem cv_mem; int retval, is; @@ -380,6 +379,7 @@ static int cvNlsConvTestSensSim(SUNNonlinearSolver NLS, cv_mem->cv_acnrm = (cv_mem->cv_errconS) ? N_VWrmsNorm(ycorSim, ewtSim) : N_VWrmsNorm(ycor, ewt); } + cv_mem->cv_acnrmcur = SUNTRUE; return(CV_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls_stg.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls_stg.c index 8df403040..45bc3bfb2 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls_stg.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls_stg.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -27,11 +27,9 @@ static int cvNlsResidualSensStg(N_Vector ycorStg, N_Vector resStg, static int cvNlsFPFunctionSensStg(N_Vector ycorStg, N_Vector resStg, void* cvode_mem); -static int cvNlsLSetupSensStg(N_Vector ycorStg, N_Vector resStg, - booleantype jbad, booleantype* jcur, - void* cvode_mem); -static int cvNlsLSolveSensStg(N_Vector ycorStg, N_Vector deltaStg, +static int cvNlsLSetupSensStg(booleantype jbad, booleantype* jcur, void* cvode_mem); +static int cvNlsLSolveSensStg(N_Vector deltaStg, void* cvode_mem); static int cvNlsConvTestSensStg(SUNNonlinearSolver NLS, N_Vector ycorStg, N_Vector delStg, realtype tol, N_Vector ewtStg, void* cvode_mem); @@ -63,9 +61,7 @@ int CVodeSetNonlinearSolverSensStg(void *cvode_mem, SUNNonlinearSolver NLS) /* check for required nonlinear solver functions */ if ( NLS->ops->gettype == NULL || - NLS->ops->initialize == NULL || NLS->ops->solve == NULL || - NLS->ops->free == NULL || NLS->ops->setsysfn == NULL ) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolverSensStg", @@ -120,7 +116,8 @@ int CVodeSetNonlinearSolverSensStg(void *cvode_mem, SUNNonlinearSolver NLS) } /* set convergence test function */ - retval = SUNNonlinSolSetConvTestFn(cv_mem->NLSstg, cvNlsConvTestSensStg); + retval = SUNNonlinSolSetConvTestFn(cv_mem->NLSstg, cvNlsConvTestSensStg, + cvode_mem); if (retval != CV_SUCCESS) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolverSensStg", @@ -140,8 +137,8 @@ int CVodeSetNonlinearSolverSensStg(void *cvode_mem, SUNNonlinearSolver NLS) /* create vector wrappers if necessary */ if (cv_mem->stgMallocDone == SUNFALSE) { - cv_mem->ycor0Stg = N_VNewEmpty_SensWrapper(cv_mem->cv_Ns); - if (cv_mem->ycor0Stg == NULL) { + cv_mem->zn0Stg = N_VNewEmpty_SensWrapper(cv_mem->cv_Ns); + if (cv_mem->zn0Stg == NULL) { cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSetNonlinearSolverSensStg", MSGCV_MEM_FAIL); return(CV_MEM_FAIL); @@ -149,7 +146,7 @@ int CVodeSetNonlinearSolverSensStg(void *cvode_mem, SUNNonlinearSolver NLS) cv_mem->ycorStg = N_VNewEmpty_SensWrapper(cv_mem->cv_Ns); if (cv_mem->ycorStg == NULL) { - N_VDestroy(cv_mem->ycor0Stg); + N_VDestroy(cv_mem->zn0Stg); cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSetNonlinearSolverSensStg", MSGCV_MEM_FAIL); return(CV_MEM_FAIL); @@ -157,7 +154,7 @@ int CVodeSetNonlinearSolverSensStg(void *cvode_mem, SUNNonlinearSolver NLS) cv_mem->ewtStg = N_VNewEmpty_SensWrapper(cv_mem->cv_Ns); if (cv_mem->ewtStg == NULL) { - N_VDestroy(cv_mem->ycor0Stg); + N_VDestroy(cv_mem->zn0Stg); N_VDestroy(cv_mem->ycorStg); cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSetNonlinearSolverSensStg", MSGCV_MEM_FAIL); @@ -169,11 +166,14 @@ int CVodeSetNonlinearSolverSensStg(void *cvode_mem, SUNNonlinearSolver NLS) /* attach vectors to vector wrappers */ for (is=0; is < cv_mem->cv_Ns; is++) { - NV_VEC_SW(cv_mem->ycor0Stg, is) = cv_mem->cv_tempvS[is]; - NV_VEC_SW(cv_mem->ycorStg, is) = cv_mem->cv_acorS[is]; - NV_VEC_SW(cv_mem->ewtStg, is) = cv_mem->cv_ewtS[is]; + NV_VEC_SW(cv_mem->zn0Stg, is) = cv_mem->cv_znS[0][is]; + NV_VEC_SW(cv_mem->ycorStg, is) = cv_mem->cv_acorS[is]; + NV_VEC_SW(cv_mem->ewtStg, is) = cv_mem->cv_ewtS[is]; } + /* Reset the acnrmScur flag to SUNFALSE */ + cv_mem->cv_acnrmScur = SUNFALSE; + return(CV_SUCCESS); } @@ -224,8 +224,7 @@ int cvNlsInitSensStg(CVodeMem cvode_mem) } -static int cvNlsLSetupSensStg(N_Vector ycorStg, N_Vector resStg, - booleantype jbad, booleantype* jcur, +static int cvNlsLSetupSensStg(booleantype jbad, booleantype* jcur, void* cvode_mem) { CVodeMem cv_mem; @@ -266,7 +265,7 @@ static int cvNlsLSetupSensStg(N_Vector ycorStg, N_Vector resStg, } -static int cvNlsLSolveSensStg(N_Vector ycorStg, N_Vector deltaStg, void* cvode_mem) +static int cvNlsLSolveSensStg(N_Vector deltaStg, void* cvode_mem) { CVodeMem cv_mem; int retval, is; @@ -343,8 +342,10 @@ static int cvNlsConvTestSensStg(SUNNonlinearSolver NLS, /* check if nonlinear system was solved successfully */ if (dcon <= ONE) { - if (cv_mem->cv_errconS) + if (cv_mem->cv_errconS) { cv_mem->cv_acnrmS = (m==0) ? Del : cvSensNorm(cv_mem, ycorS, ewtS); + cv_mem->cv_acnrmScur = SUNTRUE; + } return(CV_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls_stg1.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls_stg1.c index aeed096d5..ed6d87ddf 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls_stg1.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_nls_stg1.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -26,11 +26,9 @@ static int cvNlsResidualSensStg1(N_Vector ycor, N_Vector res, static int cvNlsFPFunctionSensStg1(N_Vector ycor, N_Vector res, void* cvode_mem); -static int cvNlsLSetupSensStg1(N_Vector ycor, N_Vector res, - booleantype jbad, booleantype* jcur, - void* cvode_mem); -static int cvNlsLSolveSensStg1(N_Vector ycor, N_Vector delta, +static int cvNlsLSetupSensStg1(booleantype jbad, booleantype* jcur, void* cvode_mem); +static int cvNlsLSolveSensStg1(N_Vector delta, void* cvode_mem); static int cvNlsConvTestSensStg1(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, realtype tol, N_Vector ewt, void* cvode_mem); @@ -62,9 +60,7 @@ int CVodeSetNonlinearSolverSensStg1(void *cvode_mem, SUNNonlinearSolver NLS) /* check for required nonlinear solver functions */ if ( NLS->ops->gettype == NULL || - NLS->ops->initialize == NULL || NLS->ops->solve == NULL || - NLS->ops->free == NULL || NLS->ops->setsysfn == NULL ) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolverSensStg1", @@ -119,7 +115,8 @@ int CVodeSetNonlinearSolverSensStg1(void *cvode_mem, SUNNonlinearSolver NLS) } /* set convergence test function */ - retval = SUNNonlinSolSetConvTestFn(cv_mem->NLSstg1, cvNlsConvTestSensStg1); + retval = SUNNonlinSolSetConvTestFn(cv_mem->NLSstg1, cvNlsConvTestSensStg1, + cvode_mem); if (retval != CV_SUCCESS) { cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolverSensStg1", @@ -136,6 +133,9 @@ int CVodeSetNonlinearSolverSensStg1(void *cvode_mem, SUNNonlinearSolver NLS) return(CV_ILL_INPUT); } + /* Reset the acnrmScur flag to SUNFALSE (always false for stg1) */ + cv_mem->cv_acnrmScur = SUNFALSE; + return(CV_SUCCESS); } @@ -174,7 +174,7 @@ int cvNlsInitSensStg1(CVodeMem cvode_mem) } /* initialize nonlinear solver */ - retval = SUNNonlinSolInitialize(cvode_mem->NLSstg1); + retval = SUNNonlinSolInitialize(cvode_mem->NLSstg1); if (retval != CV_SUCCESS) { cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODES", "cvNlsInitSensStg1", @@ -189,8 +189,7 @@ int cvNlsInitSensStg1(CVodeMem cvode_mem) } -static int cvNlsLSetupSensStg1(N_Vector ycor, N_Vector res, - booleantype jbad, booleantype* jcur, +static int cvNlsLSetupSensStg1(booleantype jbad, booleantype* jcur, void* cvode_mem) { CVodeMem cv_mem; @@ -231,7 +230,7 @@ static int cvNlsLSetupSensStg1(N_Vector ycor, N_Vector res, } -static int cvNlsLSolveSensStg1(N_Vector ycor, N_Vector delta, void* cvode_mem) +static int cvNlsLSolveSensStg1(N_Vector delta, void* cvode_mem) { CVodeMem cv_mem; int retval, is; diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_spils.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_spils.c index 0ce3a9a59..02a4e5291 100644 --- a/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_spils.c +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/cvodes_spils.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/fmod/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/cvodes/fmod/CMakeLists.txt new file mode 100644 index 000000000..8eefbb293 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/fmod/CMakeLists.txt @@ -0,0 +1,99 @@ +# --------------------------------------------------------------- +# Programmer: Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the F2003 cvodes object library + +set(cvodes_SOURCES fcvodes_mod.f90 fcvodes_mod.c) + +if(BUILD_STATIC_LIBS) + sundials_add_f2003_interface_library(sundials_fcvodes_mod_static STATIC + ${cvodes_SOURCES} + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + + # include the directoy where the .mod files reside + target_include_directories(sundials_fcvodes_mod_static + PUBLIC + $ + $ + ) + + # Set the library name and make sure it is not deleted + set_target_properties(sundials_fcvodes_mod_static + PROPERTIES OUTPUT_NAME sundials_fcvodes_mod CLEAN_DIRECT_OUTPUT 1) + + # install the library + install(TARGETS sundials_fcvodes_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # install the cvodes mod file from here since it won't go into the + # top level fortran mod file directory + install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_STATIC/fcvodes_mod.mod + DESTINATION ${Fortran_INSTALL_MODDIR}) +endif() + +if(BUILD_SHARED_LIBS) + sundials_add_f2003_interface_library(sundials_fcvodes_mod_shared SHARED + ${cvodes_SOURCES} + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + + # include the directoy where the .mod files reside + target_include_directories(sundials_fcvodes_mod_shared + PUBLIC + $ + $ + ) + + # Set the library name and make sure it is not deleted + set_target_properties(sundials_fcvodes_mod_shared PROPERTIES + OUTPUT_NAME sundials_fcvodes_mod + CLEAN_DIRECT_OUTPUT 1 + VERSION ${cvodeslib_VERSION} + SOVERSION ${cvodeslib_SOVERSION}) + + # install the library + install(TARGETS sundials_fcvodes_mod_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # install the cvodes mod file from here since it won't go into the + # top level fortran mod file directory + install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_SHARED/fcvodes_mod.mod + DESTINATION ${Fortran_INSTALL_MODDIR}) +endif() + +message(STATUS "Added CVODES F2003 interface") diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/fmod/fcvodes_mod.c b/deps/AMICI/ThirdParty/sundials/src/cvodes/fmod/fcvodes_mod.c new file mode 100644 index 000000000..bd1db84da --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/fmod/fcvodes_mod.c @@ -0,0 +1,3494 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +enum { + SWIG_MEM_OWN = 0x01, + SWIG_MEM_RVALUE = 0x02, + SWIG_MEM_CONST = 0x04 +}; + + +#define SWIG_check_mutable(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL) \ + if ((SWIG_CLASS_WRAPPER).cmemflags & SWIG_MEM_CONST) { \ + SWIG_exception_impl(FUNCNAME, SWIG_TypeError, \ + "Cannot pass const " TYPENAME " (class " FNAME ") " \ + "as a mutable reference", \ + RETURNNULL); \ + } + + +#define SWIG_check_nonnull(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL) \ + if (!(SWIG_CLASS_WRAPPER).cptr) { \ + SWIG_exception_impl(FUNCNAME, SWIG_TypeError, \ + "Cannot pass null " TYPENAME " (class " FNAME ") " \ + "as a reference", RETURNNULL); \ + } + + +#define SWIG_check_mutable_nonnull(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL) \ + SWIG_check_nonnull(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL); \ + SWIG_check_mutable(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL); + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "cvodes/cvodes.h" +#include "cvodes/cvodes_bandpre.h" +#include "cvodes/cvodes_bbdpre.h" +#include "cvodes/cvodes_diag.h" +#include "cvodes/cvodes_ls.h" + + +#include +#ifdef _MSC_VER +# ifndef strtoull +# define strtoull _strtoui64 +# endif +# ifndef strtoll +# define strtoll _strtoi64 +# endif +#endif + + +typedef struct { + void* data; + size_t size; +} SwigArrayWrapper; + + +SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() { + SwigArrayWrapper result; + result.data = NULL; + result.size = 0; + return result; +} + + +#include + + +typedef struct { + void* cptr; + int cmemflags; +} SwigClassWrapper; + + +SWIGINTERN SwigClassWrapper SwigClassWrapper_uninitialized() { + SwigClassWrapper result; + result.cptr = NULL; + result.cmemflags = 0; + return result; +} + + +SWIGINTERN void SWIG_assign(SwigClassWrapper* self, SwigClassWrapper other) { + if (self->cptr == NULL) { + /* LHS is unassigned */ + if (other.cmemflags & SWIG_MEM_RVALUE) { + /* Capture pointer from RHS, clear 'moving' flag */ + self->cptr = other.cptr; + self->cmemflags = other.cmemflags & (~SWIG_MEM_RVALUE); + } else { + /* Become a reference to the other object */ + self->cptr = other.cptr; + self->cmemflags = other.cmemflags & (~SWIG_MEM_OWN); + } + } else if (other.cptr == NULL) { + /* Replace LHS with a null pointer */ + free(self->cptr); + *self = SwigClassWrapper_uninitialized(); + } else { + if (self->cmemflags & SWIG_MEM_OWN) { + free(self->cptr); + } + self->cptr = other.cptr; + if (other.cmemflags & SWIG_MEM_RVALUE) { + /* Capture RHS */ + self->cmemflags = other.cmemflags & ~SWIG_MEM_RVALUE; + } else { + /* Point to RHS */ + self->cmemflags = other.cmemflags & ~SWIG_MEM_OWN; + } + } +} + +SWIGEXPORT void * _wrap_FCVodeCreate(int const *farg1) { + void * fresult ; + int arg1 ; + void *result = 0 ; + + arg1 = (int)(*farg1); + result = (void *)CVodeCreate(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeInit(void *farg1, CVRhsFn farg2, double const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + CVRhsFn arg2 = (CVRhsFn) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVRhsFn)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeReInit(void *farg1, double const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)CVodeReInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSStolerances(void *farg1, double const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)CVodeSStolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSVtolerances(void *farg1, double const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)CVodeSVtolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeWFtolerances(void *farg1, CVEwtFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + CVEwtFn arg2 = (CVEwtFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVEwtFn)(farg2); + result = (int)CVodeWFtolerances(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetErrHandlerFn(void *farg1, CVErrHandlerFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + CVErrHandlerFn arg2 = (CVErrHandlerFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVErrHandlerFn)(farg2); + arg3 = (void *)(farg3); + result = (int)CVodeSetErrHandlerFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetErrFile(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)CVodeSetErrFile(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetUserData(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + void *arg2 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (void *)(farg2); + result = (int)CVodeSetUserData(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxOrd(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetMaxOrd(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxNumSteps(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)CVodeSetMaxNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxHnilWarns(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetMaxHnilWarns(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetStabLimDet(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetStabLimDet(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetInitStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)CVodeSetInitStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMinStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)CVodeSetMinStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)CVodeSetMaxStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetStopTime(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)CVodeSetStopTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxErrTestFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetMaxErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxNonlinIters(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetMaxNonlinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxConvFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetMaxConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetNonlinConvCoef(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)CVodeSetNonlinConvCoef(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetConstraints(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)CVodeSetConstraints(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetNonlinearSolver(void *farg1, SUNNonlinearSolver farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNNonlinearSolver arg2 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNNonlinearSolver)(farg2); + result = (int)CVodeSetNonlinearSolver(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeRootInit(void *farg1, int const *farg2, CVRootFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVRootFn arg3 = (CVRootFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVRootFn)(farg3); + result = (int)CVodeRootInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetRootDirection(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)CVodeSetRootDirection(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetNoInactiveRootWarn(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)CVodeSetNoInactiveRootWarn(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVode(void *farg1, double const *farg2, N_Vector farg3, double *farg4, int const *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype *arg4 = (realtype *) 0 ; + int arg5 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + arg4 = (realtype *)(farg4); + arg5 = (int)(*farg5); + result = (int)CVode(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetDky(void *farg1, double const *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeGetDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVodeGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumSteps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumLinSolvSetups(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumLinSolvSetups(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumErrTestFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetLastOrder(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)CVodeGetLastOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetCurrentOrder(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)CVodeGetCurrentOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetCurrentGamma(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)CVodeGetCurrentGamma(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumStabLimOrderReds(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumStabLimOrderReds(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetActualInitStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)CVodeGetActualInitStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetLastStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)CVodeGetLastStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetCurrentStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)CVodeGetCurrentStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetCurrentState(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)CVodeGetCurrentState(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetCurrentStateSens(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector **arg2 = (N_Vector **) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector **)(farg2); + result = (int)CVodeGetCurrentStateSens(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetCurrentSensSolveIndex(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)CVodeGetCurrentSensSolveIndex(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetCurrentTime(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)CVodeGetCurrentTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetTolScaleFactor(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)CVodeGetTolScaleFactor(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetErrWeights(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)CVodeGetErrWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetEstLocalErrors(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)CVodeGetEstLocalErrors(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumGEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumGEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetRootInfo(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)CVodeGetRootInfo(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetIntegratorStats(void *farg1, long *farg2, long *farg3, long *farg4, long *farg5, int *farg6, int *farg7, double *farg8, double *farg9, double *farg10, double *farg11) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + long *arg4 = (long *) 0 ; + long *arg5 = (long *) 0 ; + int *arg6 = (int *) 0 ; + int *arg7 = (int *) 0 ; + realtype *arg8 = (realtype *) 0 ; + realtype *arg9 = (realtype *) 0 ; + realtype *arg10 = (realtype *) 0 ; + realtype *arg11 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + arg4 = (long *)(farg4); + arg5 = (long *)(farg5); + arg6 = (int *)(farg6); + arg7 = (int *)(farg7); + arg8 = (realtype *)(farg8); + arg9 = (realtype *)(farg9); + arg10 = (realtype *)(farg10); + arg11 = (realtype *)(farg11); + result = (int)CVodeGetIntegratorStats(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumNonlinSolvIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumNonlinSolvIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumNonlinSolvConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumNonlinSolvConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNonlinSolvStats(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVodeGetNonlinSolvStats(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FCVodeGetReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)CVodeGetReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FCVodeFree(void *farg1) { + void **arg1 = (void **) 0 ; + + arg1 = (void **)(farg1); + CVodeFree(arg1); +} + + +SWIGEXPORT int _wrap_FCVodeQuadInit(void *farg1, CVQuadRhsFn farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + CVQuadRhsFn arg2 = (CVQuadRhsFn) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVQuadRhsFn)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)CVodeQuadInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeQuadReInit(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)CVodeQuadReInit(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeQuadSStolerances(void *farg1, double const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)CVodeQuadSStolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeQuadSVtolerances(void *farg1, double const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)CVodeQuadSVtolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetQuadErrCon(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetQuadErrCon(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuad(void *farg1, double *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)CVodeGetQuad(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadDky(void *farg1, double const *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeGetQuadDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetQuadNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadNumErrTestFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetQuadNumErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadErrWeights(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)CVodeGetQuadErrWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadStats(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVodeGetQuadStats(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FCVodeQuadFree(void *farg1) { + void *arg1 = (void *) 0 ; + + arg1 = (void *)(farg1); + CVodeQuadFree(arg1); +} + + +SWIGEXPORT int _wrap_FCVodeSensInit(void *farg1, int const *farg2, int const *farg3, CVSensRhsFn farg4, void *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + CVSensRhsFn arg4 = (CVSensRhsFn) 0 ; + N_Vector *arg5 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + arg4 = (CVSensRhsFn)(farg4); + arg5 = (N_Vector *)(farg5); + result = (int)CVodeSensInit(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSensInit1(void *farg1, int const *farg2, int const *farg3, CVSensRhs1Fn farg4, void *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + CVSensRhs1Fn arg4 = (CVSensRhs1Fn) 0 ; + N_Vector *arg5 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + arg4 = (CVSensRhs1Fn)(farg4); + arg5 = (N_Vector *)(farg5); + result = (int)CVodeSensInit1(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSensReInit(void *farg1, int const *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (int)CVodeSensReInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSensSStolerances(void *farg1, double const *farg2, double *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype *arg3 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype *)(farg3); + result = (int)CVodeSensSStolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSensSVtolerances(void *farg1, double const *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (int)CVodeSensSVtolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSensEEtolerances(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)CVodeSensEEtolerances(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetSensDQMethod(void *farg1, int const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)CVodeSetSensDQMethod(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetSensErrCon(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetSensErrCon(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetSensMaxNonlinIters(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetSensMaxNonlinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetSensParams(void *farg1, double *farg2, double *farg3, int *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + realtype *arg3 = (realtype *) 0 ; + int *arg4 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + arg3 = (realtype *)(farg3); + arg4 = (int *)(farg4); + result = (int)CVodeSetSensParams(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetNonlinearSolverSensSim(void *farg1, SUNNonlinearSolver farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNNonlinearSolver arg2 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNNonlinearSolver)(farg2); + result = (int)CVodeSetNonlinearSolverSensSim(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetNonlinearSolverSensStg(void *farg1, SUNNonlinearSolver farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNNonlinearSolver arg2 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNNonlinearSolver)(farg2); + result = (int)CVodeSetNonlinearSolverSensStg(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetNonlinearSolverSensStg1(void *farg1, SUNNonlinearSolver farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNNonlinearSolver arg2 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNNonlinearSolver)(farg2); + result = (int)CVodeSetNonlinearSolverSensStg1(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSensToggleOff(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)CVodeSensToggleOff(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetSens(void *farg1, double *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + result = (int)CVodeGetSens(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetSens1(void *farg1, double *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeGetSens1(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetSensDky(void *farg1, double const *farg2, int const *farg3, void *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector *arg4 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector *)(farg4); + result = (int)CVodeGetSensDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetSensDky1(void *farg1, double const *farg2, int const *farg3, int const *farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + int arg4 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (int)(*farg4); + arg5 = (N_Vector)(farg5); + result = (int)CVodeGetSensDky1(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetSensNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetSensNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumRhsEvalsSens(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumRhsEvalsSens(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetSensNumErrTestFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetSensNumErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetSensNumLinSolvSetups(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetSensNumLinSolvSetups(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetSensErrWeights(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)CVodeGetSensErrWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetSensStats(void *farg1, long *farg2, long *farg3, long *farg4, long *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + long *arg4 = (long *) 0 ; + long *arg5 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + arg4 = (long *)(farg4); + arg5 = (long *)(farg5); + result = (int)CVodeGetSensStats(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetSensNumNonlinSolvIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetSensNumNonlinSolvIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetSensNumNonlinSolvConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetSensNumNonlinSolvConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetStgrSensNumNonlinSolvIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetStgrSensNumNonlinSolvIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetStgrSensNumNonlinSolvConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetStgrSensNumNonlinSolvConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetSensNonlinSolvStats(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVodeGetSensNonlinSolvStats(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FCVodeSensFree(void *farg1) { + void *arg1 = (void *) 0 ; + + arg1 = (void *)(farg1); + CVodeSensFree(arg1); +} + + +SWIGEXPORT int _wrap_FCVodeQuadSensInit(void *farg1, CVQuadSensRhsFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + CVQuadSensRhsFn arg2 = (CVQuadSensRhsFn) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVQuadSensRhsFn)(farg2); + arg3 = (N_Vector *)(farg3); + result = (int)CVodeQuadSensInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeQuadSensReInit(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)CVodeQuadSensReInit(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeQuadSensSStolerances(void *farg1, double const *farg2, double *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype *arg3 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype *)(farg3); + result = (int)CVodeQuadSensSStolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeQuadSensSVtolerances(void *farg1, double const *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (int)CVodeQuadSensSVtolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeQuadSensEEtolerances(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)CVodeQuadSensEEtolerances(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetQuadSensErrCon(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetQuadSensErrCon(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadSens(void *farg1, double *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + result = (int)CVodeGetQuadSens(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadSens1(void *farg1, double *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeGetQuadSens1(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadSensDky(void *farg1, double const *farg2, int const *farg3, void *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector *arg4 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector *)(farg4); + result = (int)CVodeGetQuadSensDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadSensDky1(void *farg1, double const *farg2, int const *farg3, int const *farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + int arg4 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (int)(*farg4); + arg5 = (N_Vector)(farg5); + result = (int)CVodeGetQuadSensDky1(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadSensNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetQuadSensNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadSensNumErrTestFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetQuadSensNumErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadSensErrWeights(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)CVodeGetQuadSensErrWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadSensStats(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVodeGetQuadSensStats(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FCVodeQuadSensFree(void *farg1) { + void *arg1 = (void *) 0 ; + + arg1 = (void *)(farg1); + CVodeQuadSensFree(arg1); +} + + +SWIGEXPORT int _wrap_FCVodeAdjInit(void *farg1, long const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + arg3 = (int)(*farg3); + result = (int)CVodeAdjInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeAdjReInit(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)CVodeAdjReInit(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FCVodeAdjFree(void *farg1) { + void *arg1 = (void *) 0 ; + + arg1 = (void *)(farg1); + CVodeAdjFree(arg1); +} + + +SWIGEXPORT int _wrap_FCVodeCreateB(void *farg1, int const *farg2, int *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int *arg3 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int *)(farg3); + result = (int)CVodeCreateB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeInitB(void *farg1, int const *farg2, CVRhsFnB farg3, double const *farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVRhsFnB arg3 = (CVRhsFnB) 0 ; + realtype arg4 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVRhsFnB)(farg3); + arg4 = (realtype)(*farg4); + arg5 = (N_Vector)(farg5); + result = (int)CVodeInitB(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeInitBS(void *farg1, int const *farg2, CVRhsFnBS farg3, double const *farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVRhsFnBS arg3 = (CVRhsFnBS) 0 ; + realtype arg4 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVRhsFnBS)(farg3); + arg4 = (realtype)(*farg4); + arg5 = (N_Vector)(farg5); + result = (int)CVodeInitBS(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeReInitB(void *farg1, int const *farg2, double const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeReInitB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSStolerancesB(void *farg1, int const *farg2, double const *farg3, double const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + realtype arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + arg4 = (realtype)(*farg4); + result = (int)CVodeSStolerancesB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSVtolerancesB(void *farg1, int const *farg2, double const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeSVtolerancesB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeQuadInitB(void *farg1, int const *farg2, CVQuadRhsFnB farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVQuadRhsFnB arg3 = (CVQuadRhsFnB) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVQuadRhsFnB)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeQuadInitB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeQuadInitBS(void *farg1, int const *farg2, CVQuadRhsFnBS farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVQuadRhsFnBS arg3 = (CVQuadRhsFnBS) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVQuadRhsFnBS)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeQuadInitBS(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeQuadReInitB(void *farg1, int const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)CVodeQuadReInitB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeQuadSStolerancesB(void *farg1, int const *farg2, double const *farg3, double const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + realtype arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + arg4 = (realtype)(*farg4); + result = (int)CVodeQuadSStolerancesB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeQuadSVtolerancesB(void *farg1, int const *farg2, double const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeQuadSVtolerancesB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeF(void *farg1, double const *farg2, N_Vector farg3, double *farg4, int const *farg5, int *farg6) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype *arg4 = (realtype *) 0 ; + int arg5 ; + int *arg6 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + arg4 = (realtype *)(farg4); + arg5 = (int)(*farg5); + arg6 = (int *)(farg6); + result = (int)CVodeF(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeB(void *farg1, double const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + result = (int)CVodeB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetAdjNoSensi(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)CVodeSetAdjNoSensi(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetUserDataB(void *farg1, int const *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (void *)(farg3); + result = (int)CVodeSetUserDataB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxOrdB(void *farg1, int const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (int)CVodeSetMaxOrdB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxNumStepsB(void *farg1, int const *farg2, long const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + long arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (long)(*farg3); + result = (int)CVodeSetMaxNumStepsB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetStabLimDetB(void *farg1, int const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (int)CVodeSetStabLimDetB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetInitStepB(void *farg1, int const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)CVodeSetInitStepB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMinStepB(void *farg1, int const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)CVodeSetMinStepB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxStepB(void *farg1, int const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)CVodeSetMaxStepB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetConstraintsB(void *farg1, int const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)CVodeSetConstraintsB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetQuadErrConB(void *farg1, int const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (int)CVodeSetQuadErrConB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetNonlinearSolverB(void *farg1, int const *farg2, SUNNonlinearSolver farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + SUNNonlinearSolver arg3 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (SUNNonlinearSolver)(farg3); + result = (int)CVodeSetNonlinearSolverB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetB(void *farg1, int const *farg2, double *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype *arg3 = (realtype *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype *)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeGetB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetQuadB(void *farg1, int const *farg2, double *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype *arg3 = (realtype *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype *)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)CVodeGetQuadB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void * _wrap_FCVodeGetAdjCVodeBmem(void *farg1, int const *farg2) { + void * fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + void *result = 0 ; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (void *)CVodeGetAdjCVodeBmem(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetAdjY(void *farg1, double const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)CVodeGetAdjY(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_CVadjCheckPointRec_my_addr_set(SwigClassWrapper const *farg1, void *farg2) { + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + void *arg2 = (void *) 0 ; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::my_addr", return ); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + arg2 = (void *)(farg2); + if (arg1) (arg1)->my_addr = arg2; +} + + +SWIGEXPORT void * _wrap_CVadjCheckPointRec_my_addr_get(SwigClassWrapper const *farg1) { + void * fresult ; + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + void *result = 0 ; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::my_addr", return 0); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + result = (void *) ((arg1)->my_addr); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_CVadjCheckPointRec_next_addr_set(SwigClassWrapper const *farg1, void *farg2) { + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + void *arg2 = (void *) 0 ; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::next_addr", return ); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + arg2 = (void *)(farg2); + if (arg1) (arg1)->next_addr = arg2; +} + + +SWIGEXPORT void * _wrap_CVadjCheckPointRec_next_addr_get(SwigClassWrapper const *farg1) { + void * fresult ; + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + void *result = 0 ; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::next_addr", return 0); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + result = (void *) ((arg1)->next_addr); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_CVadjCheckPointRec_t0_set(SwigClassWrapper const *farg1, double const *farg2) { + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + realtype arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::t0", return ); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + arg2 = (realtype)(*farg2); + if (arg1) (arg1)->t0 = arg2; +} + + +SWIGEXPORT double _wrap_CVadjCheckPointRec_t0_get(SwigClassWrapper const *farg1) { + double fresult ; + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + realtype result; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::t0", return 0); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + result = (realtype) ((arg1)->t0); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_CVadjCheckPointRec_t1_set(SwigClassWrapper const *farg1, double const *farg2) { + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + realtype arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::t1", return ); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + arg2 = (realtype)(*farg2); + if (arg1) (arg1)->t1 = arg2; +} + + +SWIGEXPORT double _wrap_CVadjCheckPointRec_t1_get(SwigClassWrapper const *farg1) { + double fresult ; + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + realtype result; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::t1", return 0); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + result = (realtype) ((arg1)->t1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_CVadjCheckPointRec_nstep_set(SwigClassWrapper const *farg1, long const *farg2) { + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + long arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::nstep", return ); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + arg2 = (long)(*farg2); + if (arg1) (arg1)->nstep = arg2; +} + + +SWIGEXPORT long _wrap_CVadjCheckPointRec_nstep_get(SwigClassWrapper const *farg1) { + long fresult ; + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + long result; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::nstep", return 0); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + result = (long) ((arg1)->nstep); + fresult = (long)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_CVadjCheckPointRec_order_set(SwigClassWrapper const *farg1, int const *farg2) { + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + int arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::order", return ); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + arg2 = (int)(*farg2); + if (arg1) (arg1)->order = arg2; +} + + +SWIGEXPORT int _wrap_CVadjCheckPointRec_order_get(SwigClassWrapper const *farg1) { + int fresult ; + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + int result; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::order", return 0); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + result = (int) ((arg1)->order); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_CVadjCheckPointRec_step_set(SwigClassWrapper const *farg1, double const *farg2) { + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + realtype arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::step", return ); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + arg2 = (realtype)(*farg2); + if (arg1) (arg1)->step = arg2; +} + + +SWIGEXPORT double _wrap_CVadjCheckPointRec_step_get(SwigClassWrapper const *farg1) { + double fresult ; + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + realtype result; + + SWIG_check_mutable_nonnull(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::step", return 0); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + result = (realtype) ((arg1)->step); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT SwigClassWrapper _wrap_new_CVadjCheckPointRec() { + SwigClassWrapper fresult ; + CVadjCheckPointRec *result = 0 ; + + result = (CVadjCheckPointRec *)calloc(1, sizeof(CVadjCheckPointRec)); + fresult.cptr = result; + fresult.cmemflags = SWIG_MEM_RVALUE | (1 ? SWIG_MEM_OWN : 0); + return fresult; +} + + +SWIGEXPORT void _wrap_delete_CVadjCheckPointRec(SwigClassWrapper *farg1) { + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + + SWIG_check_mutable(*farg1, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVadjCheckPointRec::~CVadjCheckPointRec()", return ); + arg1 = (CVadjCheckPointRec *)(farg1->cptr); + free((char *) arg1); +} + + +SWIGEXPORT void _wrap_CVadjCheckPointRec_op_assign__(SwigClassWrapper *farg1, SwigClassWrapper const *farg2) { + CVadjCheckPointRec *arg1 = (CVadjCheckPointRec *) 0 ; + CVadjCheckPointRec *arg2 = 0 ; + + (void)sizeof(arg1); + (void)sizeof(arg2); + SWIG_assign(farg1, *farg2); + +} + + +SWIGEXPORT int _wrap_FCVodeGetAdjCheckPointsInfo(void *farg1, SwigClassWrapper const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + CVadjCheckPointRec *arg2 = (CVadjCheckPointRec *) 0 ; + int result; + + arg1 = (void *)(farg1); + SWIG_check_mutable(*farg2, "CVadjCheckPointRec *", "CVadjCheckPointRec", "CVodeGetAdjCheckPointsInfo(void *,CVadjCheckPointRec *)", return 0); + arg2 = (CVadjCheckPointRec *)(farg2->cptr); + result = (int)CVodeGetAdjCheckPointsInfo(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetAdjDataPointHermite(void *farg1, int const *farg2, double *farg3, N_Vector farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype *arg3 = (realtype *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + result = (int)CVodeGetAdjDataPointHermite(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetAdjDataPointPolynomial(void *farg1, int const *farg2, double *farg3, int *farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype *arg3 = (realtype *) 0 ; + int *arg4 = (int *) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype *)(farg3); + arg4 = (int *)(farg4); + arg5 = (N_Vector)(farg5); + result = (int)CVodeGetAdjDataPointPolynomial(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetAdjCurrentCheckPoint(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + void **arg2 = (void **) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (void **)(farg2); + result = (int)CVodeGetAdjCurrentCheckPoint(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBandPrecInit(void *farg1, int64_t const *farg2, int64_t const *farg3, int64_t const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + result = (int)CVBandPrecInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBandPrecGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVBandPrecGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBandPrecGetNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVBandPrecGetNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBandPrecInitB(void *farg1, int const *farg2, int64_t const *farg3, int64_t const *farg4, int64_t const *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + sunindextype arg5 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + arg5 = (sunindextype)(*farg5); + result = (int)CVBandPrecInitB(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBBDPrecInit(void *farg1, int64_t const *farg2, int64_t const *farg3, int64_t const *farg4, int64_t const *farg5, int64_t const *farg6, double const *farg7, CVLocalFn farg8, CVCommFn farg9) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + sunindextype arg5 ; + sunindextype arg6 ; + realtype arg7 ; + CVLocalFn arg8 = (CVLocalFn) 0 ; + CVCommFn arg9 = (CVCommFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + arg5 = (sunindextype)(*farg5); + arg6 = (sunindextype)(*farg6); + arg7 = (realtype)(*farg7); + arg8 = (CVLocalFn)(farg8); + arg9 = (CVCommFn)(farg9); + result = (int)CVBBDPrecInit(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBBDPrecReInit(void *farg1, int64_t const *farg2, int64_t const *farg3, double const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + realtype arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (realtype)(*farg4); + result = (int)CVBBDPrecReInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBBDPrecGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVBBDPrecGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBBDPrecGetNumGfnEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVBBDPrecGetNumGfnEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBBDPrecInitB(void *farg1, int const *farg2, int64_t const *farg3, int64_t const *farg4, int64_t const *farg5, int64_t const *farg6, int64_t const *farg7, double const *farg8, CVLocalFnB farg9, CVCommFnB farg10) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + sunindextype arg5 ; + sunindextype arg6 ; + sunindextype arg7 ; + realtype arg8 ; + CVLocalFnB arg9 = (CVLocalFnB) 0 ; + CVCommFnB arg10 = (CVCommFnB) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + arg5 = (sunindextype)(*farg5); + arg6 = (sunindextype)(*farg6); + arg7 = (sunindextype)(*farg7); + arg8 = (realtype)(*farg8); + arg9 = (CVLocalFnB)(farg9); + arg10 = (CVCommFnB)(farg10); + result = (int)CVBBDPrecInitB(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVBBDPrecReInitB(void *farg1, int const *farg2, int64_t const *farg3, int64_t const *farg4, double const *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + realtype arg5 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + arg5 = (realtype)(*farg5); + result = (int)CVBBDPrecReInitB(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVDiag(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)CVDiag(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVDiagGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVDiagGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVDiagGetNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVDiagGetNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVDiagGetLastFlag(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVDiagGetLastFlag(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FCVDiagGetReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)CVDiagGetReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVDiagB(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVDiagB(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetLinearSolver(void *farg1, SUNLinearSolver farg2, SUNMatrix farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNLinearSolver arg2 = (SUNLinearSolver) 0 ; + SUNMatrix arg3 = (SUNMatrix) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNLinearSolver)(farg2); + arg3 = (SUNMatrix)(farg3); + result = (int)CVodeSetLinearSolver(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetJacFn(void *farg1, CVLsJacFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + CVLsJacFn arg2 = (CVLsJacFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVLsJacFn)(farg2); + result = (int)CVodeSetJacFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetMaxStepsBetweenJac(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)CVodeSetMaxStepsBetweenJac(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetLinearSolutionScaling(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)CVodeSetLinearSolutionScaling(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetEpsLin(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)CVodeSetEpsLin(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetPreconditioner(void *farg1, CVLsPrecSetupFn farg2, CVLsPrecSolveFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + CVLsPrecSetupFn arg2 = (CVLsPrecSetupFn) 0 ; + CVLsPrecSolveFn arg3 = (CVLsPrecSolveFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVLsPrecSetupFn)(farg2); + arg3 = (CVLsPrecSolveFn)(farg3); + result = (int)CVodeSetPreconditioner(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetJacTimes(void *farg1, CVLsJacTimesSetupFn farg2, CVLsJacTimesVecFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + CVLsJacTimesSetupFn arg2 = (CVLsJacTimesSetupFn) 0 ; + CVLsJacTimesVecFn arg3 = (CVLsJacTimesVecFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVLsJacTimesSetupFn)(farg2); + arg3 = (CVLsJacTimesVecFn)(farg3); + result = (int)CVodeSetJacTimes(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetLinSysFn(void *farg1, CVLsLinSysFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + CVLsLinSysFn arg2 = (CVLsLinSysFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (CVLsLinSysFn)(farg2); + result = (int)CVodeSetLinSysFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetLinWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)CVodeGetLinWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumJacEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumJacEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumPrecEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumPrecEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumPrecSolves(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumPrecSolves(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumLinIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumLinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumLinConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumLinConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumJTSetupEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumJTSetupEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumJtimesEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumJtimesEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetNumLinRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetNumLinRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeGetLastLinFlag(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)CVodeGetLastLinFlag(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FCVodeGetLinReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)CVodeGetLinReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetLinearSolverB(void *farg1, int const *farg2, SUNLinearSolver farg3, SUNMatrix farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + SUNLinearSolver arg3 = (SUNLinearSolver) 0 ; + SUNMatrix arg4 = (SUNMatrix) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (SUNLinearSolver)(farg3); + arg4 = (SUNMatrix)(farg4); + result = (int)CVodeSetLinearSolverB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetJacFnB(void *farg1, int const *farg2, CVLsJacFnB farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVLsJacFnB arg3 = (CVLsJacFnB) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVLsJacFnB)(farg3); + result = (int)CVodeSetJacFnB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetJacFnBS(void *farg1, int const *farg2, CVLsJacFnBS farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVLsJacFnBS arg3 = (CVLsJacFnBS) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVLsJacFnBS)(farg3); + result = (int)CVodeSetJacFnBS(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetEpsLinB(void *farg1, int const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)CVodeSetEpsLinB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetLinearSolutionScalingB(void *farg1, int const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (int)CVodeSetLinearSolutionScalingB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetPreconditionerB(void *farg1, int const *farg2, CVLsPrecSetupFnB farg3, CVLsPrecSolveFnB farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVLsPrecSetupFnB arg3 = (CVLsPrecSetupFnB) 0 ; + CVLsPrecSolveFnB arg4 = (CVLsPrecSolveFnB) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVLsPrecSetupFnB)(farg3); + arg4 = (CVLsPrecSolveFnB)(farg4); + result = (int)CVodeSetPreconditionerB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetPreconditionerBS(void *farg1, int const *farg2, CVLsPrecSetupFnBS farg3, CVLsPrecSolveFnBS farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVLsPrecSetupFnBS arg3 = (CVLsPrecSetupFnBS) 0 ; + CVLsPrecSolveFnBS arg4 = (CVLsPrecSolveFnBS) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVLsPrecSetupFnBS)(farg3); + arg4 = (CVLsPrecSolveFnBS)(farg4); + result = (int)CVodeSetPreconditionerBS(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetJacTimesB(void *farg1, int const *farg2, CVLsJacTimesSetupFnB farg3, CVLsJacTimesVecFnB farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVLsJacTimesSetupFnB arg3 = (CVLsJacTimesSetupFnB) 0 ; + CVLsJacTimesVecFnB arg4 = (CVLsJacTimesVecFnB) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVLsJacTimesSetupFnB)(farg3); + arg4 = (CVLsJacTimesVecFnB)(farg4); + result = (int)CVodeSetJacTimesB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetJacTimesBS(void *farg1, int const *farg2, CVLsJacTimesSetupFnBS farg3, CVLsJacTimesVecFnBS farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVLsJacTimesSetupFnBS arg3 = (CVLsJacTimesSetupFnBS) 0 ; + CVLsJacTimesVecFnBS arg4 = (CVLsJacTimesVecFnBS) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVLsJacTimesSetupFnBS)(farg3); + arg4 = (CVLsJacTimesVecFnBS)(farg4); + result = (int)CVodeSetJacTimesBS(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetLinSysFnB(void *farg1, int const *farg2, CVLsLinSysFnB farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVLsLinSysFnB arg3 = (CVLsLinSysFnB) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVLsLinSysFnB)(farg3); + result = (int)CVodeSetLinSysFnB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FCVodeSetLinSysFnBS(void *farg1, int const *farg2, CVLsLinSysFnBS farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + CVLsLinSysFnBS arg3 = (CVLsLinSysFnBS) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (CVLsLinSysFnBS)(farg3); + result = (int)CVodeSetLinSysFnBS(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/cvodes/fmod/fcvodes_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/cvodes/fmod/fcvodes_mod.f90 new file mode 100644 index 000000000..b7dc043ef --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/cvodes/fmod/fcvodes_mod.f90 @@ -0,0 +1,6125 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fcvodes_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_linearsolver_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_nonlinearsolver_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: CV_ADAMS = 1_C_INT + integer(C_INT), parameter, public :: CV_BDF = 2_C_INT + integer(C_INT), parameter, public :: CV_NORMAL = 1_C_INT + integer(C_INT), parameter, public :: CV_ONE_STEP = 2_C_INT + integer(C_INT), parameter, public :: CV_SIMULTANEOUS = 1_C_INT + integer(C_INT), parameter, public :: CV_STAGGERED = 2_C_INT + integer(C_INT), parameter, public :: CV_STAGGERED1 = 3_C_INT + integer(C_INT), parameter, public :: CV_CENTERED = 1_C_INT + integer(C_INT), parameter, public :: CV_FORWARD = 2_C_INT + integer(C_INT), parameter, public :: CV_HERMITE = 1_C_INT + integer(C_INT), parameter, public :: CV_POLYNOMIAL = 2_C_INT + integer(C_INT), parameter, public :: CV_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: CV_TSTOP_RETURN = 1_C_INT + integer(C_INT), parameter, public :: CV_ROOT_RETURN = 2_C_INT + integer(C_INT), parameter, public :: CV_WARNING = 99_C_INT + integer(C_INT), parameter, public :: CV_TOO_MUCH_WORK = -1_C_INT + integer(C_INT), parameter, public :: CV_TOO_MUCH_ACC = -2_C_INT + integer(C_INT), parameter, public :: CV_ERR_FAILURE = -3_C_INT + integer(C_INT), parameter, public :: CV_CONV_FAILURE = -4_C_INT + integer(C_INT), parameter, public :: CV_LINIT_FAIL = -5_C_INT + integer(C_INT), parameter, public :: CV_LSETUP_FAIL = -6_C_INT + integer(C_INT), parameter, public :: CV_LSOLVE_FAIL = -7_C_INT + integer(C_INT), parameter, public :: CV_RHSFUNC_FAIL = -8_C_INT + integer(C_INT), parameter, public :: CV_FIRST_RHSFUNC_ERR = -9_C_INT + integer(C_INT), parameter, public :: CV_REPTD_RHSFUNC_ERR = -10_C_INT + integer(C_INT), parameter, public :: CV_UNREC_RHSFUNC_ERR = -11_C_INT + integer(C_INT), parameter, public :: CV_RTFUNC_FAIL = -12_C_INT + integer(C_INT), parameter, public :: CV_NLS_INIT_FAIL = -13_C_INT + integer(C_INT), parameter, public :: CV_NLS_SETUP_FAIL = -14_C_INT + integer(C_INT), parameter, public :: CV_CONSTR_FAIL = -15_C_INT + integer(C_INT), parameter, public :: CV_NLS_FAIL = -16_C_INT + integer(C_INT), parameter, public :: CV_MEM_FAIL = -20_C_INT + integer(C_INT), parameter, public :: CV_MEM_NULL = -21_C_INT + integer(C_INT), parameter, public :: CV_ILL_INPUT = -22_C_INT + integer(C_INT), parameter, public :: CV_NO_MALLOC = -23_C_INT + integer(C_INT), parameter, public :: CV_BAD_K = -24_C_INT + integer(C_INT), parameter, public :: CV_BAD_T = -25_C_INT + integer(C_INT), parameter, public :: CV_BAD_DKY = -26_C_INT + integer(C_INT), parameter, public :: CV_TOO_CLOSE = -27_C_INT + integer(C_INT), parameter, public :: CV_VECTOROP_ERR = -28_C_INT + integer(C_INT), parameter, public :: CV_NO_QUAD = -30_C_INT + integer(C_INT), parameter, public :: CV_QRHSFUNC_FAIL = -31_C_INT + integer(C_INT), parameter, public :: CV_FIRST_QRHSFUNC_ERR = -32_C_INT + integer(C_INT), parameter, public :: CV_REPTD_QRHSFUNC_ERR = -33_C_INT + integer(C_INT), parameter, public :: CV_UNREC_QRHSFUNC_ERR = -34_C_INT + integer(C_INT), parameter, public :: CV_NO_SENS = -40_C_INT + integer(C_INT), parameter, public :: CV_SRHSFUNC_FAIL = -41_C_INT + integer(C_INT), parameter, public :: CV_FIRST_SRHSFUNC_ERR = -42_C_INT + integer(C_INT), parameter, public :: CV_REPTD_SRHSFUNC_ERR = -43_C_INT + integer(C_INT), parameter, public :: CV_UNREC_SRHSFUNC_ERR = -44_C_INT + integer(C_INT), parameter, public :: CV_BAD_IS = -45_C_INT + integer(C_INT), parameter, public :: CV_NO_QUADSENS = -50_C_INT + integer(C_INT), parameter, public :: CV_QSRHSFUNC_FAIL = -51_C_INT + integer(C_INT), parameter, public :: CV_FIRST_QSRHSFUNC_ERR = -52_C_INT + integer(C_INT), parameter, public :: CV_REPTD_QSRHSFUNC_ERR = -53_C_INT + integer(C_INT), parameter, public :: CV_UNREC_QSRHSFUNC_ERR = -54_C_INT + integer(C_INT), parameter, public :: CV_UNRECOGNIZED_ERR = -99_C_INT + integer(C_INT), parameter, public :: CV_NO_ADJ = -101_C_INT + integer(C_INT), parameter, public :: CV_NO_FWD = -102_C_INT + integer(C_INT), parameter, public :: CV_NO_BCK = -103_C_INT + integer(C_INT), parameter, public :: CV_BAD_TB0 = -104_C_INT + integer(C_INT), parameter, public :: CV_REIFWD_FAIL = -105_C_INT + integer(C_INT), parameter, public :: CV_FWD_FAIL = -106_C_INT + integer(C_INT), parameter, public :: CV_GETY_BADT = -107_C_INT + public :: FCVodeCreate + public :: FCVodeInit + public :: FCVodeReInit + public :: FCVodeSStolerances + public :: FCVodeSVtolerances + public :: FCVodeWFtolerances + public :: FCVodeSetErrHandlerFn + public :: FCVodeSetErrFile + public :: FCVodeSetUserData + public :: FCVodeSetMaxOrd + public :: FCVodeSetMaxNumSteps + public :: FCVodeSetMaxHnilWarns + public :: FCVodeSetStabLimDet + public :: FCVodeSetInitStep + public :: FCVodeSetMinStep + public :: FCVodeSetMaxStep + public :: FCVodeSetStopTime + public :: FCVodeSetMaxErrTestFails + public :: FCVodeSetMaxNonlinIters + public :: FCVodeSetMaxConvFails + public :: FCVodeSetNonlinConvCoef + public :: FCVodeSetConstraints + public :: FCVodeSetNonlinearSolver + public :: FCVodeRootInit + public :: FCVodeSetRootDirection + public :: FCVodeSetNoInactiveRootWarn + public :: FCVode + public :: FCVodeGetDky + public :: FCVodeGetWorkSpace + public :: FCVodeGetNumSteps + public :: FCVodeGetNumRhsEvals + public :: FCVodeGetNumLinSolvSetups + public :: FCVodeGetNumErrTestFails + public :: FCVodeGetLastOrder + public :: FCVodeGetCurrentOrder + public :: FCVodeGetCurrentGamma + public :: FCVodeGetNumStabLimOrderReds + public :: FCVodeGetActualInitStep + public :: FCVodeGetLastStep + public :: FCVodeGetCurrentStep + public :: FCVodeGetCurrentState + public :: FCVodeGetCurrentStateSens + public :: FCVodeGetCurrentSensSolveIndex + public :: FCVodeGetCurrentTime + public :: FCVodeGetTolScaleFactor + public :: FCVodeGetErrWeights + public :: FCVodeGetEstLocalErrors + public :: FCVodeGetNumGEvals + public :: FCVodeGetRootInfo + public :: FCVodeGetIntegratorStats + public :: FCVodeGetNumNonlinSolvIters + public :: FCVodeGetNumNonlinSolvConvFails + public :: FCVodeGetNonlinSolvStats + type, bind(C) :: SwigArrayWrapper + type(C_PTR), public :: data = C_NULL_PTR + integer(C_SIZE_T), public :: size = 0 + end type + public :: FCVodeGetReturnFlagName + public :: FCVodeFree + public :: FCVodeQuadInit + public :: FCVodeQuadReInit + public :: FCVodeQuadSStolerances + public :: FCVodeQuadSVtolerances + public :: FCVodeSetQuadErrCon + public :: FCVodeGetQuad + public :: FCVodeGetQuadDky + public :: FCVodeGetQuadNumRhsEvals + public :: FCVodeGetQuadNumErrTestFails + public :: FCVodeGetQuadErrWeights + public :: FCVodeGetQuadStats + public :: FCVodeQuadFree + public :: FCVodeSensInit + public :: FCVodeSensInit1 + public :: FCVodeSensReInit + public :: FCVodeSensSStolerances + public :: FCVodeSensSVtolerances + public :: FCVodeSensEEtolerances + public :: FCVodeSetSensDQMethod + public :: FCVodeSetSensErrCon + public :: FCVodeSetSensMaxNonlinIters + public :: FCVodeSetSensParams + public :: FCVodeSetNonlinearSolverSensSim + public :: FCVodeSetNonlinearSolverSensStg + public :: FCVodeSetNonlinearSolverSensStg1 + public :: FCVodeSensToggleOff + public :: FCVodeGetSens + public :: FCVodeGetSens1 + public :: FCVodeGetSensDky + public :: FCVodeGetSensDky1 + public :: FCVodeGetSensNumRhsEvals + public :: FCVodeGetNumRhsEvalsSens + public :: FCVodeGetSensNumErrTestFails + public :: FCVodeGetSensNumLinSolvSetups + public :: FCVodeGetSensErrWeights + public :: FCVodeGetSensStats + public :: FCVodeGetSensNumNonlinSolvIters + public :: FCVodeGetSensNumNonlinSolvConvFails + public :: FCVodeGetStgrSensNumNonlinSolvIters + public :: FCVodeGetStgrSensNumNonlinSolvConvFails + public :: FCVodeGetSensNonlinSolvStats + public :: FCVodeSensFree + public :: FCVodeQuadSensInit + public :: FCVodeQuadSensReInit + public :: FCVodeQuadSensSStolerances + public :: FCVodeQuadSensSVtolerances + public :: FCVodeQuadSensEEtolerances + public :: FCVodeSetQuadSensErrCon + public :: FCVodeGetQuadSens + public :: FCVodeGetQuadSens1 + public :: FCVodeGetQuadSensDky + public :: FCVodeGetQuadSensDky1 + public :: FCVodeGetQuadSensNumRhsEvals + public :: FCVodeGetQuadSensNumErrTestFails + public :: FCVodeGetQuadSensErrWeights + public :: FCVodeGetQuadSensStats + public :: FCVodeQuadSensFree + public :: FCVodeAdjInit + public :: FCVodeAdjReInit + public :: FCVodeAdjFree + public :: FCVodeCreateB + public :: FCVodeInitB + public :: FCVodeInitBS + public :: FCVodeReInitB + public :: FCVodeSStolerancesB + public :: FCVodeSVtolerancesB + public :: FCVodeQuadInitB + public :: FCVodeQuadInitBS + public :: FCVodeQuadReInitB + public :: FCVodeQuadSStolerancesB + public :: FCVodeQuadSVtolerancesB + public :: FCVodeF + public :: FCVodeB + public :: FCVodeSetAdjNoSensi + public :: FCVodeSetUserDataB + public :: FCVodeSetMaxOrdB + public :: FCVodeSetMaxNumStepsB + public :: FCVodeSetStabLimDetB + public :: FCVodeSetInitStepB + public :: FCVodeSetMinStepB + public :: FCVodeSetMaxStepB + public :: FCVodeSetConstraintsB + public :: FCVodeSetQuadErrConB + public :: FCVodeSetNonlinearSolverB + public :: FCVodeGetB + public :: FCVodeGetQuadB + public :: FCVodeGetAdjCVodeBmem + public :: FCVodeGetAdjY + + integer, parameter :: swig_cmem_own_bit = 0 + integer, parameter :: swig_cmem_rvalue_bit = 1 + integer, parameter :: swig_cmem_const_bit = 2 + type, bind(C) :: SwigClassWrapper + type(C_PTR), public :: cptr = C_NULL_PTR + integer(C_INT), public :: cmemflags = 0 + end type + ! struct CVadjCheckPointRec + type, public :: CVadjCheckPointRec + type(SwigClassWrapper), public :: swigdata + contains + procedure :: set_my_addr => swigf_CVadjCheckPointRec_my_addr_set + procedure :: get_my_addr => swigf_CVadjCheckPointRec_my_addr_get + procedure :: set_next_addr => swigf_CVadjCheckPointRec_next_addr_set + procedure :: get_next_addr => swigf_CVadjCheckPointRec_next_addr_get + procedure :: set_t0 => swigf_CVadjCheckPointRec_t0_set + procedure :: get_t0 => swigf_CVadjCheckPointRec_t0_get + procedure :: set_t1 => swigf_CVadjCheckPointRec_t1_set + procedure :: get_t1 => swigf_CVadjCheckPointRec_t1_get + procedure :: set_nstep => swigf_CVadjCheckPointRec_nstep_set + procedure :: get_nstep => swigf_CVadjCheckPointRec_nstep_get + procedure :: set_order => swigf_CVadjCheckPointRec_order_set + procedure :: get_order => swigf_CVadjCheckPointRec_order_get + procedure :: set_step => swigf_CVadjCheckPointRec_step_set + procedure :: get_step => swigf_CVadjCheckPointRec_step_get + procedure :: release => swigf_release_CVadjCheckPointRec + procedure, private :: swigf_CVadjCheckPointRec_op_assign__ + generic :: assignment(=) => swigf_CVadjCheckPointRec_op_assign__ + end type CVadjCheckPointRec + interface CVadjCheckPointRec + module procedure swigf_create_CVadjCheckPointRec + end interface + public :: FCVodeGetAdjCheckPointsInfo + public :: FCVodeGetAdjDataPointHermite + public :: FCVodeGetAdjDataPointPolynomial + public :: FCVodeGetAdjCurrentCheckPoint + public :: FCVBandPrecInit + public :: FCVBandPrecGetWorkSpace + public :: FCVBandPrecGetNumRhsEvals + public :: FCVBandPrecInitB + public :: FCVBBDPrecInit + public :: FCVBBDPrecReInit + public :: FCVBBDPrecGetWorkSpace + public :: FCVBBDPrecGetNumGfnEvals + public :: FCVBBDPrecInitB + public :: FCVBBDPrecReInitB + integer(C_INT), parameter, public :: CVDIAG_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: CVDIAG_MEM_NULL = -1_C_INT + integer(C_INT), parameter, public :: CVDIAG_LMEM_NULL = -2_C_INT + integer(C_INT), parameter, public :: CVDIAG_ILL_INPUT = -3_C_INT + integer(C_INT), parameter, public :: CVDIAG_MEM_FAIL = -4_C_INT + integer(C_INT), parameter, public :: CVDIAG_INV_FAIL = -5_C_INT + integer(C_INT), parameter, public :: CVDIAG_RHSFUNC_UNRECVR = -6_C_INT + integer(C_INT), parameter, public :: CVDIAG_RHSFUNC_RECVR = -7_C_INT + integer(C_INT), parameter, public :: CVDIAG_NO_ADJ = -101_C_INT + public :: FCVDiag + public :: FCVDiagGetWorkSpace + public :: FCVDiagGetNumRhsEvals + public :: FCVDiagGetLastFlag + public :: FCVDiagGetReturnFlagName + public :: FCVDiagB + integer(C_INT), parameter, public :: CVLS_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: CVLS_MEM_NULL = -1_C_INT + integer(C_INT), parameter, public :: CVLS_LMEM_NULL = -2_C_INT + integer(C_INT), parameter, public :: CVLS_ILL_INPUT = -3_C_INT + integer(C_INT), parameter, public :: CVLS_MEM_FAIL = -4_C_INT + integer(C_INT), parameter, public :: CVLS_PMEM_NULL = -5_C_INT + integer(C_INT), parameter, public :: CVLS_JACFUNC_UNRECVR = -6_C_INT + integer(C_INT), parameter, public :: CVLS_JACFUNC_RECVR = -7_C_INT + integer(C_INT), parameter, public :: CVLS_SUNMAT_FAIL = -8_C_INT + integer(C_INT), parameter, public :: CVLS_SUNLS_FAIL = -9_C_INT + integer(C_INT), parameter, public :: CVLS_NO_ADJ = -101_C_INT + integer(C_INT), parameter, public :: CVLS_LMEMB_NULL = -102_C_INT + public :: FCVodeSetLinearSolver + public :: FCVodeSetJacFn + public :: FCVodeSetMaxStepsBetweenJac + public :: FCVodeSetLinearSolutionScaling + public :: FCVodeSetEpsLin + public :: FCVodeSetPreconditioner + public :: FCVodeSetJacTimes + public :: FCVodeSetLinSysFn + public :: FCVodeGetLinWorkSpace + public :: FCVodeGetNumJacEvals + public :: FCVodeGetNumPrecEvals + public :: FCVodeGetNumPrecSolves + public :: FCVodeGetNumLinIters + public :: FCVodeGetNumLinConvFails + public :: FCVodeGetNumJTSetupEvals + public :: FCVodeGetNumJtimesEvals + public :: FCVodeGetNumLinRhsEvals + public :: FCVodeGetLastLinFlag + public :: FCVodeGetLinReturnFlagName + public :: FCVodeSetLinearSolverB + public :: FCVodeSetJacFnB + public :: FCVodeSetJacFnBS + public :: FCVodeSetEpsLinB + public :: FCVodeSetLinearSolutionScalingB + public :: FCVodeSetPreconditionerB + public :: FCVodeSetPreconditionerBS + public :: FCVodeSetJacTimesB + public :: FCVodeSetJacTimesBS + public :: FCVodeSetLinSysFnB + public :: FCVodeSetLinSysFnBS + +! WRAPPER DECLARATIONS +interface +function swigc_FCVodeCreate(farg1) & +bind(C, name="_wrap_FCVodeCreate") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FCVodeInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeReInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSStolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSStolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSVtolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSVtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeWFtolerances(farg1, farg2) & +bind(C, name="_wrap_FCVodeWFtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetErrHandlerFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetErrHandlerFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetErrFile(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetErrFile") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetUserData(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetUserData") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxOrd(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxOrd") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxNumSteps(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxHnilWarns(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxHnilWarns") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetStabLimDet(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetStabLimDet") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetInitStep(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetInitStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMinStep(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMinStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxStep(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetStopTime(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetStopTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxNonlinIters(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxNonlinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxConvFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetNonlinConvCoef(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetNonlinConvCoef") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetConstraints(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetConstraints") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetNonlinearSolver(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetNonlinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeRootInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeRootInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetRootDirection(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetRootDirection") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetNoInactiveRootWarn(farg1) & +bind(C, name="_wrap_FCVodeSetNoInactiveRootWarn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FCVode(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVode") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeGetDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumSteps(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumLinSolvSetups(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumLinSolvSetups") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetLastOrder(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetLastOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetCurrentOrder(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetCurrentOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetCurrentGamma(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetCurrentGamma") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumStabLimOrderReds(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumStabLimOrderReds") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetActualInitStep(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetActualInitStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetLastStep(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetLastStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetCurrentStep(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetCurrentStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetCurrentState(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetCurrentState") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetCurrentStateSens(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetCurrentStateSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetCurrentSensSolveIndex(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetCurrentSensSolveIndex") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetCurrentTime(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetCurrentTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetTolScaleFactor(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetTolScaleFactor") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetErrWeights(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetErrWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetEstLocalErrors(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetEstLocalErrors") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumGEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumGEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetRootInfo(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetRootInfo") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetIntegratorStats(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10, farg11) & +bind(C, name="_wrap_FCVodeGetIntegratorStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +type(C_PTR), value :: farg7 +type(C_PTR), value :: farg8 +type(C_PTR), value :: farg9 +type(C_PTR), value :: farg10 +type(C_PTR), value :: farg11 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumNonlinSolvIters(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumNonlinSolvIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumNonlinSolvConvFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumNonlinSolvConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNonlinSolvStats(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetNonlinSolvStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + + subroutine SWIG_free(cptr) & + bind(C, name="free") + use, intrinsic :: ISO_C_BINDING + type(C_PTR), value :: cptr +end subroutine +function swigc_FCVodeGetReturnFlagName(farg1) & +bind(C, name="_wrap_FCVodeGetReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +subroutine swigc_FCVodeFree(farg1) & +bind(C, name="_wrap_FCVodeFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FCVodeQuadInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeQuadInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeQuadReInit(farg1, farg2) & +bind(C, name="_wrap_FCVodeQuadReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeQuadSStolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeQuadSStolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeQuadSVtolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeQuadSVtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetQuadErrCon(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetQuadErrCon") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuad(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetQuad") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeGetQuadDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetQuadNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadNumErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetQuadNumErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadErrWeights(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetQuadErrWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadStats(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetQuadStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +subroutine swigc_FCVodeQuadFree(farg1) & +bind(C, name="_wrap_FCVodeQuadFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FCVodeSensInit(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVodeSensInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_FUNPTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSensInit1(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVodeSensInit1") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_FUNPTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSensReInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSensReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSensSStolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSensSStolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSensSVtolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSensSVtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSensEEtolerances(farg1) & +bind(C, name="_wrap_FCVodeSensEEtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetSensDQMethod(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetSensDQMethod") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetSensErrCon(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetSensErrCon") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetSensMaxNonlinIters(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetSensMaxNonlinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetSensParams(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeSetSensParams") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetNonlinearSolverSensSim(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetNonlinearSolverSensSim") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetNonlinearSolverSensStg(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetNonlinearSolverSensStg") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetNonlinearSolverSensStg1(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetNonlinearSolverSensStg1") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSensToggleOff(farg1) & +bind(C, name="_wrap_FCVodeSensToggleOff") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetSens(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetSens1(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeGetSens1") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetSensDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeGetSensDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetSensDky1(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVodeGetSensDky1") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT), intent(in) :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetSensNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetSensNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumRhsEvalsSens(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumRhsEvalsSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetSensNumErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetSensNumErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetSensNumLinSolvSetups(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetSensNumLinSolvSetups") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetSensErrWeights(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetSensErrWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetSensStats(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVodeGetSensStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetSensNumNonlinSolvIters(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetSensNumNonlinSolvIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetSensNumNonlinSolvConvFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetSensNumNonlinSolvConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetStgrSensNumNonlinSolvIters(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetStgrSensNumNonlinSolvIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetStgrSensNumNonlinSolvConvFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetStgrSensNumNonlinSolvConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetSensNonlinSolvStats(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetSensNonlinSolvStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +subroutine swigc_FCVodeSensFree(farg1) & +bind(C, name="_wrap_FCVodeSensFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FCVodeQuadSensInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeQuadSensInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeQuadSensReInit(farg1, farg2) & +bind(C, name="_wrap_FCVodeQuadSensReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeQuadSensSStolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeQuadSensSStolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeQuadSensSVtolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeQuadSensSVtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeQuadSensEEtolerances(farg1) & +bind(C, name="_wrap_FCVodeQuadSensEEtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetQuadSensErrCon(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetQuadSensErrCon") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadSens(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetQuadSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadSens1(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeGetQuadSens1") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadSensDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeGetQuadSensDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadSensDky1(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVodeGetQuadSensDky1") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT), intent(in) :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadSensNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetQuadSensNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadSensNumErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetQuadSensNumErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadSensErrWeights(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetQuadSensErrWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadSensStats(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetQuadSensStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +subroutine swigc_FCVodeQuadSensFree(farg1) & +bind(C, name="_wrap_FCVodeQuadSensFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FCVodeAdjInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeAdjInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeAdjReInit(farg1) & +bind(C, name="_wrap_FCVodeAdjReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +subroutine swigc_FCVodeAdjFree(farg1) & +bind(C, name="_wrap_FCVodeAdjFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FCVodeCreateB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeCreateB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeInitB(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVodeInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeInitBS(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVodeInitBS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeReInitB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeReInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSStolerancesB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeSStolerancesB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSVtolerancesB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeSVtolerancesB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeQuadInitB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeQuadInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeQuadInitBS(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeQuadInitBS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeQuadReInitB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeQuadReInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeQuadSStolerancesB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeQuadSStolerancesB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeQuadSVtolerancesB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeQuadSVtolerancesB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeF(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FCVodeF") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT), intent(in) :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetAdjNoSensi(farg1) & +bind(C, name="_wrap_FCVodeSetAdjNoSensi") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetUserDataB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetUserDataB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxOrdB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetMaxOrdB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxNumStepsB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetMaxNumStepsB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_LONG), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetStabLimDetB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetStabLimDetB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetInitStepB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetInitStepB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMinStepB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetMinStepB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxStepB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetMaxStepB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetConstraintsB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetConstraintsB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetQuadErrConB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetQuadErrConB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetNonlinearSolverB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetNonlinearSolverB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeGetB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetQuadB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeGetQuadB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetAdjCVodeBmem(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetAdjCVodeBmem") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FCVodeGetAdjY(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetAdjY") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +subroutine swigc_CVadjCheckPointRec_my_addr_set(farg1, farg2) & +bind(C, name="_wrap_CVadjCheckPointRec_my_addr_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_CVadjCheckPointRec_my_addr_get(farg1) & +bind(C, name="_wrap_CVadjCheckPointRec_my_addr_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_CVadjCheckPointRec_next_addr_set(farg1, farg2) & +bind(C, name="_wrap_CVadjCheckPointRec_next_addr_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_CVadjCheckPointRec_next_addr_get(farg1) & +bind(C, name="_wrap_CVadjCheckPointRec_next_addr_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_CVadjCheckPointRec_t0_set(farg1, farg2) & +bind(C, name="_wrap_CVadjCheckPointRec_t0_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +end subroutine + +function swigc_CVadjCheckPointRec_t0_get(farg1) & +bind(C, name="_wrap_CVadjCheckPointRec_t0_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE) :: fresult +end function + +subroutine swigc_CVadjCheckPointRec_t1_set(farg1, farg2) & +bind(C, name="_wrap_CVadjCheckPointRec_t1_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +end subroutine + +function swigc_CVadjCheckPointRec_t1_get(farg1) & +bind(C, name="_wrap_CVadjCheckPointRec_t1_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE) :: fresult +end function + +subroutine swigc_CVadjCheckPointRec_nstep_set(farg1, farg2) & +bind(C, name="_wrap_CVadjCheckPointRec_nstep_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_LONG), intent(in) :: farg2 +end subroutine + +function swigc_CVadjCheckPointRec_nstep_get(farg1) & +bind(C, name="_wrap_CVadjCheckPointRec_nstep_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_LONG) :: fresult +end function + +subroutine swigc_CVadjCheckPointRec_order_set(farg1, farg2) & +bind(C, name="_wrap_CVadjCheckPointRec_order_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_INT), intent(in) :: farg2 +end subroutine + +function swigc_CVadjCheckPointRec_order_get(farg1) & +bind(C, name="_wrap_CVadjCheckPointRec_order_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_INT) :: fresult +end function + +subroutine swigc_CVadjCheckPointRec_step_set(farg1, farg2) & +bind(C, name="_wrap_CVadjCheckPointRec_step_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +end subroutine + +function swigc_CVadjCheckPointRec_step_get(farg1) & +bind(C, name="_wrap_CVadjCheckPointRec_step_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_new_CVadjCheckPointRec() & +bind(C, name="_wrap_new_CVadjCheckPointRec") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: fresult +end function + +subroutine swigc_delete_CVadjCheckPointRec(farg1) & +bind(C, name="_wrap_delete_CVadjCheckPointRec") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper), intent(inout) :: farg1 +end subroutine + +subroutine swigc_CVadjCheckPointRec_op_assign__(farg1, farg2) & +bind(C, name="_wrap_CVadjCheckPointRec_op_assign__") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper), intent(inout) :: farg1 +type(SwigClassWrapper) :: farg2 +end subroutine + +function swigc_FCVodeGetAdjCheckPointsInfo(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetAdjCheckPointsInfo") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(C_PTR), value :: farg1 +type(SwigClassWrapper) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetAdjDataPointHermite(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVodeGetAdjDataPointHermite") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetAdjDataPointPolynomial(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVodeGetAdjDataPointPolynomial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetAdjCurrentCheckPoint(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetAdjCurrentCheckPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVBandPrecInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVBandPrecInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVBandPrecGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVBandPrecGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVBandPrecGetNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FCVBandPrecGetNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVBandPrecInitB(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVBandPrecInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +integer(C_INT64_T), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVBBDPrecInit(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) & +bind(C, name="_wrap_FCVBBDPrecInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +integer(C_INT64_T), intent(in) :: farg5 +integer(C_INT64_T), intent(in) :: farg6 +real(C_DOUBLE), intent(in) :: farg7 +type(C_FUNPTR), value :: farg8 +type(C_FUNPTR), value :: farg9 +integer(C_INT) :: fresult +end function + +function swigc_FCVBBDPrecReInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVBBDPrecReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVBBDPrecGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVBBDPrecGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVBBDPrecGetNumGfnEvals(farg1, farg2) & +bind(C, name="_wrap_FCVBBDPrecGetNumGfnEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVBBDPrecInitB(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10) & +bind(C, name="_wrap_FCVBBDPrecInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +integer(C_INT64_T), intent(in) :: farg5 +integer(C_INT64_T), intent(in) :: farg6 +integer(C_INT64_T), intent(in) :: farg7 +real(C_DOUBLE), intent(in) :: farg8 +type(C_FUNPTR), value :: farg9 +type(C_FUNPTR), value :: farg10 +integer(C_INT) :: fresult +end function + +function swigc_FCVBBDPrecReInitB(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FCVBBDPrecReInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FCVDiag(farg1) & +bind(C, name="_wrap_FCVDiag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FCVDiagGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVDiagGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVDiagGetNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FCVDiagGetNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVDiagGetLastFlag(farg1, farg2) & +bind(C, name="_wrap_FCVDiagGetLastFlag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVDiagGetReturnFlagName(farg1) & +bind(C, name="_wrap_FCVDiagGetReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +function swigc_FCVDiagB(farg1, farg2) & +bind(C, name="_wrap_FCVDiagB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetLinearSolver(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetLinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetJacFn(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetJacFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetMaxStepsBetweenJac(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetMaxStepsBetweenJac") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetLinearSolutionScaling(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetLinearSolutionScaling") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetEpsLin(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetEpsLin") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetPreconditioner(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetPreconditioner") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetJacTimes(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetJacTimes") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetLinSysFn(farg1, farg2) & +bind(C, name="_wrap_FCVodeSetLinSysFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetLinWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeGetLinWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumJacEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumJacEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumPrecEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumPrecEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumPrecSolves(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumPrecSolves") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumLinIters(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumLinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumLinConvFails(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumLinConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumJTSetupEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumJTSetupEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumJtimesEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumJtimesEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetNumLinRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetNumLinRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetLastLinFlag(farg1, farg2) & +bind(C, name="_wrap_FCVodeGetLastLinFlag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeGetLinReturnFlagName(farg1) & +bind(C, name="_wrap_FCVodeGetLinReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +function swigc_FCVodeSetLinearSolverB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeSetLinearSolverB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetJacFnB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetJacFnB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetJacFnBS(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetJacFnBS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetEpsLinB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetEpsLinB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetLinearSolutionScalingB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetLinearSolutionScalingB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetPreconditionerB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeSetPreconditionerB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetPreconditionerBS(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeSetPreconditionerBS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetJacTimesB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeSetJacTimesB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetJacTimesBS(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FCVodeSetJacTimesBS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetLinSysFnB(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetLinSysFnB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FCVodeSetLinSysFnBS(farg1, farg2, farg3) & +bind(C, name="_wrap_FCVodeSetLinSysFnBS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FCVodeCreate(lmm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: lmm +type(C_PTR) :: fresult +integer(C_INT) :: farg1 + +farg1 = lmm +fresult = swigc_FCVodeCreate(farg1) +swig_result = fresult +end function + +function FCVodeInit(cvode_mem, f, t0, y0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: f +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: y0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = f +farg3 = t0 +farg4 = c_loc(y0) +fresult = swigc_FCVodeInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeReInit(cvode_mem, t0, y0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: y0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = t0 +farg3 = c_loc(y0) +fresult = swigc_FCVodeReInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSStolerances(cvode_mem, reltol, abstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: reltol +real(C_DOUBLE), intent(in) :: abstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = cvode_mem +farg2 = reltol +farg3 = abstol +fresult = swigc_FCVodeSStolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSVtolerances(cvode_mem, reltol, abstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: reltol +type(N_Vector), target, intent(inout) :: abstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = reltol +farg3 = c_loc(abstol) +fresult = swigc_FCVodeSVtolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeWFtolerances(cvode_mem, efun) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: efun +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = cvode_mem +farg2 = efun +fresult = swigc_FCVodeWFtolerances(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetErrHandlerFn(cvode_mem, ehfun, eh_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: ehfun +type(C_PTR) :: eh_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = ehfun +farg3 = eh_data +fresult = swigc_FCVodeSetErrHandlerFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetErrFile(cvode_mem, errfp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_PTR) :: errfp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = errfp +fresult = swigc_FCVodeSetErrFile(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetUserData(cvode_mem, user_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_PTR) :: user_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = user_data +fresult = swigc_FCVodeSetUserData(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxOrd(cvode_mem, maxord) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: maxord +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = maxord +fresult = swigc_FCVodeSetMaxOrd(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxNumSteps(cvode_mem, mxsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), intent(in) :: mxsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = cvode_mem +farg2 = mxsteps +fresult = swigc_FCVodeSetMaxNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxHnilWarns(cvode_mem, mxhnil) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: mxhnil +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = mxhnil +fresult = swigc_FCVodeSetMaxHnilWarns(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetStabLimDet(cvode_mem, stldet) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: stldet +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = stldet +fresult = swigc_FCVodeSetStabLimDet(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetInitStep(cvode_mem, hin) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: hin +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = cvode_mem +farg2 = hin +fresult = swigc_FCVodeSetInitStep(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMinStep(cvode_mem, hmin) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: hmin +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = cvode_mem +farg2 = hmin +fresult = swigc_FCVodeSetMinStep(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxStep(cvode_mem, hmax) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: hmax +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = cvode_mem +farg2 = hmax +fresult = swigc_FCVodeSetMaxStep(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetStopTime(cvode_mem, tstop) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: tstop +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = cvode_mem +farg2 = tstop +fresult = swigc_FCVodeSetStopTime(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxErrTestFails(cvode_mem, maxnef) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: maxnef +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = maxnef +fresult = swigc_FCVodeSetMaxErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxNonlinIters(cvode_mem, maxcor) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: maxcor +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = maxcor +fresult = swigc_FCVodeSetMaxNonlinIters(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxConvFails(cvode_mem, maxncf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: maxncf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = maxncf +fresult = swigc_FCVodeSetMaxConvFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetNonlinConvCoef(cvode_mem, nlscoef) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: nlscoef +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = cvode_mem +farg2 = nlscoef +fresult = swigc_FCVodeSetNonlinConvCoef(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetConstraints(cvode_mem, constraints) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(N_Vector), target, intent(inout) :: constraints +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(constraints) +fresult = swigc_FCVodeSetConstraints(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetNonlinearSolver(cvode_mem, nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nls) +fresult = swigc_FCVodeSetNonlinearSolver(farg1, farg2) +swig_result = fresult +end function + +function FCVodeRootInit(cvode_mem, nrtfn, g) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: nrtfn +type(C_FUNPTR), intent(in), value :: g +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = cvode_mem +farg2 = nrtfn +farg3 = g +fresult = swigc_FCVodeRootInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetRootDirection(cvode_mem, rootdir) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootdir +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(rootdir(1)) +fresult = swigc_FCVodeSetRootDirection(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetNoInactiveRootWarn(cvode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = cvode_mem +fresult = swigc_FCVodeSetNoInactiveRootWarn(farg1) +swig_result = fresult +end function + +function FCVode(cvode_mem, tout, yout, tret, itask) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: tout +type(N_Vector), target, intent(inout) :: yout +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +integer(C_INT), intent(in) :: itask +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +integer(C_INT) :: farg5 + +farg1 = cvode_mem +farg2 = tout +farg3 = c_loc(yout) +farg4 = c_loc(tret(1)) +farg5 = itask +fresult = swigc_FCVode(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVodeGetDky(cvode_mem, t, k, dky) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(N_Vector), target, intent(inout) :: dky +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = t +farg3 = k +farg4 = c_loc(dky) +fresult = swigc_FCVodeGetDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeGetWorkSpace(cvode_mem, lenrw, leniw) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrw +integer(C_LONG), dimension(*), target, intent(inout) :: leniw +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(lenrw(1)) +farg3 = c_loc(leniw(1)) +fresult = swigc_FCVodeGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeGetNumSteps(cvode_mem, nsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nsteps(1)) +fresult = swigc_FCVodeGetNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumRhsEvals(cvode_mem, nfevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nfevals(1)) +fresult = swigc_FCVodeGetNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumLinSolvSetups(cvode_mem, nlinsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nlinsetups(1)) +fresult = swigc_FCVodeGetNumLinSolvSetups(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumErrTestFails(cvode_mem, netfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: netfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(netfails(1)) +fresult = swigc_FCVodeGetNumErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetLastOrder(cvode_mem, qlast) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), dimension(*), target, intent(inout) :: qlast +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(qlast(1)) +fresult = swigc_FCVodeGetLastOrder(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetCurrentOrder(cvode_mem, qcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), dimension(*), target, intent(inout) :: qcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(qcur(1)) +fresult = swigc_FCVodeGetCurrentOrder(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetCurrentGamma(cvode_mem, gamma) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: gamma +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(gamma(1)) +fresult = swigc_FCVodeGetCurrentGamma(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumStabLimOrderReds(cvode_mem, nslred) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nslred +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nslred(1)) +fresult = swigc_FCVodeGetNumStabLimOrderReds(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetActualInitStep(cvode_mem, hinused) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hinused +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(hinused(1)) +fresult = swigc_FCVodeGetActualInitStep(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetLastStep(cvode_mem, hlast) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(hlast(1)) +fresult = swigc_FCVodeGetLastStep(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetCurrentStep(cvode_mem, hcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(hcur(1)) +fresult = swigc_FCVodeGetCurrentStep(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetCurrentState(cvode_mem, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_PTR) :: y +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = y +fresult = swigc_FCVodeGetCurrentState(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetCurrentStateSens(cvode_mem, ys) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_PTR), target, intent(inout) :: ys +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(ys) +fresult = swigc_FCVodeGetCurrentStateSens(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetCurrentSensSolveIndex(cvode_mem, index) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), dimension(*), target, intent(inout) :: index +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(index(1)) +fresult = swigc_FCVodeGetCurrentSensSolveIndex(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetCurrentTime(cvode_mem, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(tcur(1)) +fresult = swigc_FCVodeGetCurrentTime(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetTolScaleFactor(cvode_mem, tolsfac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tolsfac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(tolsfac(1)) +fresult = swigc_FCVodeGetTolScaleFactor(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetErrWeights(cvode_mem, eweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(N_Vector), target, intent(inout) :: eweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(eweight) +fresult = swigc_FCVodeGetErrWeights(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetEstLocalErrors(cvode_mem, ele) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(N_Vector), target, intent(inout) :: ele +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(ele) +fresult = swigc_FCVodeGetEstLocalErrors(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumGEvals(cvode_mem, ngevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(ngevals(1)) +fresult = swigc_FCVodeGetNumGEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetRootInfo(cvode_mem, rootsfound) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootsfound +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(rootsfound(1)) +fresult = swigc_FCVodeGetRootInfo(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetIntegratorStats(cvode_mem, nsteps, nfevals, nlinsetups, netfails, qlast, qcur, hinused, hlast, hcur, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsteps +integer(C_LONG), dimension(*), target, intent(inout) :: nfevals +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetups +integer(C_LONG), dimension(*), target, intent(inout) :: netfails +integer(C_INT), dimension(*), target, intent(inout) :: qlast +integer(C_INT), dimension(*), target, intent(inout) :: qcur +real(C_DOUBLE), dimension(*), target, intent(inout) :: hinused +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +real(C_DOUBLE), dimension(*), target, intent(inout) :: hcur +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 +type(C_PTR) :: farg7 +type(C_PTR) :: farg8 +type(C_PTR) :: farg9 +type(C_PTR) :: farg10 +type(C_PTR) :: farg11 + +farg1 = cvode_mem +farg2 = c_loc(nsteps(1)) +farg3 = c_loc(nfevals(1)) +farg4 = c_loc(nlinsetups(1)) +farg5 = c_loc(netfails(1)) +farg6 = c_loc(qlast(1)) +farg7 = c_loc(qcur(1)) +farg8 = c_loc(hinused(1)) +farg9 = c_loc(hlast(1)) +farg10 = c_loc(hcur(1)) +farg11 = c_loc(tcur(1)) +fresult = swigc_FCVodeGetIntegratorStats(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10, farg11) +swig_result = fresult +end function + +function FCVodeGetNumNonlinSolvIters(cvode_mem, nniters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nniters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nniters(1)) +fresult = swigc_FCVodeGetNumNonlinSolvIters(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumNonlinSolvConvFails(cvode_mem, nncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nncfails(1)) +fresult = swigc_FCVodeGetNumNonlinSolvConvFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNonlinSolvStats(cvode_mem, nniters, nncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nniters +integer(C_LONG), dimension(*), target, intent(inout) :: nncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(nniters(1)) +farg3 = c_loc(nncfails(1)) +fresult = swigc_FCVodeGetNonlinSolvStats(farg1, farg2, farg3) +swig_result = fresult +end function + + +subroutine SWIG_chararray_to_string(wrap, string) + use, intrinsic :: ISO_C_BINDING + type(SwigArrayWrapper), intent(IN) :: wrap + character(kind=C_CHAR, len=:), allocatable, intent(OUT) :: string + character(kind=C_CHAR), dimension(:), pointer :: chars + integer(kind=C_SIZE_T) :: i + call c_f_pointer(wrap%data, chars, [wrap%size]) + allocate(character(kind=C_CHAR, len=wrap%size) :: string) + do i=1, wrap%size + string(i:i) = chars(i) + end do +end subroutine + +function FCVodeGetReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FCVodeGetReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +subroutine FCVodeFree(cvode_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), target, intent(inout) :: cvode_mem +type(C_PTR) :: farg1 + +farg1 = c_loc(cvode_mem) +call swigc_FCVodeFree(farg1) +end subroutine + +function FCVodeQuadInit(cvode_mem, fq, yq0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: fq +type(N_Vector), target, intent(inout) :: yq0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = fq +farg3 = c_loc(yq0) +fresult = swigc_FCVodeQuadInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeQuadReInit(cvode_mem, yq0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(N_Vector), target, intent(inout) :: yq0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(yq0) +fresult = swigc_FCVodeQuadReInit(farg1, farg2) +swig_result = fresult +end function + +function FCVodeQuadSStolerances(cvode_mem, reltolq, abstolq) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: reltolq +real(C_DOUBLE), intent(in) :: abstolq +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = cvode_mem +farg2 = reltolq +farg3 = abstolq +fresult = swigc_FCVodeQuadSStolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeQuadSVtolerances(cvode_mem, reltolq, abstolq) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: reltolq +type(N_Vector), target, intent(inout) :: abstolq +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = reltolq +farg3 = c_loc(abstolq) +fresult = swigc_FCVodeQuadSVtolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetQuadErrCon(cvode_mem, errconq) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: errconq +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = errconq +fresult = swigc_FCVodeSetQuadErrCon(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetQuad(cvode_mem, tret, yqout) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +type(N_Vector), target, intent(inout) :: yqout +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(tret(1)) +farg3 = c_loc(yqout) +fresult = swigc_FCVodeGetQuad(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeGetQuadDky(cvode_mem, t, k, dky) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(N_Vector), target, intent(inout) :: dky +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = t +farg3 = k +farg4 = c_loc(dky) +fresult = swigc_FCVodeGetQuadDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeGetQuadNumRhsEvals(cvode_mem, nfqevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfqevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nfqevals(1)) +fresult = swigc_FCVodeGetQuadNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetQuadNumErrTestFails(cvode_mem, nqetfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nqetfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nqetfails(1)) +fresult = swigc_FCVodeGetQuadNumErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetQuadErrWeights(cvode_mem, eqweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(N_Vector), target, intent(inout) :: eqweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(eqweight) +fresult = swigc_FCVodeGetQuadErrWeights(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetQuadStats(cvode_mem, nfqevals, nqetfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfqevals +integer(C_LONG), dimension(*), target, intent(inout) :: nqetfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(nfqevals(1)) +farg3 = c_loc(nqetfails(1)) +fresult = swigc_FCVodeGetQuadStats(farg1, farg2, farg3) +swig_result = fresult +end function + +subroutine FCVodeQuadFree(cvode_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: cvode_mem +type(C_PTR) :: farg1 + +farg1 = cvode_mem +call swigc_FCVodeQuadFree(farg1) +end subroutine + +function FCVodeSensInit(cvode_mem, ns, ism, fs, ys0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: ns +integer(C_INT), intent(in) :: ism +type(C_FUNPTR), intent(in), value :: fs +type(C_PTR) :: ys0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 +type(C_FUNPTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = cvode_mem +farg2 = ns +farg3 = ism +farg4 = fs +farg5 = ys0 +fresult = swigc_FCVodeSensInit(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVodeSensInit1(cvode_mem, ns, ism, fs1, ys0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: ns +integer(C_INT), intent(in) :: ism +type(C_FUNPTR), intent(in), value :: fs1 +type(C_PTR) :: ys0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 +type(C_FUNPTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = cvode_mem +farg2 = ns +farg3 = ism +farg4 = fs1 +farg5 = ys0 +fresult = swigc_FCVodeSensInit1(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVodeSensReInit(cvode_mem, ism, ys0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: ism +type(C_PTR) :: ys0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = ism +farg3 = ys0 +fresult = swigc_FCVodeSensReInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSensSStolerances(cvode_mem, reltols, abstols) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: reltols +real(C_DOUBLE), dimension(*), target, intent(inout) :: abstols +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = reltols +farg3 = c_loc(abstols(1)) +fresult = swigc_FCVodeSensSStolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSensSVtolerances(cvode_mem, reltols, abstols) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: reltols +type(C_PTR) :: abstols +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = reltols +farg3 = abstols +fresult = swigc_FCVodeSensSVtolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSensEEtolerances(cvode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = cvode_mem +fresult = swigc_FCVodeSensEEtolerances(farg1) +swig_result = fresult +end function + +function FCVodeSetSensDQMethod(cvode_mem, dqtype, dqrhomax) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: dqtype +real(C_DOUBLE), intent(in) :: dqrhomax +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = cvode_mem +farg2 = dqtype +farg3 = dqrhomax +fresult = swigc_FCVodeSetSensDQMethod(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetSensErrCon(cvode_mem, errcons) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: errcons +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = errcons +fresult = swigc_FCVodeSetSensErrCon(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetSensMaxNonlinIters(cvode_mem, maxcors) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: maxcors +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = maxcors +fresult = swigc_FCVodeSetSensMaxNonlinIters(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetSensParams(cvode_mem, p, pbar, plist) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: p +real(C_DOUBLE), dimension(*), target, intent(inout) :: pbar +integer(C_INT), dimension(*), target, intent(inout) :: plist +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = c_loc(p(1)) +farg3 = c_loc(pbar(1)) +farg4 = c_loc(plist(1)) +fresult = swigc_FCVodeSetSensParams(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeSetNonlinearSolverSensSim(cvode_mem, nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nls) +fresult = swigc_FCVodeSetNonlinearSolverSensSim(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetNonlinearSolverSensStg(cvode_mem, nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nls) +fresult = swigc_FCVodeSetNonlinearSolverSensStg(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetNonlinearSolverSensStg1(cvode_mem, nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nls) +fresult = swigc_FCVodeSetNonlinearSolverSensStg1(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSensToggleOff(cvode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = cvode_mem +fresult = swigc_FCVodeSensToggleOff(farg1) +swig_result = fresult +end function + +function FCVodeGetSens(cvode_mem, tret, ysout) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +type(C_PTR) :: ysout +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(tret(1)) +farg3 = ysout +fresult = swigc_FCVodeGetSens(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeGetSens1(cvode_mem, tret, is, ysout) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +integer(C_INT), intent(in) :: is +type(N_Vector), target, intent(inout) :: ysout +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = c_loc(tret(1)) +farg3 = is +farg4 = c_loc(ysout) +fresult = swigc_FCVodeGetSens1(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeGetSensDky(cvode_mem, t, k, dkya) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(C_PTR) :: dkya +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = t +farg3 = k +farg4 = dkya +fresult = swigc_FCVodeGetSensDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeGetSensDky1(cvode_mem, t, k, is, dky) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +integer(C_INT), intent(in) :: is +type(N_Vector), target, intent(inout) :: dky +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +integer(C_INT) :: farg4 +type(C_PTR) :: farg5 + +farg1 = cvode_mem +farg2 = t +farg3 = k +farg4 = is +farg5 = c_loc(dky) +fresult = swigc_FCVodeGetSensDky1(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVodeGetSensNumRhsEvals(cvode_mem, nfsevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfsevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nfsevals(1)) +fresult = swigc_FCVodeGetSensNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumRhsEvalsSens(cvode_mem, nfevalss) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevalss +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nfevalss(1)) +fresult = swigc_FCVodeGetNumRhsEvalsSens(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetSensNumErrTestFails(cvode_mem, nsetfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsetfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nsetfails(1)) +fresult = swigc_FCVodeGetSensNumErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetSensNumLinSolvSetups(cvode_mem, nlinsetupss) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetupss +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nlinsetupss(1)) +fresult = swigc_FCVodeGetSensNumLinSolvSetups(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetSensErrWeights(cvode_mem, esweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_PTR) :: esweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = esweight +fresult = swigc_FCVodeGetSensErrWeights(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetSensStats(cvode_mem, nfsevals, nfevalss, nsetfails, nlinsetupss) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfsevals +integer(C_LONG), dimension(*), target, intent(inout) :: nfevalss +integer(C_LONG), dimension(*), target, intent(inout) :: nsetfails +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetupss +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = cvode_mem +farg2 = c_loc(nfsevals(1)) +farg3 = c_loc(nfevalss(1)) +farg4 = c_loc(nsetfails(1)) +farg5 = c_loc(nlinsetupss(1)) +fresult = swigc_FCVodeGetSensStats(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVodeGetSensNumNonlinSolvIters(cvode_mem, nsniters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsniters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nsniters(1)) +fresult = swigc_FCVodeGetSensNumNonlinSolvIters(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetSensNumNonlinSolvConvFails(cvode_mem, nsncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nsncfails(1)) +fresult = swigc_FCVodeGetSensNumNonlinSolvConvFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetStgrSensNumNonlinSolvIters(cvode_mem, nstgr1niters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nstgr1niters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nstgr1niters(1)) +fresult = swigc_FCVodeGetStgrSensNumNonlinSolvIters(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetStgrSensNumNonlinSolvConvFails(cvode_mem, nstgr1ncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nstgr1ncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nstgr1ncfails(1)) +fresult = swigc_FCVodeGetStgrSensNumNonlinSolvConvFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetSensNonlinSolvStats(cvode_mem, nsniters, nsncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsniters +integer(C_LONG), dimension(*), target, intent(inout) :: nsncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(nsniters(1)) +farg3 = c_loc(nsncfails(1)) +fresult = swigc_FCVodeGetSensNonlinSolvStats(farg1, farg2, farg3) +swig_result = fresult +end function + +subroutine FCVodeSensFree(cvode_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: cvode_mem +type(C_PTR) :: farg1 + +farg1 = cvode_mem +call swigc_FCVodeSensFree(farg1) +end subroutine + +function FCVodeQuadSensInit(cvode_mem, fqs, yqs0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: fqs +type(C_PTR) :: yqs0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = fqs +farg3 = yqs0 +fresult = swigc_FCVodeQuadSensInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeQuadSensReInit(cvode_mem, yqs0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_PTR) :: yqs0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = yqs0 +fresult = swigc_FCVodeQuadSensReInit(farg1, farg2) +swig_result = fresult +end function + +function FCVodeQuadSensSStolerances(cvode_mem, reltolqs, abstolqs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: reltolqs +real(C_DOUBLE), dimension(*), target, intent(inout) :: abstolqs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = reltolqs +farg3 = c_loc(abstolqs(1)) +fresult = swigc_FCVodeQuadSensSStolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeQuadSensSVtolerances(cvode_mem, reltolqs, abstolqs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: reltolqs +type(C_PTR) :: abstolqs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = reltolqs +farg3 = abstolqs +fresult = swigc_FCVodeQuadSensSVtolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeQuadSensEEtolerances(cvode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = cvode_mem +fresult = swigc_FCVodeQuadSensEEtolerances(farg1) +swig_result = fresult +end function + +function FCVodeSetQuadSensErrCon(cvode_mem, errconqs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: errconqs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = errconqs +fresult = swigc_FCVodeSetQuadSensErrCon(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetQuadSens(cvode_mem, tret, yqsout) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +type(C_PTR) :: yqsout +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(tret(1)) +farg3 = yqsout +fresult = swigc_FCVodeGetQuadSens(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeGetQuadSens1(cvode_mem, tret, is, yqsout) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +integer(C_INT), intent(in) :: is +type(N_Vector), target, intent(inout) :: yqsout +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = c_loc(tret(1)) +farg3 = is +farg4 = c_loc(yqsout) +fresult = swigc_FCVodeGetQuadSens1(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeGetQuadSensDky(cvode_mem, t, k, dkyqs_all) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(C_PTR) :: dkyqs_all +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = t +farg3 = k +farg4 = dkyqs_all +fresult = swigc_FCVodeGetQuadSensDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeGetQuadSensDky1(cvode_mem, t, k, is, dkyqs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +integer(C_INT), intent(in) :: is +type(N_Vector), target, intent(inout) :: dkyqs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +integer(C_INT) :: farg4 +type(C_PTR) :: farg5 + +farg1 = cvode_mem +farg2 = t +farg3 = k +farg4 = is +farg5 = c_loc(dkyqs) +fresult = swigc_FCVodeGetQuadSensDky1(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVodeGetQuadSensNumRhsEvals(cvode_mem, nfqsevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfqsevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nfqsevals(1)) +fresult = swigc_FCVodeGetQuadSensNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetQuadSensNumErrTestFails(cvode_mem, nqsetfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nqsetfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nqsetfails(1)) +fresult = swigc_FCVodeGetQuadSensNumErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetQuadSensErrWeights(cvode_mem, eqsweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_PTR) :: eqsweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = eqsweight +fresult = swigc_FCVodeGetQuadSensErrWeights(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetQuadSensStats(cvode_mem, nfqsevals, nqsetfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfqsevals +integer(C_LONG), dimension(*), target, intent(inout) :: nqsetfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(nfqsevals(1)) +farg3 = c_loc(nqsetfails(1)) +fresult = swigc_FCVodeGetQuadSensStats(farg1, farg2, farg3) +swig_result = fresult +end function + +subroutine FCVodeQuadSensFree(cvode_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: cvode_mem +type(C_PTR) :: farg1 + +farg1 = cvode_mem +call swigc_FCVodeQuadSensFree(farg1) +end subroutine + +function FCVodeAdjInit(cvode_mem, steps, interp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), intent(in) :: steps +integer(C_INT), intent(in) :: interp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 +integer(C_INT) :: farg3 + +farg1 = cvode_mem +farg2 = steps +farg3 = interp +fresult = swigc_FCVodeAdjInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeAdjReInit(cvode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = cvode_mem +fresult = swigc_FCVodeAdjReInit(farg1) +swig_result = fresult +end function + +subroutine FCVodeAdjFree(cvode_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: cvode_mem +type(C_PTR) :: farg1 + +farg1 = cvode_mem +call swigc_FCVodeAdjFree(farg1) +end subroutine + +function FCVodeCreateB(cvode_mem, lmmb, which) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: lmmb +integer(C_INT), dimension(*), target, intent(inout) :: which +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = lmmb +farg3 = c_loc(which(1)) +fresult = swigc_FCVodeCreateB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeInitB(cvode_mem, which, fb, tb0, yb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: fb +real(C_DOUBLE), intent(in) :: tb0 +type(N_Vector), target, intent(inout) :: yb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_PTR) :: farg5 + +farg1 = cvode_mem +farg2 = which +farg3 = fb +farg4 = tb0 +farg5 = c_loc(yb0) +fresult = swigc_FCVodeInitB(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVodeInitBS(cvode_mem, which, fbs, tb0, yb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: fbs +real(C_DOUBLE), intent(in) :: tb0 +type(N_Vector), target, intent(inout) :: yb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_PTR) :: farg5 + +farg1 = cvode_mem +farg2 = which +farg3 = fbs +farg4 = tb0 +farg5 = c_loc(yb0) +fresult = swigc_FCVodeInitBS(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVodeReInitB(cvode_mem, which, tb0, yb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: tb0 +type(N_Vector), target, intent(inout) :: yb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = tb0 +farg4 = c_loc(yb0) +fresult = swigc_FCVodeReInitB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeSStolerancesB(cvode_mem, which, reltolb, abstolb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: reltolb +real(C_DOUBLE), intent(in) :: abstolb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 +real(C_DOUBLE) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = reltolb +farg4 = abstolb +fresult = swigc_FCVodeSStolerancesB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeSVtolerancesB(cvode_mem, which, reltolb, abstolb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: reltolb +type(N_Vector), target, intent(inout) :: abstolb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = reltolb +farg4 = c_loc(abstolb) +fresult = swigc_FCVodeSVtolerancesB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeQuadInitB(cvode_mem, which, fqb, yqb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: fqb +type(N_Vector), target, intent(inout) :: yqb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = fqb +farg4 = c_loc(yqb0) +fresult = swigc_FCVodeQuadInitB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeQuadInitBS(cvode_mem, which, fqbs, yqb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: fqbs +type(N_Vector), target, intent(inout) :: yqb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = fqbs +farg4 = c_loc(yqb0) +fresult = swigc_FCVodeQuadInitBS(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeQuadReInitB(cvode_mem, which, yqb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(N_Vector), target, intent(inout) :: yqb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = c_loc(yqb0) +fresult = swigc_FCVodeQuadReInitB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeQuadSStolerancesB(cvode_mem, which, reltolqb, abstolqb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: reltolqb +real(C_DOUBLE), intent(in) :: abstolqb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 +real(C_DOUBLE) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = reltolqb +farg4 = abstolqb +fresult = swigc_FCVodeQuadSStolerancesB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeQuadSVtolerancesB(cvode_mem, which, reltolqb, abstolqb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: reltolqb +type(N_Vector), target, intent(inout) :: abstolqb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = reltolqb +farg4 = c_loc(abstolqb) +fresult = swigc_FCVodeQuadSVtolerancesB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeF(cvode_mem, tout, yout, tret, itask, ncheckptr) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: tout +type(N_Vector), target, intent(inout) :: yout +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +integer(C_INT), intent(in) :: itask +integer(C_INT), dimension(*), target, intent(inout) :: ncheckptr +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +integer(C_INT) :: farg5 +type(C_PTR) :: farg6 + +farg1 = cvode_mem +farg2 = tout +farg3 = c_loc(yout) +farg4 = c_loc(tret(1)) +farg5 = itask +farg6 = c_loc(ncheckptr(1)) +fresult = swigc_FCVodeF(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FCVodeB(cvode_mem, tbout, itaskb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: tbout +integer(C_INT), intent(in) :: itaskb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 + +farg1 = cvode_mem +farg2 = tbout +farg3 = itaskb +fresult = swigc_FCVodeB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetAdjNoSensi(cvode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = cvode_mem +fresult = swigc_FCVodeSetAdjNoSensi(farg1) +swig_result = fresult +end function + +function FCVodeSetUserDataB(cvode_mem, which, user_datab) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_PTR) :: user_datab +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = user_datab +fresult = swigc_FCVodeSetUserDataB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetMaxOrdB(cvode_mem, which, maxordb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +integer(C_INT), intent(in) :: maxordb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = maxordb +fresult = swigc_FCVodeSetMaxOrdB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetMaxNumStepsB(cvode_mem, which, mxstepsb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +integer(C_LONG), intent(in) :: mxstepsb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_LONG) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = mxstepsb +fresult = swigc_FCVodeSetMaxNumStepsB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetStabLimDetB(cvode_mem, which, stldetb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +integer(C_INT), intent(in) :: stldetb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = stldetb +fresult = swigc_FCVodeSetStabLimDetB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetInitStepB(cvode_mem, which, hinb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: hinb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = hinb +fresult = swigc_FCVodeSetInitStepB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetMinStepB(cvode_mem, which, hminb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: hminb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = hminb +fresult = swigc_FCVodeSetMinStepB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetMaxStepB(cvode_mem, which, hmaxb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: hmaxb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = hmaxb +fresult = swigc_FCVodeSetMaxStepB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetConstraintsB(cvode_mem, which, constraintsb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(N_Vector), target, intent(inout) :: constraintsb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = c_loc(constraintsb) +fresult = swigc_FCVodeSetConstraintsB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetQuadErrConB(cvode_mem, which, errconqb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +integer(C_INT), intent(in) :: errconqb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = errconqb +fresult = swigc_FCVodeSetQuadErrConB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetNonlinearSolverB(cvode_mem, which, nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = c_loc(nls) +fresult = swigc_FCVodeSetNonlinearSolverB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeGetB(cvode_mem, which, tbret, yb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), dimension(*), target, intent(inout) :: tbret +type(N_Vector), target, intent(inout) :: yb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = c_loc(tbret(1)) +farg4 = c_loc(yb) +fresult = swigc_FCVodeGetB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeGetQuadB(cvode_mem, which, tbret, qb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), dimension(*), target, intent(inout) :: tbret +type(N_Vector), target, intent(inout) :: qb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = c_loc(tbret(1)) +farg4 = c_loc(qb) +fresult = swigc_FCVodeGetQuadB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeGetAdjCVodeBmem(cvode_mem, which) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = which +fresult = swigc_FCVodeGetAdjCVodeBmem(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetAdjY(cvode_mem, t, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: t +type(N_Vector), target, intent(inout) :: y +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = t +farg3 = c_loc(y) +fresult = swigc_FCVodeGetAdjY(farg1, farg2, farg3) +swig_result = fresult +end function + +subroutine swigf_CVadjCheckPointRec_my_addr_set(self, my_addr) +use, intrinsic :: ISO_C_BINDING +class(CVadjCheckPointRec), intent(in) :: self +type(C_PTR) :: my_addr +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: farg2 + +farg1 = self%swigdata +farg2 = my_addr +call swigc_CVadjCheckPointRec_my_addr_set(farg1, farg2) +end subroutine + +function swigf_CVadjCheckPointRec_my_addr_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +class(CVadjCheckPointRec), intent(in) :: self +type(C_PTR) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_CVadjCheckPointRec_my_addr_get(farg1) +swig_result = fresult +end function + +subroutine swigf_CVadjCheckPointRec_next_addr_set(self, next_addr) +use, intrinsic :: ISO_C_BINDING +class(CVadjCheckPointRec), intent(in) :: self +type(C_PTR) :: next_addr +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: farg2 + +farg1 = self%swigdata +farg2 = next_addr +call swigc_CVadjCheckPointRec_next_addr_set(farg1, farg2) +end subroutine + +function swigf_CVadjCheckPointRec_next_addr_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +class(CVadjCheckPointRec), intent(in) :: self +type(C_PTR) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_CVadjCheckPointRec_next_addr_get(farg1) +swig_result = fresult +end function + +subroutine swigf_CVadjCheckPointRec_t0_set(self, t0) +use, intrinsic :: ISO_C_BINDING +class(CVadjCheckPointRec), intent(in) :: self +real(C_DOUBLE), intent(in) :: t0 +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = self%swigdata +farg2 = t0 +call swigc_CVadjCheckPointRec_t0_set(farg1, farg2) +end subroutine + +function swigf_CVadjCheckPointRec_t0_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +class(CVadjCheckPointRec), intent(in) :: self +real(C_DOUBLE) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_CVadjCheckPointRec_t0_get(farg1) +swig_result = fresult +end function + +subroutine swigf_CVadjCheckPointRec_t1_set(self, t1) +use, intrinsic :: ISO_C_BINDING +class(CVadjCheckPointRec), intent(in) :: self +real(C_DOUBLE), intent(in) :: t1 +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = self%swigdata +farg2 = t1 +call swigc_CVadjCheckPointRec_t1_set(farg1, farg2) +end subroutine + +function swigf_CVadjCheckPointRec_t1_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +class(CVadjCheckPointRec), intent(in) :: self +real(C_DOUBLE) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_CVadjCheckPointRec_t1_get(farg1) +swig_result = fresult +end function + +subroutine swigf_CVadjCheckPointRec_nstep_set(self, nstep) +use, intrinsic :: ISO_C_BINDING +class(CVadjCheckPointRec), intent(in) :: self +integer(C_LONG), intent(in) :: nstep +type(SwigClassWrapper) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = self%swigdata +farg2 = nstep +call swigc_CVadjCheckPointRec_nstep_set(farg1, farg2) +end subroutine + +function swigf_CVadjCheckPointRec_nstep_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_LONG) :: swig_result +class(CVadjCheckPointRec), intent(in) :: self +integer(C_LONG) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_CVadjCheckPointRec_nstep_get(farg1) +swig_result = fresult +end function + +subroutine swigf_CVadjCheckPointRec_order_set(self, order) +use, intrinsic :: ISO_C_BINDING +class(CVadjCheckPointRec), intent(in) :: self +integer(C_INT), intent(in) :: order +type(SwigClassWrapper) :: farg1 +integer(C_INT) :: farg2 + +farg1 = self%swigdata +farg2 = order +call swigc_CVadjCheckPointRec_order_set(farg1, farg2) +end subroutine + +function swigf_CVadjCheckPointRec_order_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +class(CVadjCheckPointRec), intent(in) :: self +integer(C_INT) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_CVadjCheckPointRec_order_get(farg1) +swig_result = fresult +end function + +subroutine swigf_CVadjCheckPointRec_step_set(self, step) +use, intrinsic :: ISO_C_BINDING +class(CVadjCheckPointRec), intent(in) :: self +real(C_DOUBLE), intent(in) :: step +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = self%swigdata +farg2 = step +call swigc_CVadjCheckPointRec_step_set(farg1, farg2) +end subroutine + +function swigf_CVadjCheckPointRec_step_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +class(CVadjCheckPointRec), intent(in) :: self +real(C_DOUBLE) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_CVadjCheckPointRec_step_get(farg1) +swig_result = fresult +end function + +function swigf_create_CVadjCheckPointRec() & +result(self) +use, intrinsic :: ISO_C_BINDING +type(CVadjCheckPointRec) :: self +type(SwigClassWrapper) :: fresult + +fresult = swigc_new_CVadjCheckPointRec() +self%swigdata = fresult +end function + +subroutine swigf_release_CVadjCheckPointRec(self) +use, intrinsic :: ISO_C_BINDING +class(CVadjCheckPointRec), intent(inout) :: self +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +if (btest(farg1%cmemflags, swig_cmem_own_bit)) then +call swigc_delete_CVadjCheckPointRec(farg1) +endif +farg1%cptr = C_NULL_PTR +farg1%cmemflags = 0 +self%swigdata = farg1 +end subroutine + +subroutine swigf_CVadjCheckPointRec_op_assign__(self, other) +use, intrinsic :: ISO_C_BINDING +class(CVadjCheckPointRec), intent(inout) :: self +type(CVadjCheckPointRec), intent(in) :: other +type(SwigClassWrapper) :: farg1 +type(SwigClassWrapper) :: farg2 + +farg1 = self%swigdata +farg2 = other%swigdata +call swigc_CVadjCheckPointRec_op_assign__(farg1, farg2) +self%swigdata = farg1 +end subroutine + +function FCVodeGetAdjCheckPointsInfo(cvode_mem, ckpnt) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +class(CVadjCheckPointRec), intent(in) :: ckpnt +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(SwigClassWrapper) :: farg2 + +farg1 = cvode_mem +farg2 = ckpnt%swigdata +fresult = swigc_FCVodeGetAdjCheckPointsInfo(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetAdjDataPointHermite(cvode_mem, which, t, y, yd) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), dimension(*), target, intent(inout) :: t +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: yd +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = cvode_mem +farg2 = which +farg3 = c_loc(t(1)) +farg4 = c_loc(y) +farg5 = c_loc(yd) +fresult = swigc_FCVodeGetAdjDataPointHermite(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVodeGetAdjDataPointPolynomial(cvode_mem, which, t, order, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), dimension(*), target, intent(inout) :: t +integer(C_INT), dimension(*), target, intent(inout) :: order +type(N_Vector), target, intent(inout) :: y +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = cvode_mem +farg2 = which +farg3 = c_loc(t(1)) +farg4 = c_loc(order(1)) +farg5 = c_loc(y) +fresult = swigc_FCVodeGetAdjDataPointPolynomial(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVodeGetAdjCurrentCheckPoint(cvode_mem, addr) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_PTR), target, intent(inout) :: addr +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(addr) +fresult = swigc_FCVodeGetAdjCurrentCheckPoint(farg1, farg2) +swig_result = fresult +end function + +function FCVBandPrecInit(cvode_mem, n, mu, ml) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT64_T), intent(in) :: n +integer(C_INT64_T), intent(in) :: mu +integer(C_INT64_T), intent(in) :: ml +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 + +farg1 = cvode_mem +farg2 = n +farg3 = mu +farg4 = ml +fresult = swigc_FCVBandPrecInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVBandPrecGetWorkSpace(cvode_mem, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FCVBandPrecGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVBandPrecGetNumRhsEvals(cvode_mem, nfevalsbp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevalsbp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nfevalsbp(1)) +fresult = swigc_FCVBandPrecGetNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVBandPrecInitB(cvode_mem, which, nb, mub, mlb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +integer(C_INT64_T), intent(in) :: nb +integer(C_INT64_T), intent(in) :: mub +integer(C_INT64_T), intent(in) :: mlb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 +integer(C_INT64_T) :: farg5 + +farg1 = cvode_mem +farg2 = which +farg3 = nb +farg4 = mub +farg5 = mlb +fresult = swigc_FCVBandPrecInitB(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVBBDPrecInit(cvode_mem, nlocal, mudq, mldq, mukeep, mlkeep, dqrely, gloc, cfn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT64_T), intent(in) :: nlocal +integer(C_INT64_T), intent(in) :: mudq +integer(C_INT64_T), intent(in) :: mldq +integer(C_INT64_T), intent(in) :: mukeep +integer(C_INT64_T), intent(in) :: mlkeep +real(C_DOUBLE), intent(in) :: dqrely +type(C_FUNPTR), intent(in), value :: gloc +type(C_FUNPTR), intent(in), value :: cfn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 +integer(C_INT64_T) :: farg5 +integer(C_INT64_T) :: farg6 +real(C_DOUBLE) :: farg7 +type(C_FUNPTR) :: farg8 +type(C_FUNPTR) :: farg9 + +farg1 = cvode_mem +farg2 = nlocal +farg3 = mudq +farg4 = mldq +farg5 = mukeep +farg6 = mlkeep +farg7 = dqrely +farg8 = gloc +farg9 = cfn +fresult = swigc_FCVBBDPrecInit(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) +swig_result = fresult +end function + +function FCVBBDPrecReInit(cvode_mem, mudq, mldq, dqrely) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT64_T), intent(in) :: mudq +integer(C_INT64_T), intent(in) :: mldq +real(C_DOUBLE), intent(in) :: dqrely +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +real(C_DOUBLE) :: farg4 + +farg1 = cvode_mem +farg2 = mudq +farg3 = mldq +farg4 = dqrely +fresult = swigc_FCVBBDPrecReInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVBBDPrecGetWorkSpace(cvode_mem, lenrwbbdp, leniwbbdp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwbbdp +integer(C_LONG), dimension(*), target, intent(inout) :: leniwbbdp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(lenrwbbdp(1)) +farg3 = c_loc(leniwbbdp(1)) +fresult = swigc_FCVBBDPrecGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVBBDPrecGetNumGfnEvals(cvode_mem, ngevalsbbdp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevalsbbdp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(ngevalsbbdp(1)) +fresult = swigc_FCVBBDPrecGetNumGfnEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVBBDPrecInitB(cvode_mem, which, nlocalb, mudqb, mldqb, mukeepb, mlkeepb, dqrelyb, glocb, cfnb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +integer(C_INT64_T), intent(in) :: nlocalb +integer(C_INT64_T), intent(in) :: mudqb +integer(C_INT64_T), intent(in) :: mldqb +integer(C_INT64_T), intent(in) :: mukeepb +integer(C_INT64_T), intent(in) :: mlkeepb +real(C_DOUBLE), intent(in) :: dqrelyb +type(C_FUNPTR), intent(in), value :: glocb +type(C_FUNPTR), intent(in), value :: cfnb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 +integer(C_INT64_T) :: farg5 +integer(C_INT64_T) :: farg6 +integer(C_INT64_T) :: farg7 +real(C_DOUBLE) :: farg8 +type(C_FUNPTR) :: farg9 +type(C_FUNPTR) :: farg10 + +farg1 = cvode_mem +farg2 = which +farg3 = nlocalb +farg4 = mudqb +farg5 = mldqb +farg6 = mukeepb +farg7 = mlkeepb +farg8 = dqrelyb +farg9 = glocb +farg10 = cfnb +fresult = swigc_FCVBBDPrecInitB(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10) +swig_result = fresult +end function + +function FCVBBDPrecReInitB(cvode_mem, which, mudqb, mldqb, dqrelyb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +integer(C_INT64_T), intent(in) :: mudqb +integer(C_INT64_T), intent(in) :: mldqb +real(C_DOUBLE), intent(in) :: dqrelyb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 +real(C_DOUBLE) :: farg5 + +farg1 = cvode_mem +farg2 = which +farg3 = mudqb +farg4 = mldqb +farg5 = dqrelyb +fresult = swigc_FCVBBDPrecReInitB(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FCVDiag(cvode_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = cvode_mem +fresult = swigc_FCVDiag(farg1) +swig_result = fresult +end function + +function FCVDiagGetWorkSpace(cvode_mem, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FCVDiagGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVDiagGetNumRhsEvals(cvode_mem, nfevalsls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevalsls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nfevalsls(1)) +fresult = swigc_FCVDiagGetNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVDiagGetLastFlag(cvode_mem, flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: flag +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(flag(1)) +fresult = swigc_FCVDiagGetLastFlag(farg1, farg2) +swig_result = fresult +end function + +function FCVDiagGetReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FCVDiagGetReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +function FCVDiagB(cvode_mem, which) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = which +fresult = swigc_FCVDiagB(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetLinearSolver(cvode_mem, ls, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(SUNLinearSolver), target, intent(inout) :: ls +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(ls) +farg3 = c_loc(a) +fresult = swigc_FCVodeSetLinearSolver(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetJacFn(cvode_mem, jac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: jac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = cvode_mem +farg2 = jac +fresult = swigc_FCVodeSetJacFn(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetMaxStepsBetweenJac(cvode_mem, msbj) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), intent(in) :: msbj +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = cvode_mem +farg2 = msbj +fresult = swigc_FCVodeSetMaxStepsBetweenJac(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetLinearSolutionScaling(cvode_mem, onoff) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: onoff +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = cvode_mem +farg2 = onoff +fresult = swigc_FCVodeSetLinearSolutionScaling(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetEpsLin(cvode_mem, eplifac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +real(C_DOUBLE), intent(in) :: eplifac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = cvode_mem +farg2 = eplifac +fresult = swigc_FCVodeSetEpsLin(farg1, farg2) +swig_result = fresult +end function + +function FCVodeSetPreconditioner(cvode_mem, pset, psolve) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: pset +type(C_FUNPTR), intent(in), value :: psolve +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = cvode_mem +farg2 = pset +farg3 = psolve +fresult = swigc_FCVodeSetPreconditioner(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetJacTimes(cvode_mem, jtsetup, jtimes) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: jtsetup +type(C_FUNPTR), intent(in), value :: jtimes +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = cvode_mem +farg2 = jtsetup +farg3 = jtimes +fresult = swigc_FCVodeSetJacTimes(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetLinSysFn(cvode_mem, linsys) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +type(C_FUNPTR), intent(in), value :: linsys +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = cvode_mem +farg2 = linsys +fresult = swigc_FCVodeSetLinSysFn(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetLinWorkSpace(cvode_mem, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = cvode_mem +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FCVodeGetLinWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeGetNumJacEvals(cvode_mem, njevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(njevals(1)) +fresult = swigc_FCVodeGetNumJacEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumPrecEvals(cvode_mem, npevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: npevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(npevals(1)) +fresult = swigc_FCVodeGetNumPrecEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumPrecSolves(cvode_mem, npsolves) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: npsolves +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(npsolves(1)) +fresult = swigc_FCVodeGetNumPrecSolves(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumLinIters(cvode_mem, nliters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nliters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nliters(1)) +fresult = swigc_FCVodeGetNumLinIters(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumLinConvFails(cvode_mem, nlcfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nlcfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nlcfails(1)) +fresult = swigc_FCVodeGetNumLinConvFails(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumJTSetupEvals(cvode_mem, njtsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njtsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(njtsetups(1)) +fresult = swigc_FCVodeGetNumJTSetupEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumJtimesEvals(cvode_mem, njvevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njvevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(njvevals(1)) +fresult = swigc_FCVodeGetNumJtimesEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetNumLinRhsEvals(cvode_mem, nfevalsls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevalsls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(nfevalsls(1)) +fresult = swigc_FCVodeGetNumLinRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetLastLinFlag(cvode_mem, flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_LONG), dimension(*), target, intent(inout) :: flag +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = cvode_mem +farg2 = c_loc(flag(1)) +fresult = swigc_FCVodeGetLastLinFlag(farg1, farg2) +swig_result = fresult +end function + +function FCVodeGetLinReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FCVodeGetLinReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +function FCVodeSetLinearSolverB(cvode_mem, which, ls, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(SUNLinearSolver), target, intent(inout) :: ls +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = c_loc(ls) +farg4 = c_loc(a) +fresult = swigc_FCVodeSetLinearSolverB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeSetJacFnB(cvode_mem, which, jacb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: jacb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = jacb +fresult = swigc_FCVodeSetJacFnB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetJacFnBS(cvode_mem, which, jacbs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: jacbs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = jacbs +fresult = swigc_FCVodeSetJacFnBS(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetEpsLinB(cvode_mem, which, eplifacb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: eplifacb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = eplifacb +fresult = swigc_FCVodeSetEpsLinB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetLinearSolutionScalingB(cvode_mem, which, onoffb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +integer(C_INT), intent(in) :: onoffb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = onoffb +fresult = swigc_FCVodeSetLinearSolutionScalingB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetPreconditionerB(cvode_mem, which, psetb, psolveb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: psetb +type(C_FUNPTR), intent(in), value :: psolveb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = psetb +farg4 = psolveb +fresult = swigc_FCVodeSetPreconditionerB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeSetPreconditionerBS(cvode_mem, which, psetbs, psolvebs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: psetbs +type(C_FUNPTR), intent(in), value :: psolvebs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = psetbs +farg4 = psolvebs +fresult = swigc_FCVodeSetPreconditionerBS(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeSetJacTimesB(cvode_mem, which, jtsetupb, jtimesb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: jtsetupb +type(C_FUNPTR), intent(in), value :: jtimesb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = jtsetupb +farg4 = jtimesb +fresult = swigc_FCVodeSetJacTimesB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeSetJacTimesBS(cvode_mem, which, jtsetupbs, jtimesbs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: jtsetupbs +type(C_FUNPTR), intent(in), value :: jtimesbs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = cvode_mem +farg2 = which +farg3 = jtsetupbs +farg4 = jtimesbs +fresult = swigc_FCVodeSetJacTimesBS(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FCVodeSetLinSysFnB(cvode_mem, which, linsys) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: linsys +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = linsys +fresult = swigc_FCVodeSetLinSysFnB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FCVodeSetLinSysFnBS(cvode_mem, which, linsys) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: cvode_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: linsys +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = cvode_mem +farg2 = which +farg3 = linsys +fresult = swigc_FCVodeSetLinSysFnBS(farg1, farg2, farg3) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/ida/CMakeLists.txt index c14ba4803..329d4de7c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/ida/CMakeLists.txt @@ -1,9 +1,9 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU -# Radu Serban @ LLNL +# Programmer(s): Daniel R. Reynolds @ SMU +# Radu Serban @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -13,11 +13,17 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the IDA library +# --------------------------------------------------------------- + +install(CODE "MESSAGE(\"\nInstall IDA\n\")") -INSTALL(CODE "MESSAGE(\"\nInstall IDA\n\")") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) # Add variable ida_SOURCES with the sources for the IDA library -SET(ida_SOURCES +set(ida_SOURCES ida.c ida_bbdpre.c ida_direct.c @@ -30,7 +36,7 @@ SET(ida_SOURCES # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the IDA library -SET(shared_SOURCES +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_matrix.c ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c @@ -42,12 +48,13 @@ SET(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c ${sundials_SOURCE_DIR}/src/sundials/sundials_version.c ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector_senswrapper.c + ${sundials_SOURCE_DIR}/src/sundials/sundials_futils.c ${sundials_SOURCE_DIR}/src/nvector/serial/nvector_serial.c ) # Add variable sunmatrix_SOURCES with the common SUNMatrix sources which will # also be included in the IDA library -SET(sunmatrix_SOURCES +set(sunmatrix_SOURCES ${sundials_SOURCE_DIR}/src/sunmatrix/band/sunmatrix_band.c ${sundials_SOURCE_DIR}/src/sunmatrix/dense/sunmatrix_dense.c ${sundials_SOURCE_DIR}/src/sunmatrix/sparse/sunmatrix_sparse.c @@ -55,7 +62,7 @@ SET(sunmatrix_SOURCES # Add variable sunlinsol_SOURCES with the common SUNLinearSolver sources which will # also be included in the IDA library -SET(sunlinsol_SOURCES +set(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/band/sunlinsol_band.c ${sundials_SOURCE_DIR}/src/sunlinsol/dense/sunlinsol_dense.c ${sundials_SOURCE_DIR}/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c @@ -67,12 +74,13 @@ SET(sunlinsol_SOURCES # Add variable sunnonlinsol_SOURCES with the common SUNNonlinearSolver sources # which will also be included in the IDA library -SET(sunnonlinsol_SOURCES +set(sunnonlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunnonlinsol/newton/sunnonlinsol_newton.c + ${sundials_SOURCE_DIR}/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c ) # Add variable ida_HEADERS with the exported IDA header files -SET(ida_HEADERS +set(ida_HEADERS ida.h ida_bbdpre.h ida_direct.h @@ -81,59 +89,59 @@ SET(ida_HEADERS ) # Add prefix with complete path to the IDA header files -ADD_PREFIX(${sundials_SOURCE_DIR}/include/ida/ ida_HEADERS) +add_prefix(${sundials_SOURCE_DIR}/include/ida/ ida_HEADERS) # Add source directories to include directories for access to # implementation only header files. -INCLUDE_DIRECTORIES(.) +include_directories(.) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) # Build the static library -IF(BUILD_STATIC_LIBS) +if(BUILD_STATIC_LIBS) # Add the build target for the static IDA library - ADD_LIBRARY(sundials_ida_static STATIC + add_library(sundials_ida_static STATIC ${ida_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ${sunnonlinsol_SOURCES}) # Set the library name and make sure it is not deleted - SET_TARGET_PROPERTIES(sundials_ida_static + set_target_properties(sundials_ida_static PROPERTIES OUTPUT_NAME sundials_ida CLEAN_DIRECT_OUTPUT 1) # Install the IDA library - INSTALL(TARGETS sundials_ida_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS sundials_ida_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +endif(BUILD_STATIC_LIBS) # Build the shared library -IF(BUILD_SHARED_LIBS) +if(BUILD_SHARED_LIBS) # Add the build target for the IDA library - ADD_LIBRARY(sundials_ida_shared SHARED + add_library(sundials_ida_shared SHARED ${ida_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ${sunnonlinsol_SOURCES}) - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_ida_shared m) - ENDIF() + if(UNIX) + target_link_libraries(sundials_ida_shared m) + endif() # Set the library name and make sure it is not deleted - SET_TARGET_PROPERTIES(sundials_ida_shared + set_target_properties(sundials_ida_shared PROPERTIES OUTPUT_NAME sundials_ida CLEAN_DIRECT_OUTPUT 1) # Set VERSION and SOVERSION for shared libraries - SET_TARGET_PROPERTIES(sundials_ida_shared + set_target_properties(sundials_ida_shared PROPERTIES VERSION ${idalib_VERSION} SOVERSION ${idalib_SOVERSION}) # Install the IDA library - INSTALL(TARGETS sundials_ida_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS sundials_ida_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) +endif(BUILD_SHARED_LIBS) # Install the IDA header files -INSTALL(FILES ${ida_HEADERS} DESTINATION include/ida) +install(FILES ${ida_HEADERS} DESTINATION include/ida) # -MESSAGE(STATUS "Added IDA module") +message(STATUS "Added IDA module") diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/README b/deps/AMICI/ThirdParty/sundials/src/ida/README deleted file mode 100644 index cb49f0b94..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/ida/README +++ /dev/null @@ -1,110 +0,0 @@ - IDA - Release 4.1.0, Feb 2019 - Alan C. Hindmarsh and Radu Serban - Center for Applied Scientific Computing, LLNL - - -IDA is a package for the solution of differential-algebraic equation -(DAE) systems. It is written in C, but derived from the package DASPK -[4,5], which is written in FORTRAN. - -IDA can be used both on serial and parallel computers. The main -difference is in the NVECTOR module of vector kernels. The desired -version is obtained when compiling the example files by linking the -appropriate library of NVECTOR kernels. In the parallel versions, -communication between processors is done with MPI, with OpenMP, -or with Pthreads. - -When used with the serial NVECTOR module, IDA provides both direct -(dense and band) linear solvers and preconditioned Krylov (iterative) -linear solvers. Three different iterative solvers are available: scaled -preconditioned GMRES (SPGMR), scaled preconditioned BiCGStab (SPBCG), and -scaled preconditioned TFQMR (SPTFQMR). When IDA is used with the parallel -NVECTOR module, only the Krylov linear solvers are available. For the -latter case, in addition to the basic solver, the IDA package also contains -a preconditioner module called IDABBDPRE, which provides a band-block-diagonal -preconditioner. - -IDA is part of a software family called SUNDIALS: SUite of Nonlinear and -DIfferential/ALgebraic equation Solvers [3]. This suite consists of CVODE, -CVODES, ARKode, IDA, IDAS, and KINSOL. The directory structure of the -package supplied reflects this family relationship. - -For use with Fortran applications, a set of Fortran/C interface routines, -called FIDA, is also supplied. These are written in C, but assume that -the user calling program and all user-supplied routines are in Fortran. - -Several examples problem programs are included, covering both serial -and parallel cases, both small and large problem sizes, and both -linear and nonlinear problems. - -The notes below provide the location of documentation, directions for the -installation of the IDA package, and relevant references. Following that -is a brief history of revisions to the package. - - -A. Documentation ----------------- - -/sundials/doc/ida/ contains PDF files for the IDA User Guide [1] (ida_guide.pdf) -and the IDA Examples [2] (ida_examples.pdf) documents. - - -B. Installation ---------------- - -For basic installation instructions see the file /sundials/INSTALL_GUIDE.pdf. -For complete installation instructions see the "Installation Procedure" -chapter in the IDA User Guide. - - -C. References -------------- - -[1] A. C. Hindmarsh, R. Serban, and A. Collier, "User Documentation for IDA v2.9.0," - LLNL technical report UCRL-SM-208112, March 2016. - -[2] A. C. Hindmarsh, R. Serban, and A. Collier, "Example Programs for IDA v2.9.0," - LLNL technical report UCRL-SM-208113, March 2016. - -[3] A. C. Hindmarsh, P. N. Brown, K. E. Grant, S. L. Lee, R. Serban, - D. E. Shumaker, and C. S. Woodward, "SUNDIALS, Suite of Nonlinear and - Differential/Algebraic Equation Solvers," ACM Trans. Math. Softw., - 31(3), pp. 363-396, 2005. - -[4] P. N. Brown, A. C. Hindmarsh, and L. R. Petzold, Using Krylov Methods - in the Solution of Large-Scale Differential-Algebraic Systems, - SIAM J. Sci. Comp., 15 (1994), pp. 1467-1488. - -[5] P. N. Brown, A. C. Hindmarsh, and L. R. Petzold, Consistent Initial - Condition Calculation for Differential-Algebraic Systems, - SIAM J. Sci. Comp., 19 (1998), pp. 1495-1512. - - -D. Releases ------------ - -v. 4.1.0 - Feb. 2019 -v. 4.0.2 - Jan. 2019 -v. 4.0.1 - Dec. 2018 -v. 4.0.0 - Dec. 2018 -v. 3.2.1 - Oct. 2018 -v. 3.2.0 - Sep. 2018 -v. 3.1.2 - Jul. 2018 -v. 3.1.1 - May 2018 -v. 3.1.0 - Nov. 2017 -v. 3.0.0 - Sep. 2017 -v. 2.9.0 - Sep. 2016 -v. 2.8.2 - Aug. 2015 -v. 2.8.1 - Mar. 2015 -v. 2.8.0 - Mar. 2015 -v. 2.7.0 - Mar. 2012 -v. 2.6.0 - May 2009 -v. 2.5.0 - Nov. 2006 -v. 2.4.0 - Mar. 2006 -v. 2.3.0 - Apr. 2005 -v. 2.2.2 - Mar. 2005 -v. 2.2.1 - Jan. 2005 -v. 2.2.0 - Dec. 2004 -v. 2.0 - Jul. 2002 (first SUNDIALS release) -v. 1.0 - Feb. 1999 (date written) diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/README.md b/deps/AMICI/ThirdParty/sundials/src/ida/README.md new file mode 100644 index 000000000..6f7719a68 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/ida/README.md @@ -0,0 +1,64 @@ +# IDA +### Version 5.2.0 (Mar 2020) + +**Alan C. Hindmarsh and Radu Serban + Center for Applied Scientific Computing, LLNL** + +IDA is a package for the solution of differential-algebraic equation (DAE) +systems +``` +F(t,y,y') = 0, y(t0) = y0, y'(t0) = y0'. +``` +The integration methods used in IDA are variable-order, variable-coefficient BDF +(Backward Differentiation Formula) methods in fixed-leading-coefficient form. + +IDA is part of the SUNDIALS Suite of Nonlinear and Differential/Algebraic +equation Solvers which consists of ARKode, CVODE, CVODES, IDA, IDAS and KINSOL. +It is written in ANSI standard C, but is derived from the package DASPK, which +is written in FORTRAN. IDA can be used in a variety of computing environments +including serial, shared memory, distributed memory, and accelerator-based +(e.g., GPU) systems. This flexibility is obtained from a modular design that +leverages the shared vector, matrix, linear solver, and nonlinear solver APIs +used across SUNDIALS packages. + +For use with Fortran applications, a set of Fortran/C interface routines, called +FIDA, is also supplied. These are written in C, but assume that the user calling +program and all user-supplied routines are in Fortran. + +## Documentation + +See the [IDA User Guide](/doc/ida/ida_guide.pdf) and +[IDA Examples](/doc/ida/ida_examples.pdf) document for more information +about IDA usage and the provided example programs respectively. + +## Installation + +For installation instructions see the [INSTALL_GUIDE](/INSTALL_GUIDE.pdf) +or the "Installation Procedure" chapter in the IDA User Guide. + +## Release History + +Information on recent changes to IDA can be found in the "Introduction" +chapter of the IDA User Guide and a complete release history is available in +the "SUNDIALS Release History" appendix of the IDA User Guide. + +## References + +* A. C. Hindmarsh, R. Serban, and A. Collier, "User Documentation for IDA v5.2.0," + LLNL technical report UCRL-SM-208112, Mar 2020. + +* A. C. Hindmarsh, R. Serban, and A. Collier, "Example Programs for IDA v5.2.0," + LLNL technical report UCRL-SM-208113, Mar 2020. + +* A. C. Hindmarsh, P. N. Brown, K. E. Grant, S. L. Lee, R. Serban, + D. E. Shumaker, and C. S. Woodward, "SUNDIALS, Suite of Nonlinear and + Differential/Algebraic Equation Solvers," ACM Trans. Math. Softw., + 31(3), pp. 363-396, 2005. + +* P. N. Brown, A. C. Hindmarsh, and L. R. Petzold, Using Krylov Methods + in the Solution of Large-Scale Differential-Algebraic Systems, + SIAM J. Sci. Comp., 15 (1994), pp. 1467-1488. + +* P. N. Brown, A. C. Hindmarsh, and L. R. Petzold, Consistent Initial + Condition Calculation for Differential-Algebraic Systems, + SIAM J. Sci. Comp., 19 (1998), pp. 1495-1512. diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/CMakeLists.txt index 31bfe8cdb..5e1360ab9 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,9 +12,10 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the FIDA library +# --------------------------------------------------------------- # Add variable fida_SOURCES with the sources for the FIDA library -SET(fida_SOURCES +set(fida_SOURCES fidaband.c fidabbd.c fida.c @@ -30,13 +31,13 @@ SET(fida_SOURCES # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the IDA library -SET(shared_SOURCES +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/nvector/serial/fnvector_serial.c ) # Add variable sunmatrix_SOURCES with the common SUNMatrix sources which will # also be included in the IDA library -SET(sunmatrix_SOURCES +set(sunmatrix_SOURCES ${sundials_SOURCE_DIR}/src/sunmatrix/band/fsunmatrix_band.c ${sundials_SOURCE_DIR}/src/sunmatrix/dense/fsunmatrix_dense.c ${sundials_SOURCE_DIR}/src/sunmatrix/sparse/fsunmatrix_sparse.c @@ -44,7 +45,7 @@ SET(sunmatrix_SOURCES # Add variable sunlinsol_SOURCES with the common SUNLinearSolver sources which will # also be included in the IDA library -SET(sunlinsol_SOURCES +set(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/band/fsunlinsol_band.c ${sundials_SOURCE_DIR}/src/sunlinsol/dense/fsunlinsol_dense.c ${sundials_SOURCE_DIR}/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c @@ -54,53 +55,34 @@ SET(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/pcg/fsunlinsol_pcg.c ) -IF(KLU_FOUND) - LIST(APPEND sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/klu/fsunlinsol_klu.c - ) -ENDIF() - -IF(SUPERLUMT_FOUND) - LIST(APPEND sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/superlumt/fsunlinsol_superlumt.c - ) -ENDIF() - -IF(LAPACK_FOUND) - LIST(APPEND sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/lapackband/fsunlinsol_lapackband.c - ${sundials_SOURCE_DIR}/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.c - ) -ENDIF() - # Add variable sunnonlinsol_SOURCES with the common SUNNonlinearSolver sources # which will also be included in the IDA library -SET(sunnonlinsol_SOURCES +set(sunnonlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunnonlinsol/newton/fsunnonlinsol_newton.c ) # Add source directories to include directories for access to # implementation only header files (both for fida and ida) -INCLUDE_DIRECTORIES(.) -INCLUDE_DIRECTORIES(..) +include_directories(.) +include_directories(..) -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY +add_definitions(-DBUILD_SUNDIALS_LIBRARY) -# Only build STATIC libraries (we cannot build shared libraries -# for the FCMIX interfaces due to unresolved symbol errors +# Only build STATIC libraries (we cannot build shared libraries +# for the FCMIX interfaces due to unresolved symbol errors # coming from inexistent user-provided functions) # Add the build target for the FIDA library -ADD_LIBRARY(sundials_fida_static STATIC +add_library(sundials_fida_static STATIC ${fida_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ${sunnonlinsol_SOURCES}) # Set the library name and make sure it is not deleted -SET_TARGET_PROPERTIES(sundials_fida_static +set_target_properties(sundials_fida_static PROPERTIES OUTPUT_NAME sundials_fida CLEAN_DIRECT_OUTPUT 1) # Install the FIDA library -INSTALL(TARGETS sundials_fida_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(TARGETS sundials_fida_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) # -MESSAGE(STATUS "Added IDA FCMIX module") +message(STATUS "Added IDA FCMIX module") diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fida.c b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fida.c index 0bdec85cd..88f24a77c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fida.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fida.c @@ -1,9 +1,9 @@ -/*----------------------------------------------------------------- +/*----------------------------------------------------------------- * Programmer(s): Daniel R. Reynolds @ SMU * Aaron Collier and Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -65,7 +65,7 @@ extern "C" { void FIDA_MALLOC(realtype *t0, realtype *yy0, realtype *yp0, int *iatol, realtype *rtol, realtype *atol, - long int *iout, realtype *rout, + long int *iout, realtype *rout, long int *ipar, realtype *rpar, int *ier) { N_Vector Vatol; @@ -254,7 +254,7 @@ void FIDA_SETIIN(char key_name[], long int *ival, int *ier) *ier = IDASetSuppressAlg(IDA_idamem, (booleantype) *ival); else if (!strncmp(key_name,"MAX_NSTEPS_IC",13)) *ier = IDASetMaxNumStepsIC(IDA_idamem, (int) *ival); - else if (!strncmp(key_name,"MAX_NITERS_IC",13)) + else if (!strncmp(key_name,"MAX_NITERS_IC",13)) *ier = IDASetMaxNumItersIC(IDA_idamem, (int) *ival); else if (!strncmp(key_name,"MAX_NJE_IC",10)) *ier = IDASetMaxNumJacsIC(IDA_idamem, (int) *ival); @@ -307,7 +307,7 @@ void FIDA_SETVIN(char key_name[], realtype *vval, int *ier) return; } N_VSetArrayPointer(vval, Vec); - IDASetId(IDA_idamem, Vec); + *ier = IDASetId(IDA_idamem, Vec); N_VDestroy(Vec); } else if (!strncmp(key_name,"CONSTR_VEC",10)) { Vec = NULL; @@ -317,7 +317,7 @@ void FIDA_SETVIN(char key_name[], realtype *vval, int *ier) return; } N_VSetArrayPointer(vval, Vec); - IDASetConstraints(IDA_idamem, Vec); + *ier = IDASetConstraints(IDA_idamem, Vec); N_VDestroy(Vec); } else { *ier = -99; @@ -362,14 +362,14 @@ void FIDA_CALCIC(int *icopt, realtype *tout1, int *ier) /*************************************************/ -/* Fortran interface to C routine IDASetLinearSolver; see +/* Fortran interface to C routine IDASetLinearSolver; see fida.h for further details */ void FIDA_LSINIT(int *ier) { if ( (IDA_idamem == NULL) || (F2C_IDA_linsol == NULL) ) { *ier = -1; return; } - *ier = IDASetLinearSolver(IDA_idamem, F2C_IDA_linsol, + *ier = IDASetLinearSolver(IDA_idamem, F2C_IDA_linsol, F2C_IDA_matrix); return; } @@ -391,7 +391,7 @@ void FIDA_SPILSINIT(int *ier) { /*************************************************/ -/* Fortran interfaces to C "set" routines for the IDALS solver; +/* Fortran interfaces to C "set" routines for the IDALS solver; see fida.h for further details */ void FIDA_LSSETEPSLIN(realtype *eplifac, int *ier) { *ier = IDASetEpsLin(IDA_idamem, *eplifac); @@ -408,7 +408,7 @@ void FIDA_SPILSSETEPSLIN(realtype *eplifac, int *ier) { FIDA_LSSETEPSLIN(eplifac, ier); } /*** DEPRECATED ***/ -void FIDA_SPILSSETINCREMENTFACTOR(realtype *dqincfac, int *ier) +void FIDA_SPILSSETINCREMENTFACTOR(realtype *dqincfac, int *ier) { FIDA_LSSETINCREMENTFACTOR(dqincfac, ier); } @@ -453,11 +453,11 @@ void FIDA_SOLVE(realtype *tout, realtype *tret, realtype *yret, IDAGetNonlinSolvStats(IDA_idamem, &IDA_iout[6], /* NNI */ &IDA_iout[5]); /* NCFN */ - IDAGetNumBacktrackOps(IDA_idamem, + IDAGetNumBacktrackOps(IDA_idamem, &IDA_iout[10]); /* NBCKTRK */ - IDAGetTolScaleFactor(IDA_idamem, + IDAGetTolScaleFactor(IDA_idamem, &IDA_rout[4]); /* TOLSFAC */ - + /* Root finding is on */ if (IDA_nrtfn != 0) IDAGetNumGEvals(IDA_idamem, &IDA_iout[11]); /* NGE */ @@ -561,16 +561,14 @@ void FIDA_FREE(void) N_VSetArrayPointer(NULL, F2C_IDA_ypvec); N_VDestroy(F2C_IDA_ypvec); if (F2C_IDA_ewtvec != NULL) { - N_VSetArrayPointer(NULL, F2C_IDA_ewtvec); N_VDestroy(F2C_IDA_ewtvec); } if (F2C_IDA_matrix) SUNMatDestroy(F2C_IDA_matrix); if (F2C_IDA_linsol) SUNLinSolFree(F2C_IDA_linsol); - /* already freed by IDAFree */ if (F2C_IDA_nonlinsol) - F2C_IDA_nonlinsol = NULL; + SUNNonlinSolFree(F2C_IDA_nonlinsol); return; } @@ -597,7 +595,7 @@ int FIDAresfn(realtype t, N_Vector yy, N_Vector yp, IDA_userdata = (FIDAUserData) user_data; /* Call user-supplied routine */ - FIDA_RESFUN(&t, yy_data, yp_data, rr_data, + FIDA_RESFUN(&t, yy_data, yp_data, rr_data, IDA_userdata->ipar, IDA_userdata->rpar, &ier); return(ier); @@ -605,7 +603,7 @@ int FIDAresfn(realtype t, N_Vector yy, N_Vector yp, /*************************************************/ -/* Fortran interface to C routine IDASetNonlinearSolver; see +/* Fortran interface to C routine IDASetNonlinearSolver; see fida.h for further details */ void FIDA_NLSINIT(int *ier) { if ( (IDA_idamem == NULL) || (F2C_IDA_nonlinsol == NULL) ) { diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fida.h b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fida.h index b545c100e..973ff60ad 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fida.h +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fida.h @@ -3,7 +3,7 @@ * Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaband.c b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaband.c index dc5001f43..a3756b58f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaband.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaband.c @@ -3,7 +3,7 @@ * Aaron Collier @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidabbd.c b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidabbd.c index 57a6584c8..120e424bc 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidabbd.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidabbd.c @@ -3,7 +3,7 @@ * Aaron Collier @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -43,7 +43,7 @@ extern "C" { realtype* GLOC, long int* IPAR, realtype* RPAR, int* IER); extern void FIDA_COMMFN(long int* NLOC, realtype* T, - realtype* Y, realtype* YP, + realtype* Y, realtype* YP, long int* IPAR, realtype* RPAR, int* IER); @@ -58,8 +58,13 @@ void FIDA_BBDINIT(long int *Nloc, long int *mudq, long int *ml, realtype *dqrely, int *ier) { - *ier = IDABBDPrecInit(IDA_idamem, *Nloc, *mudq, - *mldq, *mu, *ml, *dqrely, + *ier = IDABBDPrecInit(IDA_idamem, + (sunindextype)(*Nloc), + (sunindextype)(*mudq), + (sunindextype)(*mldq), + (sunindextype)(*mu), + (sunindextype)(*ml), + *dqrely, (IDABBDLocalFn) FIDAgloc, (IDABBDCommFn) FIDAcfn); return; @@ -71,7 +76,10 @@ void FIDA_BBDREINIT(long int *Nloc, long int *mudq, long int *mldq, realtype *dqrely, int *ier) { - *ier = IDABBDPrecReInit(IDA_idamem, *mudq, *mldq, *dqrely); + *ier = IDABBDPrecReInit(IDA_idamem, + (sunindextype)(*mudq), + (sunindextype)(*mldq), + *dqrely); return; } @@ -101,7 +109,7 @@ int FIDAgloc(long int Nloc, realtype t, N_Vector yy, IDA_userdata = (FIDAUserData) user_data; /* Call user-supplied routine */ - FIDA_GLOCFN(&Nloc, &t, yy_data, yp_data, gval_data, + FIDA_GLOCFN(&Nloc, &t, yy_data, yp_data, gval_data, IDA_userdata->ipar, IDA_userdata->rpar, &ier); return(ier); } @@ -131,7 +139,7 @@ int FIDAcfn(long int Nloc, realtype t, N_Vector yy, N_Vector yp, IDA_userdata = (FIDAUserData) user_data; /* Call user-supplied routine */ - FIDA_COMMFN(&Nloc, &t, yy_data, yp_data, + FIDA_COMMFN(&Nloc, &t, yy_data, yp_data, IDA_userdata->ipar, IDA_userdata->rpar, &ier); return(ier); } diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidabbd.h b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidabbd.h index 6832f6a56..ce6951fa7 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidabbd.h +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidabbd.h @@ -3,7 +3,7 @@ * Aaron Collier @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidadense.c b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidadense.c index 11203aba8..75b24fadb 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidadense.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidadense.c @@ -3,7 +3,7 @@ * Aaron Collier @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaewt.c b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaewt.c index dcfdadc37..25d5e2ccf 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaewt.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaewt.c @@ -3,7 +3,7 @@ * Programmer(s): Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidajtimes.c b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidajtimes.c index 35cd0dde9..5798954ab 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidajtimes.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidajtimes.c @@ -3,7 +3,7 @@ * Aaron Collier and Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidanullmatrix.c b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidanullmatrix.c index ee87d7f10..a83030e5b 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidanullmatrix.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidanullmatrix.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidanullnonlinsol.c b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidanullnonlinsol.c index 8db385b56..540d35714 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidanullnonlinsol.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidanullnonlinsol.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidapreco.c b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidapreco.c index 0b50d7d69..43e4b4294 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidapreco.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidapreco.c @@ -2,7 +2,7 @@ * Programmer(s): Aaron Collier and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaroot.c b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaroot.c index 2cce74b75..6cbc64eff 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaroot.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaroot.c @@ -3,7 +3,7 @@ * Programmer(s): Aaron Collier and Alan C. Hindmarsh @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaroot.h b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaroot.h index 7d1d39dbe..48b09e24c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaroot.h +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidaroot.h @@ -3,7 +3,7 @@ * Programmer(s): Aaron Collier and Alan C. Hindmarsh @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidasparse.c b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidasparse.c index afd74eb35..70081cb92 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidasparse.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fcmix/fidasparse.c @@ -3,7 +3,7 @@ * Daniel R. Reynolds @ SMU *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fmod/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/ida/fmod/CMakeLists.txt new file mode 100644 index 000000000..61f448186 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fmod/CMakeLists.txt @@ -0,0 +1,100 @@ +# --------------------------------------------------------------- +# Programmer(s): Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the F2003 IDA object library +# --------------------------------------------------------------- + +set(ida_SOURCES fida_mod.f90 fida_mod.c) + +if(BUILD_STATIC_LIBS) + sundials_add_f2003_interface_library(sundials_fida_mod_static STATIC + ${ida_SOURCES} + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + + # include the directoy where the .mod files reside + target_include_directories(sundials_fida_mod_static + PUBLIC + $ + $ + ) + + # Set the library name and make sure it is not deleted + set_target_properties(sundials_fida_mod_static + PROPERTIES OUTPUT_NAME sundials_fida_mod CLEAN_DIRECT_OUTPUT 1) + + # install the library + install(TARGETS sundials_fida_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # install the ida mod file from here since it won't go into the + # top level fortran mod file directory + install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_STATIC/fida_mod.mod + DESTINATION ${Fortran_INSTALL_MODDIR}) +endif() + +if(BUILD_SHARED_LIBS) + sundials_add_f2003_interface_library(sundials_fida_mod_shared SHARED + ${ida_SOURCES} + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + + # include the directoy where the .mod files reside + target_include_directories(sundials_fida_mod_shared + PUBLIC + $ + $ + ) + + # Set the library name and make sure it is not deleted + set_target_properties(sundials_fida_mod_shared PROPERTIES + OUTPUT_NAME sundials_fida_mod + CLEAN_DIRECT_OUTPUT 1 + VERSION ${idalib_VERSION} + SOVERSION ${idalib_SOVERSION}) + + # install the library + install(TARGETS sundials_fida_mod_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # install the ida mod file from here since it won't go into the + # top level fortran mod file directory + install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_SHARED/fida_mod.mod + DESTINATION ${Fortran_INSTALL_MODDIR}) +endif() + +message(STATUS "Added IDA F2003 interface") diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fmod/fida_mod.c b/deps/AMICI/ThirdParty/sundials/src/ida/fmod/fida_mod.c new file mode 100644 index 000000000..61391f512 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fmod/fida_mod.c @@ -0,0 +1,1516 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "ida/ida.h" +#include "ida/ida_bbdpre.h" +#include "ida/ida_ls.h" + + +#include +#ifdef _MSC_VER +# ifndef strtoull +# define strtoull _strtoui64 +# endif +# ifndef strtoll +# define strtoll _strtoi64 +# endif +#endif + + +typedef struct { + void* data; + size_t size; +} SwigArrayWrapper; + + +SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() { + SwigArrayWrapper result; + result.data = NULL; + result.size = 0; + return result; +} + + +#include + +SWIGEXPORT void * _wrap_FIDACreate() { + void * fresult ; + void *result = 0 ; + + result = (void *)IDACreate(); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAInit(void *farg1, IDAResFn farg2, double const *farg3, N_Vector farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + IDAResFn arg2 = (IDAResFn) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDAResFn)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + result = (int)IDAInit(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAReInit(void *farg1, double const *farg2, N_Vector farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAReInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASStolerances(void *farg1, double const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)IDASStolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASVtolerances(void *farg1, double const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDASVtolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAWFtolerances(void *farg1, IDAEwtFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + IDAEwtFn arg2 = (IDAEwtFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDAEwtFn)(farg2); + result = (int)IDAWFtolerances(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDACalcIC(void *farg1, int const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)IDACalcIC(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetNonlinConvCoefIC(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetNonlinConvCoefIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxNumStepsIC(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxNumStepsIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxNumJacsIC(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxNumJacsIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxNumItersIC(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxNumItersIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetLineSearchOffIC(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetLineSearchOffIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetStepToleranceIC(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetStepToleranceIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxBacksIC(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxBacksIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetErrHandlerFn(void *farg1, IDAErrHandlerFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + IDAErrHandlerFn arg2 = (IDAErrHandlerFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDAErrHandlerFn)(farg2); + arg3 = (void *)(farg3); + result = (int)IDASetErrHandlerFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetErrFile(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)IDASetErrFile(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetUserData(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + void *arg2 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (void *)(farg2); + result = (int)IDASetUserData(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxOrd(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxOrd(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxNumSteps(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)IDASetMaxNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetInitStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetInitStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetMaxStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetStopTime(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetStopTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetNonlinConvCoef(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetNonlinConvCoef(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxErrTestFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxNonlinIters(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxNonlinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxConvFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetSuppressAlg(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetSuppressAlg(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetId(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)IDASetId(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetConstraints(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)IDASetConstraints(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetNonlinearSolver(void *farg1, SUNNonlinearSolver farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNNonlinearSolver arg2 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNNonlinearSolver)(farg2); + result = (int)IDASetNonlinearSolver(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDARootInit(void *farg1, int const *farg2, IDARootFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + IDARootFn arg3 = (IDARootFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (IDARootFn)(farg3); + result = (int)IDARootInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetRootDirection(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)IDASetRootDirection(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetNoInactiveRootWarn(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)IDASetNoInactiveRootWarn(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASolve(void *farg1, double const *farg2, double *farg3, N_Vector farg4, N_Vector farg5, int const *farg6) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype *arg3 = (realtype *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int arg6 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + arg6 = (int)(*farg6); + result = (int)IDASolve(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAComputeY(void *farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDAComputeY(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAComputeYp(void *farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDAComputeYp(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetDky(void *farg1, double const *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAGetDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)IDAGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumSteps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumResEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumResEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumLinSolvSetups(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumLinSolvSetups(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumErrTestFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumBacktrackOps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumBacktrackOps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetConsistentIC(void *farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDAGetConsistentIC(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetLastOrder(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)IDAGetLastOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentOrder(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)IDAGetCurrentOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentCj(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)IDAGetCurrentCj(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentY(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)IDAGetCurrentY(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentYp(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)IDAGetCurrentYp(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetActualInitStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)IDAGetActualInitStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetLastStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)IDAGetLastStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)IDAGetCurrentStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentTime(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)IDAGetCurrentTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetTolScaleFactor(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)IDAGetTolScaleFactor(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetErrWeights(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)IDAGetErrWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetEstLocalErrors(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)IDAGetEstLocalErrors(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumGEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumGEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetRootInfo(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)IDAGetRootInfo(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetIntegratorStats(void *farg1, long *farg2, long *farg3, long *farg4, long *farg5, int *farg6, int *farg7, double *farg8, double *farg9, double *farg10, double *farg11) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + long *arg4 = (long *) 0 ; + long *arg5 = (long *) 0 ; + int *arg6 = (int *) 0 ; + int *arg7 = (int *) 0 ; + realtype *arg8 = (realtype *) 0 ; + realtype *arg9 = (realtype *) 0 ; + realtype *arg10 = (realtype *) 0 ; + realtype *arg11 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + arg4 = (long *)(farg4); + arg5 = (long *)(farg5); + arg6 = (int *)(farg6); + arg7 = (int *)(farg7); + arg8 = (realtype *)(farg8); + arg9 = (realtype *)(farg9); + arg10 = (realtype *)(farg10); + arg11 = (realtype *)(farg11); + result = (int)IDAGetIntegratorStats(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumNonlinSolvIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumNonlinSolvIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumNonlinSolvConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumNonlinSolvConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNonlinSolvStats(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)IDAGetNonlinSolvStats(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FIDAGetReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)IDAGetReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FIDAFree(void *farg1) { + void **arg1 = (void **) 0 ; + + arg1 = (void **)(farg1); + IDAFree(arg1); +} + + +SWIGEXPORT int _wrap_FIDABBDPrecInit(void *farg1, int64_t const *farg2, int64_t const *farg3, int64_t const *farg4, int64_t const *farg5, int64_t const *farg6, double const *farg7, IDABBDLocalFn farg8, IDABBDCommFn farg9) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + sunindextype arg5 ; + sunindextype arg6 ; + realtype arg7 ; + IDABBDLocalFn arg8 = (IDABBDLocalFn) 0 ; + IDABBDCommFn arg9 = (IDABBDCommFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + arg5 = (sunindextype)(*farg5); + arg6 = (sunindextype)(*farg6); + arg7 = (realtype)(*farg7); + arg8 = (IDABBDLocalFn)(farg8); + arg9 = (IDABBDCommFn)(farg9); + result = (int)IDABBDPrecInit(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDABBDPrecReInit(void *farg1, int64_t const *farg2, int64_t const *farg3, double const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + realtype arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (realtype)(*farg4); + result = (int)IDABBDPrecReInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDABBDPrecGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)IDABBDPrecGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDABBDPrecGetNumGfnEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDABBDPrecGetNumGfnEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetLinearSolver(void *farg1, SUNLinearSolver farg2, SUNMatrix farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNLinearSolver arg2 = (SUNLinearSolver) 0 ; + SUNMatrix arg3 = (SUNMatrix) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNLinearSolver)(farg2); + arg3 = (SUNMatrix)(farg3); + result = (int)IDASetLinearSolver(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetJacFn(void *farg1, IDALsJacFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + IDALsJacFn arg2 = (IDALsJacFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDALsJacFn)(farg2); + result = (int)IDASetJacFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetPreconditioner(void *farg1, IDALsPrecSetupFn farg2, IDALsPrecSolveFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + IDALsPrecSetupFn arg2 = (IDALsPrecSetupFn) 0 ; + IDALsPrecSolveFn arg3 = (IDALsPrecSolveFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDALsPrecSetupFn)(farg2); + arg3 = (IDALsPrecSolveFn)(farg3); + result = (int)IDASetPreconditioner(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetJacTimes(void *farg1, IDALsJacTimesSetupFn farg2, IDALsJacTimesVecFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + IDALsJacTimesSetupFn arg2 = (IDALsJacTimesSetupFn) 0 ; + IDALsJacTimesVecFn arg3 = (IDALsJacTimesVecFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDALsJacTimesSetupFn)(farg2); + arg3 = (IDALsJacTimesVecFn)(farg3); + result = (int)IDASetJacTimes(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetEpsLin(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetEpsLin(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetLinearSolutionScaling(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetLinearSolutionScaling(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetIncrementFactor(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetIncrementFactor(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetLinWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)IDAGetLinWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumJacEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumJacEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumPrecEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumPrecEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumPrecSolves(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumPrecSolves(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumLinIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumLinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumLinConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumLinConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumJTSetupEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumJTSetupEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumJtimesEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumJtimesEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumLinResEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumLinResEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetLastLinFlag(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetLastLinFlag(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FIDAGetLinReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)IDAGetLinReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/fmod/fida_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/ida/fmod/fida_mod.f90 new file mode 100644 index 000000000..585ac92f7 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/ida/fmod/fida_mod.f90 @@ -0,0 +1,2501 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fida_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_linearsolver_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_nonlinearsolver_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: IDA_NORMAL = 1_C_INT + integer(C_INT), parameter, public :: IDA_ONE_STEP = 2_C_INT + integer(C_INT), parameter, public :: IDA_YA_YDP_INIT = 1_C_INT + integer(C_INT), parameter, public :: IDA_Y_INIT = 2_C_INT + integer(C_INT), parameter, public :: IDA_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: IDA_TSTOP_RETURN = 1_C_INT + integer(C_INT), parameter, public :: IDA_ROOT_RETURN = 2_C_INT + integer(C_INT), parameter, public :: IDA_WARNING = 99_C_INT + integer(C_INT), parameter, public :: IDA_TOO_MUCH_WORK = -1_C_INT + integer(C_INT), parameter, public :: IDA_TOO_MUCH_ACC = -2_C_INT + integer(C_INT), parameter, public :: IDA_ERR_FAIL = -3_C_INT + integer(C_INT), parameter, public :: IDA_CONV_FAIL = -4_C_INT + integer(C_INT), parameter, public :: IDA_LINIT_FAIL = -5_C_INT + integer(C_INT), parameter, public :: IDA_LSETUP_FAIL = -6_C_INT + integer(C_INT), parameter, public :: IDA_LSOLVE_FAIL = -7_C_INT + integer(C_INT), parameter, public :: IDA_RES_FAIL = -8_C_INT + integer(C_INT), parameter, public :: IDA_REP_RES_ERR = -9_C_INT + integer(C_INT), parameter, public :: IDA_RTFUNC_FAIL = -10_C_INT + integer(C_INT), parameter, public :: IDA_CONSTR_FAIL = -11_C_INT + integer(C_INT), parameter, public :: IDA_FIRST_RES_FAIL = -12_C_INT + integer(C_INT), parameter, public :: IDA_LINESEARCH_FAIL = -13_C_INT + integer(C_INT), parameter, public :: IDA_NO_RECOVERY = -14_C_INT + integer(C_INT), parameter, public :: IDA_NLS_INIT_FAIL = -15_C_INT + integer(C_INT), parameter, public :: IDA_NLS_SETUP_FAIL = -16_C_INT + integer(C_INT), parameter, public :: IDA_NLS_FAIL = -17_C_INT + integer(C_INT), parameter, public :: IDA_MEM_NULL = -20_C_INT + integer(C_INT), parameter, public :: IDA_MEM_FAIL = -21_C_INT + integer(C_INT), parameter, public :: IDA_ILL_INPUT = -22_C_INT + integer(C_INT), parameter, public :: IDA_NO_MALLOC = -23_C_INT + integer(C_INT), parameter, public :: IDA_BAD_EWT = -24_C_INT + integer(C_INT), parameter, public :: IDA_BAD_K = -25_C_INT + integer(C_INT), parameter, public :: IDA_BAD_T = -26_C_INT + integer(C_INT), parameter, public :: IDA_BAD_DKY = -27_C_INT + integer(C_INT), parameter, public :: IDA_VECTOROP_ERR = -28_C_INT + integer(C_INT), parameter, public :: IDA_UNRECOGNIZED_ERROR = -99_C_INT + public :: FIDACreate + public :: FIDAInit + public :: FIDAReInit + public :: FIDASStolerances + public :: FIDASVtolerances + public :: FIDAWFtolerances + public :: FIDACalcIC + public :: FIDASetNonlinConvCoefIC + public :: FIDASetMaxNumStepsIC + public :: FIDASetMaxNumJacsIC + public :: FIDASetMaxNumItersIC + public :: FIDASetLineSearchOffIC + public :: FIDASetStepToleranceIC + public :: FIDASetMaxBacksIC + public :: FIDASetErrHandlerFn + public :: FIDASetErrFile + public :: FIDASetUserData + public :: FIDASetMaxOrd + public :: FIDASetMaxNumSteps + public :: FIDASetInitStep + public :: FIDASetMaxStep + public :: FIDASetStopTime + public :: FIDASetNonlinConvCoef + public :: FIDASetMaxErrTestFails + public :: FIDASetMaxNonlinIters + public :: FIDASetMaxConvFails + public :: FIDASetSuppressAlg + public :: FIDASetId + public :: FIDASetConstraints + public :: FIDASetNonlinearSolver + public :: FIDARootInit + public :: FIDASetRootDirection + public :: FIDASetNoInactiveRootWarn + public :: FIDASolve + public :: FIDAComputeY + public :: FIDAComputeYp + public :: FIDAGetDky + public :: FIDAGetWorkSpace + public :: FIDAGetNumSteps + public :: FIDAGetNumResEvals + public :: FIDAGetNumLinSolvSetups + public :: FIDAGetNumErrTestFails + public :: FIDAGetNumBacktrackOps + public :: FIDAGetConsistentIC + public :: FIDAGetLastOrder + public :: FIDAGetCurrentOrder + public :: FIDAGetCurrentCj + public :: FIDAGetCurrentY + public :: FIDAGetCurrentYp + public :: FIDAGetActualInitStep + public :: FIDAGetLastStep + public :: FIDAGetCurrentStep + public :: FIDAGetCurrentTime + public :: FIDAGetTolScaleFactor + public :: FIDAGetErrWeights + public :: FIDAGetEstLocalErrors + public :: FIDAGetNumGEvals + public :: FIDAGetRootInfo + public :: FIDAGetIntegratorStats + public :: FIDAGetNumNonlinSolvIters + public :: FIDAGetNumNonlinSolvConvFails + public :: FIDAGetNonlinSolvStats + type, bind(C) :: SwigArrayWrapper + type(C_PTR), public :: data = C_NULL_PTR + integer(C_SIZE_T), public :: size = 0 + end type + public :: FIDAGetReturnFlagName + public :: FIDAFree + public :: FIDABBDPrecInit + public :: FIDABBDPrecReInit + public :: FIDABBDPrecGetWorkSpace + public :: FIDABBDPrecGetNumGfnEvals + integer(C_INT), parameter, public :: IDALS_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: IDALS_MEM_NULL = -1_C_INT + integer(C_INT), parameter, public :: IDALS_LMEM_NULL = -2_C_INT + integer(C_INT), parameter, public :: IDALS_ILL_INPUT = -3_C_INT + integer(C_INT), parameter, public :: IDALS_MEM_FAIL = -4_C_INT + integer(C_INT), parameter, public :: IDALS_PMEM_NULL = -5_C_INT + integer(C_INT), parameter, public :: IDALS_JACFUNC_UNRECVR = -6_C_INT + integer(C_INT), parameter, public :: IDALS_JACFUNC_RECVR = -7_C_INT + integer(C_INT), parameter, public :: IDALS_SUNMAT_FAIL = -8_C_INT + integer(C_INT), parameter, public :: IDALS_SUNLS_FAIL = -9_C_INT + public :: FIDASetLinearSolver + public :: FIDASetJacFn + public :: FIDASetPreconditioner + public :: FIDASetJacTimes + public :: FIDASetEpsLin + public :: FIDASetLinearSolutionScaling + public :: FIDASetIncrementFactor + public :: FIDAGetLinWorkSpace + public :: FIDAGetNumJacEvals + public :: FIDAGetNumPrecEvals + public :: FIDAGetNumPrecSolves + public :: FIDAGetNumLinIters + public :: FIDAGetNumLinConvFails + public :: FIDAGetNumJTSetupEvals + public :: FIDAGetNumJtimesEvals + public :: FIDAGetNumLinResEvals + public :: FIDAGetLastLinFlag + public :: FIDAGetLinReturnFlagName + +! WRAPPER DECLARATIONS +interface +function swigc_FIDACreate() & +bind(C, name="_wrap_FIDACreate") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: fresult +end function + +function swigc_FIDAInit(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FIDAInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FIDAReInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDASStolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASStolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASVtolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASVtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAWFtolerances(farg1, farg2) & +bind(C, name="_wrap_FIDAWFtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDACalcIC(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDACalcIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetNonlinConvCoefIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetNonlinConvCoefIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxNumStepsIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxNumStepsIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxNumJacsIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxNumJacsIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxNumItersIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxNumItersIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetLineSearchOffIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetLineSearchOffIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetStepToleranceIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetStepToleranceIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxBacksIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxBacksIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetErrHandlerFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetErrHandlerFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetErrFile(farg1, farg2) & +bind(C, name="_wrap_FIDASetErrFile") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetUserData(farg1, farg2) & +bind(C, name="_wrap_FIDASetUserData") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxOrd(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxOrd") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxNumSteps(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetInitStep(farg1, farg2) & +bind(C, name="_wrap_FIDASetInitStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxStep(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetStopTime(farg1, farg2) & +bind(C, name="_wrap_FIDASetStopTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetNonlinConvCoef(farg1, farg2) & +bind(C, name="_wrap_FIDASetNonlinConvCoef") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxNonlinIters(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxNonlinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxConvFails(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetSuppressAlg(farg1, farg2) & +bind(C, name="_wrap_FIDASetSuppressAlg") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetId(farg1, farg2) & +bind(C, name="_wrap_FIDASetId") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetConstraints(farg1, farg2) & +bind(C, name="_wrap_FIDASetConstraints") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetNonlinearSolver(farg1, farg2) & +bind(C, name="_wrap_FIDASetNonlinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDARootInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDARootInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetRootDirection(farg1, farg2) & +bind(C, name="_wrap_FIDASetRootDirection") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetNoInactiveRootWarn(farg1) & +bind(C, name="_wrap_FIDASetNoInactiveRootWarn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FIDASolve(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FIDASolve") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT), intent(in) :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FIDAComputeY(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAComputeY") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAComputeYp(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAComputeYp") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAGetDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumSteps(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumResEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumResEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumLinSolvSetups(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumLinSolvSetups") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumBacktrackOps(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumBacktrackOps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetConsistentIC(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetConsistentIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetLastOrder(farg1, farg2) & +bind(C, name="_wrap_FIDAGetLastOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentOrder(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentCj(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentCj") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentY(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentY") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentYp(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentYp") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetActualInitStep(farg1, farg2) & +bind(C, name="_wrap_FIDAGetActualInitStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetLastStep(farg1, farg2) & +bind(C, name="_wrap_FIDAGetLastStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentStep(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentTime(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetTolScaleFactor(farg1, farg2) & +bind(C, name="_wrap_FIDAGetTolScaleFactor") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetErrWeights(farg1, farg2) & +bind(C, name="_wrap_FIDAGetErrWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetEstLocalErrors(farg1, farg2) & +bind(C, name="_wrap_FIDAGetEstLocalErrors") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumGEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumGEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetRootInfo(farg1, farg2) & +bind(C, name="_wrap_FIDAGetRootInfo") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetIntegratorStats(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10, farg11) & +bind(C, name="_wrap_FIDAGetIntegratorStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +type(C_PTR), value :: farg7 +type(C_PTR), value :: farg8 +type(C_PTR), value :: farg9 +type(C_PTR), value :: farg10 +type(C_PTR), value :: farg11 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumNonlinSolvIters(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumNonlinSolvIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumNonlinSolvConvFails(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumNonlinSolvConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNonlinSolvStats(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetNonlinSolvStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + + subroutine SWIG_free(cptr) & + bind(C, name="free") + use, intrinsic :: ISO_C_BINDING + type(C_PTR), value :: cptr +end subroutine +function swigc_FIDAGetReturnFlagName(farg1) & +bind(C, name="_wrap_FIDAGetReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +subroutine swigc_FIDAFree(farg1) & +bind(C, name="_wrap_FIDAFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FIDABBDPrecInit(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) & +bind(C, name="_wrap_FIDABBDPrecInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +integer(C_INT64_T), intent(in) :: farg5 +integer(C_INT64_T), intent(in) :: farg6 +real(C_DOUBLE), intent(in) :: farg7 +type(C_FUNPTR), value :: farg8 +type(C_FUNPTR), value :: farg9 +integer(C_INT) :: fresult +end function + +function swigc_FIDABBDPrecReInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDABBDPrecReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDABBDPrecGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDABBDPrecGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDABBDPrecGetNumGfnEvals(farg1, farg2) & +bind(C, name="_wrap_FIDABBDPrecGetNumGfnEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetLinearSolver(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetLinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetJacFn(farg1, farg2) & +bind(C, name="_wrap_FIDASetJacFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetPreconditioner(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetPreconditioner") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetJacTimes(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetJacTimes") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetEpsLin(farg1, farg2) & +bind(C, name="_wrap_FIDASetEpsLin") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetLinearSolutionScaling(farg1, farg2) & +bind(C, name="_wrap_FIDASetLinearSolutionScaling") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetIncrementFactor(farg1, farg2) & +bind(C, name="_wrap_FIDASetIncrementFactor") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetLinWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetLinWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumJacEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumJacEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumPrecEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumPrecEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumPrecSolves(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumPrecSolves") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumLinIters(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumLinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumLinConvFails(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumLinConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumJTSetupEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumJTSetupEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumJtimesEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumJtimesEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumLinResEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumLinResEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetLastLinFlag(farg1, farg2) & +bind(C, name="_wrap_FIDAGetLastLinFlag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetLinReturnFlagName(farg1) & +bind(C, name="_wrap_FIDAGetLinReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FIDACreate() & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +type(C_PTR) :: fresult + +fresult = swigc_FIDACreate() +swig_result = fresult +end function + +function FIDAInit(ida_mem, res, t0, yy0, yp0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: res +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: yy0 +type(N_Vector), target, intent(inout) :: yp0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = ida_mem +farg2 = res +farg3 = t0 +farg4 = c_loc(yy0) +farg5 = c_loc(yp0) +fresult = swigc_FIDAInit(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FIDAReInit(ida_mem, t0, yy0, yp0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: yy0 +type(N_Vector), target, intent(inout) :: yp0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = t0 +farg3 = c_loc(yy0) +farg4 = c_loc(yp0) +fresult = swigc_FIDAReInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDASStolerances(ida_mem, reltol, abstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: reltol +real(C_DOUBLE), intent(in) :: abstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = ida_mem +farg2 = reltol +farg3 = abstol +fresult = swigc_FIDASStolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASVtolerances(ida_mem, reltol, abstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: reltol +type(N_Vector), target, intent(inout) :: abstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = reltol +farg3 = c_loc(abstol) +fresult = swigc_FIDASVtolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAWFtolerances(ida_mem, efun) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: efun +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = ida_mem +farg2 = efun +fresult = swigc_FIDAWFtolerances(farg1, farg2) +swig_result = fresult +end function + +function FIDACalcIC(ida_mem, icopt, tout1) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: icopt +real(C_DOUBLE), intent(in) :: tout1 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = ida_mem +farg2 = icopt +farg3 = tout1 +fresult = swigc_FIDACalcIC(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetNonlinConvCoefIC(ida_mem, epiccon) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: epiccon +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = epiccon +fresult = swigc_FIDASetNonlinConvCoefIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxNumStepsIC(ida_mem, maxnh) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxnh +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxnh +fresult = swigc_FIDASetMaxNumStepsIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxNumJacsIC(ida_mem, maxnj) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxnj +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxnj +fresult = swigc_FIDASetMaxNumJacsIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxNumItersIC(ida_mem, maxnit) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxnit +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxnit +fresult = swigc_FIDASetMaxNumItersIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetLineSearchOffIC(ida_mem, lsoff) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: lsoff +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = lsoff +fresult = swigc_FIDASetLineSearchOffIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetStepToleranceIC(ida_mem, steptol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: steptol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = steptol +fresult = swigc_FIDASetStepToleranceIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxBacksIC(ida_mem, maxbacks) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxbacks +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxbacks +fresult = swigc_FIDASetMaxBacksIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetErrHandlerFn(ida_mem, ehfun, eh_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: ehfun +type(C_PTR) :: eh_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = ehfun +farg3 = eh_data +fresult = swigc_FIDASetErrHandlerFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetErrFile(ida_mem, errfp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: errfp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = errfp +fresult = swigc_FIDASetErrFile(farg1, farg2) +swig_result = fresult +end function + +function FIDASetUserData(ida_mem, user_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: user_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = user_data +fresult = swigc_FIDASetUserData(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxOrd(ida_mem, maxord) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxord +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxord +fresult = swigc_FIDASetMaxOrd(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxNumSteps(ida_mem, mxsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), intent(in) :: mxsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = ida_mem +farg2 = mxsteps +fresult = swigc_FIDASetMaxNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FIDASetInitStep(ida_mem, hin) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: hin +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = hin +fresult = swigc_FIDASetInitStep(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxStep(ida_mem, hmax) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: hmax +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = hmax +fresult = swigc_FIDASetMaxStep(farg1, farg2) +swig_result = fresult +end function + +function FIDASetStopTime(ida_mem, tstop) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: tstop +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = tstop +fresult = swigc_FIDASetStopTime(farg1, farg2) +swig_result = fresult +end function + +function FIDASetNonlinConvCoef(ida_mem, epcon) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: epcon +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = epcon +fresult = swigc_FIDASetNonlinConvCoef(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxErrTestFails(ida_mem, maxnef) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxnef +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxnef +fresult = swigc_FIDASetMaxErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxNonlinIters(ida_mem, maxcor) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxcor +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxcor +fresult = swigc_FIDASetMaxNonlinIters(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxConvFails(ida_mem, maxncf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxncf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxncf +fresult = swigc_FIDASetMaxConvFails(farg1, farg2) +swig_result = fresult +end function + +function FIDASetSuppressAlg(ida_mem, suppressalg) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: suppressalg +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = suppressalg +fresult = swigc_FIDASetSuppressAlg(farg1, farg2) +swig_result = fresult +end function + +function FIDASetId(ida_mem, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: id +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(id) +fresult = swigc_FIDASetId(farg1, farg2) +swig_result = fresult +end function + +function FIDASetConstraints(ida_mem, constraints) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: constraints +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(constraints) +fresult = swigc_FIDASetConstraints(farg1, farg2) +swig_result = fresult +end function + +function FIDASetNonlinearSolver(ida_mem, nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nls) +fresult = swigc_FIDASetNonlinearSolver(farg1, farg2) +swig_result = fresult +end function + +function FIDARootInit(ida_mem, nrtfn, g) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: nrtfn +type(C_FUNPTR), intent(in), value :: g +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = ida_mem +farg2 = nrtfn +farg3 = g +fresult = swigc_FIDARootInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetRootDirection(ida_mem, rootdir) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootdir +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(rootdir(1)) +fresult = swigc_FIDASetRootDirection(farg1, farg2) +swig_result = fresult +end function + +function FIDASetNoInactiveRootWarn(ida_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = ida_mem +fresult = swigc_FIDASetNoInactiveRootWarn(farg1) +swig_result = fresult +end function + +function FIDASolve(ida_mem, tout, tret, yret, ypret, itask) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: tout +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +type(N_Vector), target, intent(inout) :: yret +type(N_Vector), target, intent(inout) :: ypret +integer(C_INT), intent(in) :: itask +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +integer(C_INT) :: farg6 + +farg1 = ida_mem +farg2 = tout +farg3 = c_loc(tret(1)) +farg4 = c_loc(yret) +farg5 = c_loc(ypret) +farg6 = itask +fresult = swigc_FIDASolve(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FIDAComputeY(ida_mem, ycor, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: ycor +type(N_Vector), target, intent(inout) :: y +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(ycor) +farg3 = c_loc(y) +fresult = swigc_FIDAComputeY(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAComputeYp(ida_mem, ycor, yp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: ycor +type(N_Vector), target, intent(inout) :: yp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(ycor) +farg3 = c_loc(yp) +fresult = swigc_FIDAComputeYp(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAGetDky(ida_mem, t, k, dky) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(N_Vector), target, intent(inout) :: dky +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = t +farg3 = k +farg4 = c_loc(dky) +fresult = swigc_FIDAGetDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAGetWorkSpace(ida_mem, lenrw, leniw) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrw +integer(C_LONG), dimension(*), target, intent(inout) :: leniw +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(lenrw(1)) +farg3 = c_loc(leniw(1)) +fresult = swigc_FIDAGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAGetNumSteps(ida_mem, nsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nsteps(1)) +fresult = swigc_FIDAGetNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumResEvals(ida_mem, nrevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nrevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nrevals(1)) +fresult = swigc_FIDAGetNumResEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumLinSolvSetups(ida_mem, nlinsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nlinsetups(1)) +fresult = swigc_FIDAGetNumLinSolvSetups(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumErrTestFails(ida_mem, netfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: netfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(netfails(1)) +fresult = swigc_FIDAGetNumErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumBacktrackOps(ida_mem, nbacktr) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nbacktr +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nbacktr(1)) +fresult = swigc_FIDAGetNumBacktrackOps(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetConsistentIC(ida_mem, yy0_mod, yp0_mod) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: yy0_mod +type(N_Vector), target, intent(inout) :: yp0_mod +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(yy0_mod) +farg3 = c_loc(yp0_mod) +fresult = swigc_FIDAGetConsistentIC(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAGetLastOrder(ida_mem, klast) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), dimension(*), target, intent(inout) :: klast +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(klast(1)) +fresult = swigc_FIDAGetLastOrder(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentOrder(ida_mem, kcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), dimension(*), target, intent(inout) :: kcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(kcur(1)) +fresult = swigc_FIDAGetCurrentOrder(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentCj(ida_mem, cj) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: cj +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(cj(1)) +fresult = swigc_FIDAGetCurrentCj(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentY(ida_mem, ycur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: ycur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = ycur +fresult = swigc_FIDAGetCurrentY(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentYp(ida_mem, ypcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: ypcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = ypcur +fresult = swigc_FIDAGetCurrentYp(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetActualInitStep(ida_mem, hinused) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hinused +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(hinused(1)) +fresult = swigc_FIDAGetActualInitStep(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetLastStep(ida_mem, hlast) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(hlast(1)) +fresult = swigc_FIDAGetLastStep(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentStep(ida_mem, hcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(hcur(1)) +fresult = swigc_FIDAGetCurrentStep(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentTime(ida_mem, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(tcur(1)) +fresult = swigc_FIDAGetCurrentTime(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetTolScaleFactor(ida_mem, tolsfact) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tolsfact +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(tolsfact(1)) +fresult = swigc_FIDAGetTolScaleFactor(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetErrWeights(ida_mem, eweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: eweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(eweight) +fresult = swigc_FIDAGetErrWeights(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetEstLocalErrors(ida_mem, ele) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: ele +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(ele) +fresult = swigc_FIDAGetEstLocalErrors(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumGEvals(ida_mem, ngevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(ngevals(1)) +fresult = swigc_FIDAGetNumGEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetRootInfo(ida_mem, rootsfound) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootsfound +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(rootsfound(1)) +fresult = swigc_FIDAGetRootInfo(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetIntegratorStats(ida_mem, nsteps, nrevals, nlinsetups, netfails, qlast, qcur, hinused, hlast, hcur, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsteps +integer(C_LONG), dimension(*), target, intent(inout) :: nrevals +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetups +integer(C_LONG), dimension(*), target, intent(inout) :: netfails +integer(C_INT), dimension(*), target, intent(inout) :: qlast +integer(C_INT), dimension(*), target, intent(inout) :: qcur +real(C_DOUBLE), dimension(*), target, intent(inout) :: hinused +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +real(C_DOUBLE), dimension(*), target, intent(inout) :: hcur +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 +type(C_PTR) :: farg7 +type(C_PTR) :: farg8 +type(C_PTR) :: farg9 +type(C_PTR) :: farg10 +type(C_PTR) :: farg11 + +farg1 = ida_mem +farg2 = c_loc(nsteps(1)) +farg3 = c_loc(nrevals(1)) +farg4 = c_loc(nlinsetups(1)) +farg5 = c_loc(netfails(1)) +farg6 = c_loc(qlast(1)) +farg7 = c_loc(qcur(1)) +farg8 = c_loc(hinused(1)) +farg9 = c_loc(hlast(1)) +farg10 = c_loc(hcur(1)) +farg11 = c_loc(tcur(1)) +fresult = swigc_FIDAGetIntegratorStats(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10, farg11) +swig_result = fresult +end function + +function FIDAGetNumNonlinSolvIters(ida_mem, nniters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nniters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nniters(1)) +fresult = swigc_FIDAGetNumNonlinSolvIters(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumNonlinSolvConvFails(ida_mem, nncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nncfails(1)) +fresult = swigc_FIDAGetNumNonlinSolvConvFails(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNonlinSolvStats(ida_mem, nniters, nncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nniters +integer(C_LONG), dimension(*), target, intent(inout) :: nncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(nniters(1)) +farg3 = c_loc(nncfails(1)) +fresult = swigc_FIDAGetNonlinSolvStats(farg1, farg2, farg3) +swig_result = fresult +end function + + +subroutine SWIG_chararray_to_string(wrap, string) + use, intrinsic :: ISO_C_BINDING + type(SwigArrayWrapper), intent(IN) :: wrap + character(kind=C_CHAR, len=:), allocatable, intent(OUT) :: string + character(kind=C_CHAR), dimension(:), pointer :: chars + integer(kind=C_SIZE_T) :: i + call c_f_pointer(wrap%data, chars, [wrap%size]) + allocate(character(kind=C_CHAR, len=wrap%size) :: string) + do i=1, wrap%size + string(i:i) = chars(i) + end do +end subroutine + +function FIDAGetReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FIDAGetReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +subroutine FIDAFree(ida_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), target, intent(inout) :: ida_mem +type(C_PTR) :: farg1 + +farg1 = c_loc(ida_mem) +call swigc_FIDAFree(farg1) +end subroutine + +function FIDABBDPrecInit(ida_mem, nlocal, mudq, mldq, mukeep, mlkeep, dq_rel_yy, gres, gcomm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT64_T), intent(in) :: nlocal +integer(C_INT64_T), intent(in) :: mudq +integer(C_INT64_T), intent(in) :: mldq +integer(C_INT64_T), intent(in) :: mukeep +integer(C_INT64_T), intent(in) :: mlkeep +real(C_DOUBLE), intent(in) :: dq_rel_yy +type(C_FUNPTR), intent(in), value :: gres +type(C_FUNPTR), intent(in), value :: gcomm +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 +integer(C_INT64_T) :: farg5 +integer(C_INT64_T) :: farg6 +real(C_DOUBLE) :: farg7 +type(C_FUNPTR) :: farg8 +type(C_FUNPTR) :: farg9 + +farg1 = ida_mem +farg2 = nlocal +farg3 = mudq +farg4 = mldq +farg5 = mukeep +farg6 = mlkeep +farg7 = dq_rel_yy +farg8 = gres +farg9 = gcomm +fresult = swigc_FIDABBDPrecInit(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) +swig_result = fresult +end function + +function FIDABBDPrecReInit(ida_mem, mudq, mldq, dq_rel_yy) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT64_T), intent(in) :: mudq +integer(C_INT64_T), intent(in) :: mldq +real(C_DOUBLE), intent(in) :: dq_rel_yy +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +real(C_DOUBLE) :: farg4 + +farg1 = ida_mem +farg2 = mudq +farg3 = mldq +farg4 = dq_rel_yy +fresult = swigc_FIDABBDPrecReInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDABBDPrecGetWorkSpace(ida_mem, lenrwbbdp, leniwbbdp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwbbdp +integer(C_LONG), dimension(*), target, intent(inout) :: leniwbbdp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(lenrwbbdp(1)) +farg3 = c_loc(leniwbbdp(1)) +fresult = swigc_FIDABBDPrecGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDABBDPrecGetNumGfnEvals(ida_mem, ngevalsbbdp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevalsbbdp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(ngevalsbbdp(1)) +fresult = swigc_FIDABBDPrecGetNumGfnEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDASetLinearSolver(ida_mem, ls, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(SUNLinearSolver), target, intent(inout) :: ls +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(ls) +farg3 = c_loc(a) +fresult = swigc_FIDASetLinearSolver(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetJacFn(ida_mem, jac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: jac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = ida_mem +farg2 = jac +fresult = swigc_FIDASetJacFn(farg1, farg2) +swig_result = fresult +end function + +function FIDASetPreconditioner(ida_mem, pset, psolve) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: pset +type(C_FUNPTR), intent(in), value :: psolve +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = ida_mem +farg2 = pset +farg3 = psolve +fresult = swigc_FIDASetPreconditioner(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetJacTimes(ida_mem, jtsetup, jtimes) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: jtsetup +type(C_FUNPTR), intent(in), value :: jtimes +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = ida_mem +farg2 = jtsetup +farg3 = jtimes +fresult = swigc_FIDASetJacTimes(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetEpsLin(ida_mem, eplifac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: eplifac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = eplifac +fresult = swigc_FIDASetEpsLin(farg1, farg2) +swig_result = fresult +end function + +function FIDASetLinearSolutionScaling(ida_mem, onoff) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: onoff +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = onoff +fresult = swigc_FIDASetLinearSolutionScaling(farg1, farg2) +swig_result = fresult +end function + +function FIDASetIncrementFactor(ida_mem, dqincfac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: dqincfac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = dqincfac +fresult = swigc_FIDASetIncrementFactor(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetLinWorkSpace(ida_mem, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FIDAGetLinWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAGetNumJacEvals(ida_mem, njevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(njevals(1)) +fresult = swigc_FIDAGetNumJacEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumPrecEvals(ida_mem, npevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: npevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(npevals(1)) +fresult = swigc_FIDAGetNumPrecEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumPrecSolves(ida_mem, npsolves) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: npsolves +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(npsolves(1)) +fresult = swigc_FIDAGetNumPrecSolves(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumLinIters(ida_mem, nliters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nliters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nliters(1)) +fresult = swigc_FIDAGetNumLinIters(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumLinConvFails(ida_mem, nlcfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nlcfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nlcfails(1)) +fresult = swigc_FIDAGetNumLinConvFails(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumJTSetupEvals(ida_mem, njtsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njtsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(njtsetups(1)) +fresult = swigc_FIDAGetNumJTSetupEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumJtimesEvals(ida_mem, njvevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njvevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(njvevals(1)) +fresult = swigc_FIDAGetNumJtimesEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumLinResEvals(ida_mem, nrevalsls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nrevalsls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nrevalsls(1)) +fresult = swigc_FIDAGetNumLinResEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetLastLinFlag(ida_mem, flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: flag +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(flag(1)) +fresult = swigc_FIDAGetLastLinFlag(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetLinReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FIDAGetLinReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/ida.c b/deps/AMICI/ThirdParty/sundials/src/ida/ida.c index c950af8a0..732893efe 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/ida.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/ida.c @@ -1,9 +1,8 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Alan Hindmarsh, Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -13,7 +12,6 @@ * SUNDIALS Copyright End * ----------------------------------------------------------------- * This is the implementation file for the main IDA solver. - * It is independent of the linear solver in use. * ----------------------------------------------------------------- * * EXPORTED FUNCTIONS @@ -88,7 +86,7 @@ #include "ida_impl.h" #include -#include "sunnonlinsol/sunnonlinsol_newton.h" +#include /* * ================================================================= @@ -176,7 +174,7 @@ #define MAXNI 10 /* max. Newton iterations in IC calc. */ #define EPCON RCONST(0.33) /* Newton convergence test constant */ #define MAXBACKS 100 /* max backtracks per Newton step in IDACalcIC */ -#define XRATE RCONST(0.25) /* constant for updating Jacobian/preconditioner */ +#define XRATE RCONST(0.25) /* constant for updating Jacobian/preconditioner */ /* * ================================================================= @@ -194,6 +192,7 @@ static void IDAFreeVectors(IDAMem IDA_mem); /* Initial setup */ int IDAInitialSetup(IDAMem IDA_mem); + static int IDAEwtSetSS(IDAMem IDA_mem, N_Vector ycur, N_Vector weight); static int IDAEwtSetSV(IDAMem IDA_mem, N_Vector ycur, N_Vector weight); @@ -289,6 +288,7 @@ void *IDACreate(void) IDA_mem->ida_res = NULL; IDA_mem->ida_user_data = NULL; IDA_mem->ida_itol = IDA_NN; + IDA_mem->ida_atolmin0 = SUNTRUE; IDA_mem->ida_user_efun = SUNFALSE; IDA_mem->ida_efun = NULL; IDA_mem->ida_edata = NULL; @@ -325,12 +325,12 @@ void *IDACreate(void) IDA_mem->ida_liw = 38; /* No mallocs have been done yet */ - IDA_mem->ida_VatolMallocDone = SUNFALSE; + IDA_mem->ida_VatolMallocDone = SUNFALSE; IDA_mem->ida_constraintsMallocDone = SUNFALSE; - IDA_mem->ida_idMallocDone = SUNFALSE; - IDA_mem->ida_MallocDone = SUNFALSE; + IDA_mem->ida_idMallocDone = SUNFALSE; + IDA_mem->ida_MallocDone = SUNFALSE; - /* Initialize nonlinear solver pointer */ + /* Initialize nonlinear solver variables */ IDA_mem->NLS = NULL; IDA_mem->ownNLS = SUNFALSE; @@ -628,12 +628,13 @@ int IDASStolerances(void *ida_mem, realtype reltol, realtype abstol) IDA_mem->ida_rtol = reltol; IDA_mem->ida_Satol = abstol; + IDA_mem->ida_atolmin0 = (abstol == ZERO); IDA_mem->ida_itol = IDA_SS; IDA_mem->ida_user_efun = SUNFALSE; IDA_mem->ida_efun = IDAEwtSet; - IDA_mem->ida_edata = NULL; /* will be set to ida_mem in InitialSetup; */ + IDA_mem->ida_edata = NULL; /* will be set to ida_mem in InitialSetup */ return(IDA_SUCCESS); } @@ -642,6 +643,7 @@ int IDASStolerances(void *ida_mem, realtype reltol, realtype abstol) int IDASVtolerances(void *ida_mem, realtype reltol, N_Vector abstol) { IDAMem IDA_mem; + realtype atolmin; if (ida_mem==NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASVtolerances", MSG_NO_MEM); @@ -661,7 +663,8 @@ int IDASVtolerances(void *ida_mem, realtype reltol, N_Vector abstol) return(IDA_ILL_INPUT); } - if (N_VMin(abstol) < ZERO) { + atolmin = N_VMin(abstol); + if (atolmin < ZERO) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASVtolerances", MSG_BAD_ATOL); return(IDA_ILL_INPUT); } @@ -677,12 +680,13 @@ int IDASVtolerances(void *ida_mem, realtype reltol, N_Vector abstol) IDA_mem->ida_rtol = reltol; N_VScale(ONE, abstol, IDA_mem->ida_Vatol); + IDA_mem->ida_atolmin0 = (atolmin == ZERO); IDA_mem->ida_itol = IDA_SV; IDA_mem->ida_user_efun = SUNFALSE; IDA_mem->ida_efun = IDAEwtSet; - IDA_mem->ida_edata = NULL; /* will be set to ida_mem in InitialSetup; */ + IDA_mem->ida_edata = NULL; /* will be set to ida_mem in InitialSetup */ return(IDA_SUCCESS); } @@ -870,6 +874,7 @@ int IDARootInit(void *ida_mem, int nrtfn, IDARootFn g) return(IDA_SUCCESS); } + /* * ----------------------------------------------------------------- * Main solver function @@ -971,7 +976,7 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, if (IDA_mem->ida_SetupDone == SUNFALSE) { ier = IDAInitialSetup(IDA_mem); - if (ier != IDA_SUCCESS) return(IDA_ILL_INPUT); + if (ier != IDA_SUCCESS) return(ier); IDA_mem->ida_SetupDone = SUNTRUE; } @@ -1000,22 +1005,21 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, IDA_mem->ida_hh = PT001*tdist; ypnorm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_phi[1], IDA_mem->ida_ewt, IDA_mem->ida_suppressalg); - if (ypnorm > HALF/IDA_mem->ida_hh) - IDA_mem->ida_hh = HALF/ypnorm; - if (tout < IDA_mem->ida_tn) - IDA_mem->ida_hh = -IDA_mem->ida_hh; + if (ypnorm > HALF / IDA_mem->ida_hh) IDA_mem->ida_hh = HALF/ypnorm; + if (tout < IDA_mem->ida_tn) IDA_mem->ida_hh = -IDA_mem->ida_hh; } - rh = SUNRabs(IDA_mem->ida_hh)*IDA_mem->ida_hmax_inv; + rh = SUNRabs(IDA_mem->ida_hh) * IDA_mem->ida_hmax_inv; if (rh > ONE) IDA_mem->ida_hh /= rh; if (IDA_mem->ida_tstopset) { if ( (IDA_mem->ida_tstop - IDA_mem->ida_tn)*IDA_mem->ida_hh <= ZERO) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_BAD_TSTOP, IDA_mem->ida_tstop, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", + MSG_BAD_TSTOP, IDA_mem->ida_tstop, IDA_mem->ida_tn); return(IDA_ILL_INPUT); } if ( (IDA_mem->ida_tn + IDA_mem->ida_hh - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) - IDA_mem->ida_hh = (IDA_mem->ida_tstop - IDA_mem->ida_tn)*(ONE-FOUR*IDA_mem->ida_uround); + IDA_mem->ida_hh = (IDA_mem->ida_tstop - IDA_mem->ida_tn)*(ONE - FOUR * IDA_mem->ida_uround); } IDA_mem->ida_h0u = IDA_mem->ida_hh; @@ -1026,12 +1030,14 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, if (IDA_mem->ida_nrtfn > 0) { ier = IDARcheck1(IDA_mem); if (ier == IDA_RTFUNC_FAIL) { - IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDA", "IDARcheck1", MSG_RTFUNC_FAILED, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDA", "IDARcheck1", + MSG_RTFUNC_FAILED, IDA_mem->ida_tn); return(IDA_RTFUNC_FAIL); } } - N_VScale(IDA_mem->ida_hh, IDA_mem->ida_phi[1], IDA_mem->ida_phi[1]); /* set phi[1] = hh*y' */ + /* set phi[1] = hh*y' */ + N_VScale(IDA_mem->ida_hh, IDA_mem->ida_phi[1], IDA_mem->ida_phi[1]); /* Set the convergence test constants epsNewt and toldel */ IDA_mem->ida_epsNewt = IDA_mem->ida_epcon; @@ -1060,10 +1066,12 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, ier = IDARcheck2(IDA_mem); if (ier == CLOSERT) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDARcheck2", MSG_CLOSE_ROOTS, IDA_mem->ida_tlo); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDARcheck2", + MSG_CLOSE_ROOTS, IDA_mem->ida_tlo); return(IDA_ILL_INPUT); } else if (ier == IDA_RTFUNC_FAIL) { - IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDA", "IDARcheck2", MSG_RTFUNC_FAILED, IDA_mem->ida_tlo); + IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDA", "IDARcheck2", + MSG_RTFUNC_FAILED, IDA_mem->ida_tlo); return(IDA_RTFUNC_FAIL); } else if (ier == RTFOUND) { IDA_mem->ida_tretlast = *tret = IDA_mem->ida_tlo; @@ -1087,7 +1095,8 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, IDA_mem->ida_tretlast = *tret = IDA_mem->ida_tlo; return(IDA_ROOT_RETURN); } else if (ier == IDA_RTFUNC_FAIL) { /* g failed */ - IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDA", "IDARcheck3", MSG_RTFUNC_FAILED, IDA_mem->ida_tlo); + IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDA", "IDARcheck3", + MSG_RTFUNC_FAILED, IDA_mem->ida_tlo); return(IDA_RTFUNC_FAIL); } } @@ -1095,7 +1104,7 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, } /* end of root stop check */ - /* Now test for all other stop conditions. */ + /* Now test for all other stop conditions. */ istate = IDAStopTest1(IDA_mem, tout, tret, yret, ypret, itask); if (istate != CONTINUE_STEPS) return(istate); @@ -1108,7 +1117,8 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, /* Check for too many steps taken. */ if ( (IDA_mem->ida_mxstep>0) && (nstloc >= IDA_mem->ida_mxstep) ) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_MAX_STEPS, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", + MSG_MAX_STEPS, IDA_mem->ida_tn); istate = IDA_TOO_MUCH_WORK; *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; break; /* Here yy=yret and yp=ypret already have the current solution. */ @@ -1129,9 +1139,11 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, if (ier != 0) { if (IDA_mem->ida_itol == IDA_WF) - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_EWT_NOW_FAIL, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", + MSG_EWT_NOW_FAIL, IDA_mem->ida_tn); else - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_EWT_NOW_BAD, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", + MSG_EWT_NOW_BAD, IDA_mem->ida_tn); istate = IDA_ILL_INPUT; ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); @@ -1149,7 +1161,8 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, IDA_mem->ida_tolsf = IDA_mem->ida_uround * nrm; if (IDA_mem->ida_tolsf > ONE) { IDA_mem->ida_tolsf *= TEN; - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_TOO_MUCH_ACC, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", + MSG_TOO_MUCH_ACC, IDA_mem->ida_tn); istate = IDA_TOO_MUCH_ACC; *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; if (IDA_mem->ida_nst > 0) ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); @@ -1185,7 +1198,8 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, IDA_mem->ida_tretlast = *tret = IDA_mem->ida_tlo; break; } else if (ier == IDA_RTFUNC_FAIL) { /* g failed */ - IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDA", "IDARcheck3", MSG_RTFUNC_FAILED, IDA_mem->ida_tlo); + IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDA", "IDARcheck3", + MSG_RTFUNC_FAILED, IDA_mem->ida_tlo); istate = IDA_RTFUNC_FAIL; break; } @@ -1204,7 +1218,8 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, } } if ((IDA_mem->ida_mxgnull > 0) && inactive_roots) { - IDAProcessError(IDA_mem, IDA_WARNING, "IDA", "IDASolve", MSG_INACTIVE_ROOTS); + IDAProcessError(IDA_mem, IDA_WARNING, "IDA", "IDASolve", + MSG_INACTIVE_ROOTS); } } @@ -1222,7 +1237,7 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, /* * ----------------------------------------------------------------- - * Interpolated output + * Interpolated output and extraction functions * ----------------------------------------------------------------- */ @@ -1271,8 +1286,7 @@ int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky) /* Check t for legality. Here tn - hused is t_{n-1}. */ tfuzz = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); - if (IDA_mem->ida_hh < ZERO) - tfuzz = - tfuzz; + if (IDA_mem->ida_hh < ZERO) tfuzz = - tfuzz; tp = IDA_mem->ida_tn - IDA_mem->ida_hused - tfuzz; if ((t - tp)*IDA_mem->ida_hh < ZERO) { IDAProcessError(IDA_mem, IDA_BAD_T, "IDA", "IDAGetDky", MSG_BAD_T, t, @@ -1340,6 +1354,48 @@ int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky) return(IDA_SUCCESS); } +/* + * IDAComputeY + * + * Computes y based on the current prediction and given correction. + */ +int IDAComputeY(void *ida_mem, N_Vector ycor, N_Vector y) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAComputeY", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + N_VLinearSum(ONE, IDA_mem->ida_yypredict, ONE, ycor, y); + + return(IDA_SUCCESS); +} + +/* + * IDAComputeYp + * + * Computes y' based on the current prediction and given correction. + */ +int IDAComputeYp(void *ida_mem, N_Vector ycor, N_Vector yp) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAComputeYp", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + N_VLinearSum(ONE, IDA_mem->ida_yppredict, IDA_mem->ida_cj, ycor, yp); + + return(IDA_SUCCESS); +} + /* * ----------------------------------------------------------------- * Deallocation function @@ -1365,10 +1421,11 @@ void IDAFree(void **ida_mem) IDAFreeVectors(IDA_mem); - /* if IDA created the nonlinear solver object then free it */ + /* if IDA created the NLS object then free it */ if (IDA_mem->ownNLS) { SUNNonlinSolFree(IDA_mem->NLS); IDA_mem->ownNLS = SUNFALSE; + IDA_mem->NLS = NULL; } if (IDA_mem->ida_lfree != NULL) @@ -1441,7 +1498,7 @@ static booleantype IDAAllocVectors(IDAMem IDA_mem, N_Vector tmpl) { int i, j, maxcol; - /* Allocate ewt, ee, delta, ypredict, yppredict, savres, tempv1, tempv2, tempv3 */ + /* Allocate ewt, ee, delta, yypredict, yppredict, savres, tempv1, tempv2, tempv3 */ IDA_mem->ida_ewt = N_VClone(tmpl); if (IDA_mem->ida_ewt == NULL) return(SUNFALSE); @@ -1522,7 +1579,6 @@ static booleantype IDAAllocVectors(IDAMem IDA_mem, N_Vector tmpl) return(SUNFALSE); } - /* Allocate phi[0] ... phi[maxord]. Make sure phi[2] and phi[3] are allocated (for use as temporary vectors), regardless of maxord. */ @@ -1564,35 +1620,39 @@ static void IDAFreeVectors(IDAMem IDA_mem) { int j, maxcol; - N_VDestroy(IDA_mem->ida_ewt); - N_VDestroy(IDA_mem->ida_ee); - N_VDestroy(IDA_mem->ida_delta); - N_VDestroy(IDA_mem->ida_yypredict); - N_VDestroy(IDA_mem->ida_yppredict); - N_VDestroy(IDA_mem->ida_savres); - N_VDestroy(IDA_mem->ida_tempv1); - N_VDestroy(IDA_mem->ida_tempv2); - N_VDestroy(IDA_mem->ida_tempv3); + N_VDestroy(IDA_mem->ida_ewt); IDA_mem->ida_ewt = NULL; + N_VDestroy(IDA_mem->ida_ee); IDA_mem->ida_ee = NULL; + N_VDestroy(IDA_mem->ida_delta); IDA_mem->ida_delta = NULL; + N_VDestroy(IDA_mem->ida_yypredict); IDA_mem->ida_yypredict = NULL; + N_VDestroy(IDA_mem->ida_yppredict); IDA_mem->ida_yppredict = NULL; + N_VDestroy(IDA_mem->ida_savres); IDA_mem->ida_savres = NULL; + N_VDestroy(IDA_mem->ida_tempv1); IDA_mem->ida_tempv1 = NULL; + N_VDestroy(IDA_mem->ida_tempv2); IDA_mem->ida_tempv2 = NULL; + N_VDestroy(IDA_mem->ida_tempv3); IDA_mem->ida_tempv3 = NULL; maxcol = SUNMAX(IDA_mem->ida_maxord_alloc,3); - for(j=0; j <= maxcol; j++) N_VDestroy(IDA_mem->ida_phi[j]); + for(j=0; j <= maxcol; j++) { + N_VDestroy(IDA_mem->ida_phi[j]); + IDA_mem->ida_phi[j] = NULL; + } IDA_mem->ida_lrw -= (maxcol + 10)*IDA_mem->ida_lrw1; IDA_mem->ida_liw -= (maxcol + 10)*IDA_mem->ida_liw1; if (IDA_mem->ida_VatolMallocDone) { - N_VDestroy(IDA_mem->ida_Vatol); + N_VDestroy(IDA_mem->ida_Vatol); IDA_mem->ida_Vatol = NULL; IDA_mem->ida_lrw -= IDA_mem->ida_lrw1; IDA_mem->ida_liw -= IDA_mem->ida_liw1; } if (IDA_mem->ida_constraintsMallocDone) { N_VDestroy(IDA_mem->ida_constraints); + IDA_mem->ida_constraints = NULL; IDA_mem->ida_lrw -= IDA_mem->ida_lrw1; IDA_mem->ida_liw -= IDA_mem->ida_liw1; } if (IDA_mem->ida_idMallocDone) { - N_VDestroy(IDA_mem->ida_id); + N_VDestroy(IDA_mem->ida_id); IDA_mem->ida_id = NULL; IDA_mem->ida_lrw -= IDA_mem->ida_lrw1; IDA_mem->ida_liw -= IDA_mem->ida_liw1; } @@ -1625,19 +1685,22 @@ int IDAInitialSetup(IDAMem IDA_mem) /* Test for more vector operations, depending on options */ if (IDA_mem->ida_suppressalg) if (IDA_mem->ida_phi[0]->ops->nvwrmsnormmask == NULL) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", MSG_BAD_NVECTOR); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", + MSG_BAD_NVECTOR); return(IDA_ILL_INPUT); } /* Test id vector for legality */ if (IDA_mem->ida_suppressalg && (IDA_mem->ida_id==NULL)){ - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", MSG_MISSING_ID); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", + MSG_MISSING_ID); return(IDA_ILL_INPUT); } /* Did the user specify tolerances? */ if (IDA_mem->ida_itol == IDA_NN) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", MSG_NO_TOLS); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", + MSG_NO_TOLS); return(IDA_ILL_INPUT); } @@ -1646,13 +1709,14 @@ int IDAInitialSetup(IDAMem IDA_mem) else IDA_mem->ida_edata = IDA_mem; /* Initial error weight vector */ - ier = IDA_mem->ida_efun(IDA_mem->ida_phi[0], IDA_mem->ida_ewt, - IDA_mem->ida_edata); + ier = IDA_mem->ida_efun(IDA_mem->ida_phi[0], IDA_mem->ida_ewt, IDA_mem->ida_edata); if (ier != 0) { if (IDA_mem->ida_itol == IDA_WF) - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", MSG_FAIL_EWT); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", + MSG_FAIL_EWT); else - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", MSG_BAD_EWT); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", + MSG_BAD_EWT); return(IDA_ILL_INPUT); } @@ -1660,7 +1724,8 @@ int IDAInitialSetup(IDAMem IDA_mem) if (IDA_mem->ida_constraintsSet) { conOK = N_VConstrMask(IDA_mem->ida_constraints, IDA_mem->ida_phi[0], IDA_mem->ida_tempv2); if (!conOK) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", MSG_Y0_FAIL_CONSTR); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", + MSG_Y0_FAIL_CONSTR); return(IDA_ILL_INPUT); } } @@ -1669,16 +1734,18 @@ int IDAInitialSetup(IDAMem IDA_mem) if (IDA_mem->ida_linit != NULL) { ier = IDA_mem->ida_linit(IDA_mem); if (ier != 0) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", MSG_LINIT_FAIL); + IDAProcessError(IDA_mem, IDA_LINIT_FAIL, "IDA", "IDAInitialSetup", + MSG_LINIT_FAIL); return(IDA_LINIT_FAIL); } } /* Initialize the nonlinear solver (must occur after linear solver is initialize) so - * that lsetup and lsolve pointer have been set */ + * that lsetup and lsolve pointers have been set */ ier = idaNlsInit(IDA_mem); if (ier != IDA_SUCCESS) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", MSG_NLS_INIT_FAIL); + IDAProcessError(IDA_mem, IDA_NLS_INIT_FAIL, "IDA", "IDAInitialSetup", + MSG_NLS_INIT_FAIL); return(IDA_NLS_INIT_FAIL); } @@ -1726,9 +1793,9 @@ int IDAEwtSet(N_Vector ycur, N_Vector weight, void *data) * IDAEwtSetSS * * This routine sets ewt as decribed above in the case itol=IDA_SS. - * It tests for non-positive components before inverting. IDAEwtSetSS - * returns 0 if ewt is successfully set to a positive vector - * and -1 otherwise. In the latter case, ewt is considered + * If the absolute tolerance is zero, it tests for non-positive components + * before inverting. IDAEwtSetSS returns 0 if ewt is successfully set to a + * positive vector and -1 otherwise. In the latter case, ewt is considered * undefined. */ @@ -1737,7 +1804,9 @@ static int IDAEwtSetSS(IDAMem IDA_mem, N_Vector ycur, N_Vector weight) N_VAbs(ycur, IDA_mem->ida_tempv1); N_VScale(IDA_mem->ida_rtol, IDA_mem->ida_tempv1, IDA_mem->ida_tempv1); N_VAddConst(IDA_mem->ida_tempv1, IDA_mem->ida_Satol, IDA_mem->ida_tempv1); - if (N_VMin(IDA_mem->ida_tempv1) <= ZERO) return(-1); + if (IDA_mem->ida_atolmin0) { + if (N_VMin(IDA_mem->ida_tempv1) <= ZERO) return(-1); + } N_VInv(IDA_mem->ida_tempv1, weight); return(0); } @@ -1746,18 +1815,20 @@ static int IDAEwtSetSS(IDAMem IDA_mem, N_Vector ycur, N_Vector weight) * IDAEwtSetSV * * This routine sets ewt as decribed above in the case itol=IDA_SV. - * It tests for non-positive components before inverting. IDAEwtSetSV - * returns 0 if ewt is successfully set to a positive vector - * and -1 otherwise. In the latter case, ewt is considered + * If the absolute tolerance is zero, it tests for non-positive components + * before inverting. IDAEwtSetSV returns 0 if ewt is successfully set to a + * positive vector and -1 otherwise. In the latter case, ewt is considered * undefined. */ static int IDAEwtSetSV(IDAMem IDA_mem, N_Vector ycur, N_Vector weight) { N_VAbs(ycur, IDA_mem->ida_tempv1); - N_VLinearSum(IDA_mem->ida_rtol, IDA_mem->ida_tempv1, ONE, - IDA_mem->ida_Vatol, IDA_mem->ida_tempv1); - if (N_VMin(IDA_mem->ida_tempv1) <= ZERO) return(-1); + N_VLinearSum(IDA_mem->ida_rtol, IDA_mem->ida_tempv1, + ONE, IDA_mem->ida_Vatol, IDA_mem->ida_tempv1); + if (IDA_mem->ida_atolmin0) { + if (N_VMin(IDA_mem->ida_tempv1) <= ZERO) return(-1); + } N_VInv(IDA_mem->ida_tempv1, weight); return(0); } @@ -1798,7 +1869,8 @@ static int IDAStopTest1(IDAMem IDA_mem, realtype tout, realtype *tret, if (IDA_mem->ida_tstopset) { /* Test for tn past tstop, tn = tretlast, tn past tout, tn near tstop. */ if ( (IDA_mem->ida_tn - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_BAD_TSTOP, IDA_mem->ida_tstop, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", + MSG_BAD_TSTOP, IDA_mem->ida_tstop, IDA_mem->ida_tn); return(IDA_ILL_INPUT); } } @@ -1823,7 +1895,8 @@ static int IDAStopTest1(IDAMem IDA_mem, realtype tout, realtype *tret, if (SUNRabs(IDA_mem->ida_tn - IDA_mem->ida_tstop) <= troundoff) { ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tstop, yret, ypret); if (ier != IDA_SUCCESS) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_BAD_TSTOP, IDA_mem->ida_tstop, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", + MSG_BAD_TSTOP, IDA_mem->ida_tstop, IDA_mem->ida_tn); return(IDA_ILL_INPUT); } *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tstop; @@ -1841,7 +1914,8 @@ static int IDAStopTest1(IDAMem IDA_mem, realtype tout, realtype *tret, if (IDA_mem->ida_tstopset) { /* Test for tn past tstop, tn past tretlast, and tn near tstop. */ if ((IDA_mem->ida_tn - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_BAD_TSTOP, IDA_mem->ida_tstop, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", + MSG_BAD_TSTOP, IDA_mem->ida_tstop, IDA_mem->ida_tn); return(IDA_ILL_INPUT); } } @@ -1858,7 +1932,8 @@ static int IDAStopTest1(IDAMem IDA_mem, realtype tout, realtype *tret, if (SUNRabs(IDA_mem->ida_tn - IDA_mem->ida_tstop) <= troundoff) { ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tstop, yret, ypret); if (ier != IDA_SUCCESS) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_BAD_TSTOP, IDA_mem->ida_tstop, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", + MSG_BAD_TSTOP, IDA_mem->ida_tstop, IDA_mem->ida_tn); return(IDA_ILL_INPUT); } *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tstop; @@ -1971,35 +2046,43 @@ static int IDAHandleFailure(IDAMem IDA_mem, int sflag) switch (sflag) { case IDA_ERR_FAIL: - IDAProcessError(IDA_mem, IDA_ERR_FAIL, "IDA", "IDASolve", MSG_ERR_FAILS, IDA_mem->ida_tn, IDA_mem->ida_hh); + IDAProcessError(IDA_mem, IDA_ERR_FAIL, "IDA", "IDASolve", + MSG_ERR_FAILS, IDA_mem->ida_tn, IDA_mem->ida_hh); return(IDA_ERR_FAIL); case IDA_CONV_FAIL: - IDAProcessError(IDA_mem, IDA_CONV_FAIL, "IDA", "IDASolve", MSG_CONV_FAILS, IDA_mem->ida_tn, IDA_mem->ida_hh); + IDAProcessError(IDA_mem, IDA_CONV_FAIL, "IDA", "IDASolve", + MSG_CONV_FAILS, IDA_mem->ida_tn, IDA_mem->ida_hh); return(IDA_CONV_FAIL); case IDA_LSETUP_FAIL: - IDAProcessError(IDA_mem, IDA_LSETUP_FAIL, "IDA", "IDASolve", MSG_SETUP_FAILED, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_LSETUP_FAIL, "IDA", "IDASolve", + MSG_SETUP_FAILED, IDA_mem->ida_tn); return(IDA_LSETUP_FAIL); case IDA_LSOLVE_FAIL: - IDAProcessError(IDA_mem, IDA_LSOLVE_FAIL, "IDA", "IDASolve", MSG_SOLVE_FAILED, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_LSOLVE_FAIL, "IDA", "IDASolve", + MSG_SOLVE_FAILED, IDA_mem->ida_tn); return(IDA_LSOLVE_FAIL); case IDA_REP_RES_ERR: - IDAProcessError(IDA_mem, IDA_REP_RES_ERR, "IDA", "IDASolve", MSG_REP_RES_ERR, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_REP_RES_ERR, "IDA", "IDASolve", + MSG_REP_RES_ERR, IDA_mem->ida_tn); return(IDA_REP_RES_ERR); case IDA_RES_FAIL: - IDAProcessError(IDA_mem, IDA_RES_FAIL, "IDA", "IDASolve", MSG_RES_NONRECOV, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_RES_FAIL, "IDA", "IDASolve", + MSG_RES_NONRECOV, IDA_mem->ida_tn); return(IDA_RES_FAIL); case IDA_CONSTR_FAIL: - IDAProcessError(IDA_mem, IDA_CONSTR_FAIL, "IDA", "IDASolve", MSG_FAILED_CONSTR, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_CONSTR_FAIL, "IDA", "IDASolve", + MSG_FAILED_CONSTR, IDA_mem->ida_tn); return(IDA_CONSTR_FAIL); case IDA_MEM_NULL: - IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASolve", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASolve", + MSG_NO_MEM); return(IDA_MEM_NULL); case SUN_NLS_MEM_NULL: @@ -2011,6 +2094,10 @@ static int IDAHandleFailure(IDAMem IDA_mem, int sflag) IDAProcessError(IDA_mem, IDA_NLS_SETUP_FAIL, "IDA", "IDASolve", MSG_NLS_SETUP_FAILED, IDA_mem->ida_tn); return(IDA_NLS_SETUP_FAIL); + case IDA_NLS_FAIL: + IDAProcessError(IDA_mem, IDA_NLS_FAIL, "IDA", "IDASolve", + MSG_NLS_FAIL, IDA_mem->ida_tn); + return(IDA_NLS_FAIL); } /* This return should never happen */ @@ -2157,7 +2244,7 @@ static int IDAStep(IDAMem IDA_mem) /* kflag == IDA_SUCCESS */ break; - } + } /* end loop */ /* Nonlinear system solve and error test were both successful; update data, and consider change of step and/or order */ @@ -2173,7 +2260,7 @@ static int IDAStep(IDAMem IDA_mem) before it is needed again (2) the value of ee is only valid if IDAHandleNFlag() returns either PREDICT_AGAIN or IDA_SUCCESS - */ + */ N_VScale(ck, IDA_mem->ida_ee, IDA_mem->ida_ee); @@ -2198,7 +2285,8 @@ static void IDASetCoeffs(IDAMem IDA_mem, realtype *ck) /* Set coefficients for the current stepsize h */ - if (IDA_mem->ida_hh != IDA_mem->ida_hused || IDA_mem->ida_kk != IDA_mem->ida_kused) + if ( (IDA_mem->ida_hh != IDA_mem->ida_hused) || + (IDA_mem->ida_kk != IDA_mem->ida_kused) ) IDA_mem->ida_ns = 0; IDA_mem->ida_ns = SUNMIN(IDA_mem->ida_ns+1, IDA_mem->ida_kused+2); if (IDA_mem->ida_kk + 1 >= IDA_mem->ida_ns) { @@ -2207,7 +2295,7 @@ static void IDASetCoeffs(IDAMem IDA_mem, realtype *ck) temp1 = IDA_mem->ida_hh; IDA_mem->ida_gamma[0] = ZERO; IDA_mem->ida_sigma[0] = ONE; - for(i=1; i<=IDA_mem->ida_kk; i++){ + for(i=1; i<=IDA_mem->ida_kk; i++) { temp2 = IDA_mem->ida_psi[i-1]; IDA_mem->ida_psi[i-1] = temp1; IDA_mem->ida_beta[i] = IDA_mem->ida_beta[i-1] * IDA_mem->ida_psi[i-1] / temp2; @@ -2221,7 +2309,7 @@ static void IDASetCoeffs(IDAMem IDA_mem, realtype *ck) /* compute alphas, alpha0 */ alphas = ZERO; alpha0 = ZERO; - for(i=0; iida_kk ;i++){ + for(i=0; iida_kk; i++) { alphas = alphas - ONE/(i+1); alpha0 = alpha0 - IDA_mem->ida_alpha[i]; } @@ -2238,11 +2326,12 @@ static void IDASetCoeffs(IDAMem IDA_mem, realtype *ck) /* change phi to phi-star */ /* Scale i=IDA_mem->ida_ns to i<=IDA_mem->ida_kk */ - if (IDA_mem->ida_ns <= IDA_mem->ida_kk) - (void) N_VScaleVectorArray(IDA_mem->ida_kk-IDA_mem->ida_ns+1, + if (IDA_mem->ida_ns <= IDA_mem->ida_kk) { + (void) N_VScaleVectorArray(IDA_mem->ida_kk - IDA_mem->ida_ns + 1, IDA_mem->ida_beta+IDA_mem->ida_ns, IDA_mem->ida_phi+IDA_mem->ida_ns, IDA_mem->ida_phi+IDA_mem->ida_ns); + } } @@ -2277,6 +2366,7 @@ static int IDANls(IDAMem IDA_mem) int retval; booleantype constraintsPassed, callLSetup; realtype temp1, temp2, vnorm; + N_Vector mm, tmp; callLSetup = SUNFALSE; @@ -2299,22 +2389,22 @@ static int IDANls(IDAMem IDA_mem) } /* initial guess for the correction to the predictor */ - N_VConst(ZERO, IDA_mem->ida_delta); + N_VConst(ZERO, IDA_mem->ida_ee); /* call nonlinear solver setup if it exists */ if ((IDA_mem->NLS)->ops->setup) { - retval = SUNNonlinSolSetup(IDA_mem->NLS, IDA_mem->ida_delta, IDA_mem); + retval = SUNNonlinSolSetup(IDA_mem->NLS, IDA_mem->ida_ee, IDA_mem); if (retval < 0) return(IDA_NLS_SETUP_FAIL); if (retval > 0) return(IDA_NLS_SETUP_RECVR); } /* solve the nonlinear system */ retval = SUNNonlinSolSolve(IDA_mem->NLS, - IDA_mem->ida_delta, IDA_mem->ida_ee, + IDA_mem->ida_yypredict, IDA_mem->ida_ee, IDA_mem->ida_ewt, IDA_mem->ida_epsNewt, callLSetup, IDA_mem); - /* update yy and yp based on the final correction from the nonlinear solve */ + /* update yy and yp based on the final correction from the nonlinear solver */ N_VLinearSum(ONE, IDA_mem->ida_yypredict, ONE, IDA_mem->ida_ee, IDA_mem->ida_yy); N_VLinearSum(ONE, IDA_mem->ida_yppredict, IDA_mem->ida_cj, IDA_mem->ida_ee, IDA_mem->ida_yp); @@ -2323,44 +2413,46 @@ static int IDANls(IDAMem IDA_mem) /* If otherwise successful, check and enforce inequality constraints. */ - if (IDA_mem->ida_constraintsSet){ /* Check constraints and get mask vector mm, - set where constraints failed */ - IDA_mem->ida_mm = IDA_mem->ida_tempv2; + if (IDA_mem->ida_constraintsSet) { + + /* shortcut names for temporary work vectors */ + mm = IDA_mem->ida_tempv2; + tmp = IDA_mem->ida_tempv1; + + /* Get mask vector mm, set where constraints failed */ constraintsPassed = N_VConstrMask(IDA_mem->ida_constraints, - IDA_mem->ida_yy, IDA_mem->ida_mm); + IDA_mem->ida_yy, mm); if (constraintsPassed) return(IDA_SUCCESS); - else { - N_VCompare(ONEPT5, IDA_mem->ida_constraints, IDA_mem->ida_tempv1); - /* a , where a[i] =1. when |c[i]| = 2 , c the vector of constraints */ - N_VProd(IDA_mem->ida_tempv1, IDA_mem->ida_constraints, - IDA_mem->ida_tempv1); /* a * c */ - N_VDiv(IDA_mem->ida_tempv1, IDA_mem->ida_ewt, - IDA_mem->ida_tempv1); /* a * c * wt */ - N_VLinearSum(ONE, IDA_mem->ida_yy, -PT1, - IDA_mem->ida_tempv1, IDA_mem->ida_tempv1); /* y - 0.1 * a * c * wt */ - N_VProd(IDA_mem->ida_tempv1, IDA_mem->ida_mm, - IDA_mem->ida_tempv1); /* v = mm*(y-.1*a*c*wt) */ - vnorm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_tempv1, - IDA_mem->ida_ewt, SUNFALSE); /* ||v|| */ - - /* If vector v of constraint corrections is small - in norm, correct and accept this step */ - if (vnorm <= IDA_mem->ida_epsNewt){ - N_VLinearSum(ONE, IDA_mem->ida_ee, -ONE, - IDA_mem->ida_tempv1, IDA_mem->ida_ee); /* ee <- ee - v */ - return(IDA_SUCCESS); - } - else { - /* Constraints not met -- reduce h by computing rr = h'/h */ - N_VLinearSum(ONE, IDA_mem->ida_phi[0], -ONE, IDA_mem->ida_yy, - IDA_mem->ida_tempv1); - N_VProd(IDA_mem->ida_mm, IDA_mem->ida_tempv1, IDA_mem->ida_tempv1); - IDA_mem->ida_rr = PT9*N_VMinQuotient(IDA_mem->ida_phi[0], IDA_mem->ida_tempv1); - IDA_mem->ida_rr = SUNMAX(IDA_mem->ida_rr,PT1); - return(IDA_CONSTR_RECVR); - } + + /* Constraints not met */ + + /* Compute correction to satisfy constraints */ + N_VCompare(ONEPT5, IDA_mem->ida_constraints, tmp); /* a[i] =1 when |c[i]| = 2 */ + N_VProd(tmp, IDA_mem->ida_constraints, tmp); /* a * c */ + N_VDiv(tmp, IDA_mem->ida_ewt, tmp); /* a * c * wt */ + N_VLinearSum(ONE, IDA_mem->ida_yy, -PT1, tmp, tmp); /* y - 0.1 * a * c * wt */ + N_VProd(tmp, mm, tmp); /* v = mm*(y-.1*a*c*wt) */ + + vnorm = IDAWrmsNorm(IDA_mem, tmp, IDA_mem->ida_ewt, SUNFALSE); /* ||v|| */ + + /* If vector v of constraint corrections is small in norm, correct and + accept this step */ + if (vnorm <= IDA_mem->ida_epsNewt) { + N_VLinearSum(ONE, IDA_mem->ida_ee, + -ONE, tmp, IDA_mem->ida_ee); /* ee <- ee - v */ + return(IDA_SUCCESS); } + + /* Constraints correction is too large, reduce h by computing rr = h'/h */ + N_VLinearSum(ONE, IDA_mem->ida_phi[0], -ONE, IDA_mem->ida_yy, tmp); + N_VProd(mm, tmp, tmp); + IDA_mem->ida_rr = PT9*N_VMinQuotient(IDA_mem->ida_phi[0], tmp); + IDA_mem->ida_rr = SUNMAX(IDA_mem->ida_rr, PT1); + + /* Reattempt step with new step size */ + return(IDA_CONSTR_RECVR); } + return(IDA_SUCCESS); } @@ -2474,7 +2566,7 @@ static void IDARestore(IDAMem IDA_mem, realtype saved_t) for (j = IDA_mem->ida_ns; j <= IDA_mem->ida_kk; j++) IDA_mem->ida_cvals[j-IDA_mem->ida_ns] = ONE/IDA_mem->ida_beta[j]; - (void) N_VScaleVectorArray(IDA_mem->ida_kk-IDA_mem->ida_ns+1, + (void) N_VScaleVectorArray(IDA_mem->ida_kk - IDA_mem->ida_ns + 1, IDA_mem->ida_cvals, IDA_mem->ida_phi+IDA_mem->ida_ns, IDA_mem->ida_phi+IDA_mem->ida_ns); @@ -2502,7 +2594,7 @@ static void IDARestore(IDAMem IDA_mem, realtype saved_t) * IDA_RES_RECVR > 0 * IDA_LSOLVE_RECVR > 0 * IDA_CONSTR_RECVR > 0 - * SUN_NLS_CONV_RECV > 0 + * SUN_NLS_CONV_RECVR > 0 * IDA_RES_FAIL < 0 * IDA_LSOLVE_FAIL < 0 * IDA_LSETUP_FAIL < 0 @@ -2543,7 +2635,10 @@ static int IDAHandleNFlag(IDAMem IDA_mem, int nflag, realtype err_k, realtype er if (nflag < 0) { /* nonrecoverable failure */ - return(nflag); + if (nflag == IDA_LSOLVE_FAIL) return(IDA_LSOLVE_FAIL); + else if (nflag == IDA_LSETUP_FAIL) return(IDA_LSETUP_FAIL); + else if (nflag == IDA_RES_FAIL) return(IDA_RES_FAIL); + else return(IDA_NLS_FAIL); } else { /* recoverable failure */ @@ -2652,7 +2747,8 @@ static void IDACompleteStep(IDAMem IDA_mem, realtype err_k, realtype err_km1) IDA_mem->ida_hused = IDA_mem->ida_hh; if ( (IDA_mem->ida_knew == IDA_mem->ida_kk - 1) || - (IDA_mem->ida_kk == IDA_mem->ida_maxord) ) IDA_mem->ida_phase = 1; + (IDA_mem->ida_kk == IDA_mem->ida_maxord) ) + IDA_mem->ida_phase = 1; /* For the first few steps, until either a step fails, or the order is reduced, or the order reaches its maximum, we raise the order and double @@ -2667,7 +2763,7 @@ static void IDACompleteStep(IDAMem IDA_mem, realtype err_k, realtype err_km1) if(IDA_mem->ida_nst > 1) { IDA_mem->ida_kk++; hnew = TWO * IDA_mem->ida_hh; - if( (tmp = SUNRabs(hnew)*IDA_mem->ida_hmax_inv) > ONE ) + if( (tmp = SUNRabs(hnew) * IDA_mem->ida_hmax_inv) > ONE ) hnew /= tmp; IDA_mem->ida_hh = hnew; } @@ -2724,7 +2820,7 @@ static void IDACompleteStep(IDAMem IDA_mem, realtype err_k, realtype err_km1) if (IDA_mem->ida_rr >= TWO) { hnew = TWO * IDA_mem->ida_hh; - if( (tmp = SUNRabs(hnew)*IDA_mem->ida_hmax_inv) > ONE ) + if( (tmp = SUNRabs(hnew) * IDA_mem->ida_hmax_inv) > ONE ) hnew /= tmp; } else if (IDA_mem->ida_rr <= ONE ) { IDA_mem->ida_rr = SUNMAX(HALF, SUNMIN(PT9,IDA_mem->ida_rr)); @@ -2797,8 +2893,7 @@ int IDAGetSolution(void *ida_mem, realtype t, N_Vector yret, N_Vector ypret) /* Check t for legality. Here tn - hused is t_{n-1}. */ tfuzz = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); - if (IDA_mem->ida_hh < ZERO) - tfuzz = - tfuzz; + if (IDA_mem->ida_hh < ZERO) tfuzz = - tfuzz; tp = IDA_mem->ida_tn - IDA_mem->ida_hused - tfuzz; if ((t - tp)*IDA_mem->ida_hh < ZERO) { IDAProcessError(IDA_mem, IDA_BAD_T, "IDA", "IDAGetSolution", MSG_BAD_T, t, @@ -2895,7 +2990,8 @@ static int IDARcheck1(IDAMem IDA_mem) for (i = 0; i < IDA_mem->ida_nrtfn; i++) IDA_mem->ida_iroots[i] = 0; IDA_mem->ida_tlo = IDA_mem->ida_tn; - IDA_mem->ida_ttol = (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)) * IDA_mem->ida_uround * HUNDRED; + IDA_mem->ida_ttol = ((SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)) * + IDA_mem->ida_uround * HUNDRED); /* Evaluate g at initial t and check for zero values. */ retval = IDA_mem->ida_gfun(IDA_mem->ida_tlo, IDA_mem->ida_phi[0], IDA_mem->ida_phi[1], @@ -2913,7 +3009,7 @@ static int IDARcheck1(IDAMem IDA_mem) if (!zroot) return(IDA_SUCCESS); /* Some g_i is zero at t0; look at g at t0+(small increment). */ - hratio = SUNMAX(IDA_mem->ida_ttol/SUNRabs(IDA_mem->ida_hh), PT1); + hratio = SUNMAX(IDA_mem->ida_ttol / SUNRabs(IDA_mem->ida_hh), PT1); smallh = hratio * IDA_mem->ida_hh; tplus = IDA_mem->ida_tlo + smallh; N_VLinearSum(ONE, IDA_mem->ida_phi[0], smallh, IDA_mem->ida_phi[1], IDA_mem->ida_yy); @@ -2981,13 +3077,14 @@ static int IDARcheck2(IDAMem IDA_mem) if (!zroot) return(IDA_SUCCESS); /* One or more g_i has a zero at tlo. Check g at tlo+smallh. */ - IDA_mem->ida_ttol = (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)) * IDA_mem->ida_uround * HUNDRED; + IDA_mem->ida_ttol = ((SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)) * + IDA_mem->ida_uround * HUNDRED); smallh = (IDA_mem->ida_hh > ZERO) ? IDA_mem->ida_ttol : -IDA_mem->ida_ttol; tplus = IDA_mem->ida_tlo + smallh; if ( (tplus - IDA_mem->ida_tn)*IDA_mem->ida_hh >= ZERO) { hratio = smallh/IDA_mem->ida_hh; - N_VLinearSum(ONE, IDA_mem->ida_yy, hratio, - IDA_mem->ida_phi[1], IDA_mem->ida_yy); + N_VLinearSum(ONE, IDA_mem->ida_yy, + hratio, IDA_mem->ida_phi[1], IDA_mem->ida_yy); } else { (void) IDAGetSolution(IDA_mem, tplus, IDA_mem->ida_yy, IDA_mem->ida_yp); } @@ -3034,7 +3131,7 @@ static int IDARcheck3(IDAMem IDA_mem) /* Set thi = tn or tout, whichever comes first. */ if (IDA_mem->ida_taskc == IDA_ONE_STEP) IDA_mem->ida_thi = IDA_mem->ida_tn; if (IDA_mem->ida_taskc == IDA_NORMAL) { - IDA_mem->ida_thi = ( (IDA_mem->ida_toutc - IDA_mem->ida_tn)*IDA_mem->ida_hh >= ZERO) + IDA_mem->ida_thi = ((IDA_mem->ida_toutc - IDA_mem->ida_tn)*IDA_mem->ida_hh >= ZERO) ? IDA_mem->ida_tn : IDA_mem->ida_toutc; } @@ -3043,12 +3140,14 @@ static int IDARcheck3(IDAMem IDA_mem) /* Set ghi = g(thi) and call IDARootfind to search (tlo,thi) for roots. */ - retval = IDA_mem->ida_gfun(IDA_mem->ida_thi, IDA_mem->ida_yy, IDA_mem->ida_yp, - IDA_mem->ida_ghi, IDA_mem->ida_user_data); + retval = IDA_mem->ida_gfun(IDA_mem->ida_thi, IDA_mem->ida_yy, + IDA_mem->ida_yp, IDA_mem->ida_ghi, + IDA_mem->ida_user_data); IDA_mem->ida_nge++; if (retval != 0) return(IDA_RTFUNC_FAIL); - IDA_mem->ida_ttol = (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)) * IDA_mem->ida_uround * HUNDRED; + IDA_mem->ida_ttol = ((SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)) * + IDA_mem->ida_uround * HUNDRED); ier = IDARootfind(IDA_mem); if (ier == IDA_RTFUNC_FAIL) return(IDA_RTFUNC_FAIL); for(i=0; iida_nrtfn; i++) { @@ -3056,7 +3155,8 @@ static int IDARcheck3(IDAMem IDA_mem) IDA_mem->ida_gactive[i] = SUNTRUE; } IDA_mem->ida_tlo = IDA_mem->ida_trout; - for (i = 0; i < IDA_mem->ida_nrtfn; i++) IDA_mem->ida_glo[i] = IDA_mem->ida_grout[i]; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) + IDA_mem->ida_glo[i] = IDA_mem->ida_grout[i]; /* If no root found, return IDA_SUCCESS. */ if (ier == IDA_SUCCESS) return(IDA_SUCCESS); @@ -3201,7 +3301,8 @@ static int IDARootfind(IDAMem IDA_mem) for(;;) { /* Looping point */ /* If interval size is already less than tolerance ttol, break. */ - if (SUNRabs(IDA_mem->ida_thi - IDA_mem->ida_tlo) <= IDA_mem->ida_ttol) break; + if (SUNRabs(IDA_mem->ida_thi - IDA_mem->ida_tlo) <= IDA_mem->ida_ttol) + break; /* Set weight alph. On the first two passes, set alph = 1. Thereafter, reset alph @@ -3222,15 +3323,15 @@ static int IDARootfind(IDAMem IDA_mem) /* Set next root approximation tmid and get g(tmid). If tmid is too close to tlo or thi, adjust it inward, by a fractional distance that is between 0.1 and 0.5. */ - tmid = IDA_mem->ida_thi - (IDA_mem->ida_thi - IDA_mem->ida_tlo)*IDA_mem->ida_ghi[imax] / - (IDA_mem->ida_ghi[imax] - alph*IDA_mem->ida_glo[imax]); - if (SUNRabs(tmid - IDA_mem->ida_tlo) < HALF*IDA_mem->ida_ttol) { - fracint = SUNRabs(IDA_mem->ida_thi - IDA_mem->ida_tlo)/IDA_mem->ida_ttol; + tmid = IDA_mem->ida_thi - (IDA_mem->ida_thi - IDA_mem->ida_tlo) * + IDA_mem->ida_ghi[imax] / (IDA_mem->ida_ghi[imax] - alph*IDA_mem->ida_glo[imax]); + if (SUNRabs(tmid - IDA_mem->ida_tlo) < HALF * IDA_mem->ida_ttol) { + fracint = SUNRabs(IDA_mem->ida_thi - IDA_mem->ida_tlo) / IDA_mem->ida_ttol; fracsub = (fracint > FIVE) ? PT1 : HALF/fracint; tmid = IDA_mem->ida_tlo + fracsub*(IDA_mem->ida_thi - IDA_mem->ida_tlo); } - if (SUNRabs(IDA_mem->ida_thi - tmid) < HALF*IDA_mem->ida_ttol) { - fracint = SUNRabs(IDA_mem->ida_thi - IDA_mem->ida_tlo)/IDA_mem->ida_ttol; + if (SUNRabs(IDA_mem->ida_thi - tmid) < HALF * IDA_mem->ida_ttol) { + fracint = SUNRabs(IDA_mem->ida_thi - IDA_mem->ida_tlo) / IDA_mem->ida_ttol; fracsub = (fracint > FIVE) ? PT1 : HALF/fracint; tmid = IDA_mem->ida_thi - fracsub*(IDA_mem->ida_thi - IDA_mem->ida_tlo); } @@ -3255,7 +3356,8 @@ static int IDARootfind(IDAMem IDA_mem) } else { if ( (IDA_mem->ida_glo[i] * IDA_mem->ida_grout[i] < ZERO) && (IDA_mem->ida_rootdir[i] * IDA_mem->ida_glo[i] <= ZERO) ) { - gfrac = SUNRabs(IDA_mem->ida_grout[i] / (IDA_mem->ida_grout[i] - IDA_mem->ida_glo[i])); + gfrac = SUNRabs(IDA_mem->ida_grout[i] / + (IDA_mem->ida_grout[i] - IDA_mem->ida_glo[i])); if (gfrac > maxfrac) { sgnchg = SUNTRUE; maxfrac = gfrac; @@ -3271,7 +3373,8 @@ static int IDARootfind(IDAMem IDA_mem) IDA_mem->ida_ghi[i] = IDA_mem->ida_grout[i]; side = 1; /* Stop at root thi if converged; otherwise loop. */ - if (SUNRabs(IDA_mem->ida_thi - IDA_mem->ida_tlo) <= IDA_mem->ida_ttol) break; + if (SUNRabs(IDA_mem->ida_thi - IDA_mem->ida_tlo) <= IDA_mem->ida_ttol) + break; continue; /* Return to looping point. */ } @@ -3290,7 +3393,8 @@ static int IDARootfind(IDAMem IDA_mem) IDA_mem->ida_glo[i] = IDA_mem->ida_grout[i]; side = 2; /* Stop at root thi if converged; otherwise loop back. */ - if (SUNRabs(IDA_mem->ida_thi - IDA_mem->ida_tlo) <= IDA_mem->ida_ttol) break; + if (SUNRabs(IDA_mem->ida_thi - IDA_mem->ida_tlo) <= IDA_mem->ida_ttol) + break; } /* End of root-search loop */ @@ -3374,7 +3478,7 @@ void IDAErrHandler(int error_code, const char *module, sprintf(err_type,"ERROR"); #ifndef NO_FPRINTF_OUTPUT - if (IDA_mem->ida_errfp!=NULL) { + if (IDA_mem->ida_errfp != NULL) { fprintf(IDA_mem->ida_errfp,"\n[%s %s] %s\n",module,err_type,function); fprintf(IDA_mem->ida_errfp," %s\n\n",msg); } diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/ida_bbdpre.c b/deps/AMICI/ThirdParty/sundials/src/ida/ida_bbdpre.c index 1cb11cef2..8487469bf 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/ida_bbdpre.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/ida_bbdpre.c @@ -1,10 +1,10 @@ /* - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Programmer(s): Daniel R. Reynolds @ SMU * Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -15,7 +15,7 @@ * ----------------------------------------------------------------- * This file contains implementations of routines for a * band-block-diagonal preconditioner, i.e. a block-diagonal - * matrix with banded blocks, for use with IDA, the IDASPILS + * matrix with banded blocks, for use with IDA, the IDASPILS * linear solver interface. * * NOTE: With only one processor in use, a banded matrix results @@ -50,16 +50,16 @@ static int IDABBDPrecFree(IDAMem ida_mem); /* Prototype for difference quotient Jacobian calculation routine */ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, - N_Vector yy, N_Vector yp, N_Vector gref, + N_Vector yy, N_Vector yp, N_Vector gref, N_Vector ytemp, N_Vector yptemp, N_Vector gtemp); /*--------------------------------------------------------------- User-Callable Functions: initialization, reinit and free ---------------------------------------------------------------*/ -int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, - sunindextype mudq, sunindextype mldq, - sunindextype mukeep, sunindextype mlkeep, - realtype dq_rel_yy, +int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, + sunindextype mudq, sunindextype mldq, + sunindextype mukeep, sunindextype mlkeep, + realtype dq_rel_yy, IDABBDLocalFn Gres, IDABBDCommFn Gcomm) { IDAMem IDA_mem; @@ -117,11 +117,11 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, /* Allocate memory for preconditioner matrix. */ pdata->PP = NULL; pdata->PP = SUNBandMatrixStorage(Nlocal, muk, mlk, storage_mu); - if (pdata->PP == NULL) { + if (pdata->PP == NULL) { free(pdata); pdata = NULL; IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", "IDABBDPrecInit", MSGBBD_MEM_FAIL); - return(IDALS_MEM_FAIL); + return(IDALS_MEM_FAIL); } /* Allocate memory for temporary N_Vectors */ @@ -130,7 +130,7 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, if (pdata->zlocal == NULL) { SUNMatDestroy(pdata->PP); free(pdata); pdata = NULL; - IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", "IDABBDPrecInit", MSGBBD_MEM_FAIL); return(IDALS_MEM_FAIL); } @@ -140,12 +140,12 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, N_VDestroy(pdata->zlocal); SUNMatDestroy(pdata->PP); free(pdata); pdata = NULL; - IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", "IDABBDPrecInit", MSGBBD_MEM_FAIL); return(IDALS_MEM_FAIL); } pdata->tempv1 = NULL; - pdata->tempv1 = N_VClone(IDA_mem->ida_tempv1); + pdata->tempv1 = N_VClone(IDA_mem->ida_tempv1); if (pdata->tempv1 == NULL){ N_VDestroy(pdata->rlocal); N_VDestroy(pdata->zlocal); @@ -156,7 +156,7 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, return(IDALS_MEM_FAIL); } pdata->tempv2 = NULL; - pdata->tempv2 = N_VClone(IDA_mem->ida_tempv1); + pdata->tempv2 = N_VClone(IDA_mem->ida_tempv1); if (pdata->tempv2 == NULL){ N_VDestroy(pdata->rlocal); N_VDestroy(pdata->zlocal); @@ -168,7 +168,7 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, return(IDALS_MEM_FAIL); } pdata->tempv3 = NULL; - pdata->tempv3 = N_VClone(IDA_mem->ida_tempv1); + pdata->tempv3 = N_VClone(IDA_mem->ida_tempv1); if (pdata->tempv3 == NULL){ N_VDestroy(pdata->rlocal); N_VDestroy(pdata->zlocal); @@ -181,7 +181,7 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, return(IDALS_MEM_FAIL); } pdata->tempv4 = NULL; - pdata->tempv4 = N_VClone(IDA_mem->ida_tempv1); + pdata->tempv4 = N_VClone(IDA_mem->ida_tempv1); if (pdata->tempv4 == NULL){ N_VDestroy(pdata->rlocal); N_VDestroy(pdata->zlocal); @@ -228,14 +228,14 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, "IDABBDPrecInit", MSGBBD_SUNLS_FAIL); return(IDALS_SUNLS_FAIL); } - + /* Set rel_yy based on input value dq_rel_yy (0 implies default). */ pdata->rel_yy = (dq_rel_yy > ZERO) ? - dq_rel_yy : SUNRsqrt(IDA_mem->ida_uround); + dq_rel_yy : SUNRsqrt(IDA_mem->ida_uround); /* Store Nlocal to be used in IDABBDPrecSetup */ pdata->n_local = Nlocal; - + /* Set work space sizes and initialize nge. */ pdata->rpwsize = 0; pdata->ipwsize = 0; @@ -262,7 +262,7 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, pdata->nge = 0; /* make sure pdata is free from any previous allocations */ - if (idals_mem->pfree) + if (idals_mem->pfree) idals_mem->pfree(IDA_mem); /* Point to the new pdata field in the LS memory */ @@ -309,7 +309,7 @@ int IDABBDPrecReInit(void *ida_mem, sunindextype mudq, IDAProcessError(IDA_mem, IDALS_PMEM_NULL, "IDABBDPRE", "IDABBDPrecReInit", MSGBBD_PMEM_NULL); return(IDALS_PMEM_NULL); - } + } pdata = (IBBDPrecData) idals_mem->pdata; /* Load half-bandwidths. */ @@ -319,7 +319,7 @@ int IDABBDPrecReInit(void *ida_mem, sunindextype mudq, /* Set rel_yy based on input value dq_rel_yy (0 implies default). */ pdata->rel_yy = (dq_rel_yy > ZERO) ? - dq_rel_yy : SUNRsqrt(IDA_mem->ida_uround); + dq_rel_yy : SUNRsqrt(IDA_mem->ida_uround); /* Re-initialize nge */ pdata->nge = 0; @@ -355,7 +355,7 @@ int IDABBDPrecGetWorkSpace(void *ida_mem, IDAProcessError(IDA_mem, IDALS_PMEM_NULL, "IDABBDPRE", "IDABBDPrecGetWorkSpace", MSGBBD_PMEM_NULL); return(IDALS_PMEM_NULL); - } + } pdata = (IBBDPrecData) idals_mem->pdata; *lenrwBBDP = pdata->rpwsize; @@ -391,7 +391,7 @@ int IDABBDPrecGetNumGfnEvals(void *ida_mem, IDAProcessError(IDA_mem, IDALS_PMEM_NULL, "IDABBDPRE", "IDABBDPrecGetNumGfnEvals", MSGBBD_PMEM_NULL); return(IDALS_PMEM_NULL); - } + } pdata = (IBBDPrecData) idals_mem->pdata; *ngevalsBBDP = pdata->nge; @@ -409,23 +409,23 @@ int IDABBDPrecGetNumGfnEvals(void *ida_mem, scheme via calls to the user-supplied routines glocal, gcomm. After generating the block in the band matrix PP, this routine does an LU factorization in place in PP. - + The IDABBDPrecSetup parameters used here are as follows: - + tt is the current value of the independent variable t. - + yy is the current value of the dependent variable vector, namely the predicted value of y(t). - + yp is the current value of the derivative vector y', namely the predicted value of y'(t). - + c_j is the scalar in the system Jacobian, proportional to 1/hh. - + bbd_data is the pointer to BBD memory set by IDABBDInit - + The argument rr is not used. - + Return value: The value returned by this IDABBDPrecSetup function is a int flag indicating whether it was successful. This value is @@ -436,7 +436,6 @@ int IDABBDPrecGetNumGfnEvals(void *ida_mem, static int IDABBDPrecSetup(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr, realtype c_j, void *bbd_data) { - sunindextype ier; IBBDPrecData pdata; IDAMem IDA_mem; int retval; @@ -456,11 +455,11 @@ static int IDABBDPrecSetup(realtype tt, N_Vector yy, N_Vector yp, } if (retval > 0) { return(1); - } - + } + /* Do LU factorization of matrix and return error flag */ - ier = SUNLinSolSetup_Band(pdata->LS, pdata->PP); - return(ier); + retval = SUNLinSolSetup_Band(pdata->LS, pdata->PP); + return(retval); } @@ -470,18 +469,18 @@ static int IDABBDPrecSetup(realtype tt, N_Vector yy, N_Vector yp, The function IDABBDPrecSolve computes a solution to the linear system P z = r, where P is the left preconditioner defined by the routine IDABBDPrecSetup. - + The IDABBDPrecSolve parameters used here are as follows: - + rvec is the input right-hand side vector r. - + zvec is the computed solution vector z. - + bbd_data is the pointer to BBD data set by IDABBDInit. - + The arguments tt, yy, yp, rr, c_j and delta are NOT used. - - IDABBDPrecSolve returns the value returned from the linear + + IDABBDPrecSolve returns the value returned from the linear solver object. ---------------------------------------------------------------*/ static int IDABBDPrecSolve(realtype tt, N_Vector yy, N_Vector yp, @@ -490,15 +489,15 @@ static int IDABBDPrecSolve(realtype tt, N_Vector yy, N_Vector yp, { IBBDPrecData pdata; int retval; - + pdata = (IBBDPrecData) bbd_data; /* Attach local data arrays for rvec and zvec to rlocal and zlocal */ N_VSetArrayPointer(N_VGetArrayPointer(rvec), pdata->rlocal); N_VSetArrayPointer(N_VGetArrayPointer(zvec), pdata->zlocal); - + /* Call banded solver object to do the work */ - retval = SUNLinSolSolve(pdata->LS, pdata->PP, pdata->zlocal, + retval = SUNLinSolSolve(pdata->LS, pdata->PP, pdata->zlocal, pdata->rlocal, ZERO); /* Detach local data arrays from rlocal and zlocal */ @@ -514,10 +513,10 @@ static int IDABBDPrecFree(IDAMem IDA_mem) { IDALsMem idals_mem; IBBDPrecData pdata; - + if (IDA_mem->ida_lmem == NULL) return(0); idals_mem = (IDALsMem) IDA_mem->ida_lmem; - + if (idals_mem->pdata == NULL) return(0); pdata = (IBBDPrecData) idals_mem->pdata; @@ -544,19 +543,19 @@ static int IDABBDPrecFree(IDAMem IDA_mem) to the local block of the Jacobian of G(t,y,y'). It assumes that a band matrix of type SUNMatrix is stored column-wise, and that elements within each column are contiguous. - + All matrix elements are generated as difference quotients, by way of calls to the user routine glocal. By virtue of the band structure, the number of these calls is bandwidth + 1, where bandwidth = mldq + mudq + 1. But the band matrix kept has bandwidth = mlkeep + mukeep + 1. This routine also assumes that the local elements of a vector are stored contiguously. - + Return values are: 0 (success), > 0 (recoverable error), or < 0 (nonrecoverable error). ----------------------------------------------------------------*/ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, - N_Vector yy, N_Vector yp, N_Vector gref, + N_Vector yy, N_Vector yp, N_Vector gref, N_Vector ytemp, N_Vector yptemp, N_Vector gtemp) { IDAMem IDA_mem; @@ -578,7 +577,7 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, ypdata = N_VGetArrayPointer(yp); gtempdata = N_VGetArrayPointer(gtemp); ewtdata = N_VGetArrayPointer(IDA_mem->ida_ewt); - if (IDA_mem->ida_constraints != NULL) + if (IDA_mem->ida_constraintsSet) cnsdata = N_VGetArrayPointer(IDA_mem->ida_constraints); ytempdata = N_VGetArrayPointer(ytemp); yptempdata= N_VGetArrayPointer(yptemp); @@ -590,7 +589,7 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, if (retval != 0) return(retval); } - retval = pdata->glocal(pdata->n_local, tt, yy, yp, gref, IDA_mem->ida_user_data); + retval = pdata->glocal(pdata->n_local, tt, yy, yp, gref, IDA_mem->ida_user_data); pdata->nge++; if (retval != 0) return(retval); @@ -600,13 +599,13 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, /* Loop over groups. */ for(group = 1; group <= ngroups; group++) { - + /* Loop over the components in this group. */ for(j = group-1; j < pdata->n_local; j += width) { yj = ydata[j]; ypj = ypdata[j]; ewtj = ewtdata[j]; - + /* Set increment inc to yj based on rel_yy*abs(yj), with adjustments using ypj and ewtj if this is small, and a further adjustment to give it the same sign as hh*ypj. */ @@ -614,9 +613,9 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, SUNMAX(SUNRabs(yj), SUNMAX( SUNRabs(IDA_mem->ida_hh*ypj), ONE/ewtj)); if (IDA_mem->ida_hh*ypj < ZERO) inc = -inc; inc = (yj + inc) - yj; - + /* Adjust sign(inc) again if yj has an inequality constraint. */ - if (IDA_mem->ida_constraints != NULL) { + if (IDA_mem->ida_constraintsSet) { conj = cnsdata[j]; if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} @@ -625,12 +624,12 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, /* Increment yj and ypj. */ ytempdata[j] += inc; yptempdata[j] += cj*inc; - + } /* Evaluate G with incremented y and yp arguments. */ retval = pdata->glocal(pdata->n_local, tt, ytemp, yptemp, - gtemp, IDA_mem->ida_user_data); + gtemp, IDA_mem->ida_user_data); pdata->nge++; if (retval != 0) return(retval); @@ -645,7 +644,7 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, SUNMAX(SUNRabs(yj), SUNMAX( SUNRabs(IDA_mem->ida_hh*ypj), ONE/ewtj)); if (IDA_mem->ida_hh*ypj < ZERO) inc = -inc; inc = (yj + inc) - yj; - if (IDA_mem->ida_constraints != NULL) { + if (IDA_mem->ida_constraintsSet) { conj = cnsdata[j]; if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} @@ -661,7 +660,6 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, inc_inv * (gtempdata[i] - grefdata[i]); } } - + return(0); } - diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/ida_bbdpre_impl.h b/deps/AMICI/ThirdParty/sundials/src/ida/ida_bbdpre_impl.h index e90480330..1ab20fa1b 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/ida_bbdpre_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/ida/ida_bbdpre_impl.h @@ -3,7 +3,7 @@ * Alan C. Hindmarsh and Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/ida_direct.c b/deps/AMICI/ThirdParty/sundials/src/ida/ida_direct.c index 5ba46dd78..39fc4d882 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/ida_direct.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/ida_direct.c @@ -3,7 +3,7 @@ * Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/ida_ic.c b/deps/AMICI/ThirdParty/sundials/src/ida/ida_ic.c index 305639c7f..5ecd6b7c1 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/ida_ic.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/ida_ic.c @@ -6,7 +6,7 @@ * Programmers: Alan C. Hindmarsh, and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/ida_impl.h b/deps/AMICI/ThirdParty/sundials/src/ida/ida_impl.h index 93b145853..ea9824803 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/ida_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/ida/ida_impl.h @@ -7,7 +7,7 @@ * and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -76,6 +76,7 @@ typedef struct IDAMemRec { realtype ida_rtol; /* relative tolerance */ realtype ida_Satol; /* scalar absolute tolerance */ N_Vector ida_Vatol; /* vector absolute tolerance */ + booleantype ida_atolmin0; /* flag indicating that min(atol) = 0 */ booleantype ida_user_efun; /* SUNTRUE if user provides efun */ IDAEwtFn ida_efun; /* function to set ewt */ void *ida_edata; /* user pointer passed to efun */ @@ -110,7 +111,6 @@ typedef struct IDAMemRec { N_Vector ida_ee; /* accumulated corrections to y vector, but set equal to estimated local errors upon successful return */ - N_Vector ida_mm; /* mask vector in constraints tests (= tempv2) */ N_Vector ida_tempv1; /* work space vector */ N_Vector ida_tempv2; /* work space vector */ N_Vector ida_tempv3; /* work space vector */ @@ -491,18 +491,19 @@ int idaNlsInit(IDAMem IDA_mem); #define MSG_BAD_T "Illegal value for t." MSG_TIME_INT #define MSG_BAD_TOUT "Trouble interpolating at " MSG_TIME_TOUT ". tout too far back in direction of integration." -#define MSG_ERR_FAILS "At " MSG_TIME_H "the error test failed repeatedly or with |h| = hmin." -#define MSG_CONV_FAILS "At " MSG_TIME_H "the corrector convergence failed repeatedly or with |h| = hmin." -#define MSG_SETUP_FAILED "At " MSG_TIME "the linear solver setup failed unrecoverably." -#define MSG_SOLVE_FAILED "At " MSG_TIME "the linear solver solve failed unrecoverably." -#define MSG_REP_RES_ERR "At " MSG_TIME "repeated recoverable residual errors." -#define MSG_RES_NONRECOV "At " MSG_TIME "the residual function failed unrecoverably." -#define MSG_FAILED_CONSTR "At " MSG_TIME "unable to satisfy inequality constraints." -#define MSG_RTFUNC_FAILED "At " MSG_TIME ", the rootfinding routine failed in an unrecoverable manner." -#define MSG_NO_ROOT "Rootfinding was not initialized." -#define MSG_INACTIVE_ROOTS "At the end of the first step, there are still some root functions identically 0. This warning will not be issued again." -#define MSG_NLS_INPUT_NULL "At " MSG_TIME "the nonlinear solver was passed a NULL input." -#define MSG_NLS_SETUP_FAILED "At " MSG_TIME "the nonlinear solver setup failed unrecoverably." +#define MSG_ERR_FAILS "At " MSG_TIME_H "the error test failed repeatedly or with |h| = hmin." +#define MSG_CONV_FAILS "At " MSG_TIME_H "the corrector convergence failed repeatedly or with |h| = hmin." +#define MSG_SETUP_FAILED "At " MSG_TIME "the linear solver setup failed unrecoverably." +#define MSG_SOLVE_FAILED "At " MSG_TIME "the linear solver solve failed unrecoverably." +#define MSG_REP_RES_ERR "At " MSG_TIME "repeated recoverable residual errors." +#define MSG_RES_NONRECOV "At " MSG_TIME "the residual function failed unrecoverably." +#define MSG_FAILED_CONSTR "At " MSG_TIME "unable to satisfy inequality constraints." +#define MSG_RTFUNC_FAILED "At " MSG_TIME ", the rootfinding routine failed in an unrecoverable manner." +#define MSG_NO_ROOT "Rootfinding was not initialized." +#define MSG_INACTIVE_ROOTS "At the end of the first step, there are still some root functions identically 0. This warning will not be issued again." +#define MSG_NLS_INPUT_NULL "At " MSG_TIME ", the nonlinear solver was passed a NULL input." +#define MSG_NLS_SETUP_FAILED "At " MSG_TIME ", the nonlinear solver setup failed unrecoverably." +#define MSG_NLS_FAIL "At " MSG_TIME ", the nonlinear solver failed in an unrecoverable manner." /* IDASet* / IDAGet* error messages */ diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/ida_io.c b/deps/AMICI/ThirdParty/sundials/src/ida/ida_io.c index 5c1868f83..ce6e65bc7 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/ida_io.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/ida_io.c @@ -2,12 +2,12 @@ * ----------------------------------------------------------------- * $Revision$ * $Date$ - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Programmer(s): Alan Hindmarsh, Radu Serban and * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -16,8 +16,8 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the optional inputs and - * outputs for the IDA solver. + * This is the implementation file for the optional inputs and + * outputs for the IDA solver. * ----------------------------------------------------------------- */ @@ -33,7 +33,7 @@ #define ONE RCONST(1.0) #define TWOPT5 RCONST(2.5) -/* +/* * ================================================================= * IDA optional input functions * ================================================================= @@ -117,7 +117,7 @@ int IDASetMaxOrd(void *ida_mem, int maxord) if (maxord > maxord_alloc) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetMaxOrd", MSG_BAD_MAXORD); return(IDA_ILL_INPUT); - } + } IDA_mem->ida_maxord = SUNMIN(maxord,MAXORD_DEFAULT); @@ -346,7 +346,7 @@ int IDASetId(void *ida_mem, N_Vector id) IDA_mem->ida_lrw -= IDA_mem->ida_lrw1; IDA_mem->ida_liw -= IDA_mem->ida_liw1; } - IDA_mem->ida_idMallocDone = SUNFALSE; + IDA_mem->ida_idMallocDone = SUNFALSE; return(IDA_SUCCESS); } @@ -403,9 +403,9 @@ int IDASetConstraints(void *ida_mem, N_Vector constraints) /* Check the constraints vector */ temptest = N_VMaxNorm(constraints); - if((temptest > TWOPT5) || (temptest < HALF)){ + if((temptest > TWOPT5) || (temptest < HALF)){ IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetConstraints", MSG_BAD_CONSTR); - return(IDA_ILL_INPUT); + return(IDA_ILL_INPUT); } if ( !(IDA_mem->ida_constraintsMallocDone) ) { @@ -424,7 +424,7 @@ int IDASetConstraints(void *ida_mem, N_Vector constraints) return(IDA_SUCCESS); } -/* +/* * IDASetRootDirection * * Specifies the direction of zero-crossings to be monitored. @@ -446,7 +446,7 @@ int IDASetRootDirection(void *ida_mem, int *rootdir) nrt = IDA_mem->ida_nrtfn; if (nrt==0) { IDAProcessError(NULL, IDA_ILL_INPUT, "IDA", "IDASetRootDirection", MSG_NO_ROOT); - return(IDA_ILL_INPUT); + return(IDA_ILL_INPUT); } for(i=0; iida_rootdir[i] = rootdir[i]; @@ -473,12 +473,12 @@ int IDASetNoInactiveRootWarn(void *ida_mem) IDA_mem = (IDAMem) ida_mem; IDA_mem->ida_mxgnull = 0; - + return(IDA_SUCCESS); } -/* +/* * ================================================================= * IDA IC optional input functions * ================================================================= @@ -544,7 +544,7 @@ int IDASetMaxNumJacsIC(void *ida_mem, int maxnj) if (maxnj <= 0) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetMaxNumJacsIC", MSG_BAD_MAXNJ); return(IDA_ILL_INPUT); - } + } IDA_mem->ida_maxnj = maxnj; @@ -638,7 +638,7 @@ int IDASetStepToleranceIC(void *ida_mem, realtype steptol) return(IDA_SUCCESS); } -/* +/* * ================================================================= * IDA optional input functions * ================================================================= @@ -737,13 +737,13 @@ int IDAGetNumBacktrackOps(void *ida_mem, long int *nbacktracks) int IDAGetConsistentIC(void *ida_mem, N_Vector yy0, N_Vector yp0) { IDAMem IDA_mem; - + if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetConsistentIC", MSG_NO_MEM); return (IDA_MEM_NULL); } - IDA_mem = (IDAMem) ida_mem; + IDA_mem = (IDAMem) ida_mem; if (IDA_mem->ida_kused != 0) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAGetConsistentIC", MSG_TOO_LATE); @@ -794,6 +794,60 @@ int IDAGetCurrentOrder(void *ida_mem, int *kcur) /*-----------------------------------------------------------------*/ +int IDAGetCurrentCj(void *ida_mem, realtype *cj) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetCurrentCjRatio", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *cj = IDA_mem->ida_cj; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetCurrentY(void *ida_mem, N_Vector *ycur) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetCurrentY", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *ycur = IDA_mem->ida_yy; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetCurrentYp(void *ida_mem, N_Vector *ypcur) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetCurrentYp", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *ypcur = IDA_mem->ida_yp; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + int IDAGetActualInitStep(void *ida_mem, realtype *hinused) { IDAMem IDA_mem; @@ -887,13 +941,13 @@ int IDAGetTolScaleFactor(void *ida_mem, realtype *tolsfact) int IDAGetErrWeights(void *ida_mem, N_Vector eweight) { IDAMem IDA_mem; - + if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetErrWeights", MSG_NO_MEM); return (IDA_MEM_NULL); } - IDA_mem = (IDAMem) ida_mem; + IDA_mem = (IDAMem) ida_mem; N_VScale(ONE, IDA_mem->ida_ewt, eweight); @@ -938,9 +992,9 @@ int IDAGetWorkSpace(void *ida_mem, long int *lenrw, long int *leniw) /*-----------------------------------------------------------------*/ -int IDAGetIntegratorStats(void *ida_mem, long int *nsteps, long int *nrevals, +int IDAGetIntegratorStats(void *ida_mem, long int *nsteps, long int *nrevals, long int *nlinsetups, long int *netfails, - int *klast, int *kcur, realtype *hinused, realtype *hlast, + int *klast, int *kcur, realtype *hinused, realtype *hlast, realtype *hcur, realtype *tcur) { IDAMem IDA_mem; @@ -960,7 +1014,7 @@ int IDAGetIntegratorStats(void *ida_mem, long int *nsteps, long int *nrevals, *kcur = IDA_mem->ida_kk; *hinused = IDA_mem->ida_h0u; *hlast = IDA_mem->ida_hused; - *hcur = IDA_mem->ida_hh; + *hcur = IDA_mem->ida_hh; *tcur = IDA_mem->ida_tn; return(IDA_SUCCESS); @@ -1035,7 +1089,7 @@ int IDAGetNumNonlinSolvIters(void *ida_mem, long int *nniters) retval = SUNNonlinSolGetNumIters(IDA_mem->NLS, &nls_iters); if (retval != IDA_SUCCESS) return(retval); - /* update the number of nonlinear iterations */ + /* update the number of nonlinear iterations */ *nniters += nls_iters; return(IDA_SUCCESS); @@ -1088,7 +1142,7 @@ int IDAGetNonlinSolvStats(void *ida_mem, long int *nniters, long int *nncfails) /* get number of iterations from the NLS */ retval = SUNNonlinSolGetNumIters(IDA_mem->NLS, &nls_iters); if (retval != IDA_SUCCESS) return(retval); - + /* update the number of nonlinear iterations */ *nniters += nls_iters; @@ -1173,11 +1227,15 @@ char *IDAGetReturnFlagName(long int flag) case IDA_LINESEARCH_FAIL: sprintf(name,"IDA_LINESEARCH_FAIL"); break; - + case IDA_NLS_SETUP_FAIL: + sprintf(name,"IDA_NLS_SETUP_FAIL"); + break; + case IDA_NLS_FAIL: + sprintf(name,"IDA_NLS_FAIL"); + break; default: sprintf(name,"NONE"); } return(name); } - diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/ida_ls.c b/deps/AMICI/ThirdParty/sundials/src/ida/ida_ls.c index 566605ed7..6cede7d2b 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/ida_ls.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/ida_ls.c @@ -3,7 +3,7 @@ * Alan C. Hindmarsh and Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -22,6 +22,7 @@ #include "ida_impl.h" #include "ida_ls_impl.h" #include +#include #include #include #include @@ -45,9 +46,11 @@ ---------------------------------------------------------------*/ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) { - IDAMem IDA_mem; - IDALsMem idals_mem; - int retval, LSType; + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval, LSType; + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ /* Return immediately if any input is NULL */ if (ida_mem == NULL) { @@ -64,50 +67,61 @@ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) IDA_mem = (IDAMem) ida_mem; /* Test if solver is compatible with LS interface */ - if ( (LS->ops->gettype == NULL) || - (LS->ops->initialize == NULL) || - (LS->ops->setup == NULL) || - (LS->ops->solve == NULL) ) { + if ( (LS->ops->gettype == NULL) || (LS->ops->solve == NULL) ) { IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", "LS object is missing a required operation"); return(IDALS_ILL_INPUT); } + /* Retrieve the LS type */ + LSType = SUNLinSolGetType(LS); + + /* Set flags based on LS type */ + iterative = (LSType != SUNLINEARSOLVER_DIRECT); + matrixbased = (LSType != SUNLINEARSOLVER_ITERATIVE); + /* Test if vector is compatible with LS interface */ - if ( (IDA_mem->ida_tempv1->ops->nvdotprod == NULL) || - (IDA_mem->ida_tempv1->ops->nvconst == NULL) ) { + if (IDA_mem->ida_tempv1->ops->nvconst == NULL || + IDA_mem->ida_tempv1->ops->nvwrmsnorm == NULL) { IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", MSG_LS_BAD_NVECTOR); return(IDALS_ILL_INPUT); } - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(LS); - /* Check for compatible LS type, matrix and "atimes" support */ - if ( ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) && - ( (LS->ops->resid == NULL) || - (LS->ops->numiters == NULL) ) ) { - IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", - "Iterative LS object requires 'resid' and 'numiters' routines"); - return(IDALS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_ITERATIVE) && (LS->ops->setatimes == NULL)) { - IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", - "Incompatible inputs: iterative LS must support ATimes routine"); - return(IDALS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_DIRECT) && (A == NULL)) { + if (iterative) { + + if (IDA_mem->ida_tempv1->ops->nvgetlength == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", + "IDASetLinearSolver", MSG_LS_BAD_NVECTOR); + return(IDALS_ILL_INPUT); + } + + if (LS->ops->resid == NULL || LS->ops->numiters == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", + "Iterative LS object requires 'resid' and 'numiters' routines"); + return(IDALS_ILL_INPUT); + } + + if (!matrixbased && LS->ops->setatimes == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", + "Incompatible inputs: iterative LS must support ATimes routine"); + return(IDALS_ILL_INPUT); + } + + if (matrixbased && A == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", + "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); + return(IDALS_ILL_INPUT); + } + + } else if (A == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", "Incompatible inputs: direct LS requires non-NULL matrix"); return(IDALS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) && (A == NULL)) { - IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", - "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); - return(IDALS_ILL_INPUT); + } /* free any existing system solver attached to IDA */ @@ -120,9 +134,7 @@ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) IDA_mem->ida_lfree = idaLsFree; /* Set ida_lperf if using an iterative SUNLinearSolver object */ - IDA_mem->ida_lperf = ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) ? - idaLsPerf : NULL; + IDA_mem->ida_lperf = (iterative) ? idaLsPerf : NULL; /* Allocate memory for IDALsMemRec */ idals_mem = NULL; @@ -137,6 +149,10 @@ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) /* set SUNLinearSolver pointer */ idals_mem->LS = LS; + /* Linear solver type information */ + idals_mem->iterative = iterative; + idals_mem->matrixbased = matrixbased; + /* Set defaults for Jacobian-related fields */ idals_mem->J = A; if (A != NULL) { @@ -219,10 +235,15 @@ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) return(IDALS_MEM_FAIL); } - /* Compute sqrtN from a dot product */ - N_VConst(ONE, idals_mem->ytemp); - idals_mem->sqrtN = SUNRsqrt( N_VDotProd(idals_mem->ytemp, - idals_mem->ytemp) ); + /* For iterative LS, compute sqrtN */ + if (iterative) + idals_mem->sqrtN = SUNRsqrt( N_VGetLength(idals_mem->ytemp) ); + + /* For matrix-based LS, enable solution scaling */ + if (matrixbased) + idals_mem->scalesol = SUNTRUE; + else + idals_mem->scalesol = SUNFALSE; /* Attach linear solver memory to integrator memory */ IDA_mem->ida_lmem = idals_mem; @@ -295,6 +316,29 @@ int IDASetEpsLin(void *ida_mem, realtype eplifac) } +/* IDASetLinearSolutionScaling enables or disables scaling the linear solver + solution to account for changes in cj. */ +int IDASetLinearSolutionScaling(void *ida_mem, booleantype onoff) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDASetLinearSolutionScaling", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* check for valid solver type */ + if (!(idals_mem->matrixbased)) return(IDALS_ILL_INPUT); + + /* set solution scaling flag */ + idals_mem->scalesol = onoff; + + return(IDALS_SUCCESS); +} + + /* IDASetIncrementFactor specifies increment factor for DQ approximations to Jv */ int IDASetIncrementFactor(void *ida_mem, realtype dqincfac) { @@ -769,7 +813,6 @@ int idaLsDQJac(realtype t, realtype c_j, N_Vector y, N_Vector yp, /* Verify that N_Vector supports required operations */ if (IDA_mem->ida_tempv1->ops->nvcloneempty == NULL || - IDA_mem->ida_tempv1->ops->nvwrmsnorm == NULL || IDA_mem->ida_tempv1->ops->nvlinearsum == NULL || IDA_mem->ida_tempv1->ops->nvdestroy == NULL || IDA_mem->ida_tempv1->ops->nvscale == NULL || @@ -835,7 +878,7 @@ int idaLsDenseDQJac(realtype tt, realtype c_j, N_Vector yy, ewt_data = N_VGetArrayPointer(IDA_mem->ida_ewt); y_data = N_VGetArrayPointer(yy); yp_data = N_VGetArrayPointer(yp); - if(IDA_mem->ida_constraints!=NULL) + if(IDA_mem->ida_constraintsSet) cns_data = N_VGetArrayPointer(IDA_mem->ida_constraints); srur = SUNRsqrt(IDA_mem->ida_uround); @@ -860,7 +903,7 @@ int idaLsDenseDQJac(realtype tt, realtype c_j, N_Vector yy, inc = (yj + inc) - yj; /* Adjust sign(inc) again if y_j has an inequality constraint. */ - if (IDA_mem->ida_constraints != NULL) { + if (IDA_mem->ida_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if((yj+inc)*conj <= ZERO) inc = -inc;} @@ -939,7 +982,7 @@ int idaLsBandDQJac(realtype tt, realtype c_j, N_Vector yy, rtemp_data = N_VGetArrayPointer(rtemp); ytemp_data = N_VGetArrayPointer(ytemp); yptemp_data = N_VGetArrayPointer(yptemp); - if (IDA_mem->ida_constraints != NULL) + if (IDA_mem->ida_constraintsSet) cns_data = N_VGetArrayPointer(IDA_mem->ida_constraints); /* Initialize ytemp and yptemp. */ @@ -969,7 +1012,7 @@ int idaLsBandDQJac(realtype tt, realtype c_j, N_Vector yy, inc = (yj + inc) - yj; /* Adjust sign(inc) again if yj has an inequality constraint. */ - if (IDA_mem->ida_constraints != NULL) { + if (IDA_mem->ida_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if((yj+inc)*conj <= ZERO) inc = -inc;} @@ -999,7 +1042,7 @@ int idaLsBandDQJac(realtype tt, realtype c_j, N_Vector yy, ONE/ewtj ); if (IDA_mem->ida_hh*ypj < ZERO) inc = -inc; inc = (yj + inc) - yj; - if (IDA_mem->ida_constraints != NULL) { + if (IDA_mem->ida_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if((yj+inc)*conj <= ZERO) inc = -inc;} @@ -1040,14 +1083,18 @@ int idaLsDQJtimes(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr, N_Vector y_tmp, yp_tmp; realtype sig, siginv; int iter, retval; + SUNLinearSolver_ID LSID; /* access IDALsMem structure */ retval = idaLs_AccessLMem(ida_mem, "idaLsDQJtimes", &IDA_mem, &idals_mem); if (retval != IDALS_SUCCESS) return(retval); - sig = idals_mem->sqrtN * idals_mem->dqincfac; /* GMRES */ - /*sig = idals_mem->dqincfac / N_VWrmsNorm(v, IDA_mem->ida_ewt);*/ /* BiCGStab/TFQMR */ + LSID = SUNLinSolGetID(idals_mem->LS); + if (LSID == SUNLINEARSOLVER_SPGMR || LSID == SUNLINEARSOLVER_SPFGMR) + sig = idals_mem->sqrtN * idals_mem->dqincfac; + else + sig = idals_mem->dqincfac / N_VWrmsNorm(v, IDA_mem->ida_ewt); /* Rename work1 and work2 for readibility */ y_tmp = work1; @@ -1194,13 +1241,15 @@ int idaLsSetup(IDAMem IDA_mem, N_Vector y, N_Vector yp, N_Vector r, /* Increment nje counter. */ idals_mem->nje++; - /* Zero out J; call Jacobian routine jac; return if it failed. */ - retval = SUNMatZero(idals_mem->J); - if (retval != 0) { - IDAProcessError(IDA_mem, IDALS_SUNMAT_FAIL, "IDALS", - "idaLsSetup", MSG_LS_MATZERO_FAILED); - idals_mem->last_flag = IDALS_SUNMAT_FAIL; - return(idals_mem->last_flag); + /* Clear the linear system matrix if necessary */ + if (SUNLinSolGetType(idals_mem->LS) == SUNLINEARSOLVER_DIRECT) { + retval = SUNMatZero(idals_mem->J); + if (retval != 0) { + IDAProcessError(IDA_mem, IDALS_SUNMAT_FAIL, "IDALS", + "idaLsSetup", MSG_LS_MATZERO_FAILED); + idals_mem->last_flag = IDALS_SUNMAT_FAIL; + return(idals_mem->last_flag); + } } /* Call Jacobian routine */ @@ -1241,7 +1290,7 @@ int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, { IDALsMem idals_mem; int nli_inc, retval; - realtype tol, w_mean, LSType; + realtype tol, w_mean; /* access IDALsMem structure */ if (IDA_mem->ida_lmem == NULL) { @@ -1251,16 +1300,12 @@ int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, } idals_mem = (IDALsMem) IDA_mem->ida_lmem; - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(idals_mem->LS); - /* If the linear solver is iterative: set convergence test constant tol, in terms of the Newton convergence test constant epsNewt and safety factors. The factor sqrt(Neq) assures that the convergence test is applied to the WRMS norm of the residual vector, rather than the weighted L2 norm. */ - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (idals_mem->iterative) { tol = idals_mem->sqrtN * idals_mem->eplifac * IDA_mem->ida_epsNewt; } else { tol = ZERO; @@ -1272,9 +1317,6 @@ int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, idals_mem->ypcur = ypcur; idals_mem->rcur = rescur; - /* Set initial guess x = 0 to LS */ - N_VConst(ZERO, idals_mem->x); - /* Set scaling vectors for LS to use (if applicable) */ if (idals_mem->LS->ops->setscalingvectors) { retval = SUNLinSolSetScalingVectors(idals_mem->LS, weight, weight); @@ -1298,16 +1340,18 @@ int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, <=> w_mean^2 \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 <=> \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 / w_mean^2 <=> || b - A x ||_2 < tol / w_mean - So we compute w_mean = ||w||_RMS = ||w||_2 / sqrt(n), and scale - the desired tolerance accordingly. */ - } else if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + So we compute w_mean = ||w||_RMS and scale the desired tolerance accordingly. */ + } else if (idals_mem->iterative) { - w_mean = SUNRsqrt( N_VDotProd(weight, weight) ) / idals_mem->sqrtN; + N_VConst(ONE, idals_mem->x); + w_mean = N_VWrmsNorm(weight, idals_mem->x); tol /= w_mean; } + /* Set initial guess x = 0 to LS */ + N_VConst(ZERO, idals_mem->x); + /* If a user-provided jtsetup routine is supplied, call that here */ if (idals_mem->jtsetup) { idals_mem->last_flag = idals_mem->jtsetup(IDA_mem->ida_tn, ycur, ypcur, rescur, @@ -1325,8 +1369,7 @@ int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, idals_mem->x, b, tol); /* Copy appropriate result to b (depending on solver type) */ - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (idals_mem->iterative) { /* Retrieve solver statistics */ nli_inc = SUNLinSolNumIters(idals_mem->LS); @@ -1347,9 +1390,7 @@ int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, /* If using a direct or matrix-iterative solver, scale the correction to account for change in cj */ - if ( ((LSType == SUNLINEARSOLVER_DIRECT) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE)) && - (IDA_mem->ida_cjratio != ONE) ) + if (idals_mem->scalesol && (IDA_mem->ida_cjratio != ONE)) N_VScale(TWO/(ONE + IDA_mem->ida_cjratio), b, b); /* Increment ncfl counter */ @@ -1435,10 +1476,8 @@ int idaLsPerf(IDAMem IDA_mem, int perftask) nnid = IDA_mem->ida_nni - idals_mem->nni0; if (nstd == 0 || nnid == 0) return(0); - rcfn = (realtype) ( (IDA_mem->ida_ncfn - idals_mem->ncfn0) / - ((realtype) nstd) ); - rcfl = (realtype) ( (idals_mem->ncfl - idals_mem->ncfl0) / - ((realtype) nnid) ); + rcfn = ((realtype) (IDA_mem->ida_ncfn - idals_mem->ncfn0)) / ((realtype) nstd); + rcfl = ((realtype) (idals_mem->ncfl - idals_mem->ncfl0)) / ((realtype) nnid); lcfn = (rcfn > PT9); lcfl = (rcfl > PT9); if (!(lcfn || lcfl)) return(0); diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/ida_ls_impl.h b/deps/AMICI/ThirdParty/sundials/src/ida/ida_ls_impl.h index c4ee8d42a..d2a042018 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/ida_ls_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/ida/ida_ls_impl.h @@ -3,7 +3,7 @@ * Alan C. Hindmarsh and Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -34,6 +34,10 @@ extern "C" { -----------------------------------------------------------------*/ typedef struct IDALsMemRec { + /* Linear solver type information */ + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ + /* Jacobian construction & storage */ booleantype jacDQ; /* SUNTRUE if using internal DQ Jacobian approx. */ IDALsJacFn jac; /* Jacobian routine to be called */ @@ -49,6 +53,9 @@ typedef struct IDALsMemRec { N_Vector ypcur; /* current yp vector in Newton iteration */ N_Vector rcur; /* rcur = F(tn, ycur, ypcur) */ + /* Matrix-based solver, scale solution to account for change in cj */ + booleantype scalesol; + /* Iterative solver tolerance */ realtype sqrtN; /* sqrt(N) */ realtype eplifac; /* eplifac = linear convergence factor */ @@ -69,7 +76,7 @@ typedef struct IDALsMemRec { long int ncfl0; /* ncfl0 = saved ncfl (for performance monitor) */ long int nwarn; /* nwarn = no. of warnings (for perf. monitor) */ - long int last_flag; /* last error return flag */ + int last_flag; /* last error return flag */ /* Preconditioner computation (a) user-provided: diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/ida_nls.c b/deps/AMICI/ThirdParty/sundials/src/ida/ida_nls.c index f64464bc6..ee4f67be2 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/ida_nls.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/ida_nls.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -28,9 +28,8 @@ /* private functions passed to nonlinear solver */ static int idaNlsResidual(N_Vector ycor, N_Vector res, void* ida_mem); -static int idaNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, - booleantype* jcur, void* ida_mem); -static int idaNlsLSolve(N_Vector ycor, N_Vector delta, void* ida_mem); +static int idaNlsLSetup(booleantype jbad, booleantype* jcur, void* ida_mem); +static int idaNlsLSolve(N_Vector delta, void* ida_mem); static int idaNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, realtype tol, N_Vector ewt, void* ida_mem); @@ -60,11 +59,9 @@ int IDASetNonlinearSolver(void *ida_mem, SUNNonlinearSolver NLS) } /* check for required nonlinear solver functions */ - if ( NLS->ops->gettype == NULL || - NLS->ops->initialize == NULL || - NLS->ops->solve == NULL || - NLS->ops->free == NULL || - NLS->ops->setsysfn == NULL ) { + if ( NLS->ops->gettype == NULL || + NLS->ops->solve == NULL || + NLS->ops->setsysfn == NULL ) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetNonlinearSolver", "NLS does not support required operations"); @@ -100,7 +97,7 @@ int IDASetNonlinearSolver(void *ida_mem, SUNNonlinearSolver NLS) } /* set convergence test function */ - retval = SUNNonlinSolSetConvTestFn(IDA_mem->NLS, idaNlsConvTest); + retval = SUNNonlinSolSetConvTestFn(IDA_mem->NLS, idaNlsConvTest, ida_mem); if (retval != IDA_SUCCESS) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetNonlinearSolver", @@ -166,8 +163,7 @@ int idaNlsInit(IDAMem IDA_mem) } -static int idaNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, - booleantype* jcur, void* ida_mem) +static int idaNlsLSetup(booleantype jbad, booleantype* jcur, void* ida_mem) { IDAMem IDA_mem; int retval; @@ -179,16 +175,17 @@ static int idaNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, IDA_mem = (IDAMem) ida_mem; IDA_mem->ida_nsetups++; - retval = IDA_mem->ida_lsetup(IDA_mem, IDA_mem->ida_yy, IDA_mem->ida_yp, res, - IDA_mem->ida_tempv1, IDA_mem->ida_tempv2, IDA_mem->ida_tempv3); + retval = IDA_mem->ida_lsetup(IDA_mem, IDA_mem->ida_yy, IDA_mem->ida_yp, + IDA_mem->ida_savres, IDA_mem->ida_tempv1, + IDA_mem->ida_tempv2, IDA_mem->ida_tempv3); /* update Jacobian status */ *jcur = SUNTRUE; /* update convergence test constants */ - IDA_mem->ida_cjold = IDA_mem->ida_cj; + IDA_mem->ida_cjold = IDA_mem->ida_cj; IDA_mem->ida_cjratio = ONE; - IDA_mem->ida_ss = TWENTY; + IDA_mem->ida_ss = TWENTY; if (retval < 0) return(IDA_LSETUP_FAIL); if (retval > 0) return(IDA_LSETUP_RECVR); @@ -197,7 +194,7 @@ static int idaNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, } -static int idaNlsLSolve(N_Vector ycor, N_Vector delta, void* ida_mem) +static int idaNlsLSolve(N_Vector delta, void* ida_mem) { IDAMem IDA_mem; int retval; @@ -208,7 +205,8 @@ static int idaNlsLSolve(N_Vector ycor, N_Vector delta, void* ida_mem) } IDA_mem = (IDAMem) ida_mem; - retval = IDA_mem->ida_lsolve(IDA_mem, delta, IDA_mem->ida_ewt, IDA_mem->ida_yy, IDA_mem->ida_yp, + retval = IDA_mem->ida_lsolve(IDA_mem, delta, IDA_mem->ida_ewt, + IDA_mem->ida_yy, IDA_mem->ida_yp, IDA_mem->ida_savres); if (retval < 0) return(IDA_LSOLVE_FAIL); diff --git a/deps/AMICI/ThirdParty/sundials/src/ida/ida_spils.c b/deps/AMICI/ThirdParty/sundials/src/ida/ida_spils.c index 55132140b..7e806c5f8 100644 --- a/deps/AMICI/ThirdParty/sundials/src/ida/ida_spils.c +++ b/deps/AMICI/ThirdParty/sundials/src/ida/ida_spils.c @@ -3,7 +3,7 @@ * Alan Hindmarsh, Radu Serban and Aaron Collier @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/idas/CMakeLists.txt index d83970379..f76380737 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/idas/CMakeLists.txt @@ -1,9 +1,9 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU -# Radu Serban @ LLNL +# Programmer(s): Daniel R. Reynolds @ SMU +# Radu Serban @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -13,11 +13,17 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the IDAS library +# --------------------------------------------------------------- + +install(CODE "MESSAGE(\"\nInstall IDAS\n\")") -INSTALL(CODE "MESSAGE(\"\nInstall IDAS\n\")") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) # Add variable idas_SOURCES with the sources for the IDAS library -SET(idas_SOURCES +set(idas_SOURCES idas.c idaa.c idas_direct.c @@ -34,7 +40,7 @@ SET(idas_SOURCES # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the IDAS library -SET(shared_SOURCES +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_matrix.c ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c @@ -46,12 +52,13 @@ SET(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c ${sundials_SOURCE_DIR}/src/sundials/sundials_version.c ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector_senswrapper.c + ${sundials_SOURCE_DIR}/src/sundials/sundials_futils.c ${sundials_SOURCE_DIR}/src/nvector/serial/nvector_serial.c ) # Add variable sunmatrix_SOURCES with the common SUNMatrix sources which will # also be included in the IDAS library -SET(sunmatrix_SOURCES +set(sunmatrix_SOURCES ${sundials_SOURCE_DIR}/src/sunmatrix/band/sunmatrix_band.c ${sundials_SOURCE_DIR}/src/sunmatrix/dense/sunmatrix_dense.c ${sundials_SOURCE_DIR}/src/sunmatrix/sparse/sunmatrix_sparse.c @@ -59,7 +66,7 @@ SET(sunmatrix_SOURCES # Add variable sunlinsol_SOURCES with the common SUNLinearSolver sources which will # also be included in the IDAS library -SET(sunlinsol_SOURCES +set(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/band/sunlinsol_band.c ${sundials_SOURCE_DIR}/src/sunlinsol/dense/sunlinsol_dense.c ${sundials_SOURCE_DIR}/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c @@ -71,12 +78,13 @@ SET(sunlinsol_SOURCES # Add variable sunnonlinsol_SOURCES with the common SUNNonlinearSolver sources # which will also be included in the IDAS library -SET(sunnonlinsol_SOURCES +set(sunnonlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunnonlinsol/newton/sunnonlinsol_newton.c + ${sundials_SOURCE_DIR}/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c ) # Add variable idas_HEADERS with the exported IDAS header files -SET(idas_HEADERS +set(idas_HEADERS idas.h idas_bbdpre.h idas_direct.h @@ -85,59 +93,59 @@ SET(idas_HEADERS ) # Add prefix with complete path to the IDAS header files -ADD_PREFIX(${sundials_SOURCE_DIR}/include/idas/ idas_HEADERS) +add_prefix(${sundials_SOURCE_DIR}/include/idas/ idas_HEADERS) # Add source directories to include directories for access to # implementation only header files. -INCLUDE_DIRECTORIES(.) +include_directories(.) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) # Build the static library -IF(BUILD_STATIC_LIBS) +if(BUILD_STATIC_LIBS) # Add the build target for the static IDAS library - ADD_LIBRARY(sundials_idas_static STATIC + add_library(sundials_idas_static STATIC ${idas_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ${sunnonlinsol_SOURCES}) # Set the library name and make sure it is not deleted - SET_TARGET_PROPERTIES(sundials_idas_static + set_target_properties(sundials_idas_static PROPERTIES OUTPUT_NAME sundials_idas CLEAN_DIRECT_OUTPUT 1) # Install the IDA library - INSTALL(TARGETS sundials_idas_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS sundials_idas_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +endif(BUILD_STATIC_LIBS) # Build the shared library -IF(BUILD_SHARED_LIBS) +if(BUILD_SHARED_LIBS) # Add the build target for the IDAS library - ADD_LIBRARY(sundials_idas_shared SHARED + add_library(sundials_idas_shared SHARED ${idas_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ${sunnonlinsol_SOURCES}) - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_idas_shared m) - ENDIF() + if(UNIX) + target_link_libraries(sundials_idas_shared m) + endif() # Set the library name and make sure it is not deleted - SET_TARGET_PROPERTIES(sundials_idas_shared + set_target_properties(sundials_idas_shared PROPERTIES OUTPUT_NAME sundials_idas CLEAN_DIRECT_OUTPUT 1) # Set VERSION and SOVERSION for shared libraries - SET_TARGET_PROPERTIES(sundials_idas_shared + set_target_properties(sundials_idas_shared PROPERTIES VERSION ${idaslib_VERSION} SOVERSION ${idaslib_SOVERSION}) # Install the IDAS library - INSTALL(TARGETS sundials_idas_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS sundials_idas_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) +endif(BUILD_SHARED_LIBS) # Install the IDAS header files -INSTALL(FILES ${idas_HEADERS} DESTINATION include/idas) +install(FILES ${idas_HEADERS} DESTINATION include/idas) # -MESSAGE(STATUS "Added IDAS module") +message(STATUS "Added IDAS module") diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/README b/deps/AMICI/ThirdParty/sundials/src/idas/README deleted file mode 100644 index ca1b3b293..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/idas/README +++ /dev/null @@ -1,90 +0,0 @@ - IDAS - Release 3.1.0, Feb 2019 - Radu Serban - Center for Applied Scientific Computing, LLNL - - -IDAS is a package for the solution of differential-algebraic equation (DAE) -systems with sensitivity analysis capabilities (both forward and adjoint modes). -It is written in ANSI standard C. - -IDAS can be used both on serial and parallel computers. The main -difference is in the NVECTOR module of vector kernels. The desired -version is obtained when compiling the example files by linking the -appropriate library of NVECTOR kernels. In the parallel versions, -communication between processors is done with MPI, with OpenMP, -or with Pthreads. - -When used with the serial NVECTOR module, IDAS provides both direct -(dense and band) linear solvers and preconditioned Krylov (iterative) -linear solvers. Three different iterative solvers are available: scaled -preconditioned GMRES (SPGMR), scaled preconditioned BiCGStab (SPBCG), and -scaled preconditioned TFQMR (SPTFQMR). When IDAS is used with the parallel -NVECTOR module, only the Krylov linear solvers are available. For the -latter case, in addition to the basic solver, the IDA package also contains -a preconditioner module called IDABBDPRE, which provides a band-block-diagonal -preconditioner. - -IDAS is part of a software family called SUNDIALS: SUite of Nonlinear and -DIfferential/ALgebraic equation Solvers [3]. This suite consists of CVODE, -CVODES, ARkode, IDA, IDAS, and KINSOL. The directory structure of the -package supplied reflects this family relationship. - -Several examples problem programs are included, covering both serial -and parallel cases, both small and large problem sizes, and both -linear and nonlinear problems. - -The notes below provide the location of documentation, directions for the -installation of the IDAS package, and relevant references. Following that -is a brief history of revisions to the package. - - -A. Documentation ----------------- - -/sundials/doc/idas/ contains PDF files for the IDAS User Guide [1] (idas_guide.pdf) -and the IDAS Examples [2] (idas_examples.pdf) documents. - - -B. Installation ---------------- - -For basic installation instructions see the file /sundials/INSTALL_GUIDE.pdf. -For complete installation instructions see the "Installation Procedure" -chapter in the IDAS User Guide. - - -C. References -------------- - -[1] R. Serban, C. Petra,and A. C. Hindmarsh, "User Documentation for IDAS v1.3.0," - LLNL technical report UCRL-SM-234051, March 2016. - -[2] R. Serban and A.C. Hindmarsh, "Example Programs for IDAS v1.3.0," - LLNL technical report LLNL-TR-437091, March 2016. - -[3] A. C. Hindmarsh, P. N. Brown, K. E. Grant, S. L. Lee, R. Serban, - D. E. Shumaker, and C. S. Woodward, "SUNDIALS, Suite of Nonlinear and - Differential/Algebraic Equation Solvers," ACM Trans. Math. Softw., - 31(3), pp. 363-396, 2005. - - -D. Releases ------------ - -v. 3.1.0 - Feb. 2019 -v. 3.0.2 - Jan. 2019 -v. 3.0.1 - Dec. 2018 -v. 3.0.0 - Dec. 2018 -v. 2.2.1 - Oct. 2018 -v. 2.2.0 - Sep. 2018 -v. 2.1.2 - Jul. 2018 -v. 2.1.1 - May 2018 -v. 2.1.0 - Nov. 2017 -v. 2.0.0 - Sep. 2017 -v. 1.3.0 - Sep. 2016 -v. 1.2.2 - Aug. 2015 -v. 1.2.1 - Mar. 2015 -v. 1.2.0 - Mar. 2015 -v. 1.1.0 - Mar. 2012 -v. 1.0.0 - May 2009 diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/README.md b/deps/AMICI/ThirdParty/sundials/src/idas/README.md new file mode 100644 index 000000000..d15aebde8 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/idas/README.md @@ -0,0 +1,52 @@ +# IDAS +### Version 4.2.0 (Mar 2020) + +**Radu Serban + Center for Applied Scientific Computing, LLNL** + +IDAS is a package for the solution of differential-algebraic equation (DAE) +systems +``` +F(t,y,y',p) = 0, y(t0) = y0(p), y'(t0) = y0'(p) +``` +with sensitivity analysis capabilities (both forward and adjoint modes). The +integration methods used in IDAS are variable-order, variable-coefficient BDF +(Backward Differentiation Formula) methods in fixed-leading-coefficient form. + +IDAS is part of the SUNDIALS Suite of Nonlinear and Differential/Algebraic +equation Solvers which consists of ARKode, CVODE, CVODES, IDA, IDAS and KINSOL. +It is written in ANSI standard C and can be used in a variety of computing +environments including serial, shared memory, distributed memory, and +accelerator-based (e.g., GPU) systems. This flexibility is obtained from a +modular design that leverages the shared vector, matrix, linear solver, and +nonlinear solver APIs used across SUNDIALS packages. + +## Documentation + +See the [IDAS User Guide](/doc/idas/idas_guide.pdf) and +[IDAS Examples](/doc/idas/idas_examples.pdf) document for more information +about IDAS usage and the provided example programs respectively. + +## Installation + +For installation instructions see the [INSTALL_GUIDE](/INSTALL_GUIDE.pdf) +or the "Installation Procedure" chapter in the IDAS User Guide. + +## Release History + +Information on recent changes to IDAS can be found in the "Introduction" +chapter of the IDAS User Guide and a complete release history is available in +the "SUNDIALS Release History" appendix of the IDAS User Guide. + +## References + +* R. Serban, C. Petra,and A. C. Hindmarsh, "User Documentation for IDAS v4.2.0," + LLNL technical report UCRL-SM-234051, Mar 2020. + +* R. Serban and A.C. Hindmarsh, "Example Programs for IDAS v4.2.0," + LLNL technical report LLNL-TR-437091, Mar 2020. + +* A. C. Hindmarsh, P. N. Brown, K. E. Grant, S. L. Lee, R. Serban, + D. E. Shumaker, and C. S. Woodward, "SUNDIALS, Suite of Nonlinear and + Differential/Algebraic Equation Solvers," ACM Trans. Math. Softw., + 31(3), pp. 363-396, 2005. diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/fmod/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/idas/fmod/CMakeLists.txt new file mode 100644 index 000000000..48a80516d --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/idas/fmod/CMakeLists.txt @@ -0,0 +1,99 @@ +# --------------------------------------------------------------- +# Programmer: Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the F2003 IDAS object library + +set(idas_SOURCES fidas_mod.f90 fidas_mod.c) + +if(BUILD_STATIC_LIBS) + sundials_add_f2003_interface_library(sundials_fidas_mod_static STATIC + ${idas_SOURCES} + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + + # include the directoy where the .mod files reside + target_include_directories(sundials_fidas_mod_static + PUBLIC + $ + $ + ) + + # Set the library name and make sure it is not deleted + set_target_properties(sundials_fidas_mod_static + PROPERTIES OUTPUT_NAME sundials_fidas_mod CLEAN_DIRECT_OUTPUT 1) + + # install the library + install(TARGETS sundials_fidas_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # install the idas mod file from here since it won't go into the + # top level fortran mod file directory + install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_STATIC/fidas_mod.mod + DESTINATION ${Fortran_INSTALL_MODDIR}) +endif() + +if(BUILD_SHARED_LIBS) + sundials_add_f2003_interface_library(sundials_fidas_mod_shared SHARED + ${idas_SOURCES} + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + + # include the directoy where the .mod files reside + target_include_directories(sundials_fidas_mod_shared + PUBLIC + $ + $ + ) + + # Set the library name and make sure it is not deleted + set_target_properties(sundials_fidas_mod_shared PROPERTIES + OUTPUT_NAME sundials_fidas_mod + CLEAN_DIRECT_OUTPUT 1 + VERSION ${idaslib_VERSION} + SOVERSION ${idaslib_SOVERSION}) + + # install the library + install(TARGETS sundials_fidas_mod_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # install the idas mod file from here since it won't go into the + # top level fortran mod file directory + install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_SHARED/fidas_mod.mod + DESTINATION ${Fortran_INSTALL_MODDIR}) +endif() + +message(STATUS "Added IDAS F2003 interface") diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/fmod/fidas_mod.c b/deps/AMICI/ThirdParty/sundials/src/idas/fmod/fidas_mod.c new file mode 100644 index 000000000..a41d14a7c --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/idas/fmod/fidas_mod.c @@ -0,0 +1,3539 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +enum { + SWIG_MEM_OWN = 0x01, + SWIG_MEM_RVALUE = 0x02, + SWIG_MEM_CONST = 0x04 +}; + + +#define SWIG_check_mutable(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL) \ + if ((SWIG_CLASS_WRAPPER).cmemflags & SWIG_MEM_CONST) { \ + SWIG_exception_impl(FUNCNAME, SWIG_TypeError, \ + "Cannot pass const " TYPENAME " (class " FNAME ") " \ + "as a mutable reference", \ + RETURNNULL); \ + } + + +#define SWIG_check_nonnull(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL) \ + if (!(SWIG_CLASS_WRAPPER).cptr) { \ + SWIG_exception_impl(FUNCNAME, SWIG_TypeError, \ + "Cannot pass null " TYPENAME " (class " FNAME ") " \ + "as a reference", RETURNNULL); \ + } + + +#define SWIG_check_mutable_nonnull(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL) \ + SWIG_check_nonnull(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL); \ + SWIG_check_mutable(SWIG_CLASS_WRAPPER, TYPENAME, FNAME, FUNCNAME, RETURNNULL); + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "idas/idas.h" +#include "idas/idas_bbdpre.h" +#include "idas/idas_ls.h" + + +#include +#ifdef _MSC_VER +# ifndef strtoull +# define strtoull _strtoui64 +# endif +# ifndef strtoll +# define strtoll _strtoi64 +# endif +#endif + + +typedef struct { + void* data; + size_t size; +} SwigArrayWrapper; + + +SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() { + SwigArrayWrapper result; + result.data = NULL; + result.size = 0; + return result; +} + + +#include + + +typedef struct { + void* cptr; + int cmemflags; +} SwigClassWrapper; + + +SWIGINTERN SwigClassWrapper SwigClassWrapper_uninitialized() { + SwigClassWrapper result; + result.cptr = NULL; + result.cmemflags = 0; + return result; +} + + +SWIGINTERN void SWIG_assign(SwigClassWrapper* self, SwigClassWrapper other) { + if (self->cptr == NULL) { + /* LHS is unassigned */ + if (other.cmemflags & SWIG_MEM_RVALUE) { + /* Capture pointer from RHS, clear 'moving' flag */ + self->cptr = other.cptr; + self->cmemflags = other.cmemflags & (~SWIG_MEM_RVALUE); + } else { + /* Become a reference to the other object */ + self->cptr = other.cptr; + self->cmemflags = other.cmemflags & (~SWIG_MEM_OWN); + } + } else if (other.cptr == NULL) { + /* Replace LHS with a null pointer */ + free(self->cptr); + *self = SwigClassWrapper_uninitialized(); + } else { + if (self->cmemflags & SWIG_MEM_OWN) { + free(self->cptr); + } + self->cptr = other.cptr; + if (other.cmemflags & SWIG_MEM_RVALUE) { + /* Capture RHS */ + self->cmemflags = other.cmemflags & ~SWIG_MEM_RVALUE; + } else { + /* Point to RHS */ + self->cmemflags = other.cmemflags & ~SWIG_MEM_OWN; + } + } +} + +SWIGEXPORT void * _wrap_FIDACreate() { + void * fresult ; + void *result = 0 ; + + result = (void *)IDACreate(); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAInit(void *farg1, IDAResFn farg2, double const *farg3, N_Vector farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + IDAResFn arg2 = (IDAResFn) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDAResFn)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + result = (int)IDAInit(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAReInit(void *farg1, double const *farg2, N_Vector farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAReInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASStolerances(void *farg1, double const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)IDASStolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASVtolerances(void *farg1, double const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDASVtolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAWFtolerances(void *farg1, IDAEwtFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + IDAEwtFn arg2 = (IDAEwtFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDAEwtFn)(farg2); + result = (int)IDAWFtolerances(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDACalcIC(void *farg1, int const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)IDACalcIC(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetNonlinConvCoefIC(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetNonlinConvCoefIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxNumStepsIC(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxNumStepsIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxNumJacsIC(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxNumJacsIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxNumItersIC(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxNumItersIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetLineSearchOffIC(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetLineSearchOffIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetStepToleranceIC(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetStepToleranceIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxBacksIC(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxBacksIC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetErrHandlerFn(void *farg1, IDAErrHandlerFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + IDAErrHandlerFn arg2 = (IDAErrHandlerFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDAErrHandlerFn)(farg2); + arg3 = (void *)(farg3); + result = (int)IDASetErrHandlerFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetErrFile(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)IDASetErrFile(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetUserData(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + void *arg2 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (void *)(farg2); + result = (int)IDASetUserData(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxOrd(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxOrd(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxNumSteps(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)IDASetMaxNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetInitStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetInitStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetMaxStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetStopTime(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetStopTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetNonlinConvCoef(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetNonlinConvCoef(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxErrTestFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxNonlinIters(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxNonlinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxConvFails(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetMaxConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetSuppressAlg(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetSuppressAlg(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetId(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)IDASetId(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetConstraints(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)IDASetConstraints(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetNonlinearSolver(void *farg1, SUNNonlinearSolver farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNNonlinearSolver arg2 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNNonlinearSolver)(farg2); + result = (int)IDASetNonlinearSolver(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDARootInit(void *farg1, int const *farg2, IDARootFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + IDARootFn arg3 = (IDARootFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (IDARootFn)(farg3); + result = (int)IDARootInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetRootDirection(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)IDASetRootDirection(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetNoInactiveRootWarn(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)IDASetNoInactiveRootWarn(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASolve(void *farg1, double const *farg2, double *farg3, N_Vector farg4, N_Vector farg5, int const *farg6) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype *arg3 = (realtype *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int arg6 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + arg6 = (int)(*farg6); + result = (int)IDASolve(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAComputeY(void *farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDAComputeY(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAComputeYp(void *farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDAComputeYp(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAComputeYSens(void *farg1, void *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + result = (int)IDAComputeYSens(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAComputeYpSens(void *farg1, void *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + result = (int)IDAComputeYpSens(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetDky(void *farg1, double const *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAGetDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)IDAGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumSteps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumSteps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumResEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumResEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumLinSolvSetups(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumLinSolvSetups(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumErrTestFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumBacktrackOps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumBacktrackOps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetConsistentIC(void *farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDAGetConsistentIC(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetLastOrder(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)IDAGetLastOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentOrder(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)IDAGetCurrentOrder(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentCj(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)IDAGetCurrentCj(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentY(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)IDAGetCurrentY(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentYSens(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector **arg2 = (N_Vector **) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector **)(farg2); + result = (int)IDAGetCurrentYSens(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentYp(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)IDAGetCurrentYp(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentYpSens(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector **arg2 = (N_Vector **) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector **)(farg2); + result = (int)IDAGetCurrentYpSens(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetActualInitStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)IDAGetActualInitStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetLastStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)IDAGetLastStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentStep(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)IDAGetCurrentStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetCurrentTime(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)IDAGetCurrentTime(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetTolScaleFactor(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)IDAGetTolScaleFactor(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetErrWeights(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)IDAGetErrWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetEstLocalErrors(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)IDAGetEstLocalErrors(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumGEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumGEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetRootInfo(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)IDAGetRootInfo(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetIntegratorStats(void *farg1, long *farg2, long *farg3, long *farg4, long *farg5, int *farg6, int *farg7, double *farg8, double *farg9, double *farg10, double *farg11) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + long *arg4 = (long *) 0 ; + long *arg5 = (long *) 0 ; + int *arg6 = (int *) 0 ; + int *arg7 = (int *) 0 ; + realtype *arg8 = (realtype *) 0 ; + realtype *arg9 = (realtype *) 0 ; + realtype *arg10 = (realtype *) 0 ; + realtype *arg11 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + arg4 = (long *)(farg4); + arg5 = (long *)(farg5); + arg6 = (int *)(farg6); + arg7 = (int *)(farg7); + arg8 = (realtype *)(farg8); + arg9 = (realtype *)(farg9); + arg10 = (realtype *)(farg10); + arg11 = (realtype *)(farg11); + result = (int)IDAGetIntegratorStats(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumNonlinSolvIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumNonlinSolvIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumNonlinSolvConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumNonlinSolvConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNonlinSolvStats(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)IDAGetNonlinSolvStats(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FIDAGetReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)IDAGetReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FIDAFree(void *farg1) { + void **arg1 = (void **) 0 ; + + arg1 = (void **)(farg1); + IDAFree(arg1); +} + + +SWIGEXPORT int _wrap_FIDAQuadInit(void *farg1, IDAQuadRhsFn farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + IDAQuadRhsFn arg2 = (IDAQuadRhsFn) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDAQuadRhsFn)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDAQuadInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAQuadReInit(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)IDAQuadReInit(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAQuadSStolerances(void *farg1, double const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)IDAQuadSStolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAQuadSVtolerances(void *farg1, double const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDAQuadSVtolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetQuadErrCon(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetQuadErrCon(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuad(void *farg1, double *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDAGetQuad(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadDky(void *farg1, double const *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAGetQuadDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetQuadNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadNumErrTestFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetQuadNumErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadErrWeights(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)IDAGetQuadErrWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadStats(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)IDAGetQuadStats(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FIDAQuadFree(void *farg1) { + void *arg1 = (void *) 0 ; + + arg1 = (void *)(farg1); + IDAQuadFree(arg1); +} + + +SWIGEXPORT int _wrap_FIDASensInit(void *farg1, int const *farg2, int const *farg3, IDASensResFn farg4, void *farg5, void *farg6) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + IDASensResFn arg4 = (IDASensResFn) 0 ; + N_Vector *arg5 = (N_Vector *) 0 ; + N_Vector *arg6 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + arg4 = (IDASensResFn)(farg4); + arg5 = (N_Vector *)(farg5); + arg6 = (N_Vector *)(farg6); + result = (int)IDASensInit(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASensReInit(void *farg1, int const *farg2, void *farg3, void *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector *)(farg4); + result = (int)IDASensReInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASensSStolerances(void *farg1, double const *farg2, double *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype *arg3 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype *)(farg3); + result = (int)IDASensSStolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASensSVtolerances(void *farg1, double const *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (int)IDASensSVtolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASensEEtolerances(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)IDASensEEtolerances(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSensConsistentIC(void *farg1, void *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + result = (int)IDAGetSensConsistentIC(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetSensDQMethod(void *farg1, int const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)IDASetSensDQMethod(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetSensErrCon(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetSensErrCon(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetSensMaxNonlinIters(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetSensMaxNonlinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetSensParams(void *farg1, double *farg2, double *farg3, int *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + realtype *arg3 = (realtype *) 0 ; + int *arg4 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + arg3 = (realtype *)(farg3); + arg4 = (int *)(farg4); + result = (int)IDASetSensParams(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetNonlinearSolverSensSim(void *farg1, SUNNonlinearSolver farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNNonlinearSolver arg2 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNNonlinearSolver)(farg2); + result = (int)IDASetNonlinearSolverSensSim(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetNonlinearSolverSensStg(void *farg1, SUNNonlinearSolver farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNNonlinearSolver arg2 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNNonlinearSolver)(farg2); + result = (int)IDASetNonlinearSolverSensStg(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASensToggleOff(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)IDASensToggleOff(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSens(void *farg1, double *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + result = (int)IDAGetSens(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSens1(void *farg1, double *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAGetSens1(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSensDky(void *farg1, double const *farg2, int const *farg3, void *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector *arg4 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector *)(farg4); + result = (int)IDAGetSensDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSensDky1(void *farg1, double const *farg2, int const *farg3, int const *farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + int arg4 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (int)(*farg4); + arg5 = (N_Vector)(farg5); + result = (int)IDAGetSensDky1(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSensNumResEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetSensNumResEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumResEvalsSens(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumResEvalsSens(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSensNumErrTestFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetSensNumErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSensNumLinSolvSetups(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetSensNumLinSolvSetups(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSensErrWeights(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector_S arg2 = (N_Vector_S) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector_S)(farg2); + result = (int)IDAGetSensErrWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSensStats(void *farg1, long *farg2, long *farg3, long *farg4, long *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + long *arg4 = (long *) 0 ; + long *arg5 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + arg4 = (long *)(farg4); + arg5 = (long *)(farg5); + result = (int)IDAGetSensStats(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSensNumNonlinSolvIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetSensNumNonlinSolvIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSensNumNonlinSolvConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetSensNumNonlinSolvConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetSensNonlinSolvStats(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)IDAGetSensNonlinSolvStats(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FIDASensFree(void *farg1) { + void *arg1 = (void *) 0 ; + + arg1 = (void *)(farg1); + IDASensFree(arg1); +} + + +SWIGEXPORT int _wrap_FIDAQuadSensInit(void *farg1, IDAQuadSensRhsFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + IDAQuadSensRhsFn arg2 = (IDAQuadSensRhsFn) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDAQuadSensRhsFn)(farg2); + arg3 = (N_Vector *)(farg3); + result = (int)IDAQuadSensInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAQuadSensReInit(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)IDAQuadSensReInit(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAQuadSensSStolerances(void *farg1, double const *farg2, double *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype *arg3 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype *)(farg3); + result = (int)IDAQuadSensSStolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAQuadSensSVtolerances(void *farg1, double const *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (int)IDAQuadSensSVtolerances(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAQuadSensEEtolerances(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)IDAQuadSensEEtolerances(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetQuadSensErrCon(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetQuadSensErrCon(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadSens(void *farg1, double *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + result = (int)IDAGetQuadSens(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadSens1(void *farg1, double *farg2, int const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAGetQuadSens1(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadSensDky(void *farg1, double const *farg2, int const *farg3, void *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + N_Vector *arg4 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector *)(farg4); + result = (int)IDAGetQuadSensDky(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadSensDky1(void *farg1, double const *farg2, int const *farg3, int const *farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + int arg4 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + arg4 = (int)(*farg4); + arg5 = (N_Vector)(farg5); + result = (int)IDAGetQuadSensDky1(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadSensNumRhsEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetQuadSensNumRhsEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadSensNumErrTestFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetQuadSensNumErrTestFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadSensErrWeights(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector *arg2 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector *)(farg2); + result = (int)IDAGetQuadSensErrWeights(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadSensStats(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)IDAGetQuadSensStats(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FIDAQuadSensFree(void *farg1) { + void *arg1 = (void *) 0 ; + + arg1 = (void *)(farg1); + IDAQuadSensFree(arg1); +} + + +SWIGEXPORT int _wrap_FIDAAdjInit(void *farg1, long const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + arg3 = (int)(*farg3); + result = (int)IDAAdjInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAAdjReInit(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)IDAAdjReInit(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FIDAAdjFree(void *farg1) { + void *arg1 = (void *) 0 ; + + arg1 = (void *)(farg1); + IDAAdjFree(arg1); +} + + +SWIGEXPORT int _wrap_FIDACreateB(void *farg1, int *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int *)(farg2); + result = (int)IDACreateB(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAInitB(void *farg1, int const *farg2, IDAResFnB farg3, double const *farg4, N_Vector farg5, N_Vector farg6) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + IDAResFnB arg3 = (IDAResFnB) 0 ; + realtype arg4 ; + N_Vector arg5 = (N_Vector) 0 ; + N_Vector arg6 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (IDAResFnB)(farg3); + arg4 = (realtype)(*farg4); + arg5 = (N_Vector)(farg5); + arg6 = (N_Vector)(farg6); + result = (int)IDAInitB(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAInitBS(void *farg1, int const *farg2, IDAResFnBS farg3, double const *farg4, N_Vector farg5, N_Vector farg6) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + IDAResFnBS arg3 = (IDAResFnBS) 0 ; + realtype arg4 ; + N_Vector arg5 = (N_Vector) 0 ; + N_Vector arg6 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (IDAResFnBS)(farg3); + arg4 = (realtype)(*farg4); + arg5 = (N_Vector)(farg5); + arg6 = (N_Vector)(farg6); + result = (int)IDAInitBS(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAReInitB(void *farg1, int const *farg2, double const *farg3, N_Vector farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + result = (int)IDAReInitB(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASStolerancesB(void *farg1, int const *farg2, double const *farg3, double const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + realtype arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + arg4 = (realtype)(*farg4); + result = (int)IDASStolerancesB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASVtolerancesB(void *farg1, int const *farg2, double const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDASVtolerancesB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAQuadInitB(void *farg1, int const *farg2, IDAQuadRhsFnB farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + IDAQuadRhsFnB arg3 = (IDAQuadRhsFnB) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (IDAQuadRhsFnB)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAQuadInitB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAQuadInitBS(void *farg1, int const *farg2, IDAQuadRhsFnBS farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + IDAQuadRhsFnBS arg3 = (IDAQuadRhsFnBS) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (IDAQuadRhsFnBS)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAQuadInitBS(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAQuadReInitB(void *farg1, int const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDAQuadReInitB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAQuadSStolerancesB(void *farg1, int const *farg2, double const *farg3, double const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + realtype arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + arg4 = (realtype)(*farg4); + result = (int)IDAQuadSStolerancesB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAQuadSVtolerancesB(void *farg1, int const *farg2, double const *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAQuadSVtolerancesB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDACalcICB(void *farg1, int const *farg2, double const *farg3, N_Vector farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + result = (int)IDACalcICB(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDACalcICBS(void *farg1, int const *farg2, double const *farg3, N_Vector farg4, N_Vector farg5, void *farg6, void *farg7) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + N_Vector *arg6 = (N_Vector *) 0 ; + N_Vector *arg7 = (N_Vector *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + arg6 = (N_Vector *)(farg6); + arg7 = (N_Vector *)(farg7); + result = (int)IDACalcICBS(arg1,arg2,arg3,arg4,arg5,arg6,arg7); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASolveF(void *farg1, double const *farg2, double *farg3, N_Vector farg4, N_Vector farg5, int const *farg6, int *farg7) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype *arg3 = (realtype *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int arg6 ; + int *arg7 = (int *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + arg6 = (int)(*farg6); + arg7 = (int *)(farg7); + result = (int)IDASolveF(arg1,arg2,arg3,arg4,arg5,arg6,arg7); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASolveB(void *farg1, double const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + result = (int)IDASolveB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAAdjSetNoSensi(void *farg1) { + int fresult ; + void *arg1 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + result = (int)IDAAdjSetNoSensi(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetUserDataB(void *farg1, int const *farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (void *)(farg3); + result = (int)IDASetUserDataB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxOrdB(void *farg1, int const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (int)IDASetMaxOrdB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxNumStepsB(void *farg1, int const *farg2, long const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + long arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (long)(*farg3); + result = (int)IDASetMaxNumStepsB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetInitStepB(void *farg1, int const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)IDASetInitStepB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetMaxStepB(void *farg1, int const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)IDASetMaxStepB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetSuppressAlgB(void *farg1, int const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (int)IDASetSuppressAlgB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetIdB(void *farg1, int const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDASetIdB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetConstraintsB(void *farg1, int const *farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (N_Vector)(farg3); + result = (int)IDASetConstraintsB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetQuadErrConB(void *farg1, int const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (int)IDASetQuadErrConB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetNonlinearSolverB(void *farg1, int const *farg2, SUNNonlinearSolver farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + SUNNonlinearSolver arg3 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (SUNNonlinearSolver)(farg3); + result = (int)IDASetNonlinearSolverB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetB(void *farg1, int const *farg2, double *farg3, N_Vector farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype *arg3 = (realtype *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + result = (int)IDAGetB(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetQuadB(void *farg1, int const *farg2, double *farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype *arg3 = (realtype *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype *)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAGetQuadB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void * _wrap_FIDAGetAdjIDABmem(void *farg1, int const *farg2) { + void * fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + void *result = 0 ; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (void *)IDAGetAdjIDABmem(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetConsistentICB(void *farg1, int const *farg2, N_Vector farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAGetConsistentICB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetAdjY(void *farg1, double const *farg2, N_Vector farg3, N_Vector farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)IDAGetAdjY(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_IDAadjCheckPointRec_my_addr_set(SwigClassWrapper const *farg1, void *farg2) { + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + void *arg2 = (void *) 0 ; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::my_addr", return ); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + arg2 = (void *)(farg2); + if (arg1) (arg1)->my_addr = arg2; +} + + +SWIGEXPORT void * _wrap_IDAadjCheckPointRec_my_addr_get(SwigClassWrapper const *farg1) { + void * fresult ; + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + void *result = 0 ; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::my_addr", return 0); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + result = (void *) ((arg1)->my_addr); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_IDAadjCheckPointRec_next_addr_set(SwigClassWrapper const *farg1, void *farg2) { + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + void *arg2 = (void *) 0 ; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::next_addr", return ); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + arg2 = (void *)(farg2); + if (arg1) (arg1)->next_addr = arg2; +} + + +SWIGEXPORT void * _wrap_IDAadjCheckPointRec_next_addr_get(SwigClassWrapper const *farg1) { + void * fresult ; + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + void *result = 0 ; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::next_addr", return 0); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + result = (void *) ((arg1)->next_addr); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_IDAadjCheckPointRec_t0_set(SwigClassWrapper const *farg1, double const *farg2) { + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + realtype arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::t0", return ); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + arg2 = (realtype)(*farg2); + if (arg1) (arg1)->t0 = arg2; +} + + +SWIGEXPORT double _wrap_IDAadjCheckPointRec_t0_get(SwigClassWrapper const *farg1) { + double fresult ; + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + realtype result; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::t0", return 0); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + result = (realtype) ((arg1)->t0); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_IDAadjCheckPointRec_t1_set(SwigClassWrapper const *farg1, double const *farg2) { + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + realtype arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::t1", return ); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + arg2 = (realtype)(*farg2); + if (arg1) (arg1)->t1 = arg2; +} + + +SWIGEXPORT double _wrap_IDAadjCheckPointRec_t1_get(SwigClassWrapper const *farg1) { + double fresult ; + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + realtype result; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::t1", return 0); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + result = (realtype) ((arg1)->t1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_IDAadjCheckPointRec_nstep_set(SwigClassWrapper const *farg1, long const *farg2) { + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + long arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::nstep", return ); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + arg2 = (long)(*farg2); + if (arg1) (arg1)->nstep = arg2; +} + + +SWIGEXPORT long _wrap_IDAadjCheckPointRec_nstep_get(SwigClassWrapper const *farg1) { + long fresult ; + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + long result; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::nstep", return 0); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + result = (long) ((arg1)->nstep); + fresult = (long)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_IDAadjCheckPointRec_order_set(SwigClassWrapper const *farg1, int const *farg2) { + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + int arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::order", return ); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + arg2 = (int)(*farg2); + if (arg1) (arg1)->order = arg2; +} + + +SWIGEXPORT int _wrap_IDAadjCheckPointRec_order_get(SwigClassWrapper const *farg1) { + int fresult ; + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + int result; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::order", return 0); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + result = (int) ((arg1)->order); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_IDAadjCheckPointRec_step_set(SwigClassWrapper const *farg1, double const *farg2) { + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + realtype arg2 ; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::step", return ); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + arg2 = (realtype)(*farg2); + if (arg1) (arg1)->step = arg2; +} + + +SWIGEXPORT double _wrap_IDAadjCheckPointRec_step_get(SwigClassWrapper const *farg1) { + double fresult ; + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + realtype result; + + SWIG_check_mutable_nonnull(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::step", return 0); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + result = (realtype) ((arg1)->step); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT SwigClassWrapper _wrap_new_IDAadjCheckPointRec() { + SwigClassWrapper fresult ; + IDAadjCheckPointRec *result = 0 ; + + result = (IDAadjCheckPointRec *)calloc(1, sizeof(IDAadjCheckPointRec)); + fresult.cptr = result; + fresult.cmemflags = SWIG_MEM_RVALUE | (1 ? SWIG_MEM_OWN : 0); + return fresult; +} + + +SWIGEXPORT void _wrap_delete_IDAadjCheckPointRec(SwigClassWrapper *farg1) { + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + + SWIG_check_mutable(*farg1, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAadjCheckPointRec::~IDAadjCheckPointRec()", return ); + arg1 = (IDAadjCheckPointRec *)(farg1->cptr); + free((char *) arg1); +} + + +SWIGEXPORT void _wrap_IDAadjCheckPointRec_op_assign__(SwigClassWrapper *farg1, SwigClassWrapper const *farg2) { + IDAadjCheckPointRec *arg1 = (IDAadjCheckPointRec *) 0 ; + IDAadjCheckPointRec *arg2 = 0 ; + + (void)sizeof(arg1); + (void)sizeof(arg2); + SWIG_assign(farg1, *farg2); + +} + + +SWIGEXPORT int _wrap_FIDAGetAdjCheckPointsInfo(void *farg1, SwigClassWrapper const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + IDAadjCheckPointRec *arg2 = (IDAadjCheckPointRec *) 0 ; + int result; + + arg1 = (void *)(farg1); + SWIG_check_mutable(*farg2, "IDAadjCheckPointRec *", "IDAadjCheckPointRec", "IDAGetAdjCheckPointsInfo(void *,IDAadjCheckPointRec *)", return 0); + arg2 = (IDAadjCheckPointRec *)(farg2->cptr); + result = (int)IDAGetAdjCheckPointsInfo(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetAdjDataPointHermite(void *farg1, int const *farg2, double *farg3, N_Vector farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype *arg3 = (realtype *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + result = (int)IDAGetAdjDataPointHermite(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetAdjDataPointPolynomial(void *farg1, int const *farg2, double *farg3, int *farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype *arg3 = (realtype *) 0 ; + int *arg4 = (int *) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype *)(farg3); + arg4 = (int *)(farg4); + arg5 = (N_Vector)(farg5); + result = (int)IDAGetAdjDataPointPolynomial(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetAdjCurrentCheckPoint(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + void **arg2 = (void **) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (void **)(farg2); + result = (int)IDAGetAdjCurrentCheckPoint(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDABBDPrecInit(void *farg1, int64_t const *farg2, int64_t const *farg3, int64_t const *farg4, int64_t const *farg5, int64_t const *farg6, double const *farg7, IDABBDLocalFn farg8, IDABBDCommFn farg9) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + sunindextype arg5 ; + sunindextype arg6 ; + realtype arg7 ; + IDABBDLocalFn arg8 = (IDABBDLocalFn) 0 ; + IDABBDCommFn arg9 = (IDABBDCommFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + arg5 = (sunindextype)(*farg5); + arg6 = (sunindextype)(*farg6); + arg7 = (realtype)(*farg7); + arg8 = (IDABBDLocalFn)(farg8); + arg9 = (IDABBDCommFn)(farg9); + result = (int)IDABBDPrecInit(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDABBDPrecReInit(void *farg1, int64_t const *farg2, int64_t const *farg3, double const *farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + realtype arg4 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (realtype)(*farg4); + result = (int)IDABBDPrecReInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDABBDPrecGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)IDABBDPrecGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDABBDPrecGetNumGfnEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDABBDPrecGetNumGfnEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDABBDPrecInitB(void *farg1, int const *farg2, int64_t const *farg3, int64_t const *farg4, int64_t const *farg5, int64_t const *farg6, int64_t const *farg7, double const *farg8, IDABBDLocalFnB farg9, IDABBDCommFnB farg10) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + sunindextype arg5 ; + sunindextype arg6 ; + sunindextype arg7 ; + realtype arg8 ; + IDABBDLocalFnB arg9 = (IDABBDLocalFnB) 0 ; + IDABBDCommFnB arg10 = (IDABBDCommFnB) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + arg5 = (sunindextype)(*farg5); + arg6 = (sunindextype)(*farg6); + arg7 = (sunindextype)(*farg7); + arg8 = (realtype)(*farg8); + arg9 = (IDABBDLocalFnB)(farg9); + arg10 = (IDABBDCommFnB)(farg10); + result = (int)IDABBDPrecInitB(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDABBDPrecReInitB(void *farg1, int const *farg2, int64_t const *farg3, int64_t const *farg4, double const *farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + realtype arg5 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + arg5 = (realtype)(*farg5); + result = (int)IDABBDPrecReInitB(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetLinearSolver(void *farg1, SUNLinearSolver farg2, SUNMatrix farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNLinearSolver arg2 = (SUNLinearSolver) 0 ; + SUNMatrix arg3 = (SUNMatrix) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNLinearSolver)(farg2); + arg3 = (SUNMatrix)(farg3); + result = (int)IDASetLinearSolver(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetJacFn(void *farg1, IDALsJacFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + IDALsJacFn arg2 = (IDALsJacFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDALsJacFn)(farg2); + result = (int)IDASetJacFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetPreconditioner(void *farg1, IDALsPrecSetupFn farg2, IDALsPrecSolveFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + IDALsPrecSetupFn arg2 = (IDALsPrecSetupFn) 0 ; + IDALsPrecSolveFn arg3 = (IDALsPrecSolveFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDALsPrecSetupFn)(farg2); + arg3 = (IDALsPrecSolveFn)(farg3); + result = (int)IDASetPreconditioner(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetJacTimes(void *farg1, IDALsJacTimesSetupFn farg2, IDALsJacTimesVecFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + IDALsJacTimesSetupFn arg2 = (IDALsJacTimesSetupFn) 0 ; + IDALsJacTimesVecFn arg3 = (IDALsJacTimesVecFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (IDALsJacTimesSetupFn)(farg2); + arg3 = (IDALsJacTimesVecFn)(farg3); + result = (int)IDASetJacTimes(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetEpsLin(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetEpsLin(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetLinearSolutionScaling(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)IDASetLinearSolutionScaling(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetIncrementFactor(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)IDASetIncrementFactor(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetLinWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)IDAGetLinWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumJacEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumJacEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumPrecEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumPrecEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumPrecSolves(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumPrecSolves(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumLinIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumLinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumLinConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumLinConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumJTSetupEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumJTSetupEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumJtimesEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumJtimesEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetNumLinResEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetNumLinResEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDAGetLastLinFlag(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)IDAGetLastLinFlag(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FIDAGetLinReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)IDAGetLinReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetLinearSolverB(void *farg1, int const *farg2, SUNLinearSolver farg3, SUNMatrix farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + SUNLinearSolver arg3 = (SUNLinearSolver) 0 ; + SUNMatrix arg4 = (SUNMatrix) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (SUNLinearSolver)(farg3); + arg4 = (SUNMatrix)(farg4); + result = (int)IDASetLinearSolverB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetJacFnB(void *farg1, int const *farg2, IDALsJacFnB farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + IDALsJacFnB arg3 = (IDALsJacFnB) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (IDALsJacFnB)(farg3); + result = (int)IDASetJacFnB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetJacFnBS(void *farg1, int const *farg2, IDALsJacFnBS farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + IDALsJacFnBS arg3 = (IDALsJacFnBS) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (IDALsJacFnBS)(farg3); + result = (int)IDASetJacFnBS(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetEpsLinB(void *farg1, int const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)IDASetEpsLinB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetLinearSolutionScalingB(void *farg1, int const *farg2, int const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (int)IDASetLinearSolutionScalingB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetIncrementFactorB(void *farg1, int const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)IDASetIncrementFactorB(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetPreconditionerB(void *farg1, int const *farg2, IDALsPrecSetupFnB farg3, IDALsPrecSolveFnB farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + IDALsPrecSetupFnB arg3 = (IDALsPrecSetupFnB) 0 ; + IDALsPrecSolveFnB arg4 = (IDALsPrecSolveFnB) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (IDALsPrecSetupFnB)(farg3); + arg4 = (IDALsPrecSolveFnB)(farg4); + result = (int)IDASetPreconditionerB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetPreconditionerBS(void *farg1, int const *farg2, IDALsPrecSetupFnBS farg3, IDALsPrecSolveFnBS farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + IDALsPrecSetupFnBS arg3 = (IDALsPrecSetupFnBS) 0 ; + IDALsPrecSolveFnBS arg4 = (IDALsPrecSolveFnBS) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (IDALsPrecSetupFnBS)(farg3); + arg4 = (IDALsPrecSolveFnBS)(farg4); + result = (int)IDASetPreconditionerBS(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetJacTimesB(void *farg1, int const *farg2, IDALsJacTimesSetupFnB farg3, IDALsJacTimesVecFnB farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + IDALsJacTimesSetupFnB arg3 = (IDALsJacTimesSetupFnB) 0 ; + IDALsJacTimesVecFnB arg4 = (IDALsJacTimesVecFnB) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (IDALsJacTimesSetupFnB)(farg3); + arg4 = (IDALsJacTimesVecFnB)(farg4); + result = (int)IDASetJacTimesB(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FIDASetJacTimesBS(void *farg1, int const *farg2, IDALsJacTimesSetupFnBS farg3, IDALsJacTimesVecFnBS farg4) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + IDALsJacTimesSetupFnBS arg3 = (IDALsJacTimesSetupFnBS) 0 ; + IDALsJacTimesVecFnBS arg4 = (IDALsJacTimesVecFnBS) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + arg3 = (IDALsJacTimesSetupFnBS)(farg3); + arg4 = (IDALsJacTimesVecFnBS)(farg4); + result = (int)IDASetJacTimesBS(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/fmod/fidas_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/idas/fmod/fidas_mod.f90 new file mode 100644 index 000000000..4a8da2137 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/idas/fmod/fidas_mod.f90 @@ -0,0 +1,6204 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fidas_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_linearsolver_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_nonlinearsolver_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: IDA_NORMAL = 1_C_INT + integer(C_INT), parameter, public :: IDA_ONE_STEP = 2_C_INT + integer(C_INT), parameter, public :: IDA_YA_YDP_INIT = 1_C_INT + integer(C_INT), parameter, public :: IDA_Y_INIT = 2_C_INT + integer(C_INT), parameter, public :: IDA_SIMULTANEOUS = 1_C_INT + integer(C_INT), parameter, public :: IDA_STAGGERED = 2_C_INT + integer(C_INT), parameter, public :: IDA_CENTERED = 1_C_INT + integer(C_INT), parameter, public :: IDA_FORWARD = 2_C_INT + integer(C_INT), parameter, public :: IDA_HERMITE = 1_C_INT + integer(C_INT), parameter, public :: IDA_POLYNOMIAL = 2_C_INT + integer(C_INT), parameter, public :: IDA_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: IDA_TSTOP_RETURN = 1_C_INT + integer(C_INT), parameter, public :: IDA_ROOT_RETURN = 2_C_INT + integer(C_INT), parameter, public :: IDA_WARNING = 99_C_INT + integer(C_INT), parameter, public :: IDA_TOO_MUCH_WORK = -1_C_INT + integer(C_INT), parameter, public :: IDA_TOO_MUCH_ACC = -2_C_INT + integer(C_INT), parameter, public :: IDA_ERR_FAIL = -3_C_INT + integer(C_INT), parameter, public :: IDA_CONV_FAIL = -4_C_INT + integer(C_INT), parameter, public :: IDA_LINIT_FAIL = -5_C_INT + integer(C_INT), parameter, public :: IDA_LSETUP_FAIL = -6_C_INT + integer(C_INT), parameter, public :: IDA_LSOLVE_FAIL = -7_C_INT + integer(C_INT), parameter, public :: IDA_RES_FAIL = -8_C_INT + integer(C_INT), parameter, public :: IDA_REP_RES_ERR = -9_C_INT + integer(C_INT), parameter, public :: IDA_RTFUNC_FAIL = -10_C_INT + integer(C_INT), parameter, public :: IDA_CONSTR_FAIL = -11_C_INT + integer(C_INT), parameter, public :: IDA_FIRST_RES_FAIL = -12_C_INT + integer(C_INT), parameter, public :: IDA_LINESEARCH_FAIL = -13_C_INT + integer(C_INT), parameter, public :: IDA_NO_RECOVERY = -14_C_INT + integer(C_INT), parameter, public :: IDA_NLS_INIT_FAIL = -15_C_INT + integer(C_INT), parameter, public :: IDA_NLS_SETUP_FAIL = -16_C_INT + integer(C_INT), parameter, public :: IDA_NLS_FAIL = -17_C_INT + integer(C_INT), parameter, public :: IDA_MEM_NULL = -20_C_INT + integer(C_INT), parameter, public :: IDA_MEM_FAIL = -21_C_INT + integer(C_INT), parameter, public :: IDA_ILL_INPUT = -22_C_INT + integer(C_INT), parameter, public :: IDA_NO_MALLOC = -23_C_INT + integer(C_INT), parameter, public :: IDA_BAD_EWT = -24_C_INT + integer(C_INT), parameter, public :: IDA_BAD_K = -25_C_INT + integer(C_INT), parameter, public :: IDA_BAD_T = -26_C_INT + integer(C_INT), parameter, public :: IDA_BAD_DKY = -27_C_INT + integer(C_INT), parameter, public :: IDA_VECTOROP_ERR = -28_C_INT + integer(C_INT), parameter, public :: IDA_NO_QUAD = -30_C_INT + integer(C_INT), parameter, public :: IDA_QRHS_FAIL = -31_C_INT + integer(C_INT), parameter, public :: IDA_FIRST_QRHS_ERR = -32_C_INT + integer(C_INT), parameter, public :: IDA_REP_QRHS_ERR = -33_C_INT + integer(C_INT), parameter, public :: IDA_NO_SENS = -40_C_INT + integer(C_INT), parameter, public :: IDA_SRES_FAIL = -41_C_INT + integer(C_INT), parameter, public :: IDA_REP_SRES_ERR = -42_C_INT + integer(C_INT), parameter, public :: IDA_BAD_IS = -43_C_INT + integer(C_INT), parameter, public :: IDA_NO_QUADSENS = -50_C_INT + integer(C_INT), parameter, public :: IDA_QSRHS_FAIL = -51_C_INT + integer(C_INT), parameter, public :: IDA_FIRST_QSRHS_ERR = -52_C_INT + integer(C_INT), parameter, public :: IDA_REP_QSRHS_ERR = -53_C_INT + integer(C_INT), parameter, public :: IDA_UNRECOGNIZED_ERROR = -99_C_INT + integer(C_INT), parameter, public :: IDA_NO_ADJ = -101_C_INT + integer(C_INT), parameter, public :: IDA_NO_FWD = -102_C_INT + integer(C_INT), parameter, public :: IDA_NO_BCK = -103_C_INT + integer(C_INT), parameter, public :: IDA_BAD_TB0 = -104_C_INT + integer(C_INT), parameter, public :: IDA_REIFWD_FAIL = -105_C_INT + integer(C_INT), parameter, public :: IDA_FWD_FAIL = -106_C_INT + integer(C_INT), parameter, public :: IDA_GETY_BADT = -107_C_INT + public :: FIDACreate + public :: FIDAInit + public :: FIDAReInit + public :: FIDASStolerances + public :: FIDASVtolerances + public :: FIDAWFtolerances + public :: FIDACalcIC + public :: FIDASetNonlinConvCoefIC + public :: FIDASetMaxNumStepsIC + public :: FIDASetMaxNumJacsIC + public :: FIDASetMaxNumItersIC + public :: FIDASetLineSearchOffIC + public :: FIDASetStepToleranceIC + public :: FIDASetMaxBacksIC + public :: FIDASetErrHandlerFn + public :: FIDASetErrFile + public :: FIDASetUserData + public :: FIDASetMaxOrd + public :: FIDASetMaxNumSteps + public :: FIDASetInitStep + public :: FIDASetMaxStep + public :: FIDASetStopTime + public :: FIDASetNonlinConvCoef + public :: FIDASetMaxErrTestFails + public :: FIDASetMaxNonlinIters + public :: FIDASetMaxConvFails + public :: FIDASetSuppressAlg + public :: FIDASetId + public :: FIDASetConstraints + public :: FIDASetNonlinearSolver + public :: FIDARootInit + public :: FIDASetRootDirection + public :: FIDASetNoInactiveRootWarn + public :: FIDASolve + public :: FIDAComputeY + public :: FIDAComputeYp + public :: FIDAComputeYSens + public :: FIDAComputeYpSens + public :: FIDAGetDky + public :: FIDAGetWorkSpace + public :: FIDAGetNumSteps + public :: FIDAGetNumResEvals + public :: FIDAGetNumLinSolvSetups + public :: FIDAGetNumErrTestFails + public :: FIDAGetNumBacktrackOps + public :: FIDAGetConsistentIC + public :: FIDAGetLastOrder + public :: FIDAGetCurrentOrder + public :: FIDAGetCurrentCj + public :: FIDAGetCurrentY + public :: FIDAGetCurrentYSens + public :: FIDAGetCurrentYp + public :: FIDAGetCurrentYpSens + public :: FIDAGetActualInitStep + public :: FIDAGetLastStep + public :: FIDAGetCurrentStep + public :: FIDAGetCurrentTime + public :: FIDAGetTolScaleFactor + public :: FIDAGetErrWeights + public :: FIDAGetEstLocalErrors + public :: FIDAGetNumGEvals + public :: FIDAGetRootInfo + public :: FIDAGetIntegratorStats + public :: FIDAGetNumNonlinSolvIters + public :: FIDAGetNumNonlinSolvConvFails + public :: FIDAGetNonlinSolvStats + type, bind(C) :: SwigArrayWrapper + type(C_PTR), public :: data = C_NULL_PTR + integer(C_SIZE_T), public :: size = 0 + end type + public :: FIDAGetReturnFlagName + public :: FIDAFree + public :: FIDAQuadInit + public :: FIDAQuadReInit + public :: FIDAQuadSStolerances + public :: FIDAQuadSVtolerances + public :: FIDASetQuadErrCon + public :: FIDAGetQuad + public :: FIDAGetQuadDky + public :: FIDAGetQuadNumRhsEvals + public :: FIDAGetQuadNumErrTestFails + public :: FIDAGetQuadErrWeights + public :: FIDAGetQuadStats + public :: FIDAQuadFree + public :: FIDASensInit + public :: FIDASensReInit + public :: FIDASensSStolerances + public :: FIDASensSVtolerances + public :: FIDASensEEtolerances + public :: FIDAGetSensConsistentIC + public :: FIDASetSensDQMethod + public :: FIDASetSensErrCon + public :: FIDASetSensMaxNonlinIters + public :: FIDASetSensParams + public :: FIDASetNonlinearSolverSensSim + public :: FIDASetNonlinearSolverSensStg + public :: FIDASensToggleOff + public :: FIDAGetSens + public :: FIDAGetSens1 + public :: FIDAGetSensDky + public :: FIDAGetSensDky1 + public :: FIDAGetSensNumResEvals + public :: FIDAGetNumResEvalsSens + public :: FIDAGetSensNumErrTestFails + public :: FIDAGetSensNumLinSolvSetups + public :: FIDAGetSensErrWeights + public :: FIDAGetSensStats + public :: FIDAGetSensNumNonlinSolvIters + public :: FIDAGetSensNumNonlinSolvConvFails + public :: FIDAGetSensNonlinSolvStats + public :: FIDASensFree + public :: FIDAQuadSensInit + public :: FIDAQuadSensReInit + public :: FIDAQuadSensSStolerances + public :: FIDAQuadSensSVtolerances + public :: FIDAQuadSensEEtolerances + public :: FIDASetQuadSensErrCon + public :: FIDAGetQuadSens + public :: FIDAGetQuadSens1 + public :: FIDAGetQuadSensDky + public :: FIDAGetQuadSensDky1 + public :: FIDAGetQuadSensNumRhsEvals + public :: FIDAGetQuadSensNumErrTestFails + public :: FIDAGetQuadSensErrWeights + public :: FIDAGetQuadSensStats + public :: FIDAQuadSensFree + public :: FIDAAdjInit + public :: FIDAAdjReInit + public :: FIDAAdjFree + public :: FIDACreateB + public :: FIDAInitB + public :: FIDAInitBS + public :: FIDAReInitB + public :: FIDASStolerancesB + public :: FIDASVtolerancesB + public :: FIDAQuadInitB + public :: FIDAQuadInitBS + public :: FIDAQuadReInitB + public :: FIDAQuadSStolerancesB + public :: FIDAQuadSVtolerancesB + public :: FIDACalcICB + public :: FIDACalcICBS + public :: FIDASolveF + public :: FIDASolveB + public :: FIDAAdjSetNoSensi + public :: FIDASetUserDataB + public :: FIDASetMaxOrdB + public :: FIDASetMaxNumStepsB + public :: FIDASetInitStepB + public :: FIDASetMaxStepB + public :: FIDASetSuppressAlgB + public :: FIDASetIdB + public :: FIDASetConstraintsB + public :: FIDASetQuadErrConB + public :: FIDASetNonlinearSolverB + public :: FIDAGetB + public :: FIDAGetQuadB + public :: FIDAGetAdjIDABmem + public :: FIDAGetConsistentICB + public :: FIDAGetAdjY + + integer, parameter :: swig_cmem_own_bit = 0 + integer, parameter :: swig_cmem_rvalue_bit = 1 + integer, parameter :: swig_cmem_const_bit = 2 + type, bind(C) :: SwigClassWrapper + type(C_PTR), public :: cptr = C_NULL_PTR + integer(C_INT), public :: cmemflags = 0 + end type + ! struct IDAadjCheckPointRec + type, public :: IDAadjCheckPointRec + type(SwigClassWrapper), public :: swigdata + contains + procedure :: set_my_addr => swigf_IDAadjCheckPointRec_my_addr_set + procedure :: get_my_addr => swigf_IDAadjCheckPointRec_my_addr_get + procedure :: set_next_addr => swigf_IDAadjCheckPointRec_next_addr_set + procedure :: get_next_addr => swigf_IDAadjCheckPointRec_next_addr_get + procedure :: set_t0 => swigf_IDAadjCheckPointRec_t0_set + procedure :: get_t0 => swigf_IDAadjCheckPointRec_t0_get + procedure :: set_t1 => swigf_IDAadjCheckPointRec_t1_set + procedure :: get_t1 => swigf_IDAadjCheckPointRec_t1_get + procedure :: set_nstep => swigf_IDAadjCheckPointRec_nstep_set + procedure :: get_nstep => swigf_IDAadjCheckPointRec_nstep_get + procedure :: set_order => swigf_IDAadjCheckPointRec_order_set + procedure :: get_order => swigf_IDAadjCheckPointRec_order_get + procedure :: set_step => swigf_IDAadjCheckPointRec_step_set + procedure :: get_step => swigf_IDAadjCheckPointRec_step_get + procedure :: release => swigf_release_IDAadjCheckPointRec + procedure, private :: swigf_IDAadjCheckPointRec_op_assign__ + generic :: assignment(=) => swigf_IDAadjCheckPointRec_op_assign__ + end type IDAadjCheckPointRec + interface IDAadjCheckPointRec + module procedure swigf_create_IDAadjCheckPointRec + end interface + public :: FIDAGetAdjCheckPointsInfo + public :: FIDAGetAdjDataPointHermite + public :: FIDAGetAdjDataPointPolynomial + public :: FIDAGetAdjCurrentCheckPoint + public :: FIDABBDPrecInit + public :: FIDABBDPrecReInit + public :: FIDABBDPrecGetWorkSpace + public :: FIDABBDPrecGetNumGfnEvals + public :: FIDABBDPrecInitB + public :: FIDABBDPrecReInitB + integer(C_INT), parameter, public :: IDALS_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: IDALS_MEM_NULL = -1_C_INT + integer(C_INT), parameter, public :: IDALS_LMEM_NULL = -2_C_INT + integer(C_INT), parameter, public :: IDALS_ILL_INPUT = -3_C_INT + integer(C_INT), parameter, public :: IDALS_MEM_FAIL = -4_C_INT + integer(C_INT), parameter, public :: IDALS_PMEM_NULL = -5_C_INT + integer(C_INT), parameter, public :: IDALS_JACFUNC_UNRECVR = -6_C_INT + integer(C_INT), parameter, public :: IDALS_JACFUNC_RECVR = -7_C_INT + integer(C_INT), parameter, public :: IDALS_SUNMAT_FAIL = -8_C_INT + integer(C_INT), parameter, public :: IDALS_SUNLS_FAIL = -9_C_INT + integer(C_INT), parameter, public :: IDALS_NO_ADJ = -101_C_INT + integer(C_INT), parameter, public :: IDALS_LMEMB_NULL = -102_C_INT + public :: FIDASetLinearSolver + public :: FIDASetJacFn + public :: FIDASetPreconditioner + public :: FIDASetJacTimes + public :: FIDASetEpsLin + public :: FIDASetLinearSolutionScaling + public :: FIDASetIncrementFactor + public :: FIDAGetLinWorkSpace + public :: FIDAGetNumJacEvals + public :: FIDAGetNumPrecEvals + public :: FIDAGetNumPrecSolves + public :: FIDAGetNumLinIters + public :: FIDAGetNumLinConvFails + public :: FIDAGetNumJTSetupEvals + public :: FIDAGetNumJtimesEvals + public :: FIDAGetNumLinResEvals + public :: FIDAGetLastLinFlag + public :: FIDAGetLinReturnFlagName + public :: FIDASetLinearSolverB + public :: FIDASetJacFnB + public :: FIDASetJacFnBS + public :: FIDASetEpsLinB + public :: FIDASetLinearSolutionScalingB + public :: FIDASetIncrementFactorB + public :: FIDASetPreconditionerB + public :: FIDASetPreconditionerBS + public :: FIDASetJacTimesB + public :: FIDASetJacTimesBS + +! WRAPPER DECLARATIONS +interface +function swigc_FIDACreate() & +bind(C, name="_wrap_FIDACreate") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: fresult +end function + +function swigc_FIDAInit(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FIDAInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FIDAReInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDASStolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASStolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASVtolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASVtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAWFtolerances(farg1, farg2) & +bind(C, name="_wrap_FIDAWFtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDACalcIC(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDACalcIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetNonlinConvCoefIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetNonlinConvCoefIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxNumStepsIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxNumStepsIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxNumJacsIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxNumJacsIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxNumItersIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxNumItersIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetLineSearchOffIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetLineSearchOffIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetStepToleranceIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetStepToleranceIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxBacksIC(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxBacksIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetErrHandlerFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetErrHandlerFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetErrFile(farg1, farg2) & +bind(C, name="_wrap_FIDASetErrFile") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetUserData(farg1, farg2) & +bind(C, name="_wrap_FIDASetUserData") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxOrd(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxOrd") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxNumSteps(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetInitStep(farg1, farg2) & +bind(C, name="_wrap_FIDASetInitStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxStep(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetStopTime(farg1, farg2) & +bind(C, name="_wrap_FIDASetStopTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetNonlinConvCoef(farg1, farg2) & +bind(C, name="_wrap_FIDASetNonlinConvCoef") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxNonlinIters(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxNonlinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxConvFails(farg1, farg2) & +bind(C, name="_wrap_FIDASetMaxConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetSuppressAlg(farg1, farg2) & +bind(C, name="_wrap_FIDASetSuppressAlg") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetId(farg1, farg2) & +bind(C, name="_wrap_FIDASetId") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetConstraints(farg1, farg2) & +bind(C, name="_wrap_FIDASetConstraints") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetNonlinearSolver(farg1, farg2) & +bind(C, name="_wrap_FIDASetNonlinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDARootInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDARootInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetRootDirection(farg1, farg2) & +bind(C, name="_wrap_FIDASetRootDirection") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetNoInactiveRootWarn(farg1) & +bind(C, name="_wrap_FIDASetNoInactiveRootWarn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FIDASolve(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FIDASolve") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT), intent(in) :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FIDAComputeY(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAComputeY") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAComputeYp(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAComputeYp") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAComputeYSens(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAComputeYSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAComputeYpSens(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAComputeYpSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAGetDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumSteps(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumSteps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumResEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumResEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumLinSolvSetups(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumLinSolvSetups") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumBacktrackOps(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumBacktrackOps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetConsistentIC(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetConsistentIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetLastOrder(farg1, farg2) & +bind(C, name="_wrap_FIDAGetLastOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentOrder(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentOrder") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentCj(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentCj") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentY(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentY") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentYSens(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentYSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentYp(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentYp") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentYpSens(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentYpSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetActualInitStep(farg1, farg2) & +bind(C, name="_wrap_FIDAGetActualInitStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetLastStep(farg1, farg2) & +bind(C, name="_wrap_FIDAGetLastStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentStep(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetCurrentTime(farg1, farg2) & +bind(C, name="_wrap_FIDAGetCurrentTime") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetTolScaleFactor(farg1, farg2) & +bind(C, name="_wrap_FIDAGetTolScaleFactor") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetErrWeights(farg1, farg2) & +bind(C, name="_wrap_FIDAGetErrWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetEstLocalErrors(farg1, farg2) & +bind(C, name="_wrap_FIDAGetEstLocalErrors") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumGEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumGEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetRootInfo(farg1, farg2) & +bind(C, name="_wrap_FIDAGetRootInfo") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetIntegratorStats(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10, farg11) & +bind(C, name="_wrap_FIDAGetIntegratorStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +type(C_PTR), value :: farg7 +type(C_PTR), value :: farg8 +type(C_PTR), value :: farg9 +type(C_PTR), value :: farg10 +type(C_PTR), value :: farg11 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumNonlinSolvIters(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumNonlinSolvIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumNonlinSolvConvFails(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumNonlinSolvConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNonlinSolvStats(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetNonlinSolvStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + + subroutine SWIG_free(cptr) & + bind(C, name="free") + use, intrinsic :: ISO_C_BINDING + type(C_PTR), value :: cptr +end subroutine +function swigc_FIDAGetReturnFlagName(farg1) & +bind(C, name="_wrap_FIDAGetReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +subroutine swigc_FIDAFree(farg1) & +bind(C, name="_wrap_FIDAFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FIDAQuadInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAQuadInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAQuadReInit(farg1, farg2) & +bind(C, name="_wrap_FIDAQuadReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAQuadSStolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAQuadSStolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAQuadSVtolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAQuadSVtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetQuadErrCon(farg1, farg2) & +bind(C, name="_wrap_FIDASetQuadErrCon") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuad(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetQuad") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAGetQuadDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetQuadNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadNumErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FIDAGetQuadNumErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadErrWeights(farg1, farg2) & +bind(C, name="_wrap_FIDAGetQuadErrWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadStats(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetQuadStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +subroutine swigc_FIDAQuadFree(farg1) & +bind(C, name="_wrap_FIDAQuadFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FIDASensInit(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FIDASensInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_FUNPTR), value :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FIDASensReInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDASensReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDASensSStolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASensSStolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASensSVtolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASensSVtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASensEEtolerances(farg1) & +bind(C, name="_wrap_FIDASensEEtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSensConsistentIC(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetSensConsistentIC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetSensDQMethod(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetSensDQMethod") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetSensErrCon(farg1, farg2) & +bind(C, name="_wrap_FIDASetSensErrCon") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetSensMaxNonlinIters(farg1, farg2) & +bind(C, name="_wrap_FIDASetSensMaxNonlinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetSensParams(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDASetSensParams") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetNonlinearSolverSensSim(farg1, farg2) & +bind(C, name="_wrap_FIDASetNonlinearSolverSensSim") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetNonlinearSolverSensStg(farg1, farg2) & +bind(C, name="_wrap_FIDASetNonlinearSolverSensStg") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASensToggleOff(farg1) & +bind(C, name="_wrap_FIDASensToggleOff") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSens(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSens1(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAGetSens1") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSensDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAGetSensDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSensDky1(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FIDAGetSensDky1") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT), intent(in) :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSensNumResEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetSensNumResEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumResEvalsSens(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumResEvalsSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSensNumErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FIDAGetSensNumErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSensNumLinSolvSetups(farg1, farg2) & +bind(C, name="_wrap_FIDAGetSensNumLinSolvSetups") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSensErrWeights(farg1, farg2) & +bind(C, name="_wrap_FIDAGetSensErrWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSensStats(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FIDAGetSensStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSensNumNonlinSolvIters(farg1, farg2) & +bind(C, name="_wrap_FIDAGetSensNumNonlinSolvIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSensNumNonlinSolvConvFails(farg1, farg2) & +bind(C, name="_wrap_FIDAGetSensNumNonlinSolvConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetSensNonlinSolvStats(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetSensNonlinSolvStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +subroutine swigc_FIDASensFree(farg1) & +bind(C, name="_wrap_FIDASensFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FIDAQuadSensInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAQuadSensInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAQuadSensReInit(farg1, farg2) & +bind(C, name="_wrap_FIDAQuadSensReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAQuadSensSStolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAQuadSensSStolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAQuadSensSVtolerances(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAQuadSensSVtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAQuadSensEEtolerances(farg1) & +bind(C, name="_wrap_FIDAQuadSensEEtolerances") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetQuadSensErrCon(farg1, farg2) & +bind(C, name="_wrap_FIDASetQuadSensErrCon") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadSens(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetQuadSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadSens1(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAGetQuadSens1") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadSensDky(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAGetQuadSensDky") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadSensDky1(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FIDAGetQuadSensDky1") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT), intent(in) :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadSensNumRhsEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetQuadSensNumRhsEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadSensNumErrTestFails(farg1, farg2) & +bind(C, name="_wrap_FIDAGetQuadSensNumErrTestFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadSensErrWeights(farg1, farg2) & +bind(C, name="_wrap_FIDAGetQuadSensErrWeights") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadSensStats(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetQuadSensStats") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +subroutine swigc_FIDAQuadSensFree(farg1) & +bind(C, name="_wrap_FIDAQuadSensFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FIDAAdjInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAAdjInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAAdjReInit(farg1) & +bind(C, name="_wrap_FIDAAdjReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +subroutine swigc_FIDAAdjFree(farg1) & +bind(C, name="_wrap_FIDAAdjFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FIDACreateB(farg1, farg2) & +bind(C, name="_wrap_FIDACreateB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAInitB(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FIDAInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FIDAInitBS(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FIDAInitBS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FIDAReInitB(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FIDAReInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FIDASStolerancesB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDASStolerancesB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDASVtolerancesB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDASVtolerancesB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAQuadInitB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAQuadInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAQuadInitBS(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAQuadInitBS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAQuadReInitB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAQuadReInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAQuadSStolerancesB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAQuadSStolerancesB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAQuadSVtolerancesB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAQuadSVtolerancesB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDACalcICB(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FIDACalcICB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FIDACalcICBS(farg1, farg2, farg3, farg4, farg5, farg6, farg7) & +bind(C, name="_wrap_FIDACalcICBS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +type(C_PTR), value :: farg7 +integer(C_INT) :: fresult +end function + +function swigc_FIDASolveF(farg1, farg2, farg3, farg4, farg5, farg6, farg7) & +bind(C, name="_wrap_FIDASolveF") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT), intent(in) :: farg6 +type(C_PTR), value :: farg7 +integer(C_INT) :: fresult +end function + +function swigc_FIDASolveB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASolveB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAAdjSetNoSensi(farg1) & +bind(C, name="_wrap_FIDAAdjSetNoSensi") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetUserDataB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetUserDataB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxOrdB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetMaxOrdB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxNumStepsB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetMaxNumStepsB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_LONG), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetInitStepB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetInitStepB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetMaxStepB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetMaxStepB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetSuppressAlgB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetSuppressAlgB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetIdB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetIdB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetConstraintsB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetConstraintsB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetQuadErrConB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetQuadErrConB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetNonlinearSolverB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetNonlinearSolverB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetB(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FIDAGetB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetQuadB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAGetQuadB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetAdjIDABmem(farg1, farg2) & +bind(C, name="_wrap_FIDAGetAdjIDABmem") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FIDAGetConsistentICB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAGetConsistentICB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetAdjY(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDAGetAdjY") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +subroutine swigc_IDAadjCheckPointRec_my_addr_set(farg1, farg2) & +bind(C, name="_wrap_IDAadjCheckPointRec_my_addr_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_IDAadjCheckPointRec_my_addr_get(farg1) & +bind(C, name="_wrap_IDAadjCheckPointRec_my_addr_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_IDAadjCheckPointRec_next_addr_set(farg1, farg2) & +bind(C, name="_wrap_IDAadjCheckPointRec_next_addr_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_IDAadjCheckPointRec_next_addr_get(farg1) & +bind(C, name="_wrap_IDAadjCheckPointRec_next_addr_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_IDAadjCheckPointRec_t0_set(farg1, farg2) & +bind(C, name="_wrap_IDAadjCheckPointRec_t0_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +end subroutine + +function swigc_IDAadjCheckPointRec_t0_get(farg1) & +bind(C, name="_wrap_IDAadjCheckPointRec_t0_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE) :: fresult +end function + +subroutine swigc_IDAadjCheckPointRec_t1_set(farg1, farg2) & +bind(C, name="_wrap_IDAadjCheckPointRec_t1_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +end subroutine + +function swigc_IDAadjCheckPointRec_t1_get(farg1) & +bind(C, name="_wrap_IDAadjCheckPointRec_t1_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE) :: fresult +end function + +subroutine swigc_IDAadjCheckPointRec_nstep_set(farg1, farg2) & +bind(C, name="_wrap_IDAadjCheckPointRec_nstep_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_LONG), intent(in) :: farg2 +end subroutine + +function swigc_IDAadjCheckPointRec_nstep_get(farg1) & +bind(C, name="_wrap_IDAadjCheckPointRec_nstep_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_LONG) :: fresult +end function + +subroutine swigc_IDAadjCheckPointRec_order_set(farg1, farg2) & +bind(C, name="_wrap_IDAadjCheckPointRec_order_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_INT), intent(in) :: farg2 +end subroutine + +function swigc_IDAadjCheckPointRec_order_get(farg1) & +bind(C, name="_wrap_IDAadjCheckPointRec_order_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +integer(C_INT) :: fresult +end function + +subroutine swigc_IDAadjCheckPointRec_step_set(farg1, farg2) & +bind(C, name="_wrap_IDAadjCheckPointRec_step_set") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +end subroutine + +function swigc_IDAadjCheckPointRec_step_get(farg1) & +bind(C, name="_wrap_IDAadjCheckPointRec_step_get") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_new_IDAadjCheckPointRec() & +bind(C, name="_wrap_new_IDAadjCheckPointRec") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper) :: fresult +end function + +subroutine swigc_delete_IDAadjCheckPointRec(farg1) & +bind(C, name="_wrap_delete_IDAadjCheckPointRec") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper), intent(inout) :: farg1 +end subroutine + +subroutine swigc_IDAadjCheckPointRec_op_assign__(farg1, farg2) & +bind(C, name="_wrap_IDAadjCheckPointRec_op_assign__") +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(SwigClassWrapper), intent(inout) :: farg1 +type(SwigClassWrapper) :: farg2 +end subroutine + +function swigc_FIDAGetAdjCheckPointsInfo(farg1, farg2) & +bind(C, name="_wrap_FIDAGetAdjCheckPointsInfo") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(C_PTR), value :: farg1 +type(SwigClassWrapper) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetAdjDataPointHermite(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FIDAGetAdjDataPointHermite") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetAdjDataPointPolynomial(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FIDAGetAdjDataPointPolynomial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetAdjCurrentCheckPoint(farg1, farg2) & +bind(C, name="_wrap_FIDAGetAdjCurrentCheckPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDABBDPrecInit(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) & +bind(C, name="_wrap_FIDABBDPrecInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +integer(C_INT64_T), intent(in) :: farg5 +integer(C_INT64_T), intent(in) :: farg6 +real(C_DOUBLE), intent(in) :: farg7 +type(C_FUNPTR), value :: farg8 +type(C_FUNPTR), value :: farg9 +integer(C_INT) :: fresult +end function + +function swigc_FIDABBDPrecReInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDABBDPrecReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDABBDPrecGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDABBDPrecGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDABBDPrecGetNumGfnEvals(farg1, farg2) & +bind(C, name="_wrap_FIDABBDPrecGetNumGfnEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDABBDPrecInitB(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10) & +bind(C, name="_wrap_FIDABBDPrecInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +integer(C_INT64_T), intent(in) :: farg5 +integer(C_INT64_T), intent(in) :: farg6 +integer(C_INT64_T), intent(in) :: farg7 +real(C_DOUBLE), intent(in) :: farg8 +type(C_FUNPTR), value :: farg9 +type(C_FUNPTR), value :: farg10 +integer(C_INT) :: fresult +end function + +function swigc_FIDABBDPrecReInitB(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FIDABBDPrecReInitB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetLinearSolver(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetLinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetJacFn(farg1, farg2) & +bind(C, name="_wrap_FIDASetJacFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetPreconditioner(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetPreconditioner") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetJacTimes(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetJacTimes") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetEpsLin(farg1, farg2) & +bind(C, name="_wrap_FIDASetEpsLin") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetLinearSolutionScaling(farg1, farg2) & +bind(C, name="_wrap_FIDASetLinearSolutionScaling") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetIncrementFactor(farg1, farg2) & +bind(C, name="_wrap_FIDASetIncrementFactor") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetLinWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDAGetLinWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumJacEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumJacEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumPrecEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumPrecEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumPrecSolves(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumPrecSolves") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumLinIters(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumLinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumLinConvFails(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumLinConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumJTSetupEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumJTSetupEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumJtimesEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumJtimesEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetNumLinResEvals(farg1, farg2) & +bind(C, name="_wrap_FIDAGetNumLinResEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetLastLinFlag(farg1, farg2) & +bind(C, name="_wrap_FIDAGetLastLinFlag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FIDAGetLinReturnFlagName(farg1) & +bind(C, name="_wrap_FIDAGetLinReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +function swigc_FIDASetLinearSolverB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDASetLinearSolverB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetJacFnB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetJacFnB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetJacFnBS(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetJacFnBS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetEpsLinB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetEpsLinB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetLinearSolutionScalingB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetLinearSolutionScalingB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetIncrementFactorB(farg1, farg2, farg3) & +bind(C, name="_wrap_FIDASetIncrementFactorB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetPreconditionerB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDASetPreconditionerB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetPreconditionerBS(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDASetPreconditionerBS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetJacTimesB(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDASetJacTimesB") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FIDASetJacTimesBS(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FIDASetJacTimesBS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FIDACreate() & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +type(C_PTR) :: fresult + +fresult = swigc_FIDACreate() +swig_result = fresult +end function + +function FIDAInit(ida_mem, res, t0, yy0, yp0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: res +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: yy0 +type(N_Vector), target, intent(inout) :: yp0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = ida_mem +farg2 = res +farg3 = t0 +farg4 = c_loc(yy0) +farg5 = c_loc(yp0) +fresult = swigc_FIDAInit(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FIDAReInit(ida_mem, t0, yy0, yp0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: t0 +type(N_Vector), target, intent(inout) :: yy0 +type(N_Vector), target, intent(inout) :: yp0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = t0 +farg3 = c_loc(yy0) +farg4 = c_loc(yp0) +fresult = swigc_FIDAReInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDASStolerances(ida_mem, reltol, abstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: reltol +real(C_DOUBLE), intent(in) :: abstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = ida_mem +farg2 = reltol +farg3 = abstol +fresult = swigc_FIDASStolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASVtolerances(ida_mem, reltol, abstol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: reltol +type(N_Vector), target, intent(inout) :: abstol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = reltol +farg3 = c_loc(abstol) +fresult = swigc_FIDASVtolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAWFtolerances(ida_mem, efun) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: efun +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = ida_mem +farg2 = efun +fresult = swigc_FIDAWFtolerances(farg1, farg2) +swig_result = fresult +end function + +function FIDACalcIC(ida_mem, icopt, tout1) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: icopt +real(C_DOUBLE), intent(in) :: tout1 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = ida_mem +farg2 = icopt +farg3 = tout1 +fresult = swigc_FIDACalcIC(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetNonlinConvCoefIC(ida_mem, epiccon) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: epiccon +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = epiccon +fresult = swigc_FIDASetNonlinConvCoefIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxNumStepsIC(ida_mem, maxnh) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxnh +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxnh +fresult = swigc_FIDASetMaxNumStepsIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxNumJacsIC(ida_mem, maxnj) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxnj +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxnj +fresult = swigc_FIDASetMaxNumJacsIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxNumItersIC(ida_mem, maxnit) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxnit +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxnit +fresult = swigc_FIDASetMaxNumItersIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetLineSearchOffIC(ida_mem, lsoff) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: lsoff +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = lsoff +fresult = swigc_FIDASetLineSearchOffIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetStepToleranceIC(ida_mem, steptol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: steptol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = steptol +fresult = swigc_FIDASetStepToleranceIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxBacksIC(ida_mem, maxbacks) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxbacks +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxbacks +fresult = swigc_FIDASetMaxBacksIC(farg1, farg2) +swig_result = fresult +end function + +function FIDASetErrHandlerFn(ida_mem, ehfun, eh_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: ehfun +type(C_PTR) :: eh_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = ehfun +farg3 = eh_data +fresult = swigc_FIDASetErrHandlerFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetErrFile(ida_mem, errfp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: errfp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = errfp +fresult = swigc_FIDASetErrFile(farg1, farg2) +swig_result = fresult +end function + +function FIDASetUserData(ida_mem, user_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: user_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = user_data +fresult = swigc_FIDASetUserData(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxOrd(ida_mem, maxord) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxord +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxord +fresult = swigc_FIDASetMaxOrd(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxNumSteps(ida_mem, mxsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), intent(in) :: mxsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = ida_mem +farg2 = mxsteps +fresult = swigc_FIDASetMaxNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FIDASetInitStep(ida_mem, hin) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: hin +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = hin +fresult = swigc_FIDASetInitStep(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxStep(ida_mem, hmax) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: hmax +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = hmax +fresult = swigc_FIDASetMaxStep(farg1, farg2) +swig_result = fresult +end function + +function FIDASetStopTime(ida_mem, tstop) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: tstop +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = tstop +fresult = swigc_FIDASetStopTime(farg1, farg2) +swig_result = fresult +end function + +function FIDASetNonlinConvCoef(ida_mem, epcon) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: epcon +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = epcon +fresult = swigc_FIDASetNonlinConvCoef(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxErrTestFails(ida_mem, maxnef) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxnef +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxnef +fresult = swigc_FIDASetMaxErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxNonlinIters(ida_mem, maxcor) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxcor +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxcor +fresult = swigc_FIDASetMaxNonlinIters(farg1, farg2) +swig_result = fresult +end function + +function FIDASetMaxConvFails(ida_mem, maxncf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxncf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxncf +fresult = swigc_FIDASetMaxConvFails(farg1, farg2) +swig_result = fresult +end function + +function FIDASetSuppressAlg(ida_mem, suppressalg) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: suppressalg +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = suppressalg +fresult = swigc_FIDASetSuppressAlg(farg1, farg2) +swig_result = fresult +end function + +function FIDASetId(ida_mem, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: id +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(id) +fresult = swigc_FIDASetId(farg1, farg2) +swig_result = fresult +end function + +function FIDASetConstraints(ida_mem, constraints) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: constraints +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(constraints) +fresult = swigc_FIDASetConstraints(farg1, farg2) +swig_result = fresult +end function + +function FIDASetNonlinearSolver(ida_mem, nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nls) +fresult = swigc_FIDASetNonlinearSolver(farg1, farg2) +swig_result = fresult +end function + +function FIDARootInit(ida_mem, nrtfn, g) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: nrtfn +type(C_FUNPTR), intent(in), value :: g +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = ida_mem +farg2 = nrtfn +farg3 = g +fresult = swigc_FIDARootInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetRootDirection(ida_mem, rootdir) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootdir +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(rootdir(1)) +fresult = swigc_FIDASetRootDirection(farg1, farg2) +swig_result = fresult +end function + +function FIDASetNoInactiveRootWarn(ida_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = ida_mem +fresult = swigc_FIDASetNoInactiveRootWarn(farg1) +swig_result = fresult +end function + +function FIDASolve(ida_mem, tout, tret, yret, ypret, itask) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: tout +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +type(N_Vector), target, intent(inout) :: yret +type(N_Vector), target, intent(inout) :: ypret +integer(C_INT), intent(in) :: itask +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +integer(C_INT) :: farg6 + +farg1 = ida_mem +farg2 = tout +farg3 = c_loc(tret(1)) +farg4 = c_loc(yret) +farg5 = c_loc(ypret) +farg6 = itask +fresult = swigc_FIDASolve(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FIDAComputeY(ida_mem, ycor, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: ycor +type(N_Vector), target, intent(inout) :: y +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(ycor) +farg3 = c_loc(y) +fresult = swigc_FIDAComputeY(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAComputeYp(ida_mem, ycor, yp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: ycor +type(N_Vector), target, intent(inout) :: yp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(ycor) +farg3 = c_loc(yp) +fresult = swigc_FIDAComputeYp(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAComputeYSens(ida_mem, ycor, yys) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: ycor +type(C_PTR) :: yys +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = ycor +farg3 = yys +fresult = swigc_FIDAComputeYSens(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAComputeYpSens(ida_mem, ycor, yps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: ycor +type(C_PTR) :: yps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = ycor +farg3 = yps +fresult = swigc_FIDAComputeYpSens(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAGetDky(ida_mem, t, k, dky) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(N_Vector), target, intent(inout) :: dky +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = t +farg3 = k +farg4 = c_loc(dky) +fresult = swigc_FIDAGetDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAGetWorkSpace(ida_mem, lenrw, leniw) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrw +integer(C_LONG), dimension(*), target, intent(inout) :: leniw +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(lenrw(1)) +farg3 = c_loc(leniw(1)) +fresult = swigc_FIDAGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAGetNumSteps(ida_mem, nsteps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsteps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nsteps(1)) +fresult = swigc_FIDAGetNumSteps(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumResEvals(ida_mem, nrevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nrevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nrevals(1)) +fresult = swigc_FIDAGetNumResEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumLinSolvSetups(ida_mem, nlinsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nlinsetups(1)) +fresult = swigc_FIDAGetNumLinSolvSetups(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumErrTestFails(ida_mem, netfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: netfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(netfails(1)) +fresult = swigc_FIDAGetNumErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumBacktrackOps(ida_mem, nbacktr) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nbacktr +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nbacktr(1)) +fresult = swigc_FIDAGetNumBacktrackOps(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetConsistentIC(ida_mem, yy0_mod, yp0_mod) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: yy0_mod +type(N_Vector), target, intent(inout) :: yp0_mod +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(yy0_mod) +farg3 = c_loc(yp0_mod) +fresult = swigc_FIDAGetConsistentIC(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAGetLastOrder(ida_mem, klast) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), dimension(*), target, intent(inout) :: klast +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(klast(1)) +fresult = swigc_FIDAGetLastOrder(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentOrder(ida_mem, kcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), dimension(*), target, intent(inout) :: kcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(kcur(1)) +fresult = swigc_FIDAGetCurrentOrder(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentCj(ida_mem, cj) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: cj +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(cj(1)) +fresult = swigc_FIDAGetCurrentCj(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentY(ida_mem, ycur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: ycur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = ycur +fresult = swigc_FIDAGetCurrentY(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentYSens(ida_mem, ys) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR), target, intent(inout) :: ys +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(ys) +fresult = swigc_FIDAGetCurrentYSens(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentYp(ida_mem, ypcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: ypcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = ypcur +fresult = swigc_FIDAGetCurrentYp(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentYpSens(ida_mem, yps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR), target, intent(inout) :: yps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(yps) +fresult = swigc_FIDAGetCurrentYpSens(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetActualInitStep(ida_mem, hinused) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hinused +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(hinused(1)) +fresult = swigc_FIDAGetActualInitStep(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetLastStep(ida_mem, hlast) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(hlast(1)) +fresult = swigc_FIDAGetLastStep(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentStep(ida_mem, hcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: hcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(hcur(1)) +fresult = swigc_FIDAGetCurrentStep(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetCurrentTime(ida_mem, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(tcur(1)) +fresult = swigc_FIDAGetCurrentTime(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetTolScaleFactor(ida_mem, tolsfact) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tolsfact +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(tolsfact(1)) +fresult = swigc_FIDAGetTolScaleFactor(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetErrWeights(ida_mem, eweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: eweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(eweight) +fresult = swigc_FIDAGetErrWeights(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetEstLocalErrors(ida_mem, ele) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: ele +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(ele) +fresult = swigc_FIDAGetEstLocalErrors(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumGEvals(ida_mem, ngevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(ngevals(1)) +fresult = swigc_FIDAGetNumGEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetRootInfo(ida_mem, rootsfound) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), dimension(*), target, intent(inout) :: rootsfound +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(rootsfound(1)) +fresult = swigc_FIDAGetRootInfo(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetIntegratorStats(ida_mem, nsteps, nrevals, nlinsetups, netfails, qlast, qcur, hinused, hlast, hcur, tcur) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsteps +integer(C_LONG), dimension(*), target, intent(inout) :: nrevals +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetups +integer(C_LONG), dimension(*), target, intent(inout) :: netfails +integer(C_INT), dimension(*), target, intent(inout) :: qlast +integer(C_INT), dimension(*), target, intent(inout) :: qcur +real(C_DOUBLE), dimension(*), target, intent(inout) :: hinused +real(C_DOUBLE), dimension(*), target, intent(inout) :: hlast +real(C_DOUBLE), dimension(*), target, intent(inout) :: hcur +real(C_DOUBLE), dimension(*), target, intent(inout) :: tcur +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 +type(C_PTR) :: farg7 +type(C_PTR) :: farg8 +type(C_PTR) :: farg9 +type(C_PTR) :: farg10 +type(C_PTR) :: farg11 + +farg1 = ida_mem +farg2 = c_loc(nsteps(1)) +farg3 = c_loc(nrevals(1)) +farg4 = c_loc(nlinsetups(1)) +farg5 = c_loc(netfails(1)) +farg6 = c_loc(qlast(1)) +farg7 = c_loc(qcur(1)) +farg8 = c_loc(hinused(1)) +farg9 = c_loc(hlast(1)) +farg10 = c_loc(hcur(1)) +farg11 = c_loc(tcur(1)) +fresult = swigc_FIDAGetIntegratorStats(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10, farg11) +swig_result = fresult +end function + +function FIDAGetNumNonlinSolvIters(ida_mem, nniters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nniters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nniters(1)) +fresult = swigc_FIDAGetNumNonlinSolvIters(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumNonlinSolvConvFails(ida_mem, nncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nncfails(1)) +fresult = swigc_FIDAGetNumNonlinSolvConvFails(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNonlinSolvStats(ida_mem, nniters, nncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nniters +integer(C_LONG), dimension(*), target, intent(inout) :: nncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(nniters(1)) +farg3 = c_loc(nncfails(1)) +fresult = swigc_FIDAGetNonlinSolvStats(farg1, farg2, farg3) +swig_result = fresult +end function + + +subroutine SWIG_chararray_to_string(wrap, string) + use, intrinsic :: ISO_C_BINDING + type(SwigArrayWrapper), intent(IN) :: wrap + character(kind=C_CHAR, len=:), allocatable, intent(OUT) :: string + character(kind=C_CHAR), dimension(:), pointer :: chars + integer(kind=C_SIZE_T) :: i + call c_f_pointer(wrap%data, chars, [wrap%size]) + allocate(character(kind=C_CHAR, len=wrap%size) :: string) + do i=1, wrap%size + string(i:i) = chars(i) + end do +end subroutine + +function FIDAGetReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FIDAGetReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +subroutine FIDAFree(ida_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), target, intent(inout) :: ida_mem +type(C_PTR) :: farg1 + +farg1 = c_loc(ida_mem) +call swigc_FIDAFree(farg1) +end subroutine + +function FIDAQuadInit(ida_mem, rhsq, yq0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: rhsq +type(N_Vector), target, intent(inout) :: yq0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = rhsq +farg3 = c_loc(yq0) +fresult = swigc_FIDAQuadInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAQuadReInit(ida_mem, yq0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: yq0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(yq0) +fresult = swigc_FIDAQuadReInit(farg1, farg2) +swig_result = fresult +end function + +function FIDAQuadSStolerances(ida_mem, reltolq, abstolq) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: reltolq +real(C_DOUBLE), intent(in) :: abstolq +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = ida_mem +farg2 = reltolq +farg3 = abstolq +fresult = swigc_FIDAQuadSStolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAQuadSVtolerances(ida_mem, reltolq, abstolq) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: reltolq +type(N_Vector), target, intent(inout) :: abstolq +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = reltolq +farg3 = c_loc(abstolq) +fresult = swigc_FIDAQuadSVtolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetQuadErrCon(ida_mem, errconq) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: errconq +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = errconq +fresult = swigc_FIDASetQuadErrCon(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetQuad(ida_mem, t, yqout) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: t +type(N_Vector), target, intent(inout) :: yqout +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(t(1)) +farg3 = c_loc(yqout) +fresult = swigc_FIDAGetQuad(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAGetQuadDky(ida_mem, t, k, dky) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(N_Vector), target, intent(inout) :: dky +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = t +farg3 = k +farg4 = c_loc(dky) +fresult = swigc_FIDAGetQuadDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAGetQuadNumRhsEvals(ida_mem, nrhsqevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nrhsqevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nrhsqevals(1)) +fresult = swigc_FIDAGetQuadNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetQuadNumErrTestFails(ida_mem, nqetfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nqetfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nqetfails(1)) +fresult = swigc_FIDAGetQuadNumErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetQuadErrWeights(ida_mem, eqweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(N_Vector), target, intent(inout) :: eqweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(eqweight) +fresult = swigc_FIDAGetQuadErrWeights(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetQuadStats(ida_mem, nrhsqevals, nqetfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nrhsqevals +integer(C_LONG), dimension(*), target, intent(inout) :: nqetfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(nrhsqevals(1)) +farg3 = c_loc(nqetfails(1)) +fresult = swigc_FIDAGetQuadStats(farg1, farg2, farg3) +swig_result = fresult +end function + +subroutine FIDAQuadFree(ida_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: ida_mem +type(C_PTR) :: farg1 + +farg1 = ida_mem +call swigc_FIDAQuadFree(farg1) +end subroutine + +function FIDASensInit(ida_mem, ns, ism, ress, ys0, yps0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: ns +integer(C_INT), intent(in) :: ism +type(C_FUNPTR), intent(in), value :: ress +type(C_PTR) :: ys0 +type(C_PTR) :: yps0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 +type(C_FUNPTR) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = ida_mem +farg2 = ns +farg3 = ism +farg4 = ress +farg5 = ys0 +farg6 = yps0 +fresult = swigc_FIDASensInit(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FIDASensReInit(ida_mem, ism, ys0, yps0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: ism +type(C_PTR) :: ys0 +type(C_PTR) :: yps0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = ism +farg3 = ys0 +farg4 = yps0 +fresult = swigc_FIDASensReInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDASensSStolerances(ida_mem, reltols, abstols) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: reltols +real(C_DOUBLE), dimension(*), target, intent(inout) :: abstols +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = reltols +farg3 = c_loc(abstols(1)) +fresult = swigc_FIDASensSStolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASensSVtolerances(ida_mem, reltols, abstols) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: reltols +type(C_PTR) :: abstols +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = reltols +farg3 = abstols +fresult = swigc_FIDASensSVtolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASensEEtolerances(ida_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = ida_mem +fresult = swigc_FIDASensEEtolerances(farg1) +swig_result = fresult +end function + +function FIDAGetSensConsistentIC(ida_mem, yys0, yps0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: yys0 +type(C_PTR) :: yps0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = yys0 +farg3 = yps0 +fresult = swigc_FIDAGetSensConsistentIC(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetSensDQMethod(ida_mem, dqtype, dqrhomax) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: dqtype +real(C_DOUBLE), intent(in) :: dqrhomax +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = ida_mem +farg2 = dqtype +farg3 = dqrhomax +fresult = swigc_FIDASetSensDQMethod(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetSensErrCon(ida_mem, errcons) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: errcons +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = errcons +fresult = swigc_FIDASetSensErrCon(farg1, farg2) +swig_result = fresult +end function + +function FIDASetSensMaxNonlinIters(ida_mem, maxcors) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: maxcors +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = maxcors +fresult = swigc_FIDASetSensMaxNonlinIters(farg1, farg2) +swig_result = fresult +end function + +function FIDASetSensParams(ida_mem, p, pbar, plist) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: p +real(C_DOUBLE), dimension(*), target, intent(inout) :: pbar +integer(C_INT), dimension(*), target, intent(inout) :: plist +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = c_loc(p(1)) +farg3 = c_loc(pbar(1)) +farg4 = c_loc(plist(1)) +fresult = swigc_FIDASetSensParams(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDASetNonlinearSolverSensSim(ida_mem, nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nls) +fresult = swigc_FIDASetNonlinearSolverSensSim(farg1, farg2) +swig_result = fresult +end function + +function FIDASetNonlinearSolverSensStg(ida_mem, nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nls) +fresult = swigc_FIDASetNonlinearSolverSensStg(farg1, farg2) +swig_result = fresult +end function + +function FIDASensToggleOff(ida_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = ida_mem +fresult = swigc_FIDASensToggleOff(farg1) +swig_result = fresult +end function + +function FIDAGetSens(ida_mem, tret, yysout) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +type(C_PTR) :: yysout +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(tret(1)) +farg3 = yysout +fresult = swigc_FIDAGetSens(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAGetSens1(ida_mem, tret, is, yysret) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +integer(C_INT), intent(in) :: is +type(N_Vector), target, intent(inout) :: yysret +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = c_loc(tret(1)) +farg3 = is +farg4 = c_loc(yysret) +fresult = swigc_FIDAGetSens1(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAGetSensDky(ida_mem, t, k, dkys) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(C_PTR) :: dkys +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = t +farg3 = k +farg4 = dkys +fresult = swigc_FIDAGetSensDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAGetSensDky1(ida_mem, t, k, is, dkys) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +integer(C_INT), intent(in) :: is +type(N_Vector), target, intent(inout) :: dkys +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +integer(C_INT) :: farg4 +type(C_PTR) :: farg5 + +farg1 = ida_mem +farg2 = t +farg3 = k +farg4 = is +farg5 = c_loc(dkys) +fresult = swigc_FIDAGetSensDky1(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FIDAGetSensNumResEvals(ida_mem, nressevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nressevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nressevals(1)) +fresult = swigc_FIDAGetSensNumResEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumResEvalsSens(ida_mem, nresevalss) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nresevalss +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nresevalss(1)) +fresult = swigc_FIDAGetNumResEvalsSens(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetSensNumErrTestFails(ida_mem, nsetfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsetfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nsetfails(1)) +fresult = swigc_FIDAGetSensNumErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetSensNumLinSolvSetups(ida_mem, nlinsetupss) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetupss +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nlinsetupss(1)) +fresult = swigc_FIDAGetSensNumLinSolvSetups(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetSensErrWeights(ida_mem, esweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: esweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = esweight +fresult = swigc_FIDAGetSensErrWeights(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetSensStats(ida_mem, nressevals, nresevalss, nsetfails, nlinsetupss) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nressevals +integer(C_LONG), dimension(*), target, intent(inout) :: nresevalss +integer(C_LONG), dimension(*), target, intent(inout) :: nsetfails +integer(C_LONG), dimension(*), target, intent(inout) :: nlinsetupss +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = ida_mem +farg2 = c_loc(nressevals(1)) +farg3 = c_loc(nresevalss(1)) +farg4 = c_loc(nsetfails(1)) +farg5 = c_loc(nlinsetupss(1)) +fresult = swigc_FIDAGetSensStats(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FIDAGetSensNumNonlinSolvIters(ida_mem, nsniters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsniters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nsniters(1)) +fresult = swigc_FIDAGetSensNumNonlinSolvIters(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetSensNumNonlinSolvConvFails(ida_mem, nsncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nsncfails(1)) +fresult = swigc_FIDAGetSensNumNonlinSolvConvFails(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetSensNonlinSolvStats(ida_mem, nsniters, nsncfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nsniters +integer(C_LONG), dimension(*), target, intent(inout) :: nsncfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(nsniters(1)) +farg3 = c_loc(nsncfails(1)) +fresult = swigc_FIDAGetSensNonlinSolvStats(farg1, farg2, farg3) +swig_result = fresult +end function + +subroutine FIDASensFree(ida_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: ida_mem +type(C_PTR) :: farg1 + +farg1 = ida_mem +call swigc_FIDASensFree(farg1) +end subroutine + +function FIDAQuadSensInit(ida_mem, resqs, yqs0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: resqs +type(C_PTR) :: yqs0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = resqs +farg3 = yqs0 +fresult = swigc_FIDAQuadSensInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAQuadSensReInit(ida_mem, yqs0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: yqs0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = yqs0 +fresult = swigc_FIDAQuadSensReInit(farg1, farg2) +swig_result = fresult +end function + +function FIDAQuadSensSStolerances(ida_mem, reltolqs, abstolqs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: reltolqs +real(C_DOUBLE), dimension(*), target, intent(inout) :: abstolqs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = reltolqs +farg3 = c_loc(abstolqs(1)) +fresult = swigc_FIDAQuadSensSStolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAQuadSensSVtolerances(ida_mem, reltolqs, abstolqs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: reltolqs +type(C_PTR) :: abstolqs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = reltolqs +farg3 = abstolqs +fresult = swigc_FIDAQuadSensSVtolerances(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAQuadSensEEtolerances(ida_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = ida_mem +fresult = swigc_FIDAQuadSensEEtolerances(farg1) +swig_result = fresult +end function + +function FIDASetQuadSensErrCon(ida_mem, errconqs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: errconqs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = errconqs +fresult = swigc_FIDASetQuadSensErrCon(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetQuadSens(ida_mem, tret, yyqsout) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +type(C_PTR) :: yyqsout +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(tret(1)) +farg3 = yyqsout +fresult = swigc_FIDAGetQuadSens(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAGetQuadSens1(ida_mem, tret, is, yyqsret) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +integer(C_INT), intent(in) :: is +type(N_Vector), target, intent(inout) :: yyqsret +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = c_loc(tret(1)) +farg3 = is +farg4 = c_loc(yyqsret) +fresult = swigc_FIDAGetQuadSens1(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAGetQuadSensDky(ida_mem, t, k, dkyqs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +type(C_PTR) :: dkyqs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = t +farg3 = k +farg4 = dkyqs +fresult = swigc_FIDAGetQuadSensDky(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAGetQuadSensDky1(ida_mem, t, k, is, dkyqs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: t +integer(C_INT), intent(in) :: k +integer(C_INT), intent(in) :: is +type(N_Vector), target, intent(inout) :: dkyqs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 +integer(C_INT) :: farg4 +type(C_PTR) :: farg5 + +farg1 = ida_mem +farg2 = t +farg3 = k +farg4 = is +farg5 = c_loc(dkyqs) +fresult = swigc_FIDAGetQuadSensDky1(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FIDAGetQuadSensNumRhsEvals(ida_mem, nrhsqsevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nrhsqsevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nrhsqsevals(1)) +fresult = swigc_FIDAGetQuadSensNumRhsEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetQuadSensNumErrTestFails(ida_mem, nqsetfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nqsetfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nqsetfails(1)) +fresult = swigc_FIDAGetQuadSensNumErrTestFails(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetQuadSensErrWeights(ida_mem, eqsweight) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR) :: eqsweight +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = eqsweight +fresult = swigc_FIDAGetQuadSensErrWeights(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetQuadSensStats(ida_mem, nrhsqsevals, nqsetfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nrhsqsevals +integer(C_LONG), dimension(*), target, intent(inout) :: nqsetfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(nrhsqsevals(1)) +farg3 = c_loc(nqsetfails(1)) +fresult = swigc_FIDAGetQuadSensStats(farg1, farg2, farg3) +swig_result = fresult +end function + +subroutine FIDAQuadSensFree(ida_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: ida_mem +type(C_PTR) :: farg1 + +farg1 = ida_mem +call swigc_FIDAQuadSensFree(farg1) +end subroutine + +function FIDAAdjInit(ida_mem, steps, interp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), intent(in) :: steps +integer(C_INT), intent(in) :: interp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 +integer(C_INT) :: farg3 + +farg1 = ida_mem +farg2 = steps +farg3 = interp +fresult = swigc_FIDAAdjInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAAdjReInit(ida_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = ida_mem +fresult = swigc_FIDAAdjReInit(farg1) +swig_result = fresult +end function + +subroutine FIDAAdjFree(ida_mem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: ida_mem +type(C_PTR) :: farg1 + +farg1 = ida_mem +call swigc_FIDAAdjFree(farg1) +end subroutine + +function FIDACreateB(ida_mem, which) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), dimension(*), target, intent(inout) :: which +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(which(1)) +fresult = swigc_FIDACreateB(farg1, farg2) +swig_result = fresult +end function + +function FIDAInitB(ida_mem, which, resb, tb0, yyb0, ypb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: resb +real(C_DOUBLE), intent(in) :: tb0 +type(N_Vector), target, intent(inout) :: yyb0 +type(N_Vector), target, intent(inout) :: ypb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = ida_mem +farg2 = which +farg3 = resb +farg4 = tb0 +farg5 = c_loc(yyb0) +farg6 = c_loc(ypb0) +fresult = swigc_FIDAInitB(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FIDAInitBS(ida_mem, which, ress, tb0, yyb0, ypb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: ress +real(C_DOUBLE), intent(in) :: tb0 +type(N_Vector), target, intent(inout) :: yyb0 +type(N_Vector), target, intent(inout) :: ypb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = ida_mem +farg2 = which +farg3 = ress +farg4 = tb0 +farg5 = c_loc(yyb0) +farg6 = c_loc(ypb0) +fresult = swigc_FIDAInitBS(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FIDAReInitB(ida_mem, which, tb0, yyb0, ypb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: tb0 +type(N_Vector), target, intent(inout) :: yyb0 +type(N_Vector), target, intent(inout) :: ypb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = ida_mem +farg2 = which +farg3 = tb0 +farg4 = c_loc(yyb0) +farg5 = c_loc(ypb0) +fresult = swigc_FIDAReInitB(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FIDASStolerancesB(ida_mem, which, reltolb, abstolb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: reltolb +real(C_DOUBLE), intent(in) :: abstolb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 +real(C_DOUBLE) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = reltolb +farg4 = abstolb +fresult = swigc_FIDASStolerancesB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDASVtolerancesB(ida_mem, which, reltolb, abstolb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: reltolb +type(N_Vector), target, intent(inout) :: abstolb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = reltolb +farg4 = c_loc(abstolb) +fresult = swigc_FIDASVtolerancesB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAQuadInitB(ida_mem, which, rhsqb, yqb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: rhsqb +type(N_Vector), target, intent(inout) :: yqb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = rhsqb +farg4 = c_loc(yqb0) +fresult = swigc_FIDAQuadInitB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAQuadInitBS(ida_mem, which, rhsqs, yqb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: rhsqs +type(N_Vector), target, intent(inout) :: yqb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = rhsqs +farg4 = c_loc(yqb0) +fresult = swigc_FIDAQuadInitBS(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAQuadReInitB(ida_mem, which, yqb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(N_Vector), target, intent(inout) :: yqb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = c_loc(yqb0) +fresult = swigc_FIDAQuadReInitB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAQuadSStolerancesB(ida_mem, which, reltolqb, abstolqb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: reltolqb +real(C_DOUBLE), intent(in) :: abstolqb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 +real(C_DOUBLE) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = reltolqb +farg4 = abstolqb +fresult = swigc_FIDAQuadSStolerancesB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAQuadSVtolerancesB(ida_mem, which, reltolqb, abstolqb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: reltolqb +type(N_Vector), target, intent(inout) :: abstolqb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = reltolqb +farg4 = c_loc(abstolqb) +fresult = swigc_FIDAQuadSVtolerancesB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDACalcICB(ida_mem, which, tout1, yy0, yp0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: tout1 +type(N_Vector), target, intent(inout) :: yy0 +type(N_Vector), target, intent(inout) :: yp0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = ida_mem +farg2 = which +farg3 = tout1 +farg4 = c_loc(yy0) +farg5 = c_loc(yp0) +fresult = swigc_FIDACalcICB(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FIDACalcICBS(ida_mem, which, tout1, yy0, yp0, yys0, yps0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: tout1 +type(N_Vector), target, intent(inout) :: yy0 +type(N_Vector), target, intent(inout) :: yp0 +type(C_PTR) :: yys0 +type(C_PTR) :: yps0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 +type(C_PTR) :: farg7 + +farg1 = ida_mem +farg2 = which +farg3 = tout1 +farg4 = c_loc(yy0) +farg5 = c_loc(yp0) +farg6 = yys0 +farg7 = yps0 +fresult = swigc_FIDACalcICBS(farg1, farg2, farg3, farg4, farg5, farg6, farg7) +swig_result = fresult +end function + +function FIDASolveF(ida_mem, tout, tret, yret, ypret, itask, ncheckptr) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: tout +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +type(N_Vector), target, intent(inout) :: yret +type(N_Vector), target, intent(inout) :: ypret +integer(C_INT), intent(in) :: itask +integer(C_INT), dimension(*), target, intent(inout) :: ncheckptr +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 +integer(C_INT) :: farg6 +type(C_PTR) :: farg7 + +farg1 = ida_mem +farg2 = tout +farg3 = c_loc(tret(1)) +farg4 = c_loc(yret) +farg5 = c_loc(ypret) +farg6 = itask +farg7 = c_loc(ncheckptr(1)) +fresult = swigc_FIDASolveF(farg1, farg2, farg3, farg4, farg5, farg6, farg7) +swig_result = fresult +end function + +function FIDASolveB(ida_mem, tbout, itaskb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: tbout +integer(C_INT), intent(in) :: itaskb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 + +farg1 = ida_mem +farg2 = tbout +farg3 = itaskb +fresult = swigc_FIDASolveB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAAdjSetNoSensi(ida_mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = ida_mem +fresult = swigc_FIDAAdjSetNoSensi(farg1) +swig_result = fresult +end function + +function FIDASetUserDataB(ida_mem, which, user_datab) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(C_PTR) :: user_datab +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = user_datab +fresult = swigc_FIDASetUserDataB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetMaxOrdB(ida_mem, which, maxordb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +integer(C_INT), intent(in) :: maxordb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = maxordb +fresult = swigc_FIDASetMaxOrdB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetMaxNumStepsB(ida_mem, which, mxstepsb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +integer(C_LONG), intent(in) :: mxstepsb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_LONG) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = mxstepsb +fresult = swigc_FIDASetMaxNumStepsB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetInitStepB(ida_mem, which, hinb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: hinb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = hinb +fresult = swigc_FIDASetInitStepB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetMaxStepB(ida_mem, which, hmaxb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: hmaxb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = hmaxb +fresult = swigc_FIDASetMaxStepB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetSuppressAlgB(ida_mem, which, suppressalgb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +integer(C_INT), intent(in) :: suppressalgb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = suppressalgb +fresult = swigc_FIDASetSuppressAlgB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetIdB(ida_mem, which, idb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(N_Vector), target, intent(inout) :: idb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = c_loc(idb) +fresult = swigc_FIDASetIdB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetConstraintsB(ida_mem, which, constraintsb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(N_Vector), target, intent(inout) :: constraintsb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = c_loc(constraintsb) +fresult = swigc_FIDASetConstraintsB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetQuadErrConB(ida_mem, which, errconqb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +integer(C_INT), intent(in) :: errconqb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = errconqb +fresult = swigc_FIDASetQuadErrConB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetNonlinearSolverB(ida_mem, which, nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = c_loc(nls) +fresult = swigc_FIDASetNonlinearSolverB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAGetB(ida_mem, which, tret, yy, yp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +type(N_Vector), target, intent(inout) :: yy +type(N_Vector), target, intent(inout) :: yp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = ida_mem +farg2 = which +farg3 = c_loc(tret(1)) +farg4 = c_loc(yy) +farg5 = c_loc(yp) +fresult = swigc_FIDAGetB(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FIDAGetQuadB(ida_mem, which, tret, qb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), dimension(*), target, intent(inout) :: tret +type(N_Vector), target, intent(inout) :: qb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = c_loc(tret(1)) +farg4 = c_loc(qb) +fresult = swigc_FIDAGetQuadB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAGetAdjIDABmem(ida_mem, which) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = which +fresult = swigc_FIDAGetAdjIDABmem(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetConsistentICB(ida_mem, which, yyb0, ypb0) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(N_Vector), target, intent(inout) :: yyb0 +type(N_Vector), target, intent(inout) :: ypb0 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = c_loc(yyb0) +farg4 = c_loc(ypb0) +fresult = swigc_FIDAGetConsistentICB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDAGetAdjY(ida_mem, t, yy, yp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: t +type(N_Vector), target, intent(inout) :: yy +type(N_Vector), target, intent(inout) :: yp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = t +farg3 = c_loc(yy) +farg4 = c_loc(yp) +fresult = swigc_FIDAGetAdjY(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +subroutine swigf_IDAadjCheckPointRec_my_addr_set(self, my_addr) +use, intrinsic :: ISO_C_BINDING +class(IDAadjCheckPointRec), intent(in) :: self +type(C_PTR) :: my_addr +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: farg2 + +farg1 = self%swigdata +farg2 = my_addr +call swigc_IDAadjCheckPointRec_my_addr_set(farg1, farg2) +end subroutine + +function swigf_IDAadjCheckPointRec_my_addr_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +class(IDAadjCheckPointRec), intent(in) :: self +type(C_PTR) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_IDAadjCheckPointRec_my_addr_get(farg1) +swig_result = fresult +end function + +subroutine swigf_IDAadjCheckPointRec_next_addr_set(self, next_addr) +use, intrinsic :: ISO_C_BINDING +class(IDAadjCheckPointRec), intent(in) :: self +type(C_PTR) :: next_addr +type(SwigClassWrapper) :: farg1 +type(C_PTR) :: farg2 + +farg1 = self%swigdata +farg2 = next_addr +call swigc_IDAadjCheckPointRec_next_addr_set(farg1, farg2) +end subroutine + +function swigf_IDAadjCheckPointRec_next_addr_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +class(IDAadjCheckPointRec), intent(in) :: self +type(C_PTR) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_IDAadjCheckPointRec_next_addr_get(farg1) +swig_result = fresult +end function + +subroutine swigf_IDAadjCheckPointRec_t0_set(self, t0) +use, intrinsic :: ISO_C_BINDING +class(IDAadjCheckPointRec), intent(in) :: self +real(C_DOUBLE), intent(in) :: t0 +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = self%swigdata +farg2 = t0 +call swigc_IDAadjCheckPointRec_t0_set(farg1, farg2) +end subroutine + +function swigf_IDAadjCheckPointRec_t0_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +class(IDAadjCheckPointRec), intent(in) :: self +real(C_DOUBLE) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_IDAadjCheckPointRec_t0_get(farg1) +swig_result = fresult +end function + +subroutine swigf_IDAadjCheckPointRec_t1_set(self, t1) +use, intrinsic :: ISO_C_BINDING +class(IDAadjCheckPointRec), intent(in) :: self +real(C_DOUBLE), intent(in) :: t1 +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = self%swigdata +farg2 = t1 +call swigc_IDAadjCheckPointRec_t1_set(farg1, farg2) +end subroutine + +function swigf_IDAadjCheckPointRec_t1_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +class(IDAadjCheckPointRec), intent(in) :: self +real(C_DOUBLE) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_IDAadjCheckPointRec_t1_get(farg1) +swig_result = fresult +end function + +subroutine swigf_IDAadjCheckPointRec_nstep_set(self, nstep) +use, intrinsic :: ISO_C_BINDING +class(IDAadjCheckPointRec), intent(in) :: self +integer(C_LONG), intent(in) :: nstep +type(SwigClassWrapper) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = self%swigdata +farg2 = nstep +call swigc_IDAadjCheckPointRec_nstep_set(farg1, farg2) +end subroutine + +function swigf_IDAadjCheckPointRec_nstep_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_LONG) :: swig_result +class(IDAadjCheckPointRec), intent(in) :: self +integer(C_LONG) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_IDAadjCheckPointRec_nstep_get(farg1) +swig_result = fresult +end function + +subroutine swigf_IDAadjCheckPointRec_order_set(self, order) +use, intrinsic :: ISO_C_BINDING +class(IDAadjCheckPointRec), intent(in) :: self +integer(C_INT), intent(in) :: order +type(SwigClassWrapper) :: farg1 +integer(C_INT) :: farg2 + +farg1 = self%swigdata +farg2 = order +call swigc_IDAadjCheckPointRec_order_set(farg1, farg2) +end subroutine + +function swigf_IDAadjCheckPointRec_order_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +class(IDAadjCheckPointRec), intent(in) :: self +integer(C_INT) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_IDAadjCheckPointRec_order_get(farg1) +swig_result = fresult +end function + +subroutine swigf_IDAadjCheckPointRec_step_set(self, step) +use, intrinsic :: ISO_C_BINDING +class(IDAadjCheckPointRec), intent(in) :: self +real(C_DOUBLE), intent(in) :: step +type(SwigClassWrapper) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = self%swigdata +farg2 = step +call swigc_IDAadjCheckPointRec_step_set(farg1, farg2) +end subroutine + +function swigf_IDAadjCheckPointRec_step_get(self) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +class(IDAadjCheckPointRec), intent(in) :: self +real(C_DOUBLE) :: fresult +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +fresult = swigc_IDAadjCheckPointRec_step_get(farg1) +swig_result = fresult +end function + +function swigf_create_IDAadjCheckPointRec() & +result(self) +use, intrinsic :: ISO_C_BINDING +type(IDAadjCheckPointRec) :: self +type(SwigClassWrapper) :: fresult + +fresult = swigc_new_IDAadjCheckPointRec() +self%swigdata = fresult +end function + +subroutine swigf_release_IDAadjCheckPointRec(self) +use, intrinsic :: ISO_C_BINDING +class(IDAadjCheckPointRec), intent(inout) :: self +type(SwigClassWrapper) :: farg1 + +farg1 = self%swigdata +if (btest(farg1%cmemflags, swig_cmem_own_bit)) then +call swigc_delete_IDAadjCheckPointRec(farg1) +endif +farg1%cptr = C_NULL_PTR +farg1%cmemflags = 0 +self%swigdata = farg1 +end subroutine + +subroutine swigf_IDAadjCheckPointRec_op_assign__(self, other) +use, intrinsic :: ISO_C_BINDING +class(IDAadjCheckPointRec), intent(inout) :: self +type(IDAadjCheckPointRec), intent(in) :: other +type(SwigClassWrapper) :: farg1 +type(SwigClassWrapper) :: farg2 + +farg1 = self%swigdata +farg2 = other%swigdata +call swigc_IDAadjCheckPointRec_op_assign__(farg1, farg2) +self%swigdata = farg1 +end subroutine + +function FIDAGetAdjCheckPointsInfo(ida_mem, ckpnt) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +class(IDAadjCheckPointRec), intent(in) :: ckpnt +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(SwigClassWrapper) :: farg2 + +farg1 = ida_mem +farg2 = ckpnt%swigdata +fresult = swigc_FIDAGetAdjCheckPointsInfo(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetAdjDataPointHermite(ida_mem, which, t, yy, yd) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), dimension(*), target, intent(inout) :: t +type(N_Vector), target, intent(inout) :: yy +type(N_Vector), target, intent(inout) :: yd +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = ida_mem +farg2 = which +farg3 = c_loc(t(1)) +farg4 = c_loc(yy) +farg5 = c_loc(yd) +fresult = swigc_FIDAGetAdjDataPointHermite(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FIDAGetAdjDataPointPolynomial(ida_mem, which, t, order, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), dimension(*), target, intent(inout) :: t +integer(C_INT), dimension(*), target, intent(inout) :: order +type(N_Vector), target, intent(inout) :: y +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = ida_mem +farg2 = which +farg3 = c_loc(t(1)) +farg4 = c_loc(order(1)) +farg5 = c_loc(y) +fresult = swigc_FIDAGetAdjDataPointPolynomial(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FIDAGetAdjCurrentCheckPoint(ida_mem, addr) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_PTR), target, intent(inout) :: addr +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(addr) +fresult = swigc_FIDAGetAdjCurrentCheckPoint(farg1, farg2) +swig_result = fresult +end function + +function FIDABBDPrecInit(ida_mem, nlocal, mudq, mldq, mukeep, mlkeep, dq_rel_yy, gres, gcomm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT64_T), intent(in) :: nlocal +integer(C_INT64_T), intent(in) :: mudq +integer(C_INT64_T), intent(in) :: mldq +integer(C_INT64_T), intent(in) :: mukeep +integer(C_INT64_T), intent(in) :: mlkeep +real(C_DOUBLE), intent(in) :: dq_rel_yy +type(C_FUNPTR), intent(in), value :: gres +type(C_FUNPTR), intent(in), value :: gcomm +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 +integer(C_INT64_T) :: farg5 +integer(C_INT64_T) :: farg6 +real(C_DOUBLE) :: farg7 +type(C_FUNPTR) :: farg8 +type(C_FUNPTR) :: farg9 + +farg1 = ida_mem +farg2 = nlocal +farg3 = mudq +farg4 = mldq +farg5 = mukeep +farg6 = mlkeep +farg7 = dq_rel_yy +farg8 = gres +farg9 = gcomm +fresult = swigc_FIDABBDPrecInit(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) +swig_result = fresult +end function + +function FIDABBDPrecReInit(ida_mem, mudq, mldq, dq_rel_yy) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT64_T), intent(in) :: mudq +integer(C_INT64_T), intent(in) :: mldq +real(C_DOUBLE), intent(in) :: dq_rel_yy +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +real(C_DOUBLE) :: farg4 + +farg1 = ida_mem +farg2 = mudq +farg3 = mldq +farg4 = dq_rel_yy +fresult = swigc_FIDABBDPrecReInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDABBDPrecGetWorkSpace(ida_mem, lenrwbbdp, leniwbbdp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwbbdp +integer(C_LONG), dimension(*), target, intent(inout) :: leniwbbdp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(lenrwbbdp(1)) +farg3 = c_loc(leniwbbdp(1)) +fresult = swigc_FIDABBDPrecGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDABBDPrecGetNumGfnEvals(ida_mem, ngevalsbbdp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevalsbbdp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(ngevalsbbdp(1)) +fresult = swigc_FIDABBDPrecGetNumGfnEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDABBDPrecInitB(ida_mem, which, nlocalb, mudqb, mldqb, mukeepb, mlkeepb, dq_rel_yyb, gresb, gcommb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +integer(C_INT64_T), intent(in) :: nlocalb +integer(C_INT64_T), intent(in) :: mudqb +integer(C_INT64_T), intent(in) :: mldqb +integer(C_INT64_T), intent(in) :: mukeepb +integer(C_INT64_T), intent(in) :: mlkeepb +real(C_DOUBLE), intent(in) :: dq_rel_yyb +type(C_FUNPTR), intent(in), value :: gresb +type(C_FUNPTR), intent(in), value :: gcommb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 +integer(C_INT64_T) :: farg5 +integer(C_INT64_T) :: farg6 +integer(C_INT64_T) :: farg7 +real(C_DOUBLE) :: farg8 +type(C_FUNPTR) :: farg9 +type(C_FUNPTR) :: farg10 + +farg1 = ida_mem +farg2 = which +farg3 = nlocalb +farg4 = mudqb +farg5 = mldqb +farg6 = mukeepb +farg7 = mlkeepb +farg8 = dq_rel_yyb +farg9 = gresb +farg10 = gcommb +fresult = swigc_FIDABBDPrecInitB(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10) +swig_result = fresult +end function + +function FIDABBDPrecReInitB(ida_mem, which, mudqb, mldqb, dq_rel_yyb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +integer(C_INT64_T), intent(in) :: mudqb +integer(C_INT64_T), intent(in) :: mldqb +real(C_DOUBLE), intent(in) :: dq_rel_yyb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 +real(C_DOUBLE) :: farg5 + +farg1 = ida_mem +farg2 = which +farg3 = mudqb +farg4 = mldqb +farg5 = dq_rel_yyb +fresult = swigc_FIDABBDPrecReInitB(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FIDASetLinearSolver(ida_mem, ls, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(SUNLinearSolver), target, intent(inout) :: ls +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(ls) +farg3 = c_loc(a) +fresult = swigc_FIDASetLinearSolver(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetJacFn(ida_mem, jac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: jac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = ida_mem +farg2 = jac +fresult = swigc_FIDASetJacFn(farg1, farg2) +swig_result = fresult +end function + +function FIDASetPreconditioner(ida_mem, pset, psolve) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: pset +type(C_FUNPTR), intent(in), value :: psolve +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = ida_mem +farg2 = pset +farg3 = psolve +fresult = swigc_FIDASetPreconditioner(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetJacTimes(ida_mem, jtsetup, jtimes) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +type(C_FUNPTR), intent(in), value :: jtsetup +type(C_FUNPTR), intent(in), value :: jtimes +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = ida_mem +farg2 = jtsetup +farg3 = jtimes +fresult = swigc_FIDASetJacTimes(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetEpsLin(ida_mem, eplifac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: eplifac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = eplifac +fresult = swigc_FIDASetEpsLin(farg1, farg2) +swig_result = fresult +end function + +function FIDASetLinearSolutionScaling(ida_mem, onoff) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: onoff +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = ida_mem +farg2 = onoff +fresult = swigc_FIDASetLinearSolutionScaling(farg1, farg2) +swig_result = fresult +end function + +function FIDASetIncrementFactor(ida_mem, dqincfac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +real(C_DOUBLE), intent(in) :: dqincfac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = ida_mem +farg2 = dqincfac +fresult = swigc_FIDASetIncrementFactor(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetLinWorkSpace(ida_mem, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = ida_mem +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FIDAGetLinWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDAGetNumJacEvals(ida_mem, njevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(njevals(1)) +fresult = swigc_FIDAGetNumJacEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumPrecEvals(ida_mem, npevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: npevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(npevals(1)) +fresult = swigc_FIDAGetNumPrecEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumPrecSolves(ida_mem, npsolves) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: npsolves +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(npsolves(1)) +fresult = swigc_FIDAGetNumPrecSolves(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumLinIters(ida_mem, nliters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nliters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nliters(1)) +fresult = swigc_FIDAGetNumLinIters(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumLinConvFails(ida_mem, nlcfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nlcfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nlcfails(1)) +fresult = swigc_FIDAGetNumLinConvFails(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumJTSetupEvals(ida_mem, njtsetups) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njtsetups +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(njtsetups(1)) +fresult = swigc_FIDAGetNumJTSetupEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumJtimesEvals(ida_mem, njvevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: njvevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(njvevals(1)) +fresult = swigc_FIDAGetNumJtimesEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetNumLinResEvals(ida_mem, nrevalsls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: nrevalsls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(nrevalsls(1)) +fresult = swigc_FIDAGetNumLinResEvals(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetLastLinFlag(ida_mem, flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_LONG), dimension(*), target, intent(inout) :: flag +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = ida_mem +farg2 = c_loc(flag(1)) +fresult = swigc_FIDAGetLastLinFlag(farg1, farg2) +swig_result = fresult +end function + +function FIDAGetLinReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FIDAGetLinReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +function FIDASetLinearSolverB(ida_mem, which, ls, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(SUNLinearSolver), target, intent(inout) :: ls +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = c_loc(ls) +farg4 = c_loc(a) +fresult = swigc_FIDASetLinearSolverB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDASetJacFnB(ida_mem, which, jacb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: jacb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = jacb +fresult = swigc_FIDASetJacFnB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetJacFnBS(ida_mem, which, jacbs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: jacbs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = jacbs +fresult = swigc_FIDASetJacFnBS(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetEpsLinB(ida_mem, which, eplifacb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: eplifacb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = eplifacb +fresult = swigc_FIDASetEpsLinB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetLinearSolutionScalingB(ida_mem, which, onoffb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +integer(C_INT), intent(in) :: onoffb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = onoffb +fresult = swigc_FIDASetLinearSolutionScalingB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetIncrementFactorB(ida_mem, which, dqincfacb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +real(C_DOUBLE), intent(in) :: dqincfacb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = ida_mem +farg2 = which +farg3 = dqincfacb +fresult = swigc_FIDASetIncrementFactorB(farg1, farg2, farg3) +swig_result = fresult +end function + +function FIDASetPreconditionerB(ida_mem, which, psetb, psolveb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: psetb +type(C_FUNPTR), intent(in), value :: psolveb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = psetb +farg4 = psolveb +fresult = swigc_FIDASetPreconditionerB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDASetPreconditionerBS(ida_mem, which, psetbs, psolvebs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: psetbs +type(C_FUNPTR), intent(in), value :: psolvebs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = psetbs +farg4 = psolvebs +fresult = swigc_FIDASetPreconditionerBS(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDASetJacTimesB(ida_mem, which, jtsetupb, jtimesb) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: jtsetupb +type(C_FUNPTR), intent(in), value :: jtimesb +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = jtsetupb +farg4 = jtimesb +fresult = swigc_FIDASetJacTimesB(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FIDASetJacTimesBS(ida_mem, which, jtsetupbs, jtimesbs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: ida_mem +integer(C_INT), intent(in) :: which +type(C_FUNPTR), intent(in), value :: jtsetupbs +type(C_FUNPTR), intent(in), value :: jtimesbs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = ida_mem +farg2 = which +farg3 = jtsetupbs +farg4 = jtimesbs +fresult = swigc_FIDASetJacTimesBS(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idaa.c b/deps/AMICI/ThirdParty/sundials/src/idas/idaa.c index 32bc0cb4d..7c92041c7 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idaa.c +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idaa.c @@ -2,11 +2,11 @@ * ----------------------------------------------------------------- * $Revision$ * $Date$ - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Programmer(s): Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -56,30 +56,30 @@ static booleantype IDAAdataMalloc(IDAMem IDA_mem); static void IDAAdataFree(IDAMem IDA_mem); static int IDAAdataStore(IDAMem IDA_mem, CkpntMem ck_mem); -static int IDAAckpntGet(IDAMem IDA_mem, CkpntMem ck_mem); +static int IDAAckpntGet(IDAMem IDA_mem, CkpntMem ck_mem); static booleantype IDAAhermiteMalloc(IDAMem IDA_mem); static void IDAAhermiteFree(IDAMem IDA_mem); static int IDAAhermiteStorePnt(IDAMem IDA_mem, DtpntMem d); -static int IDAAhermiteGetY(IDAMem IDA_mem, realtype t, +static int IDAAhermiteGetY(IDAMem IDA_mem, realtype t, N_Vector yy, N_Vector yp, N_Vector *yyS, N_Vector *ypS); static booleantype IDAApolynomialMalloc(IDAMem IDA_mem); static void IDAApolynomialFree(IDAMem IDA_mem); static int IDAApolynomialStorePnt(IDAMem IDA_mem, DtpntMem d); -static int IDAApolynomialGetY(IDAMem IDA_mem, realtype t, +static int IDAApolynomialGetY(IDAMem IDA_mem, realtype t, N_Vector yy, N_Vector yp, N_Vector *yyS, N_Vector *ypS); -static int IDAAfindIndex(IDAMem ida_mem, realtype t, - long int *indx, booleantype *newpoint); +static int IDAAfindIndex(IDAMem ida_mem, realtype t, + long int *indx, booleantype *newpoint); -static int IDAAres(realtype tt, - N_Vector yyB, N_Vector ypB, +static int IDAAres(realtype tt, + N_Vector yyB, N_Vector ypB, N_Vector resvalB, void *ida_mem); -static int IDAArhsQ(realtype tt, +static int IDAArhsQ(realtype tt, N_Vector yyB, N_Vector ypB, N_Vector rrQB, void *ida_mem); @@ -94,7 +94,7 @@ extern int IDAGetSolution(void *ida_mem, realtype t, N_Vector yret, N_Vector ypr /*=================================================================*/ /* - * IDAAdjInit + * IDAAdjInit * * This routine allocates space for the global IDAA memory * structure. @@ -122,7 +122,7 @@ int IDAAdjInit(void *ida_mem, long int steps, int interp) if ( (interp != IDA_HERMITE) && (interp != IDA_POLYNOMIAL) ) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAAdjInit", MSGAM_BAD_INTERP); return(IDA_ILL_INPUT); - } + } /* Allocate memory block for IDAadjMem. */ IDAADJ_mem = (IDAadjMem) malloc(sizeof(struct IDAadjMemRec)); @@ -163,9 +163,9 @@ int IDAAdjInit(void *ida_mem, long int steps, int interp) IDAADJ_mem->ia_getY = IDAAhermiteGetY; IDAADJ_mem->ia_storePnt = IDAAhermiteStorePnt; break; - + case IDA_POLYNOMIAL: - + IDAADJ_mem->ia_malloc = IDAApolynomialMalloc; IDAADJ_mem->ia_free = IDAApolynomialFree; IDAADJ_mem->ia_getY = IDAApolynomialGetY; @@ -178,9 +178,9 @@ int IDAAdjInit(void *ida_mem, long int steps, int interp) /* By default we will store but not interpolate sensitivities * - storeSensi will be set in IDASolveF to SUNFALSE if FSA is not enabled - * or if the user forced this through IDAAdjSetNoSensi - * - interpSensi will be set in IDASolveB to SUNTRUE if storeSensi is SUNTRUE - * and if at least one backward problem requires sensitivities + * or if the user forced this through IDAAdjSetNoSensi + * - interpSensi will be set in IDASolveB to SUNTRUE if storeSensi is SUNTRUE + * and if at least one backward problem requires sensitivities * - noInterp will be set in IDACalcICB to SUNTRUE before the call to * IDACalcIC and SUNFALSE after.*/ @@ -193,17 +193,20 @@ int IDAAdjInit(void *ida_mem, long int steps, int interp) IDAADJ_mem->ia_bckpbCrt = NULL; IDAADJ_mem->ia_nbckpbs = 0; - /* Flags for tracking the first calls to IDASolveF and IDASolveF. */ + /* IDASolveF and IDASolveB not called yet. */ IDAADJ_mem->ia_firstIDAFcall = SUNTRUE; IDAADJ_mem->ia_tstopIDAFcall = SUNFALSE; + IDAADJ_mem->ia_firstIDABcall = SUNTRUE; + IDAADJ_mem->ia_rootret = SUNFALSE; + /* Adjoint module initialized and allocated. */ IDA_mem->ida_adj = SUNTRUE; IDA_mem->ida_adjMallocDone = SUNTRUE; return(IDA_SUCCESS); -} +} /* * IDAAdjReInit @@ -233,7 +236,7 @@ int IDAAdjReInit(void *ida_mem) IDAADJ_mem = IDA_mem->ida_adj_mem; /* Free all stored checkpoints. */ - while (IDAADJ_mem->ck_mem != NULL) + while (IDAADJ_mem->ck_mem != NULL) IDAAckpntDelete(&(IDAADJ_mem->ck_mem)); IDAADJ_mem->ck_mem = NULL; @@ -246,7 +249,7 @@ int IDAAdjReInit(void *ida_mem) IDAADJ_mem->ia_firstIDABcall = SUNTRUE; return(IDA_SUCCESS); -} +} /* * IDAAdjFree @@ -267,7 +270,7 @@ void IDAAdjFree(void *ida_mem) /* Data for adjoint. */ IDAADJ_mem = IDA_mem->ida_adj_mem; - + /* Delete check points one by one */ while (IDAADJ_mem->ck_mem != NULL) { IDAAckpntDelete(&(IDAADJ_mem->ck_mem)); @@ -286,7 +289,7 @@ void IDAAdjFree(void *ida_mem) } } -/* +/* * ================================================================= * PRIVATE FUNCTIONS FOR BACKWARD PROBLEMS * ================================================================= @@ -328,14 +331,14 @@ static void IDAAbckpbDelete(IDABMem *IDAB_memPtr) /*=================================================================*/ /* - * IDASolveF + * IDASolveF * * This routine integrates to tout and returns solution into yout. - * In the same time, it stores check point data every 'steps' steps. - * + * In the same time, it stores check point data every 'steps' steps. + * * IDASolveF can be called repeatedly by the user. The last tout * will be used as the starting time for the backward integration. - * + * * ncheckPtr points to the number of check points stored so far. */ @@ -347,7 +350,8 @@ int IDASolveF(void *ida_mem, realtype tout, realtype *tret, CkpntMem tmp; DtpntMem *dt_mem; int flag, i; - booleantype /* iret, */ allocOK; + booleantype allocOK, earlyret; + realtype ttest; /* Is the mem OK? */ if (ida_mem == NULL) { @@ -368,7 +372,7 @@ int IDASolveF(void *ida_mem, realtype tout, realtype *tret, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASolveF", MSG_YRET_NULL); return(IDA_ILL_INPUT); } - + /* Check for ypret != NULL */ if (ypret == NULL) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASolveF", MSG_YPRET_NULL); @@ -379,15 +383,15 @@ int IDASolveF(void *ida_mem, realtype tout, realtype *tret, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASolveF", MSG_TRET_NULL); return(IDA_ILL_INPUT); } - + /* Check for valid itask */ if ( (itask != IDA_NORMAL) && (itask != IDA_ONE_STEP) ) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASolveF", MSG_BAD_ITASK); return(IDA_ILL_INPUT); } - + /* All memory checks done, proceed ... */ - + dt_mem = IDAADJ_mem->dt_mem; /* If tstop is enabled, store some info */ @@ -395,22 +399,16 @@ int IDASolveF(void *ida_mem, realtype tout, realtype *tret, IDAADJ_mem->ia_tstopIDAFcall = SUNTRUE; IDAADJ_mem->ia_tstopIDAF = IDA_mem->ida_tstop; } - - /* We will call IDASolve in IDA_ONE_STEP mode, regardless - of what itask is, so flag if we need to return */ -/* if (itask == IDA_ONE_STEP) iret = SUNTRUE; - * else iret = SUNFALSE; - */ /* On the first step: * - set tinitial * - initialize list of check points * - if needed, initialize the interpolation module * - load dt_mem[0] - * On subsequent steps, test if taking a new step is necessary. + * On subsequent steps, test if taking a new step is necessary. */ if ( IDAADJ_mem->ia_firstIDAFcall ) { - + IDAADJ_mem->ia_tinitial = IDA_mem->ida_tn; IDAADJ_mem->ck_mem = IDAAckpntInit(IDA_mem); if (IDAADJ_mem->ck_mem == NULL) { @@ -444,33 +442,57 @@ int IDASolveF(void *ida_mem, realtype tout, realtype *tret, IDAADJ_mem->ia_firstIDAFcall = SUNFALSE; - } else if ( (IDA_mem->ida_tn-tout)*IDA_mem->ida_hh >= ZERO ) { + } else if ( itask == IDA_NORMAL ) { + + /* When in normal mode, check if tout was passed or if a previous root was + not reported and return an interpolated solution. No changes to ck_mem + or dt_mem are needed. */ + + /* flag to signal if an early return is needed */ + earlyret = SUNFALSE; - /* If tout was passed, return interpolated solution. - No changes to ck_mem or dt_mem are needed. */ - *tret = tout; - flag = IDAGetSolution(IDA_mem, tout, yret, ypret); - *ncheckPtr = IDAADJ_mem->ia_nckpnts; - IDAADJ_mem->ia_newData = SUNTRUE; - IDAADJ_mem->ia_ckpntData = IDAADJ_mem->ck_mem; - IDAADJ_mem->ia_np = IDA_mem->ida_nst % IDAADJ_mem->ia_nsteps + 1; + /* if a root needs to be reported compare tout to troot otherwise compare + to the current time tn */ + ttest = (IDAADJ_mem->ia_rootret) ? IDAADJ_mem->ia_troot : IDA_mem->ida_tn; + + if ((ttest - tout)*IDA_mem->ida_hh >= ZERO) { + /* ttest is after tout, interpolate to tout */ + *tret = tout; + flag = IDAGetSolution(IDA_mem, tout, yret, ypret); + earlyret = SUNTRUE; + } else if (IDAADJ_mem->ia_rootret) { + /* tout is after troot, interpolate to troot */ + *tret = IDAADJ_mem->ia_troot; + flag = IDAGetSolution(IDA_mem, IDAADJ_mem->ia_troot, yret, ypret); + flag = IDA_ROOT_RETURN; + IDAADJ_mem->ia_rootret = SUNFALSE; + earlyret = SUNTRUE; + } + + /* return if necessary */ + if (earlyret) { + *ncheckPtr = IDAADJ_mem->ia_nckpnts; + IDAADJ_mem->ia_newData = SUNTRUE; + IDAADJ_mem->ia_ckpntData = IDAADJ_mem->ck_mem; + IDAADJ_mem->ia_np = IDA_mem->ida_nst % IDAADJ_mem->ia_nsteps + 1; + return(flag); + } - return(flag); } - /* Integrate to tout while loading check points */ + + /* Integrate to tout (in IDA_ONE_STEP mode) while loading check points */ for(;;) { /* Perform one step of the integration */ flag = IDASolve(IDA_mem, tout, tret, yret, ypret, IDA_ONE_STEP); - if (flag < 0) break; /* Test if a new check point is needed */ if ( IDA_mem->ida_nst % IDAADJ_mem->ia_nsteps == 0 ) { - IDAADJ_mem->ck_mem->ck_t1 = *tret; + IDAADJ_mem->ck_mem->ck_t1 = IDA_mem->ida_tn; /* Create a new check point, load it, and append it to the list */ tmp = IDAAckpntNew(IDA_mem); @@ -482,48 +504,60 @@ int IDASolveF(void *ida_mem, realtype tout, realtype *tret, tmp->ck_next = IDAADJ_mem->ck_mem; IDAADJ_mem->ck_mem = tmp; IDAADJ_mem->ia_nckpnts++; - + IDA_mem->ida_forceSetup = SUNTRUE; - + /* Reset i=0 and load dt_mem[0] */ dt_mem[0]->t = IDAADJ_mem->ck_mem->ck_t0; IDAADJ_mem->ia_storePnt(IDA_mem, dt_mem[0]); } else { - + /* Load next point in dt_mem */ - dt_mem[IDA_mem->ida_nst%IDAADJ_mem->ia_nsteps]->t = *tret; + dt_mem[IDA_mem->ida_nst%IDAADJ_mem->ia_nsteps]->t = IDA_mem->ida_tn; IDAADJ_mem->ia_storePnt(IDA_mem, dt_mem[IDA_mem->ida_nst % IDAADJ_mem->ia_nsteps]); + } /* Set t1 field of the current ckeck point structure for the case in which there will be no future check points */ - IDAADJ_mem->ck_mem->ck_t1 = *tret; + IDAADJ_mem->ck_mem->ck_t1 = IDA_mem->ida_tn; - /* tfinal is now set to *t */ - IDAADJ_mem->ia_tfinal = *tret; + /* tfinal is now set to tn */ + IDAADJ_mem->ia_tfinal = IDA_mem->ida_tn; - /* In IDA_ONE_STEP mode break from loop */ + /* Return if in IDA_ONE_STEP mode */ if (itask == IDA_ONE_STEP) break; - - /* Return if root reached */ - if ( flag == IDA_ROOT_RETURN ) { - IDAGetSolution(IDA_mem, *tret, yret, ypret); - break; - } + + /* IDA_NORMAL_STEP returns */ + /* Return if tout reached */ if ( (*tret - tout)*IDA_mem->ida_hh >= ZERO ) { + + /* If this was a root return, save the root time to return later */ + if (flag == IDA_ROOT_RETURN) { + IDAADJ_mem->ia_rootret = SUNTRUE; + IDAADJ_mem->ia_troot = *tret; + } + + /* Get solution value at tout to return now */ *tret = tout; - IDAGetSolution(IDA_mem, tout, yret, ypret); - /* Reset tretlast in IDA_mem so that IDAGetQuad and IDAGetSens + flag = IDAGetSolution(IDA_mem, tout, yret, ypret); + + /* Reset tretlast in IDA_mem so that IDAGetQuad and IDAGetSens * evaluate quadratures and/or sensitivities at the proper time */ IDA_mem->ida_tretlast = tout; + break; - } - } + } + + /* Return if tstop or a root was found */ + if ((flag == IDA_TSTOP_RETURN) || (flag == IDA_ROOT_RETURN)) break; - /* Get ncheck from IDAADJ_mem */ + } /* end of for(;;) */ + + /* Get ncheck from IDAADJ_mem */ *ncheckPtr = IDAADJ_mem->ia_nckpnts; /* Data is available for the last interval */ @@ -537,7 +571,7 @@ int IDASolveF(void *ida_mem, realtype tout, realtype *tret, -/* +/* * ================================================================= * FUNCTIONS FOR BACKWARD PROBLEMS * ================================================================= @@ -549,7 +583,7 @@ int IDACreateB(void *ida_mem, int *which) void* ida_memB; IDABMem new_IDAB_mem; IDAadjMem IDAADJ_mem; - + /* Is the mem OK? */ if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDACreateB", MSGAM_NULL_IDAMEM); @@ -570,7 +604,7 @@ int IDACreateB(void *ida_mem, int *which) IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAA", "IDACreateB", MSG_MEM_FAIL); return(IDA_MEM_FAIL); } - + /* Allocate the IDAMem struct needed by this backward problem. */ ida_memB = IDACreate(); if (ida_memB == NULL) { @@ -580,7 +614,7 @@ int IDACreateB(void *ida_mem, int *which) /* Save ida_mem in ida_memB as user data. */ IDASetUserData(ida_memB, ida_mem); - + /* Set same error output and handler for ida_memB. */ IDASetErrHandlerFn(ida_memB, IDA_mem->ida_ehfun, IDA_mem->ida_eh_data); IDASetErrFile(ida_memB, IDA_mem->ida_errfp); @@ -607,13 +641,13 @@ int IDACreateB(void *ida_mem, int *which) new_IDAB_mem->ida_res_withSensi = SUNFALSE; new_IDAB_mem->ida_rhsQ_withSensi = SUNFALSE; - + /* Attach the new object to the beginning of the linked list IDAADJ_mem->IDAB_mem. */ new_IDAB_mem->ida_next = IDAADJ_mem->IDAB_mem; IDAADJ_mem->IDAB_mem = new_IDAB_mem; - /* Return the assigned index. This id is used as identificator and has to be passed - to IDAInitB and other ***B functions that set the optional inputs for this + /* Return the assigned index. This id is used as identificator and has to be passed + to IDAInitB and other ***B functions that set the optional inputs for this backward problem. */ *which = IDAADJ_mem->ia_nbckpbs; @@ -657,7 +691,7 @@ int IDAInitB(void *ida_mem, int which, IDAResFnB resB, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAInitB", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -729,7 +763,7 @@ int IDAInitBS(void *ida_mem, int which, IDAResFnBS resS, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAInitBS", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -740,7 +774,7 @@ int IDAInitBS(void *ida_mem, int which, IDAResFnBS resS, /* Get the IDAMem corresponding to this backward problem. */ ida_memB = (void*) IDAB_mem->IDA_mem; - + /* Allocate and set the IDAS object */ flag = IDAInit(ida_memB, IDAAres, tB0, yyB0, ypB0); @@ -795,7 +829,7 @@ int IDAReInitB(void *ida_mem, int which, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAReInitB", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -813,14 +847,14 @@ int IDAReInitB(void *ida_mem, int which, return(flag); } -int IDASStolerancesB(void *ida_mem, int which, +int IDASStolerancesB(void *ida_mem, int which, realtype relTolB, realtype absTolB) { IDAMem IDA_mem; IDAadjMem IDAADJ_mem; IDABMem IDAB_mem; void *ida_memB; - + /* Is ida_mem valid? */ if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDASStolerancesB", MSGAM_NULL_IDAMEM); @@ -840,7 +874,7 @@ int IDASStolerancesB(void *ida_mem, int which, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASStolerancesB", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -854,16 +888,16 @@ int IDASStolerancesB(void *ida_mem, int which, /* Set tolerances and return. */ return IDASStolerances(ida_memB, relTolB, absTolB); - + } -int IDASVtolerancesB(void *ida_mem, int which, +int IDASVtolerancesB(void *ida_mem, int which, realtype relTolB, N_Vector absTolB) { IDAMem IDA_mem; IDAadjMem IDAADJ_mem; IDABMem IDAB_mem; void *ida_memB; - + /* Is ida_mem valid? */ if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDASVtolerancesB", MSGAM_NULL_IDAMEM); @@ -883,7 +917,7 @@ int IDASVtolerancesB(void *ida_mem, int which, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASVtolerancesB", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -906,7 +940,7 @@ int IDAQuadSStolerancesB(void *ida_mem, int which, IDAadjMem IDAADJ_mem; IDABMem IDAB_mem; void *ida_memB; - + /* Is ida_mem valid? */ if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAQuadSStolerancesB", MSGAM_NULL_IDAMEM); @@ -926,7 +960,7 @@ int IDAQuadSStolerancesB(void *ida_mem, int which, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAQuadSStolerancesB", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -935,7 +969,7 @@ int IDAQuadSStolerancesB(void *ida_mem, int which, IDAB_mem = IDAB_mem->ida_next; } ida_memB = (void *) IDAB_mem->IDA_mem; - + return IDAQuadSStolerances(ida_memB, reltolQB, abstolQB); } @@ -947,7 +981,7 @@ int IDAQuadSVtolerancesB(void *ida_mem, int which, IDAadjMem IDAADJ_mem; IDABMem IDAB_mem; void *ida_memB; - + /* Is ida_mem valid? */ if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAQuadSVtolerancesB", MSGAM_NULL_IDAMEM); @@ -967,7 +1001,7 @@ int IDAQuadSVtolerancesB(void *ida_mem, int which, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAQuadSVtolerancesB", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -976,7 +1010,7 @@ int IDAQuadSVtolerancesB(void *ida_mem, int which, IDAB_mem = IDAB_mem->ida_next; } ida_memB = (void *) IDAB_mem->IDA_mem; - + return IDAQuadSVtolerances(ida_memB, reltolQB, abstolQB); } @@ -988,7 +1022,7 @@ int IDAQuadInitB(void *ida_mem, int which, IDAQuadRhsFnB rhsQB, N_Vector yQB0) IDABMem IDAB_mem; void *ida_memB; int flag; - + /* Is ida_mem valid? */ if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAQuadInitB", MSGAM_NULL_IDAMEM); @@ -1008,7 +1042,7 @@ int IDAQuadInitB(void *ida_mem, int which, IDAQuadRhsFnB rhsQB, N_Vector yQB0) IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAQuadInitB", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -1028,7 +1062,7 @@ int IDAQuadInitB(void *ida_mem, int which, IDAQuadRhsFnB rhsQB, N_Vector yQB0) } -int IDAQuadInitBS(void *ida_mem, int which, +int IDAQuadInitBS(void *ida_mem, int which, IDAQuadRhsFnBS rhsQS, N_Vector yQB0) { IDAadjMem IDAADJ_mem; @@ -1055,7 +1089,7 @@ int IDAQuadInitBS(void *ida_mem, int which, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAQuadInitBS", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -1066,7 +1100,7 @@ int IDAQuadInitBS(void *ida_mem, int which, /* Get the IDAMem corresponding to this backward problem. */ ida_memB = (void*) IDAB_mem->IDA_mem; - + /* Allocate and set the IDAS object */ flag = IDAQuadInit(ida_memB, IDAArhsQ, yQB0); @@ -1085,7 +1119,8 @@ int IDAQuadReInitB(void *ida_mem, int which, N_Vector yQB0) IDAMem IDA_mem; IDAadjMem IDAADJ_mem; IDABMem IDAB_mem; - + void *ida_memB; + /* Is ida_mem valid? */ if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAQuadInitB", MSGAM_NULL_IDAMEM); @@ -1105,7 +1140,7 @@ int IDAQuadReInitB(void *ida_mem, int which, N_Vector yQB0) IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAQuadInitB", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -1113,25 +1148,26 @@ int IDAQuadReInitB(void *ida_mem, int which, N_Vector yQB0) /* advance */ IDAB_mem = IDAB_mem->ida_next; } + ida_memB = (void *) IDAB_mem->IDA_mem; - return IDAQuadReInit(ida_mem, yQB0); + return IDAQuadReInit(ida_memB, yQB0); } /* * ---------------------------------------------------------------- - * Function : IDACalcICB + * Function : IDACalcICB * ---------------------------------------------------------------- - * IDACalcIC calculates corrected initial conditions for a DAE + * IDACalcIC calculates corrected initial conditions for a DAE * backward system (index-one in semi-implicit form). - * It uses Newton iteration combined with a Linesearch algorithm. - * Calling IDACalcICB is optional. It is only necessary when the - * initial conditions do not solve the given system. I.e., if - * yB0 and ypB0 are known to satisfy the backward problem, then - * a call to IDACalcIC is NOT necessary (for index-one problems). + * It uses Newton iteration combined with a Linesearch algorithm. + * Calling IDACalcICB is optional. It is only necessary when the + * initial conditions do not solve the given system. I.e., if + * yB0 and ypB0 are known to satisfy the backward problem, then + * a call to IDACalcIC is NOT necessary (for index-one problems). */ -int IDACalcICB(void *ida_mem, int which, realtype tout1, +int IDACalcICB(void *ida_mem, int which, realtype tout1, N_Vector yy0, N_Vector yp0) { IDAMem IDA_mem; @@ -1139,7 +1175,7 @@ int IDACalcICB(void *ida_mem, int which, realtype tout1, IDABMem IDAB_mem; void *ida_memB; int flag; - + /* Is ida_mem valid? */ if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDACalcICB", MSGAM_NULL_IDAMEM); @@ -1159,7 +1195,7 @@ int IDACalcICB(void *ida_mem, int which, realtype tout1, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDACalcICB", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -1177,11 +1213,11 @@ int IDACalcICB(void *ida_mem, int which, realtype tout1, /* yyTmp and ypTmp workspaces are safe to use if IDAADataStore is not called.*/ N_VScale(ONE, yy0, IDAADJ_mem->ia_yyTmp); N_VScale(ONE, yp0, IDAADJ_mem->ia_ypTmp); - + /* Set noInterp flag to SUNTRUE, so IDAARes will use user provided values for y and y' and will not call the interpolation routine(s). */ IDAADJ_mem->ia_noInterp = SUNTRUE; - + flag = IDACalcIC(ida_memB, IDA_YA_YDP_INIT, tout1); /* Set interpolation on in IDAARes. */ @@ -1192,17 +1228,17 @@ int IDACalcICB(void *ida_mem, int which, realtype tout1, /* * ---------------------------------------------------------------- - * Function : IDACalcICBS + * Function : IDACalcICBS * ---------------------------------------------------------------- - * IDACalcIC calculates corrected initial conditions for a DAE - * backward system (index-one in semi-implicit form) that also + * IDACalcIC calculates corrected initial conditions for a DAE + * backward system (index-one in semi-implicit form) that also * dependes on the sensivities. * * It calls IDACalcIC for the 'which' backward problem. */ -int IDACalcICBS(void *ida_mem, int which, realtype tout1, - N_Vector yy0, N_Vector yp0, +int IDACalcICBS(void *ida_mem, int which, realtype tout1, + N_Vector yy0, N_Vector yp0, N_Vector *yyS0, N_Vector *ypS0) { IDAMem IDA_mem; @@ -1210,7 +1246,7 @@ int IDACalcICBS(void *ida_mem, int which, realtype tout1, IDABMem IDAB_mem; void *ida_memB; int flag, is, retval; - + /* Is ida_mem valid? */ if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDACalcICBS", MSGAM_NULL_IDAMEM); @@ -1236,7 +1272,7 @@ int IDACalcICBS(void *ida_mem, int which, realtype tout1, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDACalcICBS", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -1249,14 +1285,14 @@ int IDACalcICBS(void *ida_mem, int which, realtype tout1, /* Was InitBS called for this problem? */ if (!IDAB_mem->ida_res_withSensi) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDACalcICBS", MSGAM_NO_INITBS); - return(IDA_ILL_INPUT); + return(IDA_ILL_INPUT); } /* The wrapper for user supplied res function requires ia_bckpbCrt from IDAAdjMem to be set to curent problem. */ IDAADJ_mem->ia_bckpbCrt = IDAB_mem; - /* Save (y, y') and (y_p, y'_p) in yyTmp, ypTmp and yySTmp, ypSTmp.The wrapper + /* Save (y, y') and (y_p, y'_p) in yyTmp, ypTmp and yySTmp, ypSTmp.The wrapper for residual will use these values instead of calling interpolation routine.*/ /* The four workspaces variables are safe to use if IDAADataStore is not called.*/ @@ -1273,11 +1309,11 @@ int IDACalcICBS(void *ida_mem, int which, realtype tout1, retval = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, ypS0, IDAADJ_mem->ia_ypSTmp); if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); - + /* Set noInterp flag to SUNTRUE, so IDAARes will use user provided values for y and y' and will not call the interpolation routine(s). */ IDAADJ_mem->ia_noInterp = SUNTRUE; - + flag = IDACalcIC(ida_memB, IDA_YA_YDP_INIT, tout1); /* Set interpolation on in IDAARes. */ @@ -1290,7 +1326,7 @@ int IDACalcICBS(void *ida_mem, int which, realtype tout1, /* * IDASolveB * - * This routine performs the backward integration from tB0 + * This routine performs the backward integration from tB0 * to tinitial through a sequence of forward-backward runs in * between consecutive check points. It returns the values of * the adjoint variables and any existing quadrature variables @@ -1298,8 +1334,8 @@ int IDACalcICBS(void *ida_mem, int which, realtype tout1, * * On a successful return, IDASolveB returns IDA_SUCCESS. * - * NOTE that IDASolveB DOES NOT return the solution for the - * backward problem(s). Use IDAGetB to extract the solution + * NOTE that IDASolveB DOES NOT return the solution for the + * backward problem(s). Use IDAGetB to extract the solution * for any given backward problem. * * If there are multiple backward problems and multiple check points, @@ -1353,13 +1389,13 @@ int IDASolveB(void *ida_mem, realtype tBout, int itaskB) /* First IDABMem struct. */ tmp_IDAB_mem = IDAB_mem; - + while (tmp_IDAB_mem != NULL) { tBn = tmp_IDAB_mem->IDA_mem->ida_tn; if ( (sign*(tBn-IDAADJ_mem->ia_tinitial) < ZERO) || (sign*(IDAADJ_mem->ia_tfinal-tBn) < ZERO) ) { - IDAProcessError(IDA_mem, IDA_BAD_TB0, "IDAA", "IDASolveB", + IDAProcessError(IDA_mem, IDA_BAD_TB0, "IDAA", "IDASolveB", MSGAM_BAD_TB0, tmp_IDAB_mem->ida_index); return(IDA_BAD_TB0); } @@ -1370,12 +1406,12 @@ int IDASolveB(void *ida_mem, realtype tBout, int itaskB) return(IDA_ILL_INPUT); } - if ( tmp_IDAB_mem->ida_res_withSensi || + if ( tmp_IDAB_mem->ida_res_withSensi || tmp_IDAB_mem->ida_rhsQ_withSensi ) IDAADJ_mem->ia_interpSensi = SUNTRUE; /* Advance in list. */ - tmp_IDAB_mem = tmp_IDAB_mem->ida_next; + tmp_IDAB_mem = tmp_IDAB_mem->ida_next; } if ( IDAADJ_mem->ia_interpSensi && !IDAADJ_mem->ia_storeSensi) { @@ -1464,14 +1500,14 @@ int IDASolveB(void *ida_mem, realtype tBout, int itaskB) if ( sign*(tBn - ck_mem->ck_t0) < ZERO ) isActive = SUNFALSE; if ( isActive ) { - /* Store the address of current backward problem memory + /* Store the address of current backward problem memory * in IDAADJ_mem to be used in the wrapper functions */ IDAADJ_mem->ia_bckpbCrt = tmp_IDAB_mem; /* Integrate current backward problem */ IDASetStopTime(tmp_IDAB_mem->IDA_mem, ck_mem->ck_t0); - flag = IDASolve(tmp_IDAB_mem->IDA_mem, tBout, &tBret, - tmp_IDAB_mem->ida_yy, tmp_IDAB_mem->ida_yp, + flag = IDASolve(tmp_IDAB_mem->IDA_mem, tBout, &tBret, + tmp_IDAB_mem->ida_yy, tmp_IDAB_mem->ida_yp, itaskB); /* Set the time at which we will report solution and/or quadratures */ @@ -1489,7 +1525,7 @@ int IDASolveB(void *ida_mem, realtype tBout, int itaskB) /* Move to next backward problem */ tmp_IDAB_mem = tmp_IDAB_mem->ida_next; } /* End of while: iteration through backward problems. */ - + /* If an error occurred, return now */ if (flag <0) { IDAProcessError(IDA_mem, flag, "IDAA", "IDASolveB", @@ -1526,7 +1562,7 @@ int IDASolveB(void *ida_mem, realtype tBout, int itaskB) /* * IDAGetB * - * IDAGetB returns the state variables at the same time (also returned + * IDAGetB returns the state variables at the same time (also returned * in tret) as that at which IDASolveBreturned the solution. */ @@ -1536,7 +1572,7 @@ SUNDIALS_EXPORT int IDAGetB(void* ida_mem, int which, realtype *tret, IDAMem IDA_mem; IDAadjMem IDAADJ_mem; IDABMem IDAB_mem; - + /* Is ida_mem valid? */ if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAGetB", MSGAM_NULL_IDAMEM); @@ -1556,7 +1592,7 @@ SUNDIALS_EXPORT int IDAGetB(void* ida_mem, int which, realtype *tret, IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAGetB", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -1577,8 +1613,8 @@ SUNDIALS_EXPORT int IDAGetB(void* ida_mem, int which, realtype *tret, /* * IDAGetQuadB * - * IDAGetQuadB returns the quadrature variables at the same - * time (also returned in tret) as that at which IDASolveB + * IDAGetQuadB returns the quadrature variables at the same + * time (also returned in tret) as that at which IDASolveB * returned the solution. */ @@ -1590,7 +1626,7 @@ int IDAGetQuadB(void *ida_mem, int which, realtype *tret, N_Vector qB) void *ida_memB; int flag; long int nstB; - + /* Is ida_mem valid? */ if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAGetQuadB", MSGAM_NULL_IDAMEM); @@ -1610,7 +1646,7 @@ int IDAGetQuadB(void *ida_mem, int which, realtype *tret, N_Vector qB) IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAGetQuadB", MSGAM_BAD_WHICH); return(IDA_ILL_INPUT); } - + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ IDAB_mem = IDAADJ_mem->IDAB_mem; while (IDAB_mem != NULL) { @@ -1642,7 +1678,7 @@ int IDAGetQuadB(void *ida_mem, int which, realtype *tret, N_Vector qB) /* * IDAAckpntInit * - * This routine initializes the check point linked list with + * This routine initializes the check point linked list with * information from the initial time. */ @@ -1671,7 +1707,7 @@ static CkpntMem IDAAckpntInit(IDAMem IDA_mem) /* Alloc 3: current order, i.e. 1, + 2. */ ck_mem->ck_phi_alloc = 3; - + if (!IDAAckpntAllocVectors(IDA_mem, ck_mem)) { free(ck_mem); ck_mem = NULL; return(NULL); @@ -1688,7 +1724,7 @@ static CkpntMem IDAAckpntInit(IDAMem IDA_mem) /* * IDAAckpntNew * - * This routine allocates space for a new check point and sets + * This routine allocates space for a new check point and sets * its data from current values in IDA_mem. */ @@ -1751,7 +1787,7 @@ static CkpntMem IDAAckpntNew(IDAMem IDA_mem) return(ck_mem); } -/* IDAAckpntDelete +/* IDAAckpntDelete * * This routine deletes the first check point in list. */ @@ -1768,23 +1804,23 @@ static void IDAAckpntDelete(CkpntMem *ck_memPtr) *ck_memPtr = (*ck_memPtr)->ck_next; /* free N_Vectors in tmp */ - for (j=0; jck_phi_alloc; j++) + for (j=0; jck_phi_alloc; j++) N_VDestroy(tmp->ck_phi[j]); /* free N_Vectors for quadratures in tmp */ if (tmp->ck_quadr) { - for (j=0; jck_phi_alloc; j++) + for (j=0; jck_phi_alloc; j++) N_VDestroy(tmp->ck_phiQ[j]); } /* Free sensitivity related data. */ if (tmp->ck_sensi) { - for (j=0; jck_phi_alloc; j++) + for (j=0; jck_phi_alloc; j++) N_VDestroyVectorArray(tmp->ck_phiS[j], tmp->ck_Ns); } - + if (tmp->ck_quadr_sensi) { - for (j=0; jck_phi_alloc; j++) + for (j=0; jck_phi_alloc; j++) N_VDestroyVectorArray(tmp->ck_phiQS[j], tmp->ck_Ns); } @@ -1792,10 +1828,10 @@ static void IDAAckpntDelete(CkpntMem *ck_memPtr) } } -/* +/* * IDAAckpntAllocVectors * - * Allocate checkpoint's phi, phiQ, phiS, phiQS vectors needed to save + * Allocate checkpoint's phi, phiQ, phiS, phiQS vectors needed to save * current state of IDAMem. * */ @@ -1805,7 +1841,7 @@ static booleantype IDAAckpntAllocVectors(IDAMem IDA_mem, CkpntMem ck_mem) for (j=0; jck_phi_alloc; j++) { ck_mem->ck_phi[j] = N_VClone(IDA_mem->ida_tempv1); - if(ck_mem->ck_phi[j] == NULL) { + if(ck_mem->ck_phi[j] == NULL) { for(jj=0; jjck_phi[jj]); return(SUNFALSE); } @@ -1815,7 +1851,7 @@ static booleantype IDAAckpntAllocVectors(IDAMem IDA_mem, CkpntMem ck_mem) if(ck_mem->ck_quadr) { for (j=0; jck_phi_alloc; j++) { ck_mem->ck_phiQ[j] = N_VClone(IDA_mem->ida_eeQ); - if(ck_mem->ck_phiQ[j] == NULL) { + if(ck_mem->ck_phiQ[j] == NULL) { for (jj=0; jjck_phiQ[jj]); for(jj=0; jjck_phi_alloc; jj++) @@ -1860,7 +1896,7 @@ static booleantype IDAAckpntAllocVectors(IDAMem IDA_mem, CkpntMem ck_mem) for (jj=0; jjck_phi_alloc; jj++) N_VDestroyVectorArray(ck_mem->ck_phiS[jj], IDA_mem->ida_Ns); - if (ck_mem->ck_quadr) + if (ck_mem->ck_quadr) for (jj=0; jjck_phi_alloc; jj++) N_VDestroy(ck_mem->ck_phiQ[jj]); @@ -1874,7 +1910,7 @@ static booleantype IDAAckpntAllocVectors(IDAMem IDA_mem, CkpntMem ck_mem) return(SUNTRUE); } -/* +/* * IDAAckpntCopyVectors * * Copy phi* vectors from IDAMem in the corresponding vectors from checkpoint @@ -1936,8 +1972,8 @@ static void IDAAckpntCopyVectors(IDAMem IDA_mem, CkpntMem ck_mem) * IDAAdataMalloc * * This routine allocates memory for storing information at all - * intermediate points between two consecutive check points. - * This data is then used to interpolate the forward solution + * intermediate points between two consecutive check points. + * This data is then used to interpolate the forward solution * at any other time. */ @@ -1954,13 +1990,13 @@ static booleantype IDAAdataMalloc(IDAMem IDA_mem) if (dt_mem==NULL) return(SUNFALSE); for (i=0; i<=IDAADJ_mem->ia_nsteps; i++) { - + dt_mem[i] = (DtpntMem)malloc(sizeof(struct DtpntMemRec)); - + /* On failure, free any allocated memory and return NULL. */ if (dt_mem[i] == NULL) { - for(j=0; jck_next == NULL) { /* In this case, we just call the reinitialization routine, - * but make sure we use the same initial stepsize as on + * but make sure we use the same initial stepsize as on * the first run. */ IDASetInitStep(IDA_mem, IDA_mem->ida_h0u); @@ -2121,7 +2157,7 @@ static int IDAAckpntGet(IDAMem IDA_mem, CkpntMem ck_mem) IDA_mem->ida_ss = ck_mem->ck_ss; IDA_mem->ida_ssS = ck_mem->ck_ssS; - + /* Copy the arrays from check point data structure */ for (j=0; jck_phi_alloc; j++) N_VScale(ONE, ck_mem->ck_phi[j], IDA_mem->ida_phi[j]); @@ -2161,7 +2197,7 @@ static int IDAAckpntGet(IDAMem IDA_mem, CkpntMem ck_mem) } -/* +/* * ----------------------------------------------------------------- * Functions specific to cubic Hermite interpolation * ----------------------------------------------------------------- @@ -2171,8 +2207,8 @@ static int IDAAckpntGet(IDAMem IDA_mem, CkpntMem ck_mem) * IDAAhermiteMalloc * * This routine allocates memory for storing information at all - * intermediate points between two consecutive check points. - * This data is then used to interpolate the forward solution + * intermediate points between two consecutive check points. + * This data is then used to interpolate the forward solution * at any other time. */ @@ -2200,7 +2236,7 @@ static booleantype IDAAhermiteMalloc(IDAMem IDA_mem) /* Allocate space for sensitivities temporary vectors. */ if (IDAADJ_mem->ia_storeSensi) { - + IDAADJ_mem->ia_yySTmp = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_tempv1); if (IDAADJ_mem->ia_yySTmp == NULL) { N_VDestroy(IDAADJ_mem->ia_yyTmp); @@ -2250,7 +2286,7 @@ static booleantype IDAAhermiteMalloc(IDAMem IDA_mem) } if (IDAADJ_mem->ia_storeSensi) { - + content->yS = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_tempv1); if (content->yS == NULL) { N_VDestroy(content->y); @@ -2272,19 +2308,19 @@ static booleantype IDAAhermiteMalloc(IDAMem IDA_mem) break; } } - + dt_mem[i]->content = content; - } + } /* If an error occurred, deallocate and return */ if (!allocOK) { N_VDestroy(IDAADJ_mem->ia_yyTmp); - N_VDestroy(IDAADJ_mem->ia_ypTmp); + N_VDestroy(IDAADJ_mem->ia_ypTmp); - if (IDAADJ_mem->ia_storeSensi) { + if (IDAADJ_mem->ia_storeSensi) { N_VDestroyVectorArray(IDAADJ_mem->ia_yySTmp, IDA_mem->ida_Ns); N_VDestroyVectorArray(IDAADJ_mem->ia_ypSTmp, IDA_mem->ida_Ns); } @@ -2296,7 +2332,7 @@ static booleantype IDAAhermiteMalloc(IDAMem IDA_mem) if (IDAADJ_mem->ia_storeSensi) { N_VDestroyVectorArray(content->yS, IDA_mem->ida_Ns); - N_VDestroyVectorArray(content->ySd, IDA_mem->ida_Ns); + N_VDestroyVectorArray(content->ySd, IDA_mem->ida_Ns); } free(dt_mem[i]->content); dt_mem[i]->content = NULL; @@ -2314,7 +2350,7 @@ static booleantype IDAAhermiteMalloc(IDAMem IDA_mem) */ static void IDAAhermiteFree(IDAMem IDA_mem) -{ +{ IDAadjMem IDAADJ_mem; DtpntMem *dt_mem; HermiteDataMem content; @@ -2325,7 +2361,7 @@ static void IDAAhermiteFree(IDAMem IDA_mem) N_VDestroy(IDAADJ_mem->ia_yyTmp); N_VDestroy(IDAADJ_mem->ia_ypTmp); - if (IDAADJ_mem->ia_storeSensi) { + if (IDAADJ_mem->ia_storeSensi) { N_VDestroyVectorArray(IDAADJ_mem->ia_yySTmp, IDA_mem->ida_Ns); N_VDestroyVectorArray(IDAADJ_mem->ia_ypSTmp, IDA_mem->ida_Ns); } @@ -2343,9 +2379,9 @@ static void IDAAhermiteFree(IDAMem IDA_mem) if (IDAADJ_mem->ia_storeSensi) { N_VDestroyVectorArray(content->yS, IDA_mem->ida_Ns); - N_VDestroyVectorArray(content->ySd, IDA_mem->ida_Ns); + N_VDestroyVectorArray(content->ySd, IDA_mem->ida_Ns); } - free(dt_mem[i]->content); + free(dt_mem[i]->content); dt_mem[i]->content = NULL; } } @@ -2371,7 +2407,7 @@ static int IDAAhermiteStorePnt(IDAMem IDA_mem, DtpntMem d) /* Load solution(s) */ N_VScale(ONE, IDA_mem->ida_phi[0], content->y); - + if (IDAADJ_mem->ia_storeSensi) { for (is=0; isida_Ns; is++) IDA_mem->ida_cvals[is] = ONE; @@ -2395,8 +2431,8 @@ static int IDAAhermiteStorePnt(IDAMem IDA_mem, DtpntMem d) /* * IDAAhermiteGetY * - * This routine uses cubic piece-wise Hermite interpolation for - * the forward solution vector. + * This routine uses cubic piece-wise Hermite interpolation for + * the forward solution vector. * It is typically called by the wrapper routines before calling * user provided routines (fB, djacB, bjacB, jtimesB, psolB) but * can be directly called by the user through IDAGetAdjY @@ -2425,10 +2461,10 @@ static int IDAAhermiteGetY(IDAMem IDA_mem, realtype t, realtype cvals[4]; N_Vector Xvecs[4]; N_Vector* XXvecs[4]; - + IDAADJ_mem = IDA_mem->ida_adj_mem; dt_mem = IDAADJ_mem->dt_mem; - + /* Local value of Ns */ NS = (IDAADJ_mem->ia_interpSensi && (yyS != NULL)) ? IDA_mem->ida_Ns : 0; @@ -2472,7 +2508,7 @@ static int IDAAhermiteGetY(IDAMem IDA_mem, realtype t, } if (newpoint) { - + /* Recompute Y0 and Y1 */ content1 = (HermiteDataMem) (dt_mem[indx]->content); @@ -2579,7 +2615,7 @@ static int IDAAhermiteGetY(IDAMem IDA_mem, realtype t, retval = N_VLinearCombination(3, cvals, Xvecs, yp); if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); - + /* Sensi interpolation for 1st derivative. */ /* ypS = ySd0 + factor1 YS[0] + factor 2 YS[1], if needed */ @@ -2597,18 +2633,18 @@ static int IDAAhermiteGetY(IDAMem IDA_mem, realtype t, return(IDA_SUCCESS); } -/* +/* * ----------------------------------------------------------------- * Functions specific to Polynomial interpolation * ----------------------------------------------------------------- */ /* - * IDAApolynomialMalloc + * IDAApolynomialMalloc * * This routine allocates memory for storing information at all - * intermediate points between two consecutive check points. - * This data is then used to interpolate the forward solution + * intermediate points between two consecutive check points. + * This data is then used to interpolate the forward solution * at any other time. * * Information about the first derivative is stored only for the first @@ -2638,7 +2674,7 @@ static booleantype IDAApolynomialMalloc(IDAMem IDA_mem) } if (IDAADJ_mem->ia_storeSensi) { - + IDAADJ_mem->ia_yySTmp = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_tempv1); if (IDAADJ_mem->ia_yySTmp == NULL) { N_VDestroy(IDAADJ_mem->ia_yyTmp); @@ -2680,7 +2716,7 @@ static booleantype IDAApolynomialMalloc(IDAMem IDA_mem) /* Allocate space for yp also. Needed for the most left point interpolation. */ if (i == 0) { content->yd = N_VClone(IDA_mem->ida_tempv1); - + /* Memory allocation failure ? */ if (content->yd == NULL) { N_VDestroy(content->y); @@ -2694,7 +2730,7 @@ static booleantype IDAApolynomialMalloc(IDAMem IDA_mem) } if (IDAADJ_mem->ia_storeSensi) { - + content->yS = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_tempv1); if (content->yS == NULL) { N_VDestroy(content->y); @@ -2704,7 +2740,7 @@ static booleantype IDAApolynomialMalloc(IDAMem IDA_mem) allocOK = SUNFALSE; break; } - + if (i==0) { content->ySd = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_tempv1); if (content->ySd == NULL) { @@ -2721,7 +2757,7 @@ static booleantype IDAApolynomialMalloc(IDAMem IDA_mem) } dt_mem[i]->content = content; - } + } /* If an error occurred, deallocate and return */ if (!allocOK) { @@ -2731,7 +2767,7 @@ static booleantype IDAApolynomialMalloc(IDAMem IDA_mem) if (IDAADJ_mem->ia_storeSensi) { N_VDestroyVectorArray(IDAADJ_mem->ia_yySTmp, IDA_mem->ida_Ns); - N_VDestroyVectorArray(IDAADJ_mem->ia_ypSTmp, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDAADJ_mem->ia_ypSTmp, IDA_mem->ida_Ns); } for (i=0; iyd) N_VDestroy(content->yd); if (IDAADJ_mem->ia_storeSensi) { - + N_VDestroyVectorArray(content->yS, IDA_mem->ida_Ns); - + if (content->ySd) N_VDestroyVectorArray(content->ySd, IDA_mem->ida_Ns); } @@ -2790,9 +2826,9 @@ static void IDAApolynomialFree(IDAMem IDA_mem) if (content->yd) N_VDestroy(content->yd); if (IDAADJ_mem->ia_storeSensi) { - + N_VDestroyVectorArray(content->yS, IDA_mem->ida_Ns); - + if (content->ySd) N_VDestroyVectorArray(content->ySd, IDA_mem->ida_Ns); } @@ -2807,8 +2843,8 @@ static void IDAApolynomialFree(IDAMem IDA_mem) * This routine stores a new point y in the structure d for use * in the Polynomial interpolation. * - * Note that the time is already stored. Information about the - * first derivative is available only for the first data point, + * Note that the time is already stored. Information about the + * first derivative is available only for the first data point, * in which case content->yp is non-null. */ @@ -2829,14 +2865,14 @@ static int IDAApolynomialStorePnt(IDAMem IDA_mem, DtpntMem d) IDAAGettnSolutionYp(IDA_mem, content->yd); if (IDAADJ_mem->ia_storeSensi) { - + for (is=0; isida_Ns; is++) IDA_mem->ida_cvals[is] = ONE; retval = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, IDA_mem->ida_phiS[0], content->yS); if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); - + /* store the derivative if it is the first data point. */ if(content->ySd) IDAAGettnSolutionYpS(IDA_mem, content->ySd); @@ -2850,7 +2886,7 @@ static int IDAApolynomialStorePnt(IDAMem IDA_mem, DtpntMem d) /* * IDAApolynomialGetY * - * This routine uses polynomial interpolation for the forward solution vector. + * This routine uses polynomial interpolation for the forward solution vector. * It is typically called by the wrapper routines before calling * user provided routines (fB, djacB, bjacB, jtimesB, psolB)) but * can be directly called by the user through CVodeGetAdjY. @@ -2871,7 +2907,7 @@ static int IDAApolynomialGetY(IDAMem IDA_mem, realtype t, IDAADJ_mem = IDA_mem->ida_adj_mem; dt_mem = IDAADJ_mem->dt_mem; - + /* Local value of Ns */ NS = (IDAADJ_mem->ia_interpSensi && (yyS != NULL)) ? IDA_mem->ida_Ns : 0; @@ -2950,7 +2986,7 @@ static int IDAApolynomialGetY(IDAMem IDA_mem, realtype t, if (NS > 0) { for (is=0; isida_cvals[is] = ONE; - retval = N_VScaleVectorArray(NS, IDA_mem->ida_cvals, + retval = N_VScaleVectorArray(NS, IDA_mem->ida_cvals, content->yS, IDAADJ_mem->ia_YS[j]); if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); } @@ -2963,7 +2999,7 @@ static int IDAApolynomialGetY(IDAMem IDA_mem, realtype t, factor = delt/(IDAADJ_mem->ia_T[j]-IDAADJ_mem->ia_T[j-i]); N_VLinearSum(factor, IDAADJ_mem->ia_Y[j], -factor, IDAADJ_mem->ia_Y[j-1], IDAADJ_mem->ia_Y[j]); - for (is=0; isia_YS[j][is], -factor, IDAADJ_mem->ia_YS[j-1][is], IDAADJ_mem->ia_YS[j][is]); } @@ -2983,15 +3019,15 @@ static int IDAApolynomialGetY(IDAMem IDA_mem, realtype t, retval = N_VLinearCombinationVectorArray(NS, order+1, IDA_mem->ida_cvals, IDAADJ_mem->ia_YS, yyS); if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); } - + /* Perform the actual interpolation for yp. Writing p(t) = y0 + (t-t0)*f[t0,t1] + ... + (t-t0)(t-t1)...(t-tn)*f[t0,t1,...tn], denote psi_k(t) = (t-t0)(t-t1)...(t-tk). - The formula used for p'(t) is: + The formula used for p'(t) is: - p'(t) = f[t0,t1] + psi_1'(t)*f[t0,t1,t2] + ... + psi_n'(t)*f[t0,t1,...,tn] - + We reccursively compute psi_k'(t) from: - psi_k'(t) = (t-tk)*psi_{k-1}'(t) + psi_{k-1} @@ -3000,7 +3036,7 @@ static int IDAApolynomialGetY(IDAMem IDA_mem, realtype t, */ Psi = ONE; - Psiprime = ZERO; + Psiprime = ZERO; for(i=1; i<=order; i++) { factor = (t-IDAADJ_mem->ia_T[i-1])/delt; @@ -3022,16 +3058,16 @@ static int IDAApolynomialGetY(IDAMem IDA_mem, realtype t, return(IDA_SUCCESS); } -/* +/* * IDAAGettnSolutionYp * * Evaluates the first derivative of the solution at the last time returned by * IDASolve (tretlast). - * - * The function implements the same algorithm as in IDAGetSolution but in the + * + * The function implements the same algorithm as in IDAGetSolution but in the * particular case when t=tn (i.e. delta=0). * - * This function was implemented to avoid calls to IDAGetSolution which computes + * This function was implemented to avoid calls to IDAGetSolution which computes * y by doing a loop that is not necessary for this particular situation. */ @@ -3049,10 +3085,10 @@ static int IDAAGettnSolutionYp(IDAMem IDA_mem, N_Vector yp) } /* Compute yp as in IDAGetSolution for this particular case when t=tn. */ - + kord = IDA_mem->ida_kused; if(IDA_mem->ida_kused==0) kord=1; - + C = ONE; D = ZERO; gam = ZERO; for (j=1; j <= kord; j++) { @@ -3071,7 +3107,7 @@ static int IDAAGettnSolutionYp(IDAMem IDA_mem, N_Vector yp) } -/* +/* * IDAAGettnSolutionYpS * * Same as IDAAGettnSolutionYp, but for first derivative of the sensitivities. @@ -3095,17 +3131,17 @@ static int IDAAGettnSolutionYpS(IDAMem IDA_mem, N_Vector *ypS) return(0); } - + kord = IDA_mem->ida_kused; if(IDA_mem->ida_kused==0) kord=1; - + C = ONE; D = ZERO; gam = ZERO; for (j=1; j <= kord; j++) { D = D*gam + C/IDA_mem->ida_psi[j-1]; C = C*gam; gam = IDA_mem->ida_psi[j-1] / IDA_mem->ida_psi[j]; - + IDA_mem->ida_dvals[j-1] = D; } @@ -3132,7 +3168,7 @@ static int IDAAGettnSolutionYpS(IDAMem IDA_mem, N_Vector *ypS) * find indx (t is too far beyond limits). */ -static int IDAAfindIndex(IDAMem ida_mem, realtype t, +static int IDAAfindIndex(IDAMem ida_mem, realtype t, long int *indx, booleantype *newpoint) { IDAadjMem IDAADJ_mem; @@ -3165,7 +3201,7 @@ static int IDAAfindIndex(IDAMem ida_mem, realtype t, /* look for a new indx to the left */ *newpoint = SUNTRUE; - + *indx = IDAADJ_mem->ia_ilast; for(;;) { if ( *indx == 0 ) break; @@ -3179,7 +3215,7 @@ static int IDAAfindIndex(IDAMem ida_mem, realtype t, IDAADJ_mem->ia_ilast = *indx; if ( *indx == 0 ) { - /* t is beyond leftmost limit. Is it too far? */ + /* t is beyond leftmost limit. Is it too far? */ if ( SUNRabs(t - dt_mem[0]->t) > FUZZ_FACTOR * IDA_mem->ida_uround ) { return(IDA_GETY_BADT); } @@ -3225,7 +3261,7 @@ int IDAGetAdjY(void *ida_mem, realtype t, N_Vector yy, N_Vector yp) IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAGetAdjY", MSG_NO_MEM); return(IDA_MEM_NULL); } - IDA_mem = (IDAMem) ida_mem; + IDA_mem = (IDAMem) ida_mem; IDAADJ_mem = IDA_mem->ida_adj_mem; flag = IDAADJ_mem->ia_getY(IDA_mem, t, yy, yp, NULL, NULL); @@ -3244,8 +3280,8 @@ int IDAGetAdjY(void *ida_mem, realtype t, N_Vector yy, N_Vector yp) * the user. */ -static int IDAAres(realtype tt, - N_Vector yyB, N_Vector ypB, N_Vector rrB, +static int IDAAres(realtype tt, + N_Vector yyB, N_Vector ypB, N_Vector rrB, void *ida_mem) { IDAadjMem IDAADJ_mem; @@ -3266,7 +3302,7 @@ static int IDAAres(realtype tt, flag = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp, IDAADJ_mem->ia_yySTmp, IDAADJ_mem->ia_ypSTmp); else flag = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp, NULL, NULL); - + if (flag != IDA_SUCCESS) { IDAProcessError(IDA_mem, -1, "IDAA", "IDAAres", MSGAM_BAD_TINTERP, tt); return(-1); @@ -3275,9 +3311,9 @@ static int IDAAres(realtype tt, /* Call the user supplied residual. */ if(IDAB_mem->ida_res_withSensi) { - retval = IDAB_mem->ida_resS(tt, IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp, + retval = IDAB_mem->ida_resS(tt, IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp, IDAADJ_mem->ia_yySTmp, IDAADJ_mem->ia_ypSTmp, - yyB, ypB, + yyB, ypB, rrB, IDAB_mem->ida_user_data); }else { retval = IDAB_mem->ida_res(tt, IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp, yyB, ypB, rrB, IDAB_mem->ida_user_data); @@ -3295,7 +3331,7 @@ static int IDAAres(realtype tt, * be of IDAQuadRhsFn type. */ -static int IDAArhsQ(realtype tt, +static int IDAArhsQ(realtype tt, N_Vector yyB, N_Vector ypB, N_Vector resvalQB, void *ida_mem) { @@ -3319,17 +3355,17 @@ static int IDAArhsQ(realtype tt, } else { flag = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp, NULL, NULL); } - + if (flag != IDA_SUCCESS) { IDAProcessError(IDA_mem, -1, "IDAA", "IDAArhsQ", MSGAM_BAD_TINTERP, tt); return(-1); - } + } } /* Call user's adjoint quadrature RHS routine */ if (IDAB_mem->ida_rhsQ_withSensi) { - retval = IDAB_mem->ida_rhsQS(tt, IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp, IDAADJ_mem->ia_yySTmp, IDAADJ_mem->ia_ypSTmp, - yyB, ypB, + retval = IDAB_mem->ida_rhsQS(tt, IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp, IDAADJ_mem->ia_yySTmp, IDAADJ_mem->ia_ypSTmp, + yyB, ypB, resvalQB, IDAB_mem->ida_user_data); } else { retval = IDAB_mem->ida_rhsQ(tt, @@ -3339,5 +3375,3 @@ static int IDAArhsQ(realtype tt, } return(retval); } - - diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idaa_io.c b/deps/AMICI/ThirdParty/sundials/src/idas/idaa_io.c index b328cd9c7..993e2469a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idaa_io.c +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idaa_io.c @@ -6,7 +6,7 @@ * Programmer(s): Radu Serban and Cosmin Petra @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas.c b/deps/AMICI/ThirdParty/sundials/src/idas/idas.c index 7770b400e..d196bc152 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas.c +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas.c @@ -1,9 +1,8 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -13,7 +12,6 @@ * SUNDIALS Copyright End * ----------------------------------------------------------------- * This is the implementation file for the main IDAS solver. - * It is independent of the linear solver in use. * ----------------------------------------------------------------- * * EXPORTED FUNCTIONS @@ -35,10 +33,8 @@ * IDAQuadSensInit * IDAQuadSensReInit * IDARootInit - * * Main solver function * IDASolve - * * Interpolated output and extraction functions * IDAGetDky * IDAGetQuad @@ -47,14 +43,13 @@ * IDAGetSens1 * IDAGetSensDky * IDAGetSensDky1 - * * Deallocation functions * IDAFree * IDAQuadFree * IDASensFree * IDAQuadSensFree * - * PRIVATE FUNCTIONS + * PRIVATE FUNCTIONS * ----------------- * IDACheckNvector * Memory allocation/deallocation @@ -124,7 +119,7 @@ * IDARcheck2 * IDARcheck3 * IDARootfind - * IDA Error message handling functions + * IDA Error message handling functions * IDAProcessError * IDAErrHandler * Internal DQ approximations for sensitivity RHS @@ -135,7 +130,7 @@ * ----------------------------------------------------------------- */ -/* +/* * ================================================================= * IMPORTED HEADER FILES * ================================================================= @@ -148,11 +143,10 @@ #include "idas_impl.h" #include -#include #include #include -/* +/* * ================================================================= * IDAS PRIVATE CONSTANTS * ================================================================= @@ -178,14 +172,14 @@ #define PT001 RCONST(0.001) /* real 0.001 */ #define PT0001 RCONST(0.0001) /* real 0.0001 */ -/* +/* * ================================================================= * IDAS ROUTINE-SPECIFIC CONSTANTS * ================================================================= */ -/* - * Control constants for lower-level functions used by IDASolve +/* + * Control constants for lower-level functions used by IDASolve * ------------------------------------------------------------ */ @@ -199,22 +193,22 @@ /* IDACompleteStep constants */ -#define UNSET -1 -#define LOWER 1 -#define RAISE 2 -#define MAINTAIN 3 +#define UNSET -1 +#define LOWER +1 +#define RAISE +2 +#define MAINTAIN +3 /* IDATestError constants */ -#define ERROR_TEST_FAIL +7 +#define ERROR_TEST_FAIL +7 /* * Control constants for lower-level rootfinding functions * ------------------------------------------------------- */ -#define RTFOUND 1 -#define CLOSERT 3 +#define RTFOUND +1 +#define CLOSERT +3 /* * Control constants for sensitivity DQ @@ -238,14 +232,9 @@ #define MAXNI 10 /* max. Newton iterations in IC calc. */ #define EPCON RCONST(0.33) /* Newton convergence test constant */ #define MAXBACKS 100 /* max backtracks per Newton step in IDACalcIC */ +#define XRATE RCONST(0.25) /* constant for updating Jacobian/preconditioner */ - -/* IDANewtonIter constants */ - -#define MAXIT 4 -#define XRATE RCONST(0.25) /* constant for updating Jacobian/preconditioner */ - -/* +/* * ================================================================= * PRIVATE FUNCTION PROTOTYPES * ================================================================= @@ -310,15 +299,15 @@ static int IDASensNls(IDAMem IDA_mem); static int IDAQuadNls(IDAMem IDA_mem); static int IDAQuadSensNls(IDAMem IDA_mem); -/* Error tests */ +/* Error test */ -static int IDATestError(IDAMem IDA_mem, realtype ck, +static int IDATestError(IDAMem IDA_mem, realtype ck, realtype *err_k, realtype *err_km1, realtype *err_km2); -static int IDAQuadTestError(IDAMem IDA_mem, realtype ck, +static int IDAQuadTestError(IDAMem IDA_mem, realtype ck, realtype *err_k, realtype *err_km1, realtype *err_km2); -static int IDASensTestError(IDAMem IDA_mem, realtype ck, +static int IDASensTestError(IDAMem IDA_mem, realtype ck, realtype *err_k, realtype *err_km1, realtype *err_km2); -static int IDAQuadSensTestError(IDAMem IDA_mem, realtype ck, +static int IDAQuadSensTestError(IDAMem IDA_mem, realtype ck, realtype *err_k, realtype *err_km1, realtype *err_km2); /* Handling of convergence and/or error test failures */ @@ -333,13 +322,14 @@ static void IDAReset(IDAMem IDA_mem); static void IDACompleteStep(IDAMem IDA_mem, realtype err_k, realtype err_km1); /* Function called to evaluate the solutions y(t) and y'(t) at t. Also used in IDAA */ + int IDAGetSolution(void *ida_mem, realtype t, N_Vector yret, N_Vector ypret); /* Stopping tests and failure handling */ -static int IDAStopTest1(IDAMem IDA_mem, realtype tout,realtype *tret, +static int IDAStopTest1(IDAMem IDA_mem, realtype tout,realtype *tret, N_Vector yret, N_Vector ypret, int itask); -static int IDAStopTest2(IDAMem IDA_mem, realtype tout, realtype *tret, +static int IDAStopTest2(IDAMem IDA_mem, realtype tout, realtype *tret, N_Vector yret, N_Vector ypret, int itask); static int IDAHandleFailure(IDAMem IDA_mem, int sflag); @@ -349,7 +339,7 @@ static realtype IDAQuadWrmsNormUpdate(IDAMem IDA_mem, realtype old_nrm, N_Vector xQ, N_Vector wQ); static realtype IDAQuadSensWrmsNorm(IDAMem IDA_mem, N_Vector *xQS, N_Vector *wQS); -static realtype IDAQuadSensWrmsNormUpdate(IDAMem IDA_mem, realtype old_nrm, +static realtype IDAQuadSensWrmsNormUpdate(IDAMem IDA_mem, realtype old_nrm, N_Vector *xQS, N_Vector *wQS); /* Functions for rootfinding */ @@ -361,46 +351,46 @@ static int IDARootfind(IDAMem IDA_mem); /* Sensitivity residual DQ function */ -static int IDASensRes1DQ(int Ns, realtype t, +static int IDASensRes1DQ(int Ns, realtype t, N_Vector yy, N_Vector yp, N_Vector resval, int iS, N_Vector yyS, N_Vector ypS, N_Vector resvalS, void *user_dataS, N_Vector ytemp, N_Vector yptemp, N_Vector restemp); -static int IDAQuadSensRhsInternalDQ(int Ns, realtype t, +static int IDAQuadSensRhsInternalDQ(int Ns, realtype t, N_Vector yy, N_Vector yp, N_Vector *yyS, N_Vector *ypS, N_Vector rrQ, N_Vector *resvalQS, - void *ida_mem, + void *ida_mem, N_Vector yytmp, N_Vector yptmp, N_Vector tmpQS); -static int IDAQuadSensRhs1InternalDQ(IDAMem IDA_mem, int is, realtype t, - N_Vector yy, N_Vector y, +static int IDAQuadSensRhs1InternalDQ(IDAMem IDA_mem, int is, realtype t, + N_Vector yy, N_Vector y, N_Vector yyS, N_Vector ypS, - N_Vector resvalQ, N_Vector resvalQS, + N_Vector resvalQ, N_Vector resvalQS, N_Vector yytmp, N_Vector yptmp, N_Vector tmpQS); -/* +/* * ================================================================= * EXPORTED FUNCTIONS IMPLEMENTATION * ================================================================= */ -/* +/* * ----------------------------------------------------------------- * Creation, allocation and re-initialization functions * ----------------------------------------------------------------- */ -/* +/* * IDACreate * - * IDACreate creates an internal memory block for a problem to + * IDACreate creates an internal memory block for a problem to * be solved by IDA. - * If successful, IDACreate returns a pointer to the problem memory. - * This pointer should be passed to IDAInit. - * If an initialization error occurs, IDACreate prints an error - * message to standard err and returns NULL. + * If successful, IDACreate returns a pointer to the problem memory. + * This pointer should be passed to IDAInit. + * If an initialization error occurs, IDACreate prints an error + * message to standard err and returns NULL. */ void *IDACreate(void) @@ -424,6 +414,7 @@ void *IDACreate(void) IDA_mem->ida_res = NULL; IDA_mem->ida_user_data = NULL; IDA_mem->ida_itol = IDA_NN; + IDA_mem->ida_atolmin0 = SUNTRUE; IDA_mem->ida_user_efun = SUNFALSE; IDA_mem->ida_efun = NULL; IDA_mem->ida_edata = NULL; @@ -437,7 +428,6 @@ void *IDACreate(void) IDA_mem->ida_epcon = EPCON; IDA_mem->ida_maxnef = MXNEF; IDA_mem->ida_maxncf = MXNCF; - IDA_mem->ida_maxcor = MAXIT; IDA_mem->ida_suppressalg = SUNFALSE; IDA_mem->ida_id = NULL; IDA_mem->ida_constraints = NULL; @@ -461,6 +451,7 @@ void *IDACreate(void) IDA_mem->ida_rhsQ = NULL; IDA_mem->ida_errconQ = SUNFALSE; IDA_mem->ida_itolQ = IDA_NN; + IDA_mem->ida_atolQmin0 = SUNTRUE; /* Set default values for sensi. optional inputs */ IDA_mem->ida_sensi = SUNFALSE; @@ -473,8 +464,8 @@ void *IDACreate(void) IDA_mem->ida_pbar = NULL; IDA_mem->ida_plist = NULL; IDA_mem->ida_errconS = SUNFALSE; - IDA_mem->ida_maxcorS = MAXIT; IDA_mem->ida_itolS = IDA_EE; + IDA_mem->ida_atolSmin0 = NULL; IDA_mem->ida_ism = -1; /* initialize to invalid option */ /* Defaults for sensi. quadr. optional inputs. */ @@ -484,6 +475,7 @@ void *IDACreate(void) IDA_mem->ida_rhsQSDQ = SUNTRUE; IDA_mem->ida_errconQS = SUNFALSE; IDA_mem->ida_itolQS = IDA_EE; + IDA_mem->ida_atolQSmin0 = NULL; /* Set defaults for ASA. */ IDA_mem->ida_adj = SUNFALSE; @@ -494,7 +486,6 @@ void *IDACreate(void) IDA_mem->ida_liw = 38; /* No mallocs have been done yet */ - IDA_mem->ida_VatolMallocDone = SUNFALSE; IDA_mem->ida_constraintsMallocDone = SUNFALSE; IDA_mem->ida_idMallocDone = SUNFALSE; @@ -519,14 +510,14 @@ void *IDACreate(void) IDA_mem->NLSsim = NULL; IDA_mem->ownNLSsim = SUNFALSE; - IDA_mem->ycor0Sim = NULL; + IDA_mem->ypredictSim = NULL; IDA_mem->ycorSim = NULL; IDA_mem->ewtSim = NULL; IDA_mem->simMallocDone = SUNFALSE; IDA_mem->NLSstg = NULL; IDA_mem->ownNLSstg = SUNFALSE; - IDA_mem->ycor0Stg = NULL; + IDA_mem->ypredictStg = NULL; IDA_mem->ycorStg = NULL; IDA_mem->ewtStg = NULL; IDA_mem->stgMallocDone = SUNFALSE; @@ -542,7 +533,7 @@ void *IDACreate(void) * * IDAInit allocates and initializes memory for a problem. All * problem specification inputs are checked for errors. If any - * error occurs during initialization, it is reported to the + * error occurs during initialization, it is reported to the * error handler function. */ @@ -562,22 +553,22 @@ int IDAInit(void *ida_mem, IDAResFn res, return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; - + /* Check for legal input parameters */ - - if (yy0 == NULL) { + + if (yy0 == NULL) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInit", MSG_Y0_NULL); - return(IDA_ILL_INPUT); + return(IDA_ILL_INPUT); } - - if (yp0 == NULL) { + + if (yp0 == NULL) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInit", MSG_YP0_NULL); - return(IDA_ILL_INPUT); + return(IDA_ILL_INPUT); } - if (res == NULL) { + if (res == NULL) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInit", MSG_RES_NULL); - return(IDA_ILL_INPUT); + return(IDA_ILL_INPUT); } /* Test if all required vector operations are implemented */ @@ -672,9 +663,9 @@ int IDAInit(void *ida_mem, IDAResFn res, /* Initialize the phi array */ - N_VScale(ONE, yy0, IDA_mem->ida_phi[0]); - N_VScale(ONE, yp0, IDA_mem->ida_phi[1]); - + N_VScale(ONE, yy0, IDA_mem->ida_phi[0]); + N_VScale(ONE, yp0, IDA_mem->ida_phi[1]); + /* Initialize all the counters and other optional output values */ IDA_mem->ida_nst = 0; @@ -683,7 +674,7 @@ int IDAInit(void *ida_mem, IDAResFn res, IDA_mem->ida_netf = 0; IDA_mem->ida_nni = 0; IDA_mem->ida_nsetups = 0; - + IDA_mem->ida_kused = 0; IDA_mem->ida_hused = ZERO; IDA_mem->ida_tolsf = ONE; @@ -693,7 +684,7 @@ int IDAInit(void *ida_mem, IDAResFn res, IDA_mem->ida_irfnd = 0; /* Initialize counters specific to IC calculation. */ - IDA_mem->ida_nbacktr = 0; + IDA_mem->ida_nbacktr = 0; /* Initialize root-finding variables */ @@ -740,7 +731,7 @@ int IDAReInit(void *ida_mem, IDAMem IDA_mem; /* Check for legal input parameters */ - + if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAReInit", MSG_NO_MEM); return(IDA_MEM_NULL); @@ -748,22 +739,22 @@ int IDAReInit(void *ida_mem, IDA_mem = (IDAMem) ida_mem; /* Check if problem was malloc'ed */ - + if (IDA_mem->ida_MallocDone == SUNFALSE) { IDAProcessError(IDA_mem, IDA_NO_MALLOC, "IDAS", "IDAReInit", MSG_NO_MALLOC); return(IDA_NO_MALLOC); } /* Check for legal input parameters */ - - if (yy0 == NULL) { + + if (yy0 == NULL) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAReInit", MSG_Y0_NULL); - return(IDA_ILL_INPUT); + return(IDA_ILL_INPUT); } - - if (yp0 == NULL) { + + if (yp0 == NULL) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAReInit", MSG_YP0_NULL); - return(IDA_ILL_INPUT); + return(IDA_ILL_INPUT); } /* Copy the input parameters into IDA memory block */ @@ -776,18 +767,18 @@ int IDAReInit(void *ida_mem, /* Initialize the phi array */ - N_VScale(ONE, yy0, IDA_mem->ida_phi[0]); - N_VScale(ONE, yp0, IDA_mem->ida_phi[1]); - + N_VScale(ONE, yy0, IDA_mem->ida_phi[0]); + N_VScale(ONE, yp0, IDA_mem->ida_phi[1]); + /* Initialize all the counters and other optional output values */ - + IDA_mem->ida_nst = 0; IDA_mem->ida_nre = 0; IDA_mem->ida_ncfn = 0; IDA_mem->ida_netf = 0; IDA_mem->ida_nni = 0; IDA_mem->ida_nsetups = 0; - + IDA_mem->ida_kused = 0; IDA_mem->ida_hused = ZERO; IDA_mem->ida_tolsf = ONE; @@ -799,7 +790,7 @@ int IDAReInit(void *ida_mem, /* Initial setup not done yet */ IDA_mem->ida_SetupDone = SUNFALSE; - + /* Problem has been successfully re-initialized */ return(IDA_SUCCESS); @@ -817,7 +808,7 @@ int IDAReInit(void *ida_mem, * * IDASStolerances specifies scalar relative and absolute tolerances. * IDASVtolerances specifies scalar relative tolerance and a vector - * absolute tolerance (a potentially different absolute tolerance + * absolute tolerance (a potentially different absolute tolerance * for each vector component). * IDAWFtolerances specifies a user-provides function (of type IDAEwtFn) * which will be called to set the error weight vector. @@ -839,6 +830,7 @@ int IDASStolerances(void *ida_mem, realtype reltol, realtype abstol) } /* Check inputs */ + if (reltol < ZERO) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASStolerances", MSG_BAD_RTOL); return(IDA_ILL_INPUT); @@ -850,14 +842,16 @@ int IDASStolerances(void *ida_mem, realtype reltol, realtype abstol) } /* Copy tolerances into memory */ - IDA_mem->ida_rtol = reltol; + + IDA_mem->ida_rtol = reltol; IDA_mem->ida_Satol = abstol; + IDA_mem->ida_atolmin0 = (abstol == ZERO); IDA_mem->ida_itol = IDA_SS; IDA_mem->ida_user_efun = SUNFALSE; IDA_mem->ida_efun = IDAEwtSet; - IDA_mem->ida_edata = NULL; /* will be set to ida_mem in InitialSetup */ + IDA_mem->ida_edata = NULL; /* will be set to ida_mem in InitialSetup */ return(IDA_SUCCESS); } @@ -866,6 +860,7 @@ int IDASStolerances(void *ida_mem, realtype reltol, realtype abstol) int IDASVtolerances(void *ida_mem, realtype reltol, N_Vector abstol) { IDAMem IDA_mem; + realtype atolmin; if (ida_mem==NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASVtolerances", MSG_NO_MEM); @@ -885,13 +880,14 @@ int IDASVtolerances(void *ida_mem, realtype reltol, N_Vector abstol) return(IDA_ILL_INPUT); } - if (N_VMin(abstol) < ZERO) { + atolmin = N_VMin(abstol); + if (atolmin < ZERO) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASVtolerances", MSG_BAD_ATOL); return(IDA_ILL_INPUT); } /* Copy tolerances into memory */ - + if ( !(IDA_mem->ida_VatolMallocDone) ) { IDA_mem->ida_Vatol = N_VClone(IDA_mem->ida_ewt); IDA_mem->ida_lrw += IDA_mem->ida_lrw1; @@ -901,12 +897,13 @@ int IDASVtolerances(void *ida_mem, realtype reltol, N_Vector abstol) IDA_mem->ida_rtol = reltol; N_VScale(ONE, abstol, IDA_mem->ida_Vatol); + IDA_mem->ida_atolmin0 = (atolmin == ZERO); IDA_mem->ida_itol = IDA_SV; IDA_mem->ida_user_efun = SUNFALSE; IDA_mem->ida_efun = IDAEwtSet; - IDA_mem->ida_edata = NULL; /* will be set to ida_mem in InitialSetup */ + IDA_mem->ida_edata = NULL; /* will be set to ida_mem in InitialSetup */ return(IDA_SUCCESS); } @@ -941,10 +938,10 @@ int IDAWFtolerances(void *ida_mem, IDAEwtFn efun) /* * IDAQuadMalloc * - * IDAQuadMalloc allocates and initializes quadrature related - * memory for a problem. All problem specification inputs are - * checked for errors. If any error occurs during initialization, - * it is reported to the file whose file pointer is errfp. + * IDAQuadMalloc allocates and initializes quadrature related + * memory for a problem. All problem specification inputs are + * checked for errors. If any error occurs during initialization, + * it is reported to the file whose file pointer is errfp. * The return value is IDA_SUCCESS = 0 if no errors occurred, or * a negative value otherwise. */ @@ -1001,9 +998,9 @@ int IDAQuadInit(void *ida_mem, IDAQuadRhsFn rhsQ, N_Vector yQ0) /* * IDAQuadReInit * - * IDAQuadReInit re-initializes IDAS's quadrature related memory - * for a problem, assuming it has already been allocated in prior - * calls to IDAInit and IDAQuadMalloc. + * IDAQuadReInit re-initializes IDAS's quadrature related memory + * for a problem, assuming it has already been allocated in prior + * calls to IDAInit and IDAQuadMalloc. * All problem specification inputs are checked for errors. * If any error occurs during initialization, it is reported to the * file whose file pointer is errfp. @@ -1050,7 +1047,7 @@ int IDAQuadReInit(void *ida_mem, N_Vector yQ0) /* * IDAQuadSStolerances * IDAQuadSVtolerances - * + * * * These functions specify the integration tolerances for quadrature * variables. One of them MUST be called before the first call to @@ -1059,8 +1056,8 @@ int IDAQuadReInit(void *ida_mem, N_Vector yQ0) * * IDASStolerances specifies scalar relative and absolute tolerances. * IDASVtolerances specifies scalar relative tolerance and a vector - * absolute tolerance (a potentially different absolute tolerance - * for each vector component). + * absolute tolerance (a potentially different absolute tolerance + * for each vector component). */ int IDAQuadSStolerances(void *ida_mem, realtype reltolQ, realtype abstolQ) { @@ -1078,7 +1075,7 @@ int IDAQuadSStolerances(void *ida_mem, realtype reltolQ, realtype abstolQ) IDAProcessError(IDA_mem, IDA_NO_QUAD, "IDAS", "IDAQuadSStolerances", MSG_NO_QUAD); return(IDA_NO_QUAD); } - + /* Test user-supplied tolerances */ if (reltolQ < ZERO) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAQuadSStolerances", MSG_BAD_RTOLQ); @@ -1095,6 +1092,7 @@ int IDAQuadSStolerances(void *ida_mem, realtype reltolQ, realtype abstolQ) IDA_mem->ida_rtolQ = reltolQ; IDA_mem->ida_SatolQ = abstolQ; + IDA_mem->ida_atolQmin0 = (abstolQ == ZERO); return (IDA_SUCCESS); @@ -1103,6 +1101,7 @@ int IDAQuadSStolerances(void *ida_mem, realtype reltolQ, realtype abstolQ) int IDAQuadSVtolerances(void *ida_mem, realtype reltolQ, N_Vector abstolQ) { IDAMem IDA_mem; + realtype atolmin; /*Check ida mem*/ if (ida_mem==NULL) { @@ -1116,19 +1115,20 @@ int IDAQuadSVtolerances(void *ida_mem, realtype reltolQ, N_Vector abstolQ) IDAProcessError(IDA_mem, IDA_NO_QUAD, "IDAS", "IDAQuadSVtolerances", MSG_NO_QUAD); return(IDA_NO_QUAD); } - + /* Test user-supplied tolerances */ if (reltolQ < ZERO) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAQuadSVtolerances", MSG_BAD_RTOLQ); return(IDA_ILL_INPUT); } - + if (abstolQ == NULL) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAQuadSVtolerances", MSG_NULL_ATOLQ); return(IDA_ILL_INPUT); } - - if (N_VMin(abstolQ)ida_VatolQ); + IDA_mem->ida_atolQmin0 = (atolmin == ZERO); return(IDA_SUCCESS); } @@ -1153,24 +1154,24 @@ int IDAQuadSVtolerances(void *ida_mem, realtype reltolQ, N_Vector abstolQ) /* * IDASenMalloc * - * IDASensInit allocates and initializes sensitivity related - * memory for a problem. All problem specification inputs are - * checked for errors. If any error occurs during initialization, - * it is reported to the file whose file pointer is errfp. + * IDASensInit allocates and initializes sensitivity related + * memory for a problem. All problem specification inputs are + * checked for errors. If any error occurs during initialization, + * it is reported to the file whose file pointer is errfp. * The return value is IDA_SUCCESS = 0 if no errors occurred, or * a negative value otherwise. */ -int IDASensInit(void *ida_mem, int Ns, int ism, +int IDASensInit(void *ida_mem, int Ns, int ism, IDASensResFn fS, N_Vector *yS0, N_Vector *ypS0) - + { IDAMem IDA_mem; booleantype allocOK; int is, retval; SUNNonlinearSolver NLS; - + /* Check ida_mem */ if (ida_mem==NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASensInit", MSG_NO_MEM); @@ -1191,7 +1192,7 @@ int IDASensInit(void *ida_mem, int Ns, int ism, return(IDA_ILL_INPUT); } IDA_mem->ida_ism = ism; - + /* Check if yS0 and ypS0 are non-null */ if (yS0 == NULL) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASensInit", MSG_NULL_YYS0); @@ -1240,9 +1241,9 @@ int IDASensInit(void *ida_mem, int Ns, int ism, return(IDA_MEM_FAIL); } } - - /*---------------------------------------------- - All error checking is complete at this point + + /*---------------------------------------------- + All error checking is complete at this point -----------------------------------------------*/ /* Initialize the phiS array */ @@ -1493,10 +1494,10 @@ int IDASensSStolerances(void *ida_mem, realtype reltolS, realtype *abstolS) if (IDA_mem->ida_sensMallocDone == SUNFALSE) { IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDASensSStolerances", MSG_NO_SENSI); return(IDA_NO_SENS); - } + } /* Test user-supplied tolerances */ - + if (reltolS < ZERO) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASensSStolerances", MSG_BAD_RTOLS); return(IDA_ILL_INPUT); @@ -1522,12 +1523,15 @@ int IDASensSStolerances(void *ida_mem, realtype reltolS, realtype *abstolS) if ( !(IDA_mem->ida_SatolSMallocDone) ) { IDA_mem->ida_SatolS = NULL; IDA_mem->ida_SatolS = (realtype *)malloc(IDA_mem->ida_Ns*sizeof(realtype)); + IDA_mem->ida_atolSmin0 = (booleantype *)malloc(IDA_mem->ida_Ns*sizeof(booleantype)); IDA_mem->ida_lrw += IDA_mem->ida_Ns; IDA_mem->ida_SatolSMallocDone = SUNTRUE; } - for (is=0; isida_Ns; is++) + for (is=0; isida_Ns; is++) { IDA_mem->ida_SatolS[is] = abstolS[is]; + IDA_mem->ida_atolSmin0[is] = (abstolS[is] == ZERO); + } return(IDA_SUCCESS); } @@ -1537,6 +1541,7 @@ int IDASensSVtolerances(void *ida_mem, realtype reltolS, N_Vector *abstolS) { IDAMem IDA_mem; int is, retval; + realtype *atolmin; /* Check ida_mem pointer */ if (ida_mem == NULL) { @@ -1550,10 +1555,10 @@ int IDASensSVtolerances(void *ida_mem, realtype reltolS, N_Vector *abstolS) if (IDA_mem->ida_sensMallocDone == SUNFALSE) { IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDASensSVtolerances", MSG_NO_SENSI); return(IDA_NO_SENS); - } + } /* Test user-supplied tolerances */ - + if (reltolS < ZERO) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASensSVtolerances", MSG_BAD_RTOLS); return(IDA_ILL_INPUT); @@ -1564,10 +1569,13 @@ int IDASensSVtolerances(void *ida_mem, realtype reltolS, N_Vector *abstolS) return(IDA_ILL_INPUT); } + atolmin = (realtype *)malloc(IDA_mem->ida_Ns*sizeof(realtype)); for (is=0; isida_Ns; is++) { - if (N_VMin(abstolS[is])ida_VatolSMallocDone ) { IDA_mem->ida_VatolS = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_tempv1); + IDA_mem->ida_atolSmin0 = (booleantype *)malloc(IDA_mem->ida_Ns*sizeof(booleantype)); IDA_mem->ida_lrw += IDA_mem->ida_Ns*IDA_mem->ida_lrw1; IDA_mem->ida_liw += IDA_mem->ida_Ns*IDA_mem->ida_liw1; IDA_mem->ida_VatolSMallocDone = SUNTRUE; } - for (is=0; isida_Ns; is++) + for (is=0; isida_Ns; is++) { IDA_mem->ida_cvals[is] = ONE; + IDA_mem->ida_atolSmin0[is] = (atolmin[is] == ZERO); + } + free(atolmin); retval = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, abstolS, IDA_mem->ida_VatolS); if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); - + return(IDA_SUCCESS); } @@ -1596,7 +1608,7 @@ int IDASensEEtolerances(void *ida_mem) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASensEEtolerances", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASensEEtolerances", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; @@ -1606,7 +1618,7 @@ int IDASensEEtolerances(void *ida_mem) if (IDA_mem->ida_sensMallocDone == SUNFALSE) { IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDASensEEtolerances", MSG_NO_SENSI); return(IDA_NO_SENS); - } + } IDA_mem->ida_itolS = IDA_EE; @@ -1621,27 +1633,27 @@ int IDAQuadSensInit(void *ida_mem, IDAQuadSensRhsFn rhsQS, N_Vector *yQS0) int is, retval; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadSensInit", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadSensInit", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; /* Check if sensitivity analysis is active */ if (!IDA_mem->ida_sensi) { - IDAProcessError(NULL, IDA_NO_SENS, "IDAS", "IDAQuadSensInit", MSG_NO_SENSI); + IDAProcessError(NULL, IDA_NO_SENS, "IDAS", "IDAQuadSensInit", MSG_NO_SENSI); return(IDA_NO_SENS); } /* Verifiy yQS0 parameter. */ if (yQS0==NULL) { - IDAProcessError(NULL, IDA_ILL_INPUT, "IDAS", "IDAQuadSensInit", MSG_NULL_YQS0); - return(IDA_ILL_INPUT); + IDAProcessError(NULL, IDA_ILL_INPUT, "IDAS", "IDAQuadSensInit", MSG_NULL_YQS0); + return(IDA_ILL_INPUT); } /* Allocate vector needed for quadratures' sensitivities. */ allocOK = IDAQuadSensAllocVectors(IDA_mem, yQS0[0]); - if (!allocOK) { - IDAProcessError(NULL, IDA_MEM_FAIL, "IDAS", "IDAQuadSensInit", MSG_MEM_FAIL); + if (!allocOK) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDAS", "IDAQuadSensInit", MSG_MEM_FAIL); return(IDA_MEM_FAIL); } @@ -1684,17 +1696,17 @@ int IDAQuadSensReInit(void *ida_mem, N_Vector *yQS0) int is, retval; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadSensReInit", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadSensReInit", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; /* Check if sensitivity analysis is active */ if (!IDA_mem->ida_sensi) { - IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAQuadSensReInit", MSG_NO_SENSI); + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAQuadSensReInit", MSG_NO_SENSI); return(IDA_NO_SENS); } - + /* Was sensitivity for quadrature already initialized? */ if (!IDA_mem->ida_quadSensMallocDone) { IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAQuadSensReInit", MSG_NO_QUADSENSI); @@ -1703,10 +1715,10 @@ int IDAQuadSensReInit(void *ida_mem, N_Vector *yQS0) /* Verifiy yQS0 parameter. */ if (yQS0==NULL) { - IDAProcessError(NULL, IDA_ILL_INPUT, "IDAS", "IDAQuadSensReInit", MSG_NULL_YQS0); - return(IDA_ILL_INPUT); + IDAProcessError(NULL, IDA_ILL_INPUT, "IDAS", "IDAQuadSensReInit", MSG_NULL_YQS0); + return(IDA_ILL_INPUT); } - + /* Error checking complete at this point. */ /* Initialize phiQS[0] in the history array */ @@ -1749,21 +1761,21 @@ int IDAQuadSensReInit(void *ida_mem, N_Vector *yQS0) int IDAQuadSensSStolerances(void *ida_mem, realtype reltolQS, realtype *abstolQS) { - IDAMem IDA_mem; - int is; + IDAMem IDA_mem; + int is; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadSensSStolerances", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadSensSStolerances", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; /* Check if sensitivity analysis is active */ if (!IDA_mem->ida_sensi) { - IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAQuadSensSStolerances", MSG_NO_SENSI); + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAQuadSensSStolerances", MSG_NO_SENSI); return(IDA_NO_SENS); } - + /* Was sensitivity for quadrature already initialized? */ if (!IDA_mem->ida_quadSensMallocDone) { IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAQuadSensSStolerances", MSG_NO_QUADSENSI); @@ -1787,40 +1799,44 @@ int IDAQuadSensSStolerances(void *ida_mem, realtype reltolQS, realtype *abstolQS IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAQuadSensSStolerances", MSG_BAD_ABSTOLQS); return(IDA_ILL_INPUT); } - + /* Save data. */ IDA_mem->ida_itolQS = IDA_SS; IDA_mem->ida_rtolQS = reltolQS; if ( !(IDA_mem->ida_SatolQSMallocDone) ) { IDA_mem->ida_SatolQS = (realtype *)malloc(IDA_mem->ida_Ns*sizeof(realtype)); + IDA_mem->ida_atolQSmin0 = (booleantype *)malloc(IDA_mem->ida_Ns*sizeof(booleantype)); IDA_mem->ida_lrw += IDA_mem->ida_Ns; IDA_mem->ida_SatolQSMallocDone = SUNTRUE; } - for (is=0; isida_Ns; is++) + for (is=0; isida_Ns; is++) { IDA_mem->ida_SatolQS[is] = abstolQS[is]; + IDA_mem->ida_atolQSmin0[is] = (abstolQS[is] == ZERO); + } return(IDA_SUCCESS); } int IDAQuadSensSVtolerances(void *ida_mem, realtype reltolQS, N_Vector *abstolQS) { - IDAMem IDA_mem; + IDAMem IDA_mem; int is, retval; + realtype *atolmin; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadSensSVtolerances", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadSensSVtolerances", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; /* Check if sensitivity analysis is active */ if (!IDA_mem->ida_sensi) { - IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAQuadSensSVtolerances", MSG_NO_SENSI); + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAQuadSensSVtolerances", MSG_NO_SENSI); return(IDA_NO_SENS); } - + /* Was sensitivity for quadrature already initialized? */ if (!IDA_mem->ida_quadSensMallocDone) { IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAQuadSensSVtolerances", MSG_NO_QUADSENSI); @@ -1839,25 +1855,33 @@ int IDAQuadSensSVtolerances(void *ida_mem, realtype reltolQS, N_Vector *abstolQS return(IDA_ILL_INPUT); } - for (is=0; isida_Ns; is++) - if (N_VMin(abstolQS[is]) < ZERO) { + atolmin = (realtype *)malloc(IDA_mem->ida_Ns*sizeof(realtype)); + for (is=0; isida_Ns; is++) { + atolmin[is] = N_VMin(abstolQS[is]); + if (atolmin[is] < ZERO) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAQuadSensSVtolerances", MSG_BAD_ABSTOLQS); + free(atolmin); return(IDA_ILL_INPUT); } - + } + /* Save data. */ IDA_mem->ida_itolQS = IDA_SV; IDA_mem->ida_rtolQS = reltolQS; if ( !(IDA_mem->ida_VatolQSMallocDone) ) { IDA_mem->ida_VatolQS = N_VCloneVectorArray(IDA_mem->ida_Ns, abstolQS[0]); + IDA_mem->ida_atolQSmin0 = (booleantype *)malloc(IDA_mem->ida_Ns*sizeof(booleantype)); IDA_mem->ida_lrw += IDA_mem->ida_Ns*IDA_mem->ida_lrw1Q; IDA_mem->ida_liw += IDA_mem->ida_Ns*IDA_mem->ida_liw1Q; IDA_mem->ida_VatolQSMallocDone = SUNTRUE; } - - for (is=0; isida_Ns; is++) + + for (is=0; isida_Ns; is++) { IDA_mem->ida_cvals[is] = ONE; + IDA_mem->ida_atolQSmin0[is] = (atolmin[is] == ZERO); + } + free(atolmin); retval = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, abstolQS, IDA_mem->ida_VatolQS); @@ -1868,20 +1892,20 @@ int IDAQuadSensSVtolerances(void *ida_mem, realtype reltolQS, N_Vector *abstolQS int IDAQuadSensEEtolerances(void *ida_mem) { - IDAMem IDA_mem; + IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadSensEEtolerances", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadSensEEtolerances", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; /* Check if sensitivity analysis is active */ if (!IDA_mem->ida_sensi) { - IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAQuadSensEEtolerances", MSG_NO_SENSI); + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAQuadSensEEtolerances", MSG_NO_SENSI); return(IDA_NO_SENS); } - + /* Was sensitivity for quadrature already initialized? */ if (!IDA_mem->ida_quadSensMallocDone) { IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAQuadSensEEtolerances", MSG_NO_QUADSENSI); @@ -2053,7 +2077,7 @@ int IDARootInit(void *ida_mem, int nrtfn, IDARootFn g) IDA_mem->ida_gactive = NULL; IDA_mem->ida_gactive = (booleantype *) malloc(nrt*sizeof(booleantype)); if (IDA_mem->ida_gactive == NULL) { - free(IDA_mem->ida_glo); IDA_mem->ida_glo = NULL; + free(IDA_mem->ida_glo); IDA_mem->ida_glo = NULL; free(IDA_mem->ida_ghi); IDA_mem->ida_ghi = NULL; free(IDA_mem->ida_grout); IDA_mem->ida_grout = NULL; free(IDA_mem->ida_iroots); IDA_mem->ida_iroots = NULL; @@ -2075,8 +2099,7 @@ int IDARootInit(void *ida_mem, int nrtfn, IDARootFn g) } - -/* +/* * ----------------------------------------------------------------- * Main solver function * ----------------------------------------------------------------- @@ -2085,9 +2108,9 @@ int IDARootInit(void *ida_mem, int nrtfn, IDARootFn g) /* * IDASolve * - * This routine is the main driver of the IDA package. + * This routine is the main driver of the IDA package. * - * It integrates over an independent variable interval defined by the user, + * It integrates over an independent variable interval defined by the user, * by calling IDAStep to take internal independent variable steps. * * The first time that IDASolve is called for a successfully initialized @@ -2100,10 +2123,10 @@ int IDARootInit(void *ida_mem, int nrtfn, IDARootFn g) * * IDASolve returns integer values corresponding to success and failure as below: * - * successful returns: + * successful returns: * - * IDA_SUCCESS - * IDA_TSTOP_RETURN + * IDA_SUCCESS + * IDA_TSTOP_RETURN * * failed returns: * @@ -2113,9 +2136,9 @@ int IDARootInit(void *ida_mem, int nrtfn, IDARootFn g) * IDA_TOO_MUCH_ACC * IDA_CONV_FAIL * IDA_LSETUP_FAIL - * IDA_LSOLVE_FAIL + * IDA_LSOLVE_FAIL * IDA_CONSTR_FAIL - * IDA_ERR_FAIL + * IDA_ERR_FAIL * IDA_REP_RES_ERR * IDA_RES_FAIL */ @@ -2124,12 +2147,13 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, N_Vector yret, N_Vector ypret, int itask) { long int nstloc; - int sflag, istate, ier, irfndp, is, ir; + int sflag, istate, ier, irfndp, ir, is; realtype tdist, troundoff, ypnorm, rh, nrm; IDAMem IDA_mem; booleantype inactive_roots; /* Check for legal inputs in all cases. */ + if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASolve", MSG_NO_MEM); return(IDA_MEM_NULL); @@ -2137,24 +2161,26 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, IDA_mem = (IDAMem) ida_mem; /* Check if problem was malloc'ed */ + if (IDA_mem->ida_MallocDone == SUNFALSE) { IDAProcessError(IDA_mem, IDA_NO_MALLOC, "IDAS", "IDASolve", MSG_NO_MALLOC); return(IDA_NO_MALLOC); } /* Check for legal arguments */ + if (yret == NULL) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_YRET_NULL); return(IDA_ILL_INPUT); } - IDA_mem->ida_yy = yret; + IDA_mem->ida_yy = yret; if (ypret == NULL) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_YPRET_NULL); return(IDA_ILL_INPUT); } IDA_mem->ida_yp = ypret; - + if (tret == NULL) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_TRET_NULL); return(IDA_ILL_INPUT); @@ -2165,7 +2191,7 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, return(IDA_ILL_INPUT); } - if (itask == IDA_NORMAL) IDA_mem->ida_toutc = tout; + if (itask == IDA_NORMAL) IDA_mem->ida_toutc = tout; IDA_mem->ida_taskc = itask; /* Sensitivity-specific tests (if using internal DQ functions) */ @@ -2191,6 +2217,7 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, if (IDA_mem->ida_nst == 0) { /* This is the first call */ /* Check inputs to IDA for correctness and consistency */ + if (IDA_mem->ida_SetupDone == SUNFALSE) { ier = IDAInitialSetup(IDA_mem); if (ier != IDA_SUCCESS) return(ier); @@ -2232,7 +2259,7 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, ypnorm = IDAQuadSensWrmsNormUpdate(IDA_mem, ypnorm, IDA_mem->ida_phiQS[1], IDA_mem->ida_ewtQS); - if (ypnorm > HALF/IDA_mem->ida_hh) IDA_mem->ida_hh = HALF/ypnorm; + if (ypnorm > HALF / IDA_mem->ida_hh) IDA_mem->ida_hh = HALF/ypnorm; if (tout < IDA_mem->ida_tn) IDA_mem->ida_hh = -IDA_mem->ida_hh; } @@ -2245,7 +2272,7 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, MSG_BAD_TSTOP, IDA_mem->ida_tstop, IDA_mem->ida_tn); return(IDA_ILL_INPUT); } - if ( (IDA_mem->ida_tn + IDA_mem->ida_hh - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) + if ( (IDA_mem->ida_tn + IDA_mem->ida_hh - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) IDA_mem->ida_hh = (IDA_mem->ida_tstop - IDA_mem->ida_tn)*(ONE - FOUR * IDA_mem->ida_uround); } @@ -2257,15 +2284,18 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, if (IDA_mem->ida_nrtfn > 0) { ier = IDARcheck1(IDA_mem); if (ier == IDA_RTFUNC_FAIL) { - IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDAS", "IDARcheck1", MSG_RTFUNC_FAILED, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDAS", "IDARcheck1", + MSG_RTFUNC_FAILED, IDA_mem->ida_tn); return(IDA_RTFUNC_FAIL); } } - N_VScale(IDA_mem->ida_hh, IDA_mem->ida_phi[1], IDA_mem->ida_phi[1]); /* set phi[1] = hh*y' */ + /* set phi[1] = hh*y' */ + N_VScale(IDA_mem->ida_hh, IDA_mem->ida_phi[1], IDA_mem->ida_phi[1]); + /* set phiQ[1] = hh*yQ' */ if (IDA_mem->ida_quadr) - N_VScale(IDA_mem->ida_hh, IDA_mem->ida_phiQ[1], IDA_mem->ida_phiQ[1]); /* set phiQ[1] = hh*yQ' */ + N_VScale(IDA_mem->ida_hh, IDA_mem->ida_phiQ[1], IDA_mem->ida_phiQ[1]); if (IDA_mem->ida_sensi || IDA_mem->ida_quadr_sensi) for (is=0; isida_Ns; is++) @@ -2307,14 +2337,16 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, if (IDA_mem->ida_nrtfn > 0) { irfndp = IDA_mem->ida_irfnd; - + ier = IDARcheck2(IDA_mem); if (ier == CLOSERT) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDARcheck2", MSG_CLOSE_ROOTS, IDA_mem->ida_tlo); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDARcheck2", + MSG_CLOSE_ROOTS, IDA_mem->ida_tlo); return(IDA_ILL_INPUT); } else if (ier == IDA_RTFUNC_FAIL) { - IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDAS", "IDARcheck2", MSG_RTFUNC_FAILED, IDA_mem->ida_tlo); + IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDAS", "IDARcheck2", + MSG_RTFUNC_FAILED, IDA_mem->ida_tlo); return(IDA_RTFUNC_FAIL); } else if (ier == RTFOUND) { IDA_mem->ida_tretlast = *tret = IDA_mem->ida_tlo; @@ -2338,7 +2370,8 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, IDA_mem->ida_tretlast = *tret = IDA_mem->ida_tlo; return(IDA_ROOT_RETURN); } else if (ier == IDA_RTFUNC_FAIL) { /* g failed */ - IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDAS", "IDARcheck3", MSG_RTFUNC_FAILED, IDA_mem->ida_tlo); + IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDAS", "IDARcheck3", + MSG_RTFUNC_FAILED, IDA_mem->ida_tlo); return(IDA_RTFUNC_FAIL); } } @@ -2355,11 +2388,12 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, /* Looping point for internal steps. */ for(;;) { - + /* Check for too many steps taken. */ if ( (IDA_mem->ida_mxstep>0) && (nstloc >= IDA_mem->ida_mxstep) ) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_MAX_STEPS, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", + MSG_MAX_STEPS, IDA_mem->ida_tn); istate = IDA_TOO_MUCH_WORK; *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; break; /* Here yy=yret and yp=ypret already have the current solution. */ @@ -2374,23 +2408,30 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, if (IDA_mem->ida_nst > 0) { - ier = IDA_mem->ida_efun(IDA_mem->ida_phi[0], - IDA_mem->ida_ewt, IDA_mem->ida_edata); + ier = IDA_mem->ida_efun(IDA_mem->ida_phi[0], IDA_mem->ida_ewt, + IDA_mem->ida_edata); + if (ier != 0) { + if (IDA_mem->ida_itol == IDA_WF) - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_EWT_NOW_FAIL, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", + MSG_EWT_NOW_FAIL, IDA_mem->ida_tn); else - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_EWT_NOW_BAD, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", + MSG_EWT_NOW_BAD, IDA_mem->ida_tn); + istate = IDA_ILL_INPUT; ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; break; + } if (IDA_mem->ida_quadr && IDA_mem->ida_errconQ) { ier = IDAQuadEwtSet(IDA_mem, IDA_mem->ida_phiQ[0], IDA_mem->ida_ewtQ); if (ier != 0) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_EWTQ_NOW_BAD, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", + MSG_EWTQ_NOW_BAD, IDA_mem->ida_tn); istate = IDA_ILL_INPUT; ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; @@ -2401,7 +2442,8 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, if (IDA_mem->ida_sensi) { ier = IDASensEwtSet(IDA_mem, IDA_mem->ida_phiS[0], IDA_mem->ida_ewtS); if (ier != 0) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_EWTS_NOW_BAD, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", + MSG_EWTS_NOW_BAD, IDA_mem->ida_tn); istate = IDA_ILL_INPUT; ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; @@ -2412,7 +2454,8 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, if (IDA_mem->ida_quadr_sensi && IDA_mem->ida_errconQS) { ier = IDAQuadSensEwtSet(IDA_mem, IDA_mem->ida_phiQS[0], IDA_mem->ida_ewtQS); if (ier != 0) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_EWTQS_NOW_BAD, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", + MSG_EWTQS_NOW_BAD, IDA_mem->ida_tn); istate = IDA_ILL_INPUT; ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); IDA_mem->ida_tretlast = *tret = IDA_mem->ida_tn; @@ -2421,11 +2464,11 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, } } - + /* Check for too much accuracy requested. */ - - nrm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_phi[0], - IDA_mem->ida_ewt, IDA_mem->ida_suppressalg); + + nrm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_phi[0], IDA_mem->ida_ewt, + IDA_mem->ida_suppressalg); if (IDA_mem->ida_errconQ) nrm = IDAQuadWrmsNormUpdate(IDA_mem, nrm, IDA_mem->ida_phiQ[0], IDA_mem->ida_ewtQ); @@ -2439,7 +2482,8 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, IDA_mem->ida_tolsf = IDA_mem->ida_uround * nrm; if (IDA_mem->ida_tolsf > ONE) { IDA_mem->ida_tolsf *= TEN; - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_TOO_MUCH_ACC, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", + MSG_TOO_MUCH_ACC, IDA_mem->ida_tn); istate = IDA_TOO_MUCH_ACC; *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; if (IDA_mem->ida_nst > 0) ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); @@ -2458,7 +2502,7 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); break; } - + nstloc++; /* If tstop is set and was reached, reset IDA_mem->ida_tn = tstop */ @@ -2482,7 +2526,8 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, IDA_mem->ida_tretlast = *tret = IDA_mem->ida_tlo; break; } else if (ier == IDA_RTFUNC_FAIL) { /* g failed */ - IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDAS", "IDARcheck3", MSG_RTFUNC_FAILED, IDA_mem->ida_tlo); + IDAProcessError(IDA_mem, IDA_RTFUNC_FAIL, "IDAS", "IDARcheck3", + MSG_RTFUNC_FAILED, IDA_mem->ida_tlo); istate = IDA_RTFUNC_FAIL; break; } @@ -2494,14 +2539,15 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, if (IDA_mem->ida_nst==1) { inactive_roots = SUNFALSE; - for (ir=0; irida_nrtfn; ir++) { + for (ir=0; irida_nrtfn; ir++) { if (!IDA_mem->ida_gactive[ir]) { inactive_roots = SUNTRUE; break; } } if ((IDA_mem->ida_mxgnull > 0) && inactive_roots) { - IDAProcessError(IDA_mem, IDA_WARNING, "IDAS", "IDASolve", MSG_INACTIVE_ROOTS); + IDAProcessError(IDA_mem, IDA_WARNING, "IDAS", "IDASolve", + MSG_INACTIVE_ROOTS); } } @@ -2514,30 +2560,29 @@ int IDASolve(void *ida_mem, realtype tout, realtype *tret, } /* End of step loop */ - return(istate); + return(istate); } -/* +/* * ----------------------------------------------------------------- * Interpolated output and extraction functions * ----------------------------------------------------------------- */ - - -/* +/* * IDAGetDky * - * This routine evaluates the k-th derivative of y(t) as the value of - * the k-th derivative of the interpolating polynomial at the independent + * This routine evaluates the k-th derivative of y(t) as the value of + * the k-th derivative of the interpolating polynomial at the independent * variable t, and stores the results in the vector dky. It uses the current * independent variable value, tn, and the method order last used, kused. - * + * * The return values are: - * IDA_SUCCESS if t is legal, or - * IDA_BAD_T if t is not within the interval of the last step taken. - * IDA_BAD_DKY if the dky vector is NULL. - * IDA_BAD_K if the requested k is not in the range 0,1,...,order used + * IDA_SUCCESS if t is legal + * IDA_BAD_T if t is not within the interval of the last step taken + * IDA_BAD_DKY if the dky vector is NULL + * IDA_BAD_K if the requested k is not in the range [0,order used] + * IDA_VECTOROP_ERR if the fused vector operation fails * */ @@ -2554,13 +2599,13 @@ int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky) IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetDky", MSG_NO_MEM); return (IDA_MEM_NULL); } - IDA_mem = (IDAMem) ida_mem; + IDA_mem = (IDAMem) ida_mem; if (dky == NULL) { IDAProcessError(IDA_mem, IDA_BAD_DKY, "IDAS", "IDAGetDky", MSG_NULL_DKY); return(IDA_BAD_DKY); } - + if ((k < 0) || (k > IDA_mem->ida_kused)) { IDAProcessError(IDA_mem, IDA_BAD_K, "IDAS", "IDAGetDky", MSG_BAD_K); return(IDA_BAD_K); @@ -2572,8 +2617,8 @@ int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky) if (IDA_mem->ida_hh < ZERO) tfuzz = - tfuzz; tp = IDA_mem->ida_tn - IDA_mem->ida_hused - tfuzz; if ((t - tp)*IDA_mem->ida_hh < ZERO) { - IDAProcessError(IDA_mem, IDA_BAD_T, "IDAS", "IDAGetDky", MSG_BAD_T, - t, IDA_mem->ida_tn-IDA_mem->ida_hused, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_BAD_T, "IDAS", "IDAGetDky", MSG_BAD_T, t, + IDA_mem->ida_tn-IDA_mem->ida_hused, IDA_mem->ida_tn); return(IDA_BAD_T); } @@ -2589,7 +2634,7 @@ int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky) /* The below reccurence is used to compute the k-th derivative of the solution: c_j^(k) = ( k * c_{j-1}^(k-1) + c_{j-1}^{k} (Delta+psi_{j-1}) ) / psi_j - + Translated in indexes notation: cjk[j] = ( k*cjk_1[j-1] + cjk[j-1]*(delt+psi[j-2]) ) / psi[j-1] @@ -2597,8 +2642,8 @@ int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky) In order to be able to deal with k=0 in the same way as for k>0, the following conventions were adopted: - - c_0(t) = 1 , c_0^(-1)(t)=0 - - psij_1 stands for psi[-1]=0 when j=1 + - c_0(t) = 1 , c_0^(-1)(t)=0 + - psij_1 stands for psi[-1]=0 when j=1 for psi[j-2] when j>1 */ if(i==0) { @@ -2619,7 +2664,7 @@ int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky) /*j does not need to go till kused */ for(j=i+1; j<=IDA_mem->ida_kused-k+i; j++) { - cjk[j] = ( i* cjk_1[j-1] + cjk[j-1] * (delt + psij_1) ) / IDA_mem->ida_psi[j-1]; + cjk[j] = ( i* cjk_1[j-1] + cjk[j-1] * (delt + psij_1) ) / IDA_mem->ida_psi[j-1]; psij_1 = IDA_mem->ida_psi[j-1]; } @@ -2629,8 +2674,10 @@ int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky) /* Compute sum (c_j(t) * phi(t)) */ - retval = N_VLinearCombination(IDA_mem->ida_kused-k+1, cjk+k, IDA_mem->ida_phi+k, dky); - if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + /* Sum j=k to j<=IDA_mem->ida_kused */ + retval = N_VLinearCombination(IDA_mem->ida_kused-k+1, cjk+k, + IDA_mem->ida_phi+k, dky); + if (retval != IDA_SUCCESS) return(IDA_VECTOROP_ERR); return(IDA_SUCCESS); } @@ -2638,8 +2685,8 @@ int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky) /* * IDAGetQuad * - * The following function can be called to obtain the quadrature - * variables after a successful integration step. + * The following function can be called to obtain the quadrature + * variables after a successful integration step. * * This is just a wrapper that calls IDAGetQuadDky with k=0. */ @@ -2662,7 +2709,7 @@ int IDAGetQuad(void *ida_mem, realtype *ptret, N_Vector yQout) /* * IDAGetQuadDky * - * Returns the quadrature variables (or their + * Returns the quadrature variables (or their * derivatives up to the current method order) at any time within * the last integration step (dense output). */ @@ -2679,7 +2726,7 @@ int IDAGetQuadDky(void *ida_mem, realtype t, int k, N_Vector dkyQ) IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadDky", MSG_NO_MEM); return (IDA_MEM_NULL); } - IDA_mem = (IDAMem) ida_mem; + IDA_mem = (IDAMem) ida_mem; /* Ckeck if quadrature was initialized */ if (IDA_mem->ida_quadr != SUNTRUE) { @@ -2691,14 +2738,14 @@ int IDAGetQuadDky(void *ida_mem, realtype t, int k, N_Vector dkyQ) IDAProcessError(IDA_mem, IDA_BAD_DKY, "IDAS", "IDAGetQuadDky", MSG_NULL_DKY); return(IDA_BAD_DKY); } - + if ((k < 0) || (k > IDA_mem->ida_kk)) { IDAProcessError(IDA_mem, IDA_BAD_K, "IDAS", "IDAGetQuadDky", MSG_BAD_K); return(IDA_BAD_K); } /* Check t for legality. Here tn - hused is t_{n-1}. */ - + tfuzz = HUNDRED * IDA_mem->ida_uround * (IDA_mem->ida_tn + IDA_mem->ida_hh); tp = IDA_mem->ida_tn - IDA_mem->ida_hused - tfuzz; if ( (t - tp)*IDA_mem->ida_hh < ZERO) { @@ -2744,12 +2791,12 @@ int IDAGetQuadDky(void *ida_mem, realtype t, int k, N_Vector dkyQ) } -/* +/* * IDAGetSens * * This routine extracts sensitivity solution into yySout at the * time at which IDASolve returned the solution. - * This is just a wrapper that calls IDAGetSensDky1 with k=0 and + * This is just a wrapper that calls IDAGetSensDky1 with k=0 and * is=0, 1, ... ,NS-1. */ @@ -2765,7 +2812,7 @@ int IDAGetSens(void *ida_mem, realtype *ptret, N_Vector *yySout) } IDA_mem = (IDAMem) ida_mem; - /*Check the parameters */ + /*Check the parameters */ if (yySout == NULL) { IDAProcessError(IDA_mem, IDA_BAD_DKY, "IDAS", "IDAGetSens", MSG_NULL_DKY); return(IDA_BAD_DKY); @@ -2778,7 +2825,7 @@ int IDAGetSens(void *ida_mem, realtype *ptret, N_Vector *yySout) } *ptret = IDA_mem->ida_tretlast; - + for(is=0; isida_Ns; is++) if( IDA_SUCCESS != (ierr = IDAGetSensDky1(ida_mem, *ptret, 0, is, yySout[is])) ) break; @@ -2788,9 +2835,9 @@ int IDAGetSens(void *ida_mem, realtype *ptret, N_Vector *yySout) /* * IDAGetSensDky * - * Computes the k-th derivative of all sensitivities of the y function at + * Computes the k-th derivative of all sensitivities of the y function at * time t. It repeatedly calls IDAGetSensDky1. The argument dkyS must be - * a pointer to N_Vector and must be allocated by the user to hold at + * a pointer to N_Vector and must be allocated by the user to hold at * least Ns vectors. */ int IDAGetSensDky(void *ida_mem, realtype t, int k, N_Vector *dkySout) @@ -2815,17 +2862,17 @@ int IDAGetSensDky(void *ida_mem, realtype t, int k, N_Vector *dkySout) IDAProcessError(IDA_mem, IDA_BAD_DKY, "IDAS", "IDAGetSensDky", MSG_NULL_DKY); return(IDA_BAD_DKY); } - + if ((k < 0) || (k > IDA_mem->ida_kk)) { IDAProcessError(IDA_mem, IDA_BAD_K, "IDAS", "IDAGetSensDky", MSG_BAD_K); return(IDA_BAD_K); - } + } for (is=0; isida_Ns; is++) { ier = IDAGetSensDky1(ida_mem, t, k, is, dkySout[is]); if (ier!=IDA_SUCCESS) break; } - + return(ier); } @@ -2857,18 +2904,18 @@ int IDAGetSens1(void *ida_mem, realtype *ptret, int is, N_Vector yySret) * IDAGetSensDky1 * * IDASensDky1 computes the kth derivative of the yS[is] function - * at time t, where tn-hu <= t <= tn, tn denotes the current - * internal time reached, and hu is the last internal step size - * successfully used by the solver. The user may request + * at time t, where tn-hu <= t <= tn, tn denotes the current + * internal time reached, and hu is the last internal step size + * successfully used by the solver. The user may request * is=0, 1, ..., Ns-1 and k=0, 1, ..., kk, where kk is the current - * order. The derivative vector is returned in dky. This vector - * must be allocated by the caller. It is only legal to call this - * function after a successful return from IDASolve with sensitivity + * order. The derivative vector is returned in dky. This vector + * must be allocated by the caller. It is only legal to call this + * function after a successful return from IDASolve with sensitivity * computation enabled. */ int IDAGetSensDky1(void *ida_mem, realtype t, int k, int is, N_Vector dkyS) { - IDAMem IDA_mem; + IDAMem IDA_mem; realtype tfuzz, tp, delt, psij_1; int i, j, retval; realtype cjk [MXORDP1]; @@ -2895,15 +2942,15 @@ int IDAGetSensDky1(void *ida_mem, realtype t, int k, int is, N_Vector dkyS) if(is<0 || is >= IDA_mem->ida_Ns) { IDAProcessError(IDA_mem, IDA_BAD_IS, "IDAS", "IDAGetSensDky1", MSG_BAD_IS); } - + /* Is the requested order valid? */ if ((k < 0) || (k > IDA_mem->ida_kused)) { IDAProcessError(IDA_mem, IDA_BAD_K, "IDAS", "IDAGetSensDky1", MSG_BAD_K); return(IDA_BAD_K); - } + } /* Check t for legality. Here tn - hused is t_{n-1}. */ - + tfuzz = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); if (IDA_mem->ida_hh < ZERO) tfuzz = - tfuzz; tp = IDA_mem->ida_tn - IDA_mem->ida_hused - tfuzz; @@ -2922,24 +2969,24 @@ int IDAGetSensDky1(void *ida_mem, realtype t, int k, int is, N_Vector dkyS) delt = t - IDA_mem->ida_tn; for(i=0; i<=k; i++) { - - if(i==0) { + + if(i==0) { cjk[i] = 1; psij_1 = 0; - }else { + }else { cjk[i] = cjk[i-1]*i / IDA_mem->ida_psi[i-1]; psij_1 = IDA_mem->ida_psi[i-1]; } - /* Update cjk based on the reccurence */ + /* Update cjk based on the reccurence */ for(j=i+1; j<=IDA_mem->ida_kused-k+i; j++) { - cjk[j] = ( i* cjk_1[j-1] + cjk[j-1] * (delt + psij_1) ) / IDA_mem->ida_psi[j-1]; + cjk[j] = ( i* cjk_1[j-1] + cjk[j-1] * (delt + psij_1) ) / IDA_mem->ida_psi[j-1]; psij_1 = IDA_mem->ida_psi[j-1]; } /* Update cjk_1 for the next step */ for(j=i+1; j<=IDA_mem->ida_kused-k+i; j++) cjk_1[j] = cjk[j]; - } + } /* Compute sum (c_j(t) * phi(t)) */ for(j=k; j<=IDA_mem->ida_kused; j++) @@ -2952,12 +2999,12 @@ int IDAGetSensDky1(void *ida_mem, realtype t, int k, int is, N_Vector dkyS) return(IDA_SUCCESS); } -/* +/* * IDAGetQuadSens * * This routine extracts quadrature sensitivity solution into yyQSout at the * time at which IDASolve returned the solution. - * This is just a wrapper that calls IDAGetQuadSensDky1 with k=0 and + * This is just a wrapper that calls IDAGetQuadSensDky1 with k=0 and * is=0, 1, ... ,NS-1. */ @@ -2973,7 +3020,7 @@ int IDAGetQuadSens(void *ida_mem, realtype *ptret, N_Vector *yyQSout) } IDA_mem = (IDAMem) ida_mem; - /*Check the parameters */ + /*Check the parameters */ if (yyQSout == NULL) { IDAProcessError(IDA_mem, IDA_BAD_DKY, "IDAS", "IDAGetQuadSens", MSG_NULL_DKY); return(IDA_BAD_DKY); @@ -2986,7 +3033,7 @@ int IDAGetQuadSens(void *ida_mem, realtype *ptret, N_Vector *yyQSout) } *ptret = IDA_mem->ida_tretlast; - + for(is=0; isida_Ns; is++) if( IDA_SUCCESS != (ierr = IDAGetQuadSensDky1(ida_mem, *ptret, 0, is, yyQSout[is])) ) break; @@ -2996,9 +3043,9 @@ int IDAGetQuadSens(void *ida_mem, realtype *ptret, N_Vector *yyQSout) /* * IDAGetQuadSensDky * - * Computes the k-th derivative of all quadratures sensitivities of the y function at - * time t. It repeatedly calls IDAGetQuadSensDky. The argument dkyS must be - * a pointer to N_Vector and must be allocated by the user to hold at + * Computes the k-th derivative of all quadratures sensitivities of the y function at + * time t. It repeatedly calls IDAGetQuadSensDky. The argument dkyS must be + * a pointer to N_Vector and must be allocated by the user to hold at * least Ns vectors. */ int IDAGetQuadSensDky(void *ida_mem, realtype t, int k, N_Vector *dkyQSout) @@ -3028,17 +3075,17 @@ int IDAGetQuadSensDky(void *ida_mem, realtype t, int k, N_Vector *dkyQSout) IDAProcessError(IDA_mem, IDA_BAD_DKY, "IDAS", "IDAGetQuadSensDky", MSG_NULL_DKY); return(IDA_BAD_DKY); } - + if ((k < 0) || (k > IDA_mem->ida_kk)) { IDAProcessError(IDA_mem, IDA_BAD_K, "IDAS", "IDAGetQuadSensDky", MSG_BAD_K); return(IDA_BAD_K); - } + } for (is=0; isida_Ns; is++) { ier = IDAGetQuadSensDky1(ida_mem, t, k, is, dkyQSout[is]); if (ier!=IDA_SUCCESS) break; } - + return(ier); } @@ -3085,18 +3132,18 @@ int IDAGetQuadSens1(void *ida_mem, realtype *ptret, int is, N_Vector yyQSret) * IDAGetQuadSensDky1 * * IDAGetQuadSensDky1 computes the kth derivative of the yS[is] function - * at time t, where tn-hu <= t <= tn, tn denotes the current - * internal time reached, and hu is the last internal step size - * successfully used by the solver. The user may request + * at time t, where tn-hu <= t <= tn, tn denotes the current + * internal time reached, and hu is the last internal step size + * successfully used by the solver. The user may request * is=0, 1, ..., Ns-1 and k=0, 1, ..., kk, where kk is the current - * order. The derivative vector is returned in dky. This vector - * must be allocated by the caller. It is only legal to call this - * function after a successful return from IDASolve with sensitivity + * order. The derivative vector is returned in dky. This vector + * must be allocated by the caller. It is only legal to call this + * function after a successful return from IDASolve with sensitivity * computation enabled. */ int IDAGetQuadSensDky1(void *ida_mem, realtype t, int k, int is, N_Vector dkyQS) { - IDAMem IDA_mem; + IDAMem IDA_mem; realtype tfuzz, tp, delt, psij_1; int i, j, retval; realtype cjk [MXORDP1]; @@ -3129,15 +3176,15 @@ int IDAGetQuadSensDky1(void *ida_mem, realtype t, int k, int is, N_Vector dkyQS) if(is<0 || is >= IDA_mem->ida_Ns) { IDAProcessError(IDA_mem, IDA_BAD_IS, "IDAS", "IDAGetQuadSensDky1", MSG_BAD_IS); } - + /* Is the requested order valid? */ if ((k < 0) || (k > IDA_mem->ida_kused)) { IDAProcessError(IDA_mem, IDA_BAD_K, "IDAS", "IDAGetQuadSensDky1", MSG_BAD_K); return(IDA_BAD_K); - } + } /* Check t for legality. Here tn - hused is t_{n-1}. */ - + tfuzz = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); if (IDA_mem->ida_hh < ZERO) tfuzz = - tfuzz; tp = IDA_mem->ida_tn - IDA_mem->ida_hused - tfuzz; @@ -3156,24 +3203,24 @@ int IDAGetQuadSensDky1(void *ida_mem, realtype t, int k, int is, N_Vector dkyQS) delt = t - IDA_mem->ida_tn; for(i=0; i<=k; i++) { - - if(i==0) { + + if(i==0) { cjk[i] = 1; psij_1 = 0; - }else { + }else { cjk[i] = cjk[i-1]*i / IDA_mem->ida_psi[i-1]; psij_1 = IDA_mem->ida_psi[i-1]; } - /* Update cjk based on the reccurence */ + /* Update cjk based on the reccurence */ for(j=i+1; j<=IDA_mem->ida_kused-k+i; j++) { - cjk[j] = ( i* cjk_1[j-1] + cjk[j-1] * (delt + psij_1) ) / IDA_mem->ida_psi[j-1]; + cjk[j] = ( i* cjk_1[j-1] + cjk[j-1] * (delt + psij_1) ) / IDA_mem->ida_psi[j-1]; psij_1 = IDA_mem->ida_psi[j-1]; } /* Update cjk_1 for the next step */ for(j=i+1; j<=IDA_mem->ida_kused-k+i; j++) cjk_1[j] = cjk[j]; - } + } /* Compute sum (c_j(t) * phi(t)) */ for(j=k; j<=IDA_mem->ida_kused; j++) @@ -3186,7 +3233,95 @@ int IDAGetQuadSensDky1(void *ida_mem, realtype t, int k, int is, N_Vector dkyQS) return(IDA_SUCCESS); } -/* +/* + * IDAComputeY + * + * Computes y based on the current prediction and given correction. + */ +int IDAComputeY(void *ida_mem, N_Vector ycor, N_Vector y) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAComputeY", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + N_VLinearSum(ONE, IDA_mem->ida_yypredict, ONE, ycor, y); + + return(IDA_SUCCESS); +} + +/* + * IDAComputeYp + * + * Computes y' based on the current prediction and given correction. + */ +int IDAComputeYp(void *ida_mem, N_Vector ycor, N_Vector yp) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAComputeYp", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + N_VLinearSum(ONE, IDA_mem->ida_yppredict, IDA_mem->ida_cj, ycor, yp); + + return(IDA_SUCCESS); +} + +/* + * IDAComputeYSens + * + * Computes yS based on the current prediction and given correction. + */ +int IDAComputeYSens(void *ida_mem, N_Vector *ycorS, N_Vector *yyS) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAComputeYSens", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_yySpredict, + ONE, ycorS, yyS); + + return(IDA_SUCCESS); +} + +/* + * IDAComputeYpSens + * + * Computes yS' based on the current prediction and given correction. + */ +int IDAComputeYpSens(void *ida_mem, N_Vector *ycorS, N_Vector *ypS) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAComputeYpSens", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_ypSpredict, + IDA_mem->ida_cj, ycorS, ypS); + + return(IDA_SUCCESS); +} + +/* * ----------------------------------------------------------------- * Deallocation functions * ----------------------------------------------------------------- @@ -3208,7 +3343,7 @@ void IDAFree(void **ida_mem) if (*ida_mem == NULL) return; IDA_mem = (IDAMem) (*ida_mem); - + IDAFreeVectors(IDA_mem); IDAQuadFree(IDA_mem); @@ -3219,14 +3354,21 @@ void IDAFree(void **ida_mem) IDAAdjFree(IDA_mem); + /* if IDA created the NLS object then free it */ + if (IDA_mem->ownNLS) { + SUNNonlinSolFree(IDA_mem->NLS); + IDA_mem->ownNLS = SUNFALSE; + IDA_mem->NLS = NULL; + } + if (IDA_mem->ida_lfree != NULL) IDA_mem->ida_lfree(IDA_mem); if (IDA_mem->ida_nrtfn > 0) { - free(IDA_mem->ida_glo); IDA_mem->ida_glo = NULL; - free(IDA_mem->ida_ghi); IDA_mem->ida_ghi = NULL; - free(IDA_mem->ida_grout); IDA_mem->ida_grout = NULL; - free(IDA_mem->ida_iroots); IDA_mem->ida_iroots = NULL; + free(IDA_mem->ida_glo); IDA_mem->ida_glo = NULL; + free(IDA_mem->ida_ghi); IDA_mem->ida_ghi = NULL; + free(IDA_mem->ida_grout); IDA_mem->ida_grout = NULL; + free(IDA_mem->ida_iroots); IDA_mem->ida_iroots = NULL; free(IDA_mem->ida_rootdir); IDA_mem->ida_rootdir = NULL; free(IDA_mem->ida_gactive); IDA_mem->ida_gactive = NULL; } @@ -3235,13 +3377,6 @@ void IDAFree(void **ida_mem) free(IDA_mem->ida_Xvecs); IDA_mem->ida_Xvecs = NULL; free(IDA_mem->ida_Zvecs); IDA_mem->ida_Zvecs = NULL; - /* if IDA created the NLS object then free it */ - if (IDA_mem->ownNLS) { - SUNNonlinSolFree(IDA_mem->NLS); - IDA_mem->ownNLS = SUNFALSE; - IDA_mem->NLS = NULL; - } - free(*ida_mem); *ida_mem = NULL; } @@ -3251,13 +3386,13 @@ void IDAFree(void **ida_mem) * * IDAQuadFree frees the problem memory in ida_mem allocated * for quadrature integration. Its only argument is the pointer - * ida_mem returned by IDACreate. + * ida_mem returned by IDACreate. */ void IDAQuadFree(void *ida_mem) { IDAMem IDA_mem; - + if (ida_mem == NULL) return; IDA_mem = (IDAMem) ida_mem; @@ -3292,15 +3427,15 @@ void IDASensFree(void *ida_mem) /* free any vector wrappers */ if (IDA_mem->simMallocDone) { - N_VDestroy(IDA_mem->ycor0Sim); IDA_mem->ycor0Sim = NULL; - N_VDestroy(IDA_mem->ycorSim); IDA_mem->ycorSim = NULL; - N_VDestroy(IDA_mem->ewtSim); IDA_mem->ewtSim = NULL; + N_VDestroy(IDA_mem->ypredictSim); IDA_mem->ypredictSim = NULL; + N_VDestroy(IDA_mem->ycorSim); IDA_mem->ycorSim = NULL; + N_VDestroy(IDA_mem->ewtSim); IDA_mem->ewtSim = NULL; IDA_mem->simMallocDone = SUNFALSE; } if (IDA_mem->stgMallocDone) { - N_VDestroy(IDA_mem->ycor0Stg); IDA_mem->ycor0Stg = NULL; - N_VDestroy(IDA_mem->ycorStg); IDA_mem->ycorStg = NULL; - N_VDestroy(IDA_mem->ewtStg); IDA_mem->ewtStg = NULL; + N_VDestroy(IDA_mem->ypredictStg); IDA_mem->ypredictStg = NULL; + N_VDestroy(IDA_mem->ycorStg); IDA_mem->ycorStg = NULL; + N_VDestroy(IDA_mem->ewtStg); IDA_mem->ewtStg = NULL; IDA_mem->stgMallocDone = SUNFALSE; } @@ -3315,14 +3450,20 @@ void IDASensFree(void *ida_mem) IDA_mem->ownNLSstg = SUNFALSE; IDA_mem->NLSstg = NULL; } + + /* free min atol array if necessary */ + if (IDA_mem->ida_atolSmin0) { + free(IDA_mem->ida_atolSmin0); + IDA_mem->ida_atolSmin0 = NULL; + } } /* * IDAQuadSensFree * * IDAQuadSensFree frees the problem memory in ida_mem allocated - * for quadrature sensitivity analysis. Its only argument is the - * pointer ida_mem returned by IDACreate. + * for quadrature sensitivity analysis. Its only argument is the + * pointer ida_mem returned by IDACreate. */ void IDAQuadSensFree(void* ida_mem) { @@ -3336,9 +3477,15 @@ void IDAQuadSensFree(void* ida_mem) IDA_mem->ida_quadSensMallocDone=SUNFALSE; IDA_mem->ida_quadr_sensi = SUNFALSE; } + + /* free min atol array if necessary */ + if (IDA_mem->ida_atolQSmin0) { + free(IDA_mem->ida_atolQSmin0); + IDA_mem->ida_atolQSmin0 = NULL; + } } -/* +/* * ================================================================= * PRIVATE FUNCTIONS * ================================================================= @@ -3369,7 +3516,7 @@ static booleantype IDACheckNvector(N_Vector tmpl) return(SUNTRUE); } -/* +/* * ----------------------------------------------------------------- * Memory allocation/deallocation * ----------------------------------------------------------------- @@ -3380,8 +3527,8 @@ static booleantype IDACheckNvector(N_Vector tmpl) * * This routine allocates the IDA vectors ewt, tempv1, tempv2, and * phi[0], ..., phi[maxord]. - * If all memory allocations are successful, IDAAllocVectors returns - * SUNTRUE. Otherwise all allocated memory is freed and IDAAllocVectors + * If all memory allocations are successful, IDAAllocVectors returns + * SUNTRUE. Otherwise all allocated memory is freed and IDAAllocVectors * returns SUNFALSE. * This routine also sets the optional outputs lrw and liw, which are * (respectively) the lengths of the real and integer work spaces @@ -3393,7 +3540,7 @@ static booleantype IDAAllocVectors(IDAMem IDA_mem, N_Vector tmpl) int i, j, maxcol; /* Allocate ewt, ee, delta, yypredict, yppredict, savres, tempv1, tempv2, tempv3 */ - + IDA_mem->ida_ewt = N_VClone(tmpl); if (IDA_mem->ida_ewt == NULL) return(SUNFALSE); @@ -3489,8 +3636,7 @@ static booleantype IDAAllocVectors(IDAMem IDA_mem, N_Vector tmpl) N_VDestroy(IDA_mem->ida_tempv1); N_VDestroy(IDA_mem->ida_tempv2); N_VDestroy(IDA_mem->ida_tempv3); - for (i=0; i < j; i++) - N_VDestroy(IDA_mem->ida_phi[i]); + for (i=0; i < j; i++) N_VDestroy(IDA_mem->ida_phi[i]); return(SUNFALSE); } } @@ -3514,16 +3660,16 @@ static booleantype IDAAllocVectors(IDAMem IDA_mem, N_Vector tmpl) static void IDAFreeVectors(IDAMem IDA_mem) { int j, maxcol; - - N_VDestroy(IDA_mem->ida_ewt); IDA_mem->ida_ewt = NULL; - N_VDestroy(IDA_mem->ida_ee); IDA_mem->ida_ee = NULL; - N_VDestroy(IDA_mem->ida_delta); IDA_mem->ida_delta = NULL; + + N_VDestroy(IDA_mem->ida_ewt); IDA_mem->ida_ewt = NULL; + N_VDestroy(IDA_mem->ida_ee); IDA_mem->ida_ee = NULL; + N_VDestroy(IDA_mem->ida_delta); IDA_mem->ida_delta = NULL; N_VDestroy(IDA_mem->ida_yypredict); IDA_mem->ida_yypredict = NULL; N_VDestroy(IDA_mem->ida_yppredict); IDA_mem->ida_yppredict = NULL; - N_VDestroy(IDA_mem->ida_savres); IDA_mem->ida_savres = NULL; - N_VDestroy(IDA_mem->ida_tempv1); IDA_mem->ida_tempv1 = NULL; - N_VDestroy(IDA_mem->ida_tempv2); IDA_mem->ida_tempv2 = NULL; - N_VDestroy(IDA_mem->ida_tempv3); IDA_mem->ida_tempv3 = NULL; + N_VDestroy(IDA_mem->ida_savres); IDA_mem->ida_savres = NULL; + N_VDestroy(IDA_mem->ida_tempv1); IDA_mem->ida_tempv1 = NULL; + N_VDestroy(IDA_mem->ida_tempv2); IDA_mem->ida_tempv2 = NULL; + N_VDestroy(IDA_mem->ida_tempv3); IDA_mem->ida_tempv3 = NULL; maxcol = SUNMAX(IDA_mem->ida_maxord_alloc,3); for(j=0; j <= maxcol; j++) { N_VDestroy(IDA_mem->ida_phi[j]); @@ -3540,7 +3686,8 @@ static void IDAFreeVectors(IDAMem IDA_mem) } if (IDA_mem->ida_constraintsMallocDone) { - N_VDestroy(IDA_mem->ida_constraints); IDA_mem->ida_constraints = NULL; + N_VDestroy(IDA_mem->ida_constraints); + IDA_mem->ida_constraints = NULL; IDA_mem->ida_lrw -= IDA_mem->ida_lrw1; IDA_mem->ida_liw -= IDA_mem->ida_liw1; } @@ -3556,11 +3703,11 @@ static void IDAFreeVectors(IDAMem IDA_mem) /* * IDAQuadAllocVectors * - * NOTE: Space for ewtQ is allocated even when errconQ=SUNFALSE, + * NOTE: Space for ewtQ is allocated even when errconQ=SUNFALSE, * although in this case, ewtQ is never used. The reason for this * decision is to allow the user to re-initialize the quadrature * computation with errconQ=SUNTRUE, after an initialization with - * errconQ=SUNFALSE, without new memory allocation within + * errconQ=SUNFALSE, without new memory allocation within * IDAQuadReInit. */ @@ -3658,7 +3805,7 @@ static void IDAQuadFreeVectors(IDAMem IDA_mem) static booleantype IDASensAllocVectors(IDAMem IDA_mem, N_Vector tmpl) { int j, maxcol; - + IDA_mem->ida_tmpS1 = IDA_mem->ida_tempv1; IDA_mem->ida_tmpS2 = IDA_mem->ida_tempv2; @@ -3668,7 +3815,7 @@ static booleantype IDASensAllocVectors(IDAMem IDA_mem, N_Vector tmpl) if (IDA_mem->ida_tmpS3==NULL) { return(SUNFALSE); } - + IDA_mem->ida_ewtS = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); if (IDA_mem->ida_ewtS==NULL) { N_VDestroy(IDA_mem->ida_tmpS3); @@ -3689,7 +3836,7 @@ static booleantype IDASensAllocVectors(IDAMem IDA_mem, N_Vector tmpl) N_VDestroy(IDA_mem->ida_tmpS3); return(SUNFALSE); } - + IDA_mem->ida_ypS = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); if (IDA_mem->ida_ypS==NULL) { N_VDestroyVectorArray(IDA_mem->ida_yyS, IDA_mem->ida_Ns); @@ -3820,7 +3967,7 @@ static void IDASensFreeVectors(IDAMem IDA_mem) N_VDestroy(IDA_mem->ida_tmpS3); maxcol = SUNMAX(IDA_mem->ida_maxord_alloc, 4); - for (j=0; j<=maxcol; j++) + for (j=0; j<=maxcol; j++) N_VDestroyVectorArray(IDA_mem->ida_phiS[j], IDA_mem->ida_Ns); free(IDA_mem->ida_pbar); IDA_mem->ida_pbar = NULL; @@ -3834,7 +3981,7 @@ static void IDASensFreeVectors(IDAMem IDA_mem) IDA_mem->ida_lrw -= IDA_mem->ida_Ns*IDA_mem->ida_lrw1; IDA_mem->ida_liw -= IDA_mem->ida_Ns*IDA_mem->ida_liw1; IDA_mem->ida_VatolSMallocDone = SUNFALSE; - } + } if (IDA_mem->ida_SatolSMallocDone) { free(IDA_mem->ida_SatolS); IDA_mem->ida_SatolS = NULL; IDA_mem->ida_lrw -= IDA_mem->ida_Ns; @@ -3846,11 +3993,11 @@ static void IDASensFreeVectors(IDAMem IDA_mem) /* * IDAQuadSensAllocVectors * - * Create (through duplication) N_Vectors used for quadrature sensitivity analysis, + * Create (through duplication) N_Vectors used for quadrature sensitivity analysis, * using the N_Vector 'tmpl' as a template. */ -static booleantype IDAQuadSensAllocVectors(IDAMem IDA_mem, N_Vector tmpl) +static booleantype IDAQuadSensAllocVectors(IDAMem IDA_mem, N_Vector tmpl) { int i, j, maxcol; @@ -3933,7 +4080,7 @@ static void IDAQuadSensFreeVectors(IDAMem IDA_mem) N_VDestroyVectorArray(IDA_mem->ida_tempvQS, IDA_mem->ida_Ns); N_VDestroy(IDA_mem->ida_savrhsQ); - for (j=0; j<=maxcol; j++) N_VDestroyVectorArray(IDA_mem->ida_phiQS[j], IDA_mem->ida_Ns); + for (j=0; j<=maxcol; j++) N_VDestroyVectorArray(IDA_mem->ida_phiQS[j], IDA_mem->ida_Ns); IDA_mem->ida_lrw -= (maxcol + 5)*IDA_mem->ida_Ns*IDA_mem->ida_lrw1Q; IDA_mem->ida_liw -= (maxcol + 5)*IDA_mem->ida_Ns*IDA_mem->ida_liw1Q; @@ -3952,7 +4099,7 @@ static void IDAQuadSensFreeVectors(IDAMem IDA_mem) } -/* +/* * ----------------------------------------------------------------- * Initial setup * ----------------------------------------------------------------- @@ -3961,36 +4108,39 @@ static void IDAQuadSensFreeVectors(IDAMem IDA_mem) /* * IDAInitialSetup * - * This routine is called by IDASolve once at the first step. - * It performs all checks on optional inputs and inputs to + * This routine is called by IDASolve once at the first step. + * It performs all checks on optional inputs and inputs to * IDAInit/IDAReInit that could not be done before. * - * If no merror is encountered, IDAInitialSetup returns IDA_SUCCESS. - * Otherwise, it returns an error flag and reported to the error + * If no error is encountered, IDAInitialSetup returns IDA_SUCCESS. + * Otherwise, it returns an error flag and reported to the error * handler function. */ int IDAInitialSetup(IDAMem IDA_mem) { booleantype conOK; - int ier, retval; + int ier; /* Test for more vector operations, depending on options */ if (IDA_mem->ida_suppressalg) if (IDA_mem->ida_phi[0]->ops->nvwrmsnormmask == NULL) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_BAD_NVECTOR); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_BAD_NVECTOR); return(IDA_ILL_INPUT); } /* Test id vector for legality */ - if (IDA_mem->ida_suppressalg && (IDA_mem->ida_id==NULL)){ - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_MISSING_ID); - return(IDA_ILL_INPUT); + if (IDA_mem->ida_suppressalg && (IDA_mem->ida_id==NULL)){ + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_MISSING_ID); + return(IDA_ILL_INPUT); } /* Did the user specify tolerances? */ if (IDA_mem->ida_itol == IDA_NN) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_NO_TOLS); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_NO_TOLS); return(IDA_ILL_INPUT); } @@ -3998,28 +4148,32 @@ int IDAInitialSetup(IDAMem IDA_mem) if (IDA_mem->ida_user_efun) IDA_mem->ida_edata = IDA_mem->ida_user_data; else IDA_mem->ida_edata = IDA_mem; - /* Initial error weight vectors */ + /* Initial error weight vector */ ier = IDA_mem->ida_efun(IDA_mem->ida_phi[0], IDA_mem->ida_ewt, IDA_mem->ida_edata); if (ier != 0) { - if (IDA_mem->ida_itol == IDA_WF) - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_FAIL_EWT); + if (IDA_mem->ida_itol == IDA_WF) + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_FAIL_EWT); else - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_BAD_EWT); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_BAD_EWT); return(IDA_ILL_INPUT); } if (IDA_mem->ida_quadr) { /* Evaluate quadrature rhs and set phiQ[1] */ - retval = IDA_mem->ida_rhsQ(IDA_mem->ida_tn, IDA_mem->ida_phi[0], - IDA_mem->ida_phi[1], IDA_mem->ida_phiQ[1], - IDA_mem->ida_user_data); + ier = IDA_mem->ida_rhsQ(IDA_mem->ida_tn, IDA_mem->ida_phi[0], + IDA_mem->ida_phi[1], IDA_mem->ida_phiQ[1], + IDA_mem->ida_user_data); IDA_mem->ida_nrQe++; - if (retval < 0) { - IDAProcessError(IDA_mem, IDA_QRHS_FAIL, "IDAS", "IDAInitialSetup", MSG_QRHSFUNC_FAILED); + if (ier < 0) { + IDAProcessError(IDA_mem, IDA_QRHS_FAIL, "IDAS", "IDAInitialSetup", + MSG_QRHSFUNC_FAILED); return(IDA_QRHS_FAIL); - } else if (retval > 0) { - IDAProcessError(IDA_mem, IDA_FIRST_QRHS_ERR, "IDAS", "IDAInitialSetup", MSG_QRHSFUNC_FIRST); + } else if (ier > 0) { + IDAProcessError(IDA_mem, IDA_FIRST_QRHS_ERR, "IDAS", "IDAInitialSetup", + MSG_QRHSFUNC_FIRST); return(IDA_FIRST_QRHS_ERR); } @@ -4027,14 +4181,16 @@ int IDAInitialSetup(IDAMem IDA_mem) /* Did the user specify tolerances? */ if (IDA_mem->ida_itolQ == IDA_NN) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_NO_TOLQ); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_NO_TOLQ); return(IDA_ILL_INPUT); } - + /* Load ewtQ */ ier = IDAQuadEwtSet(IDA_mem, IDA_mem->ida_phiQ[0], IDA_mem->ida_ewtQ); if (ier != 0) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_BAD_EWTQ); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_BAD_EWTQ); return(IDA_ILL_INPUT); } } @@ -4046,14 +4202,16 @@ int IDAInitialSetup(IDAMem IDA_mem) /* Did the user specify tolerances? */ if (IDA_mem->ida_itolS == IDA_NN) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_NO_TOLS); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_NO_TOLS); return(IDA_ILL_INPUT); } - + /* Load ewtS */ ier = IDASensEwtSet(IDA_mem, IDA_mem->ida_phiS[0], IDA_mem->ida_ewtS); if (ier != 0) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_BAD_EWTS); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_BAD_EWTS); return(IDA_ILL_INPUT); } } else { @@ -4063,17 +4221,20 @@ int IDAInitialSetup(IDAMem IDA_mem) if (IDA_mem->ida_quadr_sensi) { /* store the quadrature sensitivity residual. */ - retval = IDA_mem->ida_rhsQS(IDA_mem->ida_Ns, IDA_mem->ida_tn, - IDA_mem->ida_phi[0], IDA_mem->ida_phi[1], - IDA_mem->ida_phiS[0], IDA_mem->ida_phiS[1], - IDA_mem->ida_phiQ[1], IDA_mem->ida_phiQS[1], - IDA_mem->ida_user_dataQS, IDA_mem->ida_tmpS1, IDA_mem->ida_tmpS2, IDA_mem->ida_tmpS3); + ier = IDA_mem->ida_rhsQS(IDA_mem->ida_Ns, IDA_mem->ida_tn, + IDA_mem->ida_phi[0], IDA_mem->ida_phi[1], + IDA_mem->ida_phiS[0], IDA_mem->ida_phiS[1], + IDA_mem->ida_phiQ[1], IDA_mem->ida_phiQS[1], + IDA_mem->ida_user_dataQS, IDA_mem->ida_tmpS1, + IDA_mem->ida_tmpS2, IDA_mem->ida_tmpS3); IDA_mem->ida_nrQSe++; - if (retval < 0) { - IDAProcessError(IDA_mem, IDA_QSRHS_FAIL, "IDAS", "IDAInitialSetup", MSG_QSRHSFUNC_FAILED); + if (ier < 0) { + IDAProcessError(IDA_mem, IDA_QSRHS_FAIL, "IDAS", "IDAInitialSetup", + MSG_QSRHSFUNC_FAILED); return(IDA_QRHS_FAIL); - } else if (retval > 0) { - IDAProcessError(IDA_mem, IDA_FIRST_QSRHS_ERR, "IDAS", "IDAInitialSetup", MSG_QSRHSFUNC_FIRST); + } else if (ier > 0) { + IDAProcessError(IDA_mem, IDA_FIRST_QSRHS_ERR, "IDAS", "IDAInitialSetup", + MSG_QSRHSFUNC_FIRST); return(IDA_FIRST_QSRHS_ERR); } @@ -4081,16 +4242,18 @@ int IDAInitialSetup(IDAMem IDA_mem) * (i.e. quadrature integration must be enabled) and to the problem parameters */ if (IDA_mem->ida_rhsQSDQ) { - + /* Test if quadratures are defined, so we can use fQ */ if (!IDA_mem->ida_quadr) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_NULL_RHSQ); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_NULL_RHSQ); return(IDA_ILL_INPUT); } - + /* Test if we have the problem parameters */ if (IDA_mem->ida_p == NULL) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_NULL_P); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_NULL_P); return(IDA_ILL_INPUT); } } @@ -4098,20 +4261,23 @@ int IDAInitialSetup(IDAMem IDA_mem) if (IDA_mem->ida_errconQS) { /* Did the user specify tolerances? */ if (IDA_mem->ida_itolQS == IDA_NN) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_NO_TOLQS); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_NO_TOLQS); return(IDA_ILL_INPUT); } /* If needed, did the user provide quadrature tolerances? */ if ( (IDA_mem->ida_itolQS == IDA_EE) && (IDA_mem->ida_itolQ == IDA_NN) ) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_NO_TOLQ); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_NO_TOLQ); return(IDA_ILL_INPUT); } - + /* Load ewtS */ ier = IDAQuadSensEwtSet(IDA_mem, IDA_mem->ida_phiQS[0], IDA_mem->ida_ewtQS); if (ier != 0) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_BAD_EWTQS); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_BAD_EWTQS); return(IDA_ILL_INPUT); } } @@ -4123,22 +4289,25 @@ int IDAInitialSetup(IDAMem IDA_mem) if (IDA_mem->ida_constraintsSet) { if (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_BAD_ISM_CONSTR); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_BAD_ISM_CONSTR); return(IDA_ILL_INPUT); } conOK = N_VConstrMask(IDA_mem->ida_constraints, IDA_mem->ida_phi[0], IDA_mem->ida_tempv2); - if (!conOK) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_Y0_FAIL_CONSTR); - return(IDA_ILL_INPUT); + if (!conOK) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", + MSG_Y0_FAIL_CONSTR); + return(IDA_ILL_INPUT); } } /* Call linit function if it exists. */ if (IDA_mem->ida_linit != NULL) { - retval = IDA_mem->ida_linit(IDA_mem); - if (retval != 0) { - IDAProcessError(IDA_mem, IDA_LINIT_FAIL, "IDAS", "IDAInitialSetup", MSG_LINIT_FAIL); + ier = IDA_mem->ida_linit(IDA_mem); + if (ier != 0) { + IDAProcessError(IDA_mem, IDA_LINIT_FAIL, "IDAS", "IDAInitialSetup", + MSG_LINIT_FAIL); return(IDA_LINIT_FAIL); } } @@ -4148,29 +4317,26 @@ int IDAInitialSetup(IDAMem IDA_mem) /* always initialize the DAE NLS in case the user disables sensitivities later */ ier = idaNlsInit(IDA_mem); - if (ier != IDA_SUCCESS) { - IDAProcessError(IDA_mem, IDA_NLS_INIT_FAIL, "IDAS", - "IDAInitialSetup", MSG_NLS_INIT_FAIL); + IDAProcessError(IDA_mem, IDA_NLS_INIT_FAIL, "IDAS", "IDAInitialSetup", + MSG_NLS_INIT_FAIL); return(IDA_NLS_INIT_FAIL); } if (IDA_mem->NLSsim != NULL) { ier = idaNlsInitSensSim(IDA_mem); - if (ier != IDA_SUCCESS) { - IDAProcessError(IDA_mem, IDA_NLS_INIT_FAIL, "IDAS", - "IDAInitialSetup", MSG_NLS_INIT_FAIL); + IDAProcessError(IDA_mem, IDA_NLS_INIT_FAIL, "IDAS", "IDAInitialSetup", + MSG_NLS_INIT_FAIL); return(IDA_NLS_INIT_FAIL); } } if (IDA_mem->NLSstg != NULL) { ier = idaNlsInitSensStg(IDA_mem); - if (ier != IDA_SUCCESS) { - IDAProcessError(IDA_mem, IDA_NLS_INIT_FAIL, "IDAS", - "IDAInitialSetup", MSG_NLS_INIT_FAIL); + IDAProcessError(IDA_mem, IDA_NLS_INIT_FAIL, "IDAS", "IDAInitialSetup", + MSG_NLS_INIT_FAIL); return(IDA_NLS_INIT_FAIL); } } @@ -4205,11 +4371,11 @@ int IDAEwtSet(N_Vector ycur, N_Vector weight, void *data) IDA_mem = (IDAMem) data; switch(IDA_mem->ida_itol) { - case IDA_SS: - flag = IDAEwtSetSS(IDA_mem, ycur, weight); + case IDA_SS: + flag = IDAEwtSetSS(IDA_mem, ycur, weight); break; - case IDA_SV: - flag = IDAEwtSetSV(IDA_mem, ycur, weight); + case IDA_SV: + flag = IDAEwtSetSV(IDA_mem, ycur, weight); break; } return(flag); @@ -4219,9 +4385,9 @@ int IDAEwtSet(N_Vector ycur, N_Vector weight, void *data) * IDAEwtSetSS * * This routine sets ewt as decribed above in the case itol=IDA_SS. - * It tests for non-positive components before inverting. IDAEwtSetSS - * returns 0 if ewt is successfully set to a positive vector - * and -1 otherwise. In the latter case, ewt is considered + * If the absolute tolerance is zero, it tests for non-positive components + * before inverting. IDAEwtSetSS returns 0 if ewt is successfully set to a + * positive vector and -1 otherwise. In the latter case, ewt is considered * undefined. */ @@ -4230,7 +4396,9 @@ static int IDAEwtSetSS(IDAMem IDA_mem, N_Vector ycur, N_Vector weight) N_VAbs(ycur, IDA_mem->ida_tempv1); N_VScale(IDA_mem->ida_rtol, IDA_mem->ida_tempv1, IDA_mem->ida_tempv1); N_VAddConst(IDA_mem->ida_tempv1, IDA_mem->ida_Satol, IDA_mem->ida_tempv1); - if (N_VMin(IDA_mem->ida_tempv1) <= ZERO) return(-1); + if (IDA_mem->ida_atolmin0) { + if (N_VMin(IDA_mem->ida_tempv1) <= ZERO) return(-1); + } N_VInv(IDA_mem->ida_tempv1, weight); return(0); } @@ -4239,17 +4407,20 @@ static int IDAEwtSetSS(IDAMem IDA_mem, N_Vector ycur, N_Vector weight) * IDAEwtSetSV * * This routine sets ewt as decribed above in the case itol=IDA_SV. - * It tests for non-positive components before inverting. IDAEwtSetSV - * returns 0 if ewt is successfully set to a positive vector - * and -1 otherwise. In the latter case, ewt is considered + * If the absolute tolerance is zero, it tests for non-positive components + * before inverting. IDAEwtSetSV returns 0 if ewt is successfully set to a + * positive vector and -1 otherwise. In the latter case, ewt is considered * undefined. */ static int IDAEwtSetSV(IDAMem IDA_mem, N_Vector ycur, N_Vector weight) { N_VAbs(ycur, IDA_mem->ida_tempv1); - N_VLinearSum(IDA_mem->ida_rtol, IDA_mem->ida_tempv1, ONE, IDA_mem->ida_Vatol, IDA_mem->ida_tempv1); - if (N_VMin(IDA_mem->ida_tempv1) <= ZERO) return(-1); + N_VLinearSum(IDA_mem->ida_rtol, IDA_mem->ida_tempv1, + ONE, IDA_mem->ida_Vatol, IDA_mem->ida_tempv1); + if (IDA_mem->ida_atolmin0) { + if (N_VMin(IDA_mem->ida_tempv1) <= ZERO) return(-1); + } N_VInv(IDA_mem->ida_tempv1, weight); return(0); } @@ -4264,10 +4435,10 @@ static int IDAQuadEwtSet(IDAMem IDA_mem, N_Vector qcur, N_Vector weightQ) int flag=0; switch (IDA_mem->ida_itolQ) { - case IDA_SS: + case IDA_SS: flag = IDAQuadEwtSetSS(IDA_mem, qcur, weightQ); break; - case IDA_SV: + case IDA_SV: flag = IDAQuadEwtSetSV(IDA_mem, qcur, weightQ); break; } @@ -4291,7 +4462,9 @@ static int IDAQuadEwtSetSS(IDAMem IDA_mem, N_Vector qcur, N_Vector weightQ) N_VAbs(qcur, tempvQ); N_VScale(IDA_mem->ida_rtolQ, tempvQ, tempvQ); N_VAddConst(tempvQ, IDA_mem->ida_SatolQ, tempvQ); - if (N_VMin(tempvQ) <= ZERO) return(-1); + if (IDA_mem->ida_atolQmin0) { + if (N_VMin(tempvQ) <= ZERO) return(-1); + } N_VInv(tempvQ, weightQ); return(0); @@ -4311,7 +4484,9 @@ static int IDAQuadEwtSetSV(IDAMem IDA_mem, N_Vector qcur, N_Vector weightQ) N_VAbs(qcur, tempvQ); N_VLinearSum(IDA_mem->ida_rtolQ, tempvQ, ONE, IDA_mem->ida_VatolQ, tempvQ); - if (N_VMin(tempvQ) <= ZERO) return(-1); + if (IDA_mem->ida_atolQmin0) { + if (N_VMin(tempvQ) <= ZERO) return(-1); + } N_VInv(tempvQ, weightQ); return(0); @@ -4330,10 +4505,10 @@ int IDASensEwtSet(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS) case IDA_EE: flag = IDASensEwtSetEE(IDA_mem, yScur, weightS); break; - case IDA_SS: + case IDA_SS: flag = IDASensEwtSetSS(IDA_mem, yScur, weightS); break; - case IDA_SV: + case IDA_SV: flag = IDASensEwtSetSV(IDA_mem, yScur, weightS); break; } @@ -4381,12 +4556,14 @@ static int IDASensEwtSetEE(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS) static int IDASensEwtSetSS(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS) { int is; - + for (is=0; isida_Ns; is++) { N_VAbs(yScur[is], IDA_mem->ida_tempv1); N_VScale(IDA_mem->ida_rtolS, IDA_mem->ida_tempv1, IDA_mem->ida_tempv1); N_VAddConst(IDA_mem->ida_tempv1, IDA_mem->ida_SatolS[is], IDA_mem->ida_tempv1); - if (N_VMin(IDA_mem->ida_tempv1) <= ZERO) return(-1); + if (IDA_mem->ida_atolSmin0[is]) { + if (N_VMin(IDA_mem->ida_tempv1) <= ZERO) return(-1); + } N_VInv(IDA_mem->ida_tempv1, weightS[is]); } return(0); @@ -4400,11 +4577,13 @@ static int IDASensEwtSetSS(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS) static int IDASensEwtSetSV(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS) { int is; - + for (is=0; isida_Ns; is++) { N_VAbs(yScur[is], IDA_mem->ida_tempv1); N_VLinearSum(IDA_mem->ida_rtolS, IDA_mem->ida_tempv1, ONE, IDA_mem->ida_VatolS[is], IDA_mem->ida_tempv1); - if (N_VMin(IDA_mem->ida_tempv1) <= ZERO) return(-1); + if (IDA_mem->ida_atolSmin0[is]) { + if (N_VMin(IDA_mem->ida_tempv1) <= ZERO) return(-1); + } N_VInv(IDA_mem->ida_tempv1, weightS[is]); } @@ -4424,10 +4603,10 @@ int IDAQuadSensEwtSet(IDAMem IDA_mem, N_Vector *yQScur, N_Vector *weightQS) case IDA_EE: flag = IDAQuadSensEwtSetEE(IDA_mem, yQScur, weightQS); break; - case IDA_SS: + case IDA_SS: flag = IDAQuadSensEwtSetSS(IDA_mem, yQScur, weightQS); break; - case IDA_SV: + case IDA_SV: flag = IDAQuadSensEwtSetSV(IDA_mem, yQScur, weightQS); break; } @@ -4478,7 +4657,9 @@ static int IDAQuadSensEwtSetSS(IDAMem IDA_mem, N_Vector *yQScur, N_Vector *weigh N_VAbs(yQScur[is], tempvQ); N_VScale(IDA_mem->ida_rtolQS, tempvQ, tempvQ); N_VAddConst(tempvQ, IDA_mem->ida_SatolQS[is], tempvQ); - if (N_VMin(tempvQ) <= ZERO) return(-1); + if (IDA_mem->ida_atolQSmin0[is]) { + if (N_VMin(tempvQ) <= ZERO) return(-1); + } N_VInv(tempvQ, weightQS[is]); } @@ -4492,19 +4673,20 @@ static int IDAQuadSensEwtSetSV(IDAMem IDA_mem, N_Vector *yQScur, N_Vector *weigh /* Use ypQ as temporary storage */ tempvQ = IDA_mem->ida_ypQ; - + for (is=0; isida_Ns; is++) { N_VAbs(yQScur[is], tempvQ); N_VLinearSum(IDA_mem->ida_rtolQS, tempvQ, ONE, IDA_mem->ida_VatolQS[is], tempvQ); - if (N_VMin(tempvQ) <= ZERO) return(-1); + if (IDA_mem->ida_atolQSmin0[is]) { + if (N_VMin(tempvQ) <= ZERO) return(-1); + } N_VInv(tempvQ, weightQS[is]); } return(0); } - -/* +/* * ----------------------------------------------------------------- * Stopping tests * ----------------------------------------------------------------- @@ -4521,20 +4703,20 @@ static int IDAQuadSensEwtSetSV(IDAMem IDA_mem, N_Vector *yQScur, N_Vector *weigh * CONTINUE_STEPS if no stop conditions were found * IDA_SUCCESS for a normal return to the user * IDA_TSTOP_RETURN for a tstop-reached return to the user - * IDA_ILL_INPUT for an illegal-input return to the user + * IDA_ILL_INPUT for an illegal-input return to the user * * In the tstop cases, this routine may adjust the stepsize hh to cause * the next step to reach tstop exactly. */ -static int IDAStopTest1(IDAMem IDA_mem, realtype tout, realtype *tret, +static int IDAStopTest1(IDAMem IDA_mem, realtype tout, realtype *tret, N_Vector yret, N_Vector ypret, int itask) { int ier; realtype troundoff; switch (itask) { - + case IDA_NORMAL: if (IDA_mem->ida_tstopset) { @@ -4574,12 +4756,12 @@ static int IDAStopTest1(IDAMem IDA_mem, realtype tout, realtype *tret, IDA_mem->ida_tstopset = SUNFALSE; return(IDA_TSTOP_RETURN); } - if ((IDA_mem->ida_tn + IDA_mem->ida_hh - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) + if ((IDA_mem->ida_tn + IDA_mem->ida_hh - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) IDA_mem->ida_hh = (IDA_mem->ida_tstop - IDA_mem->ida_tn)*(ONE - FOUR * IDA_mem->ida_uround); } return(CONTINUE_STEPS); - + case IDA_ONE_STEP: if (IDA_mem->ida_tstopset) { @@ -4611,12 +4793,12 @@ static int IDAStopTest1(IDAMem IDA_mem, realtype tout, realtype *tret, IDA_mem->ida_tstopset = SUNFALSE; return(IDA_TSTOP_RETURN); } - if ((IDA_mem->ida_tn + IDA_mem->ida_hh - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) + if ((IDA_mem->ida_tn + IDA_mem->ida_hh - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) IDA_mem->ida_hh = (IDA_mem->ida_tstop - IDA_mem->ida_tn)*(ONE - FOUR * IDA_mem->ida_uround); } return(CONTINUE_STEPS); - + } return(IDA_ILL_INPUT); /* This return should never happen. */ } @@ -4631,7 +4813,7 @@ static int IDAStopTest1(IDAMem IDA_mem, realtype tout, realtype *tret, * CONTINUE_STEPS if no stop conditions were found * IDA_SUCCESS for a normal return to the user * IDA_TSTOP_RETURN for a tstop-reached return to the user - * IDA_ILL_INPUT for an illegal-input return to the user + * IDA_ILL_INPUT for an illegal-input return to the user * * In the two cases with tstop, this routine may reset the stepsize hh * to cause the next step to reach tstop exactly. @@ -4643,7 +4825,7 @@ static int IDAStopTest1(IDAMem IDA_mem, realtype tout, realtype *tret, * because the same test was made prior to the step. */ -static int IDAStopTest2(IDAMem IDA_mem, realtype tout, realtype *tret, +static int IDAStopTest2(IDAMem IDA_mem, realtype tout, realtype *tret, N_Vector yret, N_Vector ypret, int itask) { /* int ier; */ @@ -4651,7 +4833,7 @@ static int IDAStopTest2(IDAMem IDA_mem, realtype tout, realtype *tret, switch (itask) { - case IDA_NORMAL: + case IDA_NORMAL: /* Test for tn past tout. */ if ((IDA_mem->ida_tn - tout)*IDA_mem->ida_hh >= ZERO) { @@ -4669,7 +4851,7 @@ static int IDAStopTest2(IDAMem IDA_mem, realtype tout, realtype *tret, IDA_mem->ida_tstopset = SUNFALSE; return(IDA_TSTOP_RETURN); } - if ((IDA_mem->ida_tn + IDA_mem->ida_hh - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) + if ((IDA_mem->ida_tn + IDA_mem->ida_hh - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) IDA_mem->ida_hh = (IDA_mem->ida_tstop - IDA_mem->ida_tn)*(ONE - FOUR * IDA_mem->ida_uround); } @@ -4686,7 +4868,7 @@ static int IDAStopTest2(IDAMem IDA_mem, realtype tout, realtype *tret, IDA_mem->ida_tstopset = SUNFALSE; return(IDA_TSTOP_RETURN); } - if ((IDA_mem->ida_tn + IDA_mem->ida_hh - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) + if ((IDA_mem->ida_tn + IDA_mem->ida_hh - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) IDA_mem->ida_hh = (IDA_mem->ida_tstop - IDA_mem->ida_tn)*(ONE - FOUR * IDA_mem->ida_uround); } @@ -4697,7 +4879,7 @@ static int IDAStopTest2(IDAMem IDA_mem, realtype tout, realtype *tret, return IDA_ILL_INPUT; /* This return should never happen. */ } -/* +/* * ----------------------------------------------------------------- * Error handler * ----------------------------------------------------------------- @@ -4717,55 +4899,97 @@ static int IDAHandleFailure(IDAMem IDA_mem, int sflag) switch (sflag) { case IDA_ERR_FAIL: - IDAProcessError(IDA_mem, IDA_ERR_FAIL, "IDAS", "IDASolve", MSG_ERR_FAILS, IDA_mem->ida_tn, IDA_mem->ida_hh); + IDAProcessError(IDA_mem, IDA_ERR_FAIL, "IDAS", "IDASolve", + MSG_ERR_FAILS, IDA_mem->ida_tn, IDA_mem->ida_hh); return(IDA_ERR_FAIL); case IDA_CONV_FAIL: - IDAProcessError(IDA_mem, IDA_CONV_FAIL, "IDAS", "IDASolve", MSG_CONV_FAILS, IDA_mem->ida_tn, IDA_mem->ida_hh); + IDAProcessError(IDA_mem, IDA_CONV_FAIL, "IDAS", "IDASolve", + MSG_CONV_FAILS, IDA_mem->ida_tn, IDA_mem->ida_hh); return(IDA_CONV_FAIL); - case IDA_LSETUP_FAIL: - IDAProcessError(IDA_mem, IDA_LSETUP_FAIL, "IDAS", "IDASolve", MSG_SETUP_FAILED, IDA_mem->ida_tn); + case IDA_LSETUP_FAIL: + IDAProcessError(IDA_mem, IDA_LSETUP_FAIL, "IDAS", "IDASolve", + MSG_SETUP_FAILED, IDA_mem->ida_tn); return(IDA_LSETUP_FAIL); - case IDA_LSOLVE_FAIL: - IDAProcessError(IDA_mem, IDA_LSOLVE_FAIL, "IDAS", "IDASolve", MSG_SOLVE_FAILED, IDA_mem->ida_tn); + case IDA_LSOLVE_FAIL: + IDAProcessError(IDA_mem, IDA_LSOLVE_FAIL, "IDAS", "IDASolve", + MSG_SOLVE_FAILED, IDA_mem->ida_tn); return(IDA_LSOLVE_FAIL); case IDA_REP_RES_ERR: - IDAProcessError(IDA_mem, IDA_REP_RES_ERR, "IDAS", "IDASolve", MSG_REP_RES_ERR, IDA_mem->ida_tn); + IDAProcessError(IDA_mem, IDA_REP_RES_ERR, "IDAS", "IDASolve", + MSG_REP_RES_ERR, IDA_mem->ida_tn); return(IDA_REP_RES_ERR); - case IDA_RES_FAIL: - IDAProcessError(IDA_mem, IDA_RES_FAIL, "IDAS", "IDASolve", MSG_RES_NONRECOV, IDA_mem->ida_tn); + case IDA_RES_FAIL: + IDAProcessError(IDA_mem, IDA_RES_FAIL, "IDAS", "IDASolve", + MSG_RES_NONRECOV, IDA_mem->ida_tn); return(IDA_RES_FAIL); - case IDA_CONSTR_FAIL: - IDAProcessError(IDA_mem, IDA_CONSTR_FAIL, "IDAS", "IDASolve", MSG_FAILED_CONSTR, IDA_mem->ida_tn); + case IDA_REP_QRHS_ERR: + IDAProcessError(IDA_mem, IDA_REP_QRHS_ERR, "IDAS", "IDASolve", + MSG_QRHSFUNC_REPTD, IDA_mem->ida_tn); + return(IDA_REP_QRHS_ERR); + + case IDA_QRHS_FAIL: + IDAProcessError(IDA_mem, IDA_QRHS_FAIL, "IDAS", "IDASolve", + MSG_QRHSFUNC_FAILED, IDA_mem->ida_tn); + return(IDA_QRHS_FAIL); + + case IDA_REP_SRES_ERR: + IDAProcessError(IDA_mem, IDA_REP_SRES_ERR, "IDAS", "IDASolve", + MSG_SRES_REPTD, IDA_mem->ida_tn); + return(IDA_REP_SRES_ERR); + + case IDA_SRES_FAIL: + IDAProcessError(IDA_mem, IDA_SRES_FAIL, "IDAS", "IDASolve", + MSG_SRES_FAILED, IDA_mem->ida_tn); + return(IDA_SRES_FAIL); + + case IDA_REP_QSRHS_ERR: + IDAProcessError(IDA_mem, IDA_REP_QSRHS_ERR, "IDAS", "IDASolve", + MSG_QSRHSFUNC_REPTD, IDA_mem->ida_tn); + return(IDA_REP_QSRHS_ERR); + + case IDA_QSRHS_FAIL: + IDAProcessError(IDA_mem, IDA_QSRHS_FAIL, "IDAS", "IDASolve", + MSG_QSRHSFUNC_FAILED, IDA_mem->ida_tn); + return(IDA_QSRHS_FAIL); + + case IDA_CONSTR_FAIL: + IDAProcessError(IDA_mem, IDA_CONSTR_FAIL, "IDAS", "IDASolve", + MSG_FAILED_CONSTR, IDA_mem->ida_tn); return(IDA_CONSTR_FAIL); case IDA_MEM_NULL: - IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASolve", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASolve", + MSG_NO_MEM); return(IDA_MEM_NULL); case SUN_NLS_MEM_NULL: - IDAProcessError(IDA_mem, IDA_MEM_NULL, "IDA", "IDASolve", + IDAProcessError(IDA_mem, IDA_MEM_NULL, "IDAS", "IDASolve", MSG_NLS_INPUT_NULL, IDA_mem->ida_tn); return(IDA_MEM_NULL); case IDA_NLS_SETUP_FAIL: - IDAProcessError(IDA_mem, IDA_NLS_SETUP_FAIL, "IDA", "IDASolve", + IDAProcessError(IDA_mem, IDA_NLS_SETUP_FAIL, "IDAS", "IDASolve", MSG_NLS_SETUP_FAILED, IDA_mem->ida_tn); return(IDA_NLS_SETUP_FAIL); + case IDA_NLS_FAIL: + IDAProcessError(IDA_mem, IDA_NLS_FAIL, "IDA", "IDASolve", + MSG_NLS_FAIL, IDA_mem->ida_tn); + return(IDA_NLS_FAIL); } /* This return should never happen */ - IDAProcessError(IDA_mem, IDA_UNRECOGNIZED_ERROR, "IDA", "IDASolve", + IDAProcessError(IDA_mem, IDA_UNRECOGNIZED_ERROR, "IDAS", "IDASolve", "IDA encountered an unrecognized error. Please report this to the Sundials developers at sundials-users@llnl.gov"); return (IDA_UNRECOGNIZED_ERROR); } -/* +/* * ----------------------------------------------------------------- * Main IDAStep function * ----------------------------------------------------------------- @@ -4782,7 +5006,7 @@ static int IDAHandleFailure(IDAMem IDA_mem, int sflag) * yy is used for y, and yp is used for y'. The function F is supplied as 'res' * by the user. * - * The methods used are modified divided difference, fixed leading + * The methods used are modified divided difference, fixed leading * coefficient forms of backward differentiation formulas. * The code adjusts the stepsize and order to control the local error per step. * @@ -4803,23 +5027,23 @@ static int IDAHandleFailure(IDAMem IDA_mem, int sflag) * tt -- Independent variable. * yy -- Solution vector at tt. * yp -- Derivative of solution vector after successful stelp. - * res -- User-supplied function to evaluate the residual. See the + * res -- User-supplied function to evaluate the residual. See the * description given in file ida.h . * lsetup -- Routine to prepare for the linear solver call. It may either * save or recalculate quantities used by lsolve. (Optional) * lsolve -- Routine to solve a linear system. A prior call to lsetup - * may be required. + * may be required. * hh -- Appropriate step size for next step. * ewt -- Vector of weights used in all convergence tests. - * phi -- Array of divided differences used by IDAStep. This array is composed - * of (maxord+1) nvectors (each of size Neq). (maxord+1) is the maximum + * phi -- Array of divided differences used by IDAStep. This array is composed + * of (maxord+1) nvectors (each of size Neq). (maxord+1) is the maximum * order for the problem, maxord, plus 1. * * Return values are: - * IDA_SUCCESS IDA_RES_FAIL LSETUP_ERROR_NONRECVR - * IDA_LSOLVE_FAIL IDA_ERR_FAIL - * IDA_CONSTR_FAIL IDA_CONV_FAIL - * IDA_REP_RES_ERR + * IDA_SUCCESS IDA_RES_FAIL LSETUP_ERROR_NONRECVR + * IDA_LSOLVE_FAIL IDA_ERR_FAIL + * IDA_CONSTR_FAIL IDA_CONV_FAIL + * IDA_REP_RES_ERR */ static int IDAStep(IDAMem IDA_mem) @@ -4855,7 +5079,7 @@ static int IDAStep(IDAMem IDA_mem) /* Looping point for attempts to take a step */ - for(;;) { + for(;;) { /*----------------------- Set method coefficients @@ -4898,11 +5122,11 @@ static int IDAStep(IDAMem IDA_mem) /* restore and decide what to do */ IDARestore(IDA_mem, saved_t); - kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, + kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, &(IDA_mem->ida_ncfn), &ncf, &(IDA_mem->ida_netf), &nef); - /* exit on nonrecoverable failure */ + /* exit on nonrecoverable failure */ if (kflag != PREDICT_AGAIN) return(kflag); /* recoverable error; predict again */ @@ -4912,7 +5136,7 @@ static int IDAStep(IDAMem IDA_mem) } /*---------------------------- - Advance quadrature variables + Advance quadrature variables ----------------------------*/ if (IDA_mem->ida_quadr) { @@ -4927,13 +5151,13 @@ static int IDAStep(IDAMem IDA_mem) /* restore and decide what to do */ IDARestore(IDA_mem, saved_t); - kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, + kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, &(IDA_mem->ida_ncfnQ), &ncf, &(IDA_mem->ida_netfQ), &nef); - /* exit on nonrecoverable failure */ + /* exit on nonrecoverable failure */ if (kflag != PREDICT_AGAIN) return(kflag); - + /* recoverable error; predict again */ if(IDA_mem->ida_nst==0) IDAReset(IDA_mem); continue; @@ -4945,8 +5169,8 @@ static int IDAStep(IDAMem IDA_mem) --------------------------------------------------*/ if (sensi_stg) { - /* Evaluate res at converged y, needed for future evaluations of sens. RHS - If res() fails recoverably, treat it as a convergence failure and + /* Evaluate res at converged y, needed for future evaluations of sens. RHS + If res() fails recoverably, treat it as a convergence failure and attempt the step again */ retval = IDA_mem->ida_res(IDA_mem->ida_tn, @@ -4955,13 +5179,13 @@ static int IDAStep(IDAMem IDA_mem) if (retval < 0) return(IDA_RES_FAIL); if (retval > 0) continue; - + /* Compute predicted values for yyS and ypS */ IDASensPredict(IDA_mem, IDA_mem->ida_yySpredict, IDA_mem->ida_ypSpredict); /* Nonlinear system solution */ nflag = IDASensNls(IDA_mem); - + /* If NLS was successful, perform error test */ if (IDA_mem->ida_errconS && (nflag == IDA_SUCCESS)) nflag = IDASensTestError(IDA_mem, ck, &err_k, &err_km1, &err_km2); @@ -4971,13 +5195,13 @@ static int IDAStep(IDAMem IDA_mem) /* restore and decide what to do */ IDARestore(IDA_mem, saved_t); - kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, + kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, &(IDA_mem->ida_ncfnQ), &ncf, &(IDA_mem->ida_netfQ), &nef); - - /* exit on nonrecoverable failure */ + + /* exit on nonrecoverable failure */ if (kflag != PREDICT_AGAIN) return(kflag); - + /* recoverable error; predict again */ if(IDA_mem->ida_nst==0) IDAReset(IDA_mem); continue; @@ -5000,13 +5224,13 @@ static int IDAStep(IDAMem IDA_mem) /* restore and decide what to do */ IDARestore(IDA_mem, saved_t); - kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, + kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, &(IDA_mem->ida_ncfnQ), &ncf, &(IDA_mem->ida_netfQ), &nef); - /* exit on nonrecoverable failure */ + /* exit on nonrecoverable failure */ if (kflag != PREDICT_AGAIN) return(kflag); - + /* recoverable error; predict again */ if(IDA_mem->ida_nst==0) IDAReset(IDA_mem); continue; @@ -5023,7 +5247,7 @@ static int IDAStep(IDAMem IDA_mem) IDACompleteStep(IDA_mem, err_k, err_km1); - /* + /* Rescale ee vector to be the estimated local error Notes: (1) altering the value of ee is permissible since @@ -5039,86 +5263,13 @@ static int IDAStep(IDAMem IDA_mem) return(IDA_SUCCESS); } -/* - * IDAGetSolution - * - * This routine evaluates y(t) and y'(t) as the value and derivative of - * the interpolating polynomial at the independent variable t, and stores - * the results in the vectors yret and ypret. It uses the current - * independent variable value, tn, and the method order last used, kused. - * This function is called by IDASolve with t = tout, t = tn, or t = tstop. - * - * If kused = 0 (no step has been taken), or if t = tn, then the order used - * here is taken to be 1, giving yret = phi[0], ypret = phi[1]/psi[0]. - * - * The return values are: - * IDA_SUCCESS if t is legal, or - * IDA_BAD_T if t is not within the interval of the last step taken. - */ - -int IDAGetSolution(void *ida_mem, realtype t, N_Vector yret, N_Vector ypret) -{ - IDAMem IDA_mem; - realtype tfuzz, tp, delt, c, d, gam; - int j, kord, retval; - - if (ida_mem == NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSolution", MSG_NO_MEM); - return (IDA_MEM_NULL); - } - IDA_mem = (IDAMem) ida_mem; - - /* Check t for legality. Here tn - hused is t_{n-1}. */ - - tfuzz = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); - if (IDA_mem->ida_hh < ZERO) tfuzz = - tfuzz; - tp = IDA_mem->ida_tn - IDA_mem->ida_hused - tfuzz; - if ((t - tp)*IDA_mem->ida_hh < ZERO) { - IDAProcessError(IDA_mem, IDA_BAD_T, "IDAS", "IDAGetSolution", MSG_BAD_T, - t, IDA_mem->ida_tn-IDA_mem->ida_hused, IDA_mem->ida_tn); - return(IDA_BAD_T); - } - - /* Initialize kord = (kused or 1). */ - - kord = IDA_mem->ida_kused; - if (IDA_mem->ida_kused == 0) kord = 1; - - /* Accumulate multiples of columns phi[j] into yret and ypret. */ - - delt = t - IDA_mem->ida_tn; - c = ONE; d = ZERO; - gam = delt / IDA_mem->ida_psi[0]; - - IDA_mem->ida_cvals[0] = c; - for (j=1; j <= kord; j++) { - d = d*gam + c / IDA_mem->ida_psi[j-1]; - c = c*gam; - gam = (delt + IDA_mem->ida_psi[j-1]) / IDA_mem->ida_psi[j]; - - IDA_mem->ida_cvals[j] = c; - IDA_mem->ida_dvals[j-1] = d; - } - - retval = N_VLinearCombination(kord+1, IDA_mem->ida_cvals, - IDA_mem->ida_phi, yret); - if (retval != IDA_SUCCESS) return(IDA_VECTOROP_ERR); - - retval = N_VLinearCombination(kord, IDA_mem->ida_dvals, - IDA_mem->ida_phi+1, ypret); - if (retval != IDA_SUCCESS) return(IDA_VECTOROP_ERR); - - return(IDA_SUCCESS); -} - - /* * IDASetCoeffs * * This routine computes the coefficients relevant to the current step. * The counter ns counts the number of consecutive steps taken at * constant stepsize h and order k, up to a maximum of k + 2. - * Then the first ns components of beta will be one, and on a step + * Then the first ns components of beta will be one, and on a step * with ns = k + 2, the coefficients alpha, etc. need not be reset here. * Also, IDACompleteStep prohibits an order increase until ns = k + 2. */ @@ -5134,19 +5285,19 @@ static void IDASetCoeffs(IDAMem IDA_mem, realtype *ck) (IDA_mem->ida_kk != IDA_mem->ida_kused) ) IDA_mem->ida_ns = 0; IDA_mem->ida_ns = SUNMIN(IDA_mem->ida_ns+1, IDA_mem->ida_kused+2); - if (IDA_mem->ida_kk+1 >= IDA_mem->ida_ns) { + if (IDA_mem->ida_kk + 1 >= IDA_mem->ida_ns) { IDA_mem->ida_beta[0] = ONE; IDA_mem->ida_alpha[0] = ONE; temp1 = IDA_mem->ida_hh; IDA_mem->ida_gamma[0] = ZERO; IDA_mem->ida_sigma[0] = ONE; - for(i=1;i<=IDA_mem->ida_kk;i++){ + for(i=1; i<=IDA_mem->ida_kk; i++) { temp2 = IDA_mem->ida_psi[i-1]; IDA_mem->ida_psi[i-1] = temp1; IDA_mem->ida_beta[i] = IDA_mem->ida_beta[i-1] * IDA_mem->ida_psi[i-1] / temp2; temp1 = temp2 + IDA_mem->ida_hh; IDA_mem->ida_alpha[i] = IDA_mem->ida_hh / temp1; - IDA_mem->ida_sigma[i] = i * IDA_mem->ida_sigma[i-1] * IDA_mem->ida_alpha[i]; + IDA_mem->ida_sigma[i] = i * IDA_mem->ida_sigma[i-1] * IDA_mem->ida_alpha[i]; IDA_mem->ida_gamma[i] = IDA_mem->ida_gamma[i-1] + IDA_mem->ida_alpha[i-1] / IDA_mem->ida_hh; } IDA_mem->ida_psi[IDA_mem->ida_kk] = temp1; @@ -5154,7 +5305,7 @@ static void IDASetCoeffs(IDAMem IDA_mem, realtype *ck) /* compute alphas, alpha0 */ alphas = ZERO; alpha0 = ZERO; - for(i=0;iida_kk;i++){ + for(i=0; iida_kk; i++) { alphas = alphas - ONE/(i+1); alpha0 = alpha0 - IDA_mem->ida_alpha[i]; } @@ -5162,15 +5313,16 @@ static void IDASetCoeffs(IDAMem IDA_mem, realtype *ck) /* compute leading coefficient cj */ IDA_mem->ida_cjlast = IDA_mem->ida_cj; IDA_mem->ida_cj = -alphas/IDA_mem->ida_hh; - + /* compute variable stepsize error coefficient ck */ *ck = SUNRabs(IDA_mem->ida_alpha[IDA_mem->ida_kk] + alphas - alpha0); *ck = SUNMAX(*ck, IDA_mem->ida_alpha[IDA_mem->ida_kk]); /* change phi to phi-star */ - if (IDA_mem->ida_ns <= IDA_mem->ida_kk) { + /* Scale i=IDA_mem->ida_ns to i<=IDA_mem->ida_kk */ + if (IDA_mem->ida_ns <= IDA_mem->ida_kk) { for(i=IDA_mem->ida_ns; i<=IDA_mem->ida_kk; i++) IDA_mem->ida_cvals[i-IDA_mem->ida_ns] = IDA_mem->ida_beta[i]; @@ -5224,7 +5376,7 @@ static void IDASetCoeffs(IDAMem IDA_mem, realtype *ck) } -/* +/* * ----------------------------------------------------------------- * Nonlinear solver functions * ----------------------------------------------------------------- @@ -5256,6 +5408,7 @@ static int IDANls(IDAMem IDA_mem) int retval; booleantype constraintsPassed, callLSetup, sensi_sim; realtype temp1, temp2, vnorm; + N_Vector mm, tmp; /* Are we computing sensitivities with the IDA_SIMULTANEOUS approach? */ sensi_sim = (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)); @@ -5279,21 +5432,24 @@ static int IDANls(IDAMem IDA_mem) temp2 = ONE/temp1; if (IDA_mem->ida_cjratio < temp1 || IDA_mem->ida_cjratio > temp2) callLSetup = SUNTRUE; if (IDA_mem->ida_forceSetup) callLSetup = SUNTRUE; - if (IDA_mem->ida_cj != IDA_mem->ida_cjlast) {IDA_mem->ida_ss = HUNDRED; IDA_mem->ida_ssS = HUNDRED;} + if (IDA_mem->ida_cj != IDA_mem->ida_cjlast) { + IDA_mem->ida_ss = HUNDRED; + IDA_mem->ida_ssS = HUNDRED; + } } /* initial guess for the correction to the predictor */ if (sensi_sim) - N_VConst(ZERO, IDA_mem->ycor0Sim); + N_VConst(ZERO, IDA_mem->ycorSim); else - N_VConst(ZERO, IDA_mem->ida_delta); + N_VConst(ZERO, IDA_mem->ida_ee); /* call nonlinear solver setup if it exists */ if ((IDA_mem->NLS)->ops->setup) { if (sensi_sim) - retval = SUNNonlinSolSetup(IDA_mem->NLS, IDA_mem->ycor0Sim, IDA_mem); + retval = SUNNonlinSolSetup(IDA_mem->NLS, IDA_mem->ycorSim, IDA_mem); else - retval = SUNNonlinSolSetup(IDA_mem->NLS, IDA_mem->ida_delta, IDA_mem); + retval = SUNNonlinSolSetup(IDA_mem->NLS, IDA_mem->ida_ee, IDA_mem); if (retval < 0) return(IDA_NLS_SETUP_FAIL); if (retval > 0) return(IDA_NLS_SETUP_RECVR); @@ -5302,12 +5458,12 @@ static int IDANls(IDAMem IDA_mem) /* solve the nonlinear system */ if (sensi_sim) retval = SUNNonlinSolSolve(IDA_mem->NLSsim, - IDA_mem->ycor0Sim, IDA_mem->ycorSim, + IDA_mem->ypredictSim, IDA_mem->ycorSim, IDA_mem->ewtSim, IDA_mem->ida_epsNewt, callLSetup, IDA_mem); else retval = SUNNonlinSolSolve(IDA_mem->NLS, - IDA_mem->ida_delta, IDA_mem->ida_ee, + IDA_mem->ida_yypredict, IDA_mem->ida_ee, IDA_mem->ida_ewt, IDA_mem->ida_epsNewt, callLSetup, IDA_mem); @@ -5330,35 +5486,44 @@ static int IDANls(IDAMem IDA_mem) /* If otherwise successful, check and enforce inequality constraints. */ - if (IDA_mem->ida_constraintsSet){ /* Check constraints and get mask vector mm, - set where constraints failed */ - IDA_mem->ida_mm = IDA_mem->ida_tempv2; - constraintsPassed = N_VConstrMask(IDA_mem->ida_constraints,IDA_mem->ida_yy,IDA_mem->ida_mm); + if (IDA_mem->ida_constraintsSet) { + + /* shortcut names for temporary work vectors */ + mm = IDA_mem->ida_tempv2; + tmp = IDA_mem->ida_tempv1; + + /* Get mask vector mm, set where constraints failed */ + constraintsPassed = N_VConstrMask(IDA_mem->ida_constraints, + IDA_mem->ida_yy, mm); if (constraintsPassed) return(IDA_SUCCESS); - else { - N_VCompare(ONEPT5, IDA_mem->ida_constraints, IDA_mem->ida_tempv1); - /* a , where a[i] =1. when |c[i]| = 2 , c the vector of constraints */ - N_VProd(IDA_mem->ida_tempv1, IDA_mem->ida_constraints, IDA_mem->ida_tempv1); /* a * c */ - N_VDiv(IDA_mem->ida_tempv1, IDA_mem->ida_ewt, IDA_mem->ida_tempv1); /* a * c * wt */ - N_VLinearSum(ONE, IDA_mem->ida_yy, -PT1, IDA_mem->ida_tempv1, IDA_mem->ida_tempv1);/* y - 0.1 * a * c * wt */ - N_VProd(IDA_mem->ida_tempv1, IDA_mem->ida_mm, IDA_mem->ida_tempv1); /* v = mm*(y-.1*a*c*wt) */ - vnorm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_tempv1, IDA_mem->ida_ewt, SUNFALSE); /* ||v|| */ - - /* If vector v of constraint corrections is small - in norm, correct and accept this step */ - if (vnorm <= IDA_mem->ida_epsNewt){ - N_VLinearSum(ONE, IDA_mem->ida_ee, -ONE, IDA_mem->ida_tempv1, IDA_mem->ida_ee); /* ee <- ee - v */ - return(IDA_SUCCESS); - } - else { - /* Constraints not met -- reduce h by computing rr = h'/h */ - N_VLinearSum(ONE, IDA_mem->ida_phi[0], -ONE, IDA_mem->ida_yy, IDA_mem->ida_tempv1); - N_VProd(IDA_mem->ida_mm, IDA_mem->ida_tempv1, IDA_mem->ida_tempv1); - IDA_mem->ida_rr = PT9*N_VMinQuotient(IDA_mem->ida_phi[0], IDA_mem->ida_tempv1); - IDA_mem->ida_rr = SUNMAX(IDA_mem->ida_rr,PT1); - return(IDA_CONSTR_RECVR); - } + + /* Constraints not met */ + + /* Compute correction to satisfy constraints */ + N_VCompare(ONEPT5, IDA_mem->ida_constraints, tmp); /* a[i] =1 when |c[i]| = 2 */ + N_VProd(tmp, IDA_mem->ida_constraints, tmp); /* a * c */ + N_VDiv(tmp, IDA_mem->ida_ewt, tmp); /* a * c * wt */ + N_VLinearSum(ONE, IDA_mem->ida_yy, -PT1, tmp, tmp); /* y - 0.1 * a * c * wt */ + N_VProd(tmp, mm, tmp); /* v = mm*(y-.1*a*c*wt) */ + + vnorm = IDAWrmsNorm(IDA_mem, tmp, IDA_mem->ida_ewt, SUNFALSE); /* ||v|| */ + + /* If vector v of constraint corrections is small in norm, correct and + accept this step */ + if (vnorm <= IDA_mem->ida_epsNewt) { + N_VLinearSum(ONE, IDA_mem->ida_ee, + -ONE, tmp, IDA_mem->ida_ee); /* ee <- ee - v */ + return(IDA_SUCCESS); } + + /* Constraints correction is too large, reduce h by computing rr = h'/h */ + N_VLinearSum(ONE, IDA_mem->ida_phi[0], -ONE, IDA_mem->ida_yy, tmp); + N_VProd(mm, tmp, tmp); + IDA_mem->ida_rr = PT9*N_VMinQuotient(IDA_mem->ida_phi[0], tmp); + IDA_mem->ida_rr = SUNMAX(IDA_mem->ida_rr, PT1); + + /* Reattempt step with new step size */ + return(IDA_CONSTR_RECVR); } return(IDA_SUCCESS); @@ -5387,10 +5552,10 @@ static void IDAPredict(IDAMem IDA_mem) /* * IDAQuadNls - * + * * This routine solves for the quadrature variables at the new step. * It does not solve a nonlinear system, but rather updates the - * quadrature variables. The name for this function is just for + * quadrature variables. The name for this function is just for * uniformity purposes. * */ @@ -5401,7 +5566,7 @@ static int IDAQuadNls(IDAMem IDA_mem) /* Predict: load yyQ and ypQ */ IDAQuadPredict(IDA_mem); - + /* Compute correction eeQ */ retval = IDA_mem->ida_rhsQ(IDA_mem->ida_tn, IDA_mem->ida_yy, IDA_mem->ida_yp, IDA_mem->ida_eeQ, @@ -5446,8 +5611,8 @@ static void IDAQuadPredict(IDAMem IDA_mem) /* * IDASensNls * - * This routine attempts to solve, one by one, all the sensitivity - * linear systems using nonlinear iterations and the linear solver + * This routine attempts to solve, one by one, all the sensitivity + * linear systems using nonlinear iterations and the linear solver * specified (Staggered approach). */ @@ -5459,11 +5624,11 @@ static int IDASensNls(IDAMem IDA_mem) callLSetup = SUNFALSE; /* initial guess for the correction to the predictor */ - N_VConst(ZERO, IDA_mem->ycor0Stg); + N_VConst(ZERO, IDA_mem->ycorStg); /* solve the nonlinear system */ retval = SUNNonlinSolSolve(IDA_mem->NLSstg, - IDA_mem->ycor0Stg, IDA_mem->ycorStg, + IDA_mem->ypredictStg, IDA_mem->ycorStg, IDA_mem->ewtStg, IDA_mem->ida_epsNewt, callLSetup, IDA_mem); @@ -5475,7 +5640,7 @@ static int IDASensNls(IDAMem IDA_mem) ONE, IDA_mem->ida_ypSpredict, IDA_mem->ida_cj, IDA_mem->ida_eeS, IDA_mem->ida_ypS); - if (retval != IDA_SUCCESS) + if (retval != IDA_SUCCESS) IDA_mem->ida_ncfnS++; return(retval); @@ -5485,7 +5650,7 @@ static int IDASensNls(IDAMem IDA_mem) /* * IDASensPredict * - * This routine loads the predicted values for the is-th sensitivity + * This routine loads the predicted values for the is-th sensitivity * in the vectors yySens and ypSens. * * When ism=IDA_STAGGERED, yySens = yyS[is] and ypSens = ypS[is] @@ -5510,10 +5675,10 @@ static void IDASensPredict(IDAMem IDA_mem, N_Vector *yySens, N_Vector *ypSens) /* * IDAQuadSensNls - * - * This routine solves for the snesitivity quadrature variables at the - * new step. It does not solve a nonlinear system, but rather updates - * the sensitivity variables. The name for this function is just for + * + * This routine solves for the snesitivity quadrature variables at the + * new step. It does not solve a nonlinear system, but rather updates + * the sensitivity variables. The name for this function is just for * uniformity purposes. * */ @@ -5523,9 +5688,9 @@ static int IDAQuadSensNls(IDAMem IDA_mem) int retval; N_Vector *ypQS; - /* Predict: load yyQS and ypQS for each sensitivity. Store + /* Predict: load yyQS and ypQS for each sensitivity. Store 1st order information in tempvQS. */ - + ypQS = IDA_mem->ida_tempvQS; IDAQuadSensPredict(IDA_mem, IDA_mem->ida_yyQS, ypQS); @@ -5581,7 +5746,7 @@ static void IDAQuadSensPredict(IDAMem IDA_mem, N_Vector *yQS, N_Vector *ypQS) } -/* +/* * ----------------------------------------------------------------- * Error test * ----------------------------------------------------------------- @@ -5590,82 +5755,78 @@ static void IDAQuadSensPredict(IDAMem IDA_mem, N_Vector *yQS, N_Vector *ypQS) /* * IDATestError * - * This routine estimates errors at orders k, k-1, k-2, decides - * whether or not to suggest an order reduction, and performs - * the local error test. + * This routine estimates errors at orders k, k-1, k-2, decides + * whether or not to suggest an order decrease, and performs + * the local error test. * * IDATestError returns either IDA_SUCCESS or ERROR_TEST_FAIL. */ -static int IDATestError(IDAMem IDA_mem, realtype ck, +static int IDATestError(IDAMem IDA_mem, realtype ck, realtype *err_k, realtype *err_km1, realtype *err_km2) { realtype enorm_k, enorm_km1, enorm_km2; /* error norms */ realtype terr_k, terr_km1, terr_km2; /* local truncation error norms */ /* Compute error for order k. */ - enorm_k = IDAWrmsNorm(IDA_mem, IDA_mem->ida_ee, IDA_mem->ida_ewt, IDA_mem->ida_suppressalg); *err_k = IDA_mem->ida_sigma[IDA_mem->ida_kk] * enorm_k; - terr_k = (IDA_mem->ida_kk+1) * (*err_k); + terr_k = (IDA_mem->ida_kk + 1) * (*err_k); IDA_mem->ida_knew = IDA_mem->ida_kk; if ( IDA_mem->ida_kk > 1 ) { /* Compute error at order k-1 */ - N_VLinearSum(ONE, IDA_mem->ida_phi[IDA_mem->ida_kk], ONE, IDA_mem->ida_ee, IDA_mem->ida_delta); - enorm_km1 = IDAWrmsNorm(IDA_mem, IDA_mem->ida_delta, IDA_mem->ida_ewt, IDA_mem->ida_suppressalg); - *err_km1 = IDA_mem->ida_sigma[IDA_mem->ida_kk-1] * enorm_km1; + enorm_km1 = IDAWrmsNorm(IDA_mem, IDA_mem->ida_delta, + IDA_mem->ida_ewt, IDA_mem->ida_suppressalg); + *err_km1 = IDA_mem->ida_sigma[IDA_mem->ida_kk - 1] * enorm_km1; terr_km1 = IDA_mem->ida_kk * (*err_km1); if ( IDA_mem->ida_kk > 2 ) { /* Compute error at order k-2 */ - - N_VLinearSum(ONE, IDA_mem->ida_phi[IDA_mem->ida_kk-1], ONE, IDA_mem->ida_delta, IDA_mem->ida_delta); - enorm_km2 = IDAWrmsNorm(IDA_mem, IDA_mem->ida_delta, IDA_mem->ida_ewt, IDA_mem->ida_suppressalg); - *err_km2 = IDA_mem->ida_sigma[IDA_mem->ida_kk-2] * enorm_km2; - terr_km2 = (IDA_mem->ida_kk-1) * (*err_km2); - - /* Reduce order if errors are reduced */ - + N_VLinearSum(ONE, IDA_mem->ida_phi[IDA_mem->ida_kk - 1], ONE, + IDA_mem->ida_delta, IDA_mem->ida_delta); + enorm_km2 = IDAWrmsNorm(IDA_mem, IDA_mem->ida_delta, + IDA_mem->ida_ewt, IDA_mem->ida_suppressalg); + *err_km2 = IDA_mem->ida_sigma[IDA_mem->ida_kk - 2] * enorm_km2; + terr_km2 = (IDA_mem->ida_kk - 1) * (*err_km2); + + /* Decrease order if errors are reduced */ if (SUNMAX(terr_km1, terr_km2) <= terr_k) IDA_mem->ida_knew = IDA_mem->ida_kk - 1; } else { - /* Reduce order to 1 if errors are reduced by at least 1/2 */ - + /* Decrease order to 1 if errors are reduced by at least 1/2 */ if (terr_km1 <= (HALF * terr_k) ) - IDA_mem->ida_knew = IDA_mem->ida_kk - 1; + IDA_mem->ida_knew = IDA_mem->ida_kk - 1; } } /* Perform error test */ - if (ck * enorm_k > ONE) return(ERROR_TEST_FAIL); else return(IDA_SUCCESS); - } /* * IDAQuadTestError * - * This routine estimates quadrature errors and updates errors at - * orders k, k-1, k-2, decides whether or not to suggest an order reduction, - * and performs the local error test. + * This routine estimates quadrature errors and updates errors at + * orders k, k-1, k-2, decides whether or not to suggest an order reduction, + * and performs the local error test. * - * IDAQuadTestError returns the updated local error estimate at orders k, + * IDAQuadTestError returns the updated local error estimate at orders k, * k-1, and k-2. These are norms of type SUNMAX(|err|,|errQ|). * * The return flag can be either IDA_SUCCESS or ERROR_TEST_FAIL. */ -static int IDAQuadTestError(IDAMem IDA_mem, realtype ck, +static int IDAQuadTestError(IDAMem IDA_mem, realtype ck, realtype *err_k, realtype *err_km1, realtype *err_km2) { realtype enormQ; @@ -5685,9 +5846,9 @@ static int IDAQuadTestError(IDAMem IDA_mem, realtype ck, check_for_reduction = SUNTRUE; } terr_k = (IDA_mem->ida_kk+1) * (*err_k); - + if ( IDA_mem->ida_kk > 1 ) { - + /* Update error at order k-1 */ N_VLinearSum(ONE, IDA_mem->ida_phiQ[IDA_mem->ida_kk], ONE, IDA_mem->ida_eeQ, tempv); errQ_km1 = IDA_mem->ida_sigma[IDA_mem->ida_kk-1] * N_VWrmsNorm(tempv, IDA_mem->ida_ewtQ); @@ -5716,13 +5877,13 @@ static int IDAQuadTestError(IDAMem IDA_mem, realtype ck, /* Decrease order if errors are reduced */ if (SUNMAX(terr_km1, terr_km2) <= terr_k) IDA_mem->ida_knew = IDA_mem->ida_kk - 1; - + } else { - + /* Decrease order to 1 if errors are reduced by at least 1/2 */ if (terr_km1 <= (HALF * terr_k) ) - IDA_mem->ida_knew = IDA_mem->ida_kk - 1; - + IDA_mem->ida_knew = IDA_mem->ida_kk - 1; + } } @@ -5738,17 +5899,17 @@ static int IDAQuadTestError(IDAMem IDA_mem, realtype ck, /* * IDASensTestError * - * This routine estimates sensitivity errors and updates errors at - * orders k, k-1, k-2, decides whether or not to suggest an order reduction, + * This routine estimates sensitivity errors and updates errors at + * orders k, k-1, k-2, decides whether or not to suggest an order reduction, * and performs the local error test. (Used only in staggered approach). * - * IDASensTestError returns the updated local error estimate at orders k, + * IDASensTestError returns the updated local error estimate at orders k, * k-1, and k-2. These are norms of type SUNMAX(|err|,|errQ|,|errS|). * * The return flag can be either IDA_SUCCESS or ERROR_TEST_FAIL. */ -static int IDASensTestError(IDAMem IDA_mem, realtype ck, +static int IDASensTestError(IDAMem IDA_mem, realtype ck, realtype *err_k, realtype *err_km1, realtype *err_km2) { realtype enormS; @@ -5769,9 +5930,9 @@ static int IDASensTestError(IDAMem IDA_mem, realtype ck, check_for_reduction = SUNTRUE; } terr_k = (IDA_mem->ida_kk+1) * (*err_k); - + if ( IDA_mem->ida_kk > 1 ) { - + /* Update error at order k-1 */ retval = N_VLinearSumVectorArray(IDA_mem->ida_Ns, ONE, IDA_mem->ida_phiS[IDA_mem->ida_kk], @@ -5812,13 +5973,13 @@ static int IDASensTestError(IDAMem IDA_mem, realtype ck, /* Decrease order if errors are reduced */ if (SUNMAX(terr_km1, terr_km2) <= terr_k) IDA_mem->ida_knew = IDA_mem->ida_kk - 1; - + } else { - + /* Decrease order to 1 if errors are reduced by at least 1/2 */ if (terr_km1 <= (HALF * terr_k) ) - IDA_mem->ida_knew = IDA_mem->ida_kk - 1; - + IDA_mem->ida_knew = IDA_mem->ida_kk - 1; + } } @@ -5834,19 +5995,19 @@ static int IDASensTestError(IDAMem IDA_mem, realtype ck, /* * IDAQuadSensTestError * - * This routine estimates quadrature sensitivity errors and updates - * errors at orders k, k-1, k-2, decides whether or not to suggest - * an order reduction and performs the local error test. (Used + * This routine estimates quadrature sensitivity errors and updates + * errors at orders k, k-1, k-2, decides whether or not to suggest + * an order reduction and performs the local error test. (Used * only in staggered approach). * - * IDAQuadSensTestError returns the updated local error estimate at - * orders k, k-1, and k-2. These are norms of type + * IDAQuadSensTestError returns the updated local error estimate at + * orders k, k-1, and k-2. These are norms of type * SUNMAX(|err|,|errQ|,|errS|,|errQS|). * * The return flag can be either IDA_SUCCESS or ERROR_TEST_FAIL. */ -static int IDAQuadSensTestError(IDAMem IDA_mem, realtype ck, +static int IDAQuadSensTestError(IDAMem IDA_mem, realtype ck, realtype *err_k, realtype *err_km1, realtype *err_km2) { realtype enormQS; @@ -5866,9 +6027,9 @@ static int IDAQuadSensTestError(IDAMem IDA_mem, realtype ck, check_for_reduction = SUNTRUE; } terr_k = (IDA_mem->ida_kk+1) * (*err_k); - + if ( IDA_mem->ida_kk > 1 ) { - + /* Update error at order k-1 */ retval = N_VLinearSumVectorArray(IDA_mem->ida_Ns, ONE, IDA_mem->ida_phiQS[IDA_mem->ida_kk], @@ -5912,7 +6073,7 @@ static int IDAQuadSensTestError(IDAMem IDA_mem, realtype ck, } else { /* Decrease order to 1 if errors are reduced by at least 1/2 */ if (terr_km1 <= (HALF * terr_k) ) - IDA_mem->ida_knew = IDA_mem->ida_kk - 1; + IDA_mem->ida_knew = IDA_mem->ida_kk - 1; } } } @@ -5924,7 +6085,7 @@ static int IDAQuadSensTestError(IDAMem IDA_mem, realtype ck, /* * IDARestore * - * This routine restores IDA_mem->ida_tn, psi, and phi in the event of a failure. + * This routine restores tn, psi, and phi in the event of a failure. * It changes back phi-star to phi (changed in IDASetCoeffs) */ @@ -5933,13 +6094,13 @@ static void IDARestore(IDAMem IDA_mem, realtype saved_t) int i, j, is; IDA_mem->ida_tn = saved_t; - + for (i = 1; i <= IDA_mem->ida_kk; i++) IDA_mem->ida_psi[i-1] = IDA_mem->ida_psi[i] - IDA_mem->ida_hh; if (IDA_mem->ida_ns <= IDA_mem->ida_kk) { - for(i=IDA_mem->ida_ns; i<=IDA_mem->ida_kk; i++) + for(i = IDA_mem->ida_ns; i <= IDA_mem->ida_kk; i++) IDA_mem->ida_cvals[i-IDA_mem->ida_ns] = ONE/IDA_mem->ida_beta[i]; (void) N_VScaleVectorArray(IDA_mem->ida_kk - IDA_mem->ida_ns + 1, @@ -5992,7 +6153,7 @@ static void IDARestore(IDAMem IDA_mem, realtype saved_t) } -/* +/* * ----------------------------------------------------------------- * Handler for convergence and/or error test failures * ----------------------------------------------------------------- @@ -6001,10 +6162,10 @@ static void IDARestore(IDAMem IDA_mem, realtype saved_t) /* * IDAHandleNFlag * - * This routine handles failures indicated by the input variable nflag. + * This routine handles failures indicated by the input variable nflag. * Positive values indicate various recoverable failures while negative * values indicate nonrecoverable failures. This routine adjusts the - * step size for recoverable failures. + * step size for recoverable failures. * * Possible nflag values (input): * @@ -6029,10 +6190,10 @@ static void IDARestore(IDAMem IDA_mem, realtype saved_t) * PREDICT_AGAIN * * --nonrecoverable-- - * IDA_CONSTR_FAIL - * IDA_REP_RES_ERR - * IDA_ERR_FAIL - * IDA_CONV_FAIL + * IDA_CONSTR_FAIL + * IDA_REP_RES_ERR + * IDA_ERR_FAIL + * IDA_CONV_FAIL * IDA_RES_FAIL * IDA_LSETUP_FAIL * IDA_LSOLVE_FAIL @@ -6046,22 +6207,28 @@ static int IDAHandleNFlag(IDAMem IDA_mem, int nflag, realtype err_k, realtype er realtype err_knew; IDA_mem->ida_phase = 1; - + if (nflag != ERROR_TEST_FAIL) { /*----------------------- - Nonlinear solver failed + Nonlinear solver failed -----------------------*/ (*ncfPtr)++; /* local counter for convergence failures */ (*ncfnPtr)++; /* global counter for convergence failures */ - + if (nflag < 0) { /* nonrecoverable failure */ - return(nflag); + if (nflag == IDA_LSOLVE_FAIL) return(IDA_LSOLVE_FAIL); + else if (nflag == IDA_LSETUP_FAIL) return(IDA_LSETUP_FAIL); + else if (nflag == IDA_RES_FAIL) return(IDA_RES_FAIL); + else if (nflag == IDA_QRHS_FAIL) return(IDA_QRHS_FAIL); + else if (nflag == IDA_SRES_FAIL) return(IDA_SRES_FAIL); + else if (nflag == IDA_QSRHS_FAIL) return(IDA_QSRHS_FAIL); + else return(IDA_NLS_FAIL); } else { /* recoverable failure */ - + /* Reduce step size for a new prediction Note that if nflag=IDA_CONSTR_RECVR then rr was already set in IDANls */ if (nflag != IDA_CONSTR_RECVR) IDA_mem->ida_rr = QUARTER; @@ -6070,47 +6237,47 @@ static int IDAHandleNFlag(IDAMem IDA_mem, int nflag, realtype err_k, realtype er /* Test if there were too many convergence failures */ if (*ncfPtr < IDA_mem->ida_maxncf) return(PREDICT_AGAIN); else if (nflag == IDA_RES_RECVR) return(IDA_REP_RES_ERR); - else if (nflag == IDA_SRES_RECVR) return(IDA_REP_SRES_ERR); else if (nflag == IDA_QRHS_RECVR) return(IDA_REP_QRHS_ERR); + else if (nflag == IDA_SRES_RECVR) return(IDA_REP_SRES_ERR); else if (nflag == IDA_QSRHS_RECVR) return(IDA_REP_QSRHS_ERR); else if (nflag == IDA_CONSTR_RECVR) return(IDA_CONSTR_FAIL); else return(IDA_CONV_FAIL); } - - } else { + + } else { /*----------------- - Error Test failed + Error Test failed -----------------*/ (*nefPtr)++; /* local counter for error test failures */ (*netfPtr)++; /* global counter for error test failures */ - + if (*nefPtr == 1) { - - /* On first error test failure, keep current order or lower order by one. + + /* On first error test failure, keep current order or lower order by one. Compute new stepsize based on differences of the solution. */ - - err_knew = (IDA_mem->ida_kk==IDA_mem->ida_knew)? err_k : err_km1; - IDA_mem->ida_kk = IDA_mem->ida_knew; - IDA_mem->ida_rr = PT9 * SUNRpowerR( TWO * err_knew + PT0001,(-ONE/(IDA_mem->ida_kk+1)) ); + err_knew = (IDA_mem->ida_kk == IDA_mem->ida_knew) ? err_k : err_km1; + + IDA_mem->ida_kk = IDA_mem->ida_knew; + IDA_mem->ida_rr = PT9 * SUNRpowerR( TWO * err_knew + PT0001, -ONE/(IDA_mem->ida_kk + 1) ); IDA_mem->ida_rr = SUNMAX(QUARTER, SUNMIN(PT9,IDA_mem->ida_rr)); IDA_mem->ida_hh *= IDA_mem->ida_rr; return(PREDICT_AGAIN); - + } else if (*nefPtr == 2) { - - /* On second error test failure, use current order or decrease order by one. + + /* On second error test failure, use current order or decrease order by one. Reduce stepsize by factor of 1/4. */ IDA_mem->ida_kk = IDA_mem->ida_knew; IDA_mem->ida_rr = QUARTER; IDA_mem->ida_hh *= IDA_mem->ida_rr; return(PREDICT_AGAIN); - + } else if (*nefPtr < IDA_mem->ida_maxnef) { - + /* On third and subsequent error test failures, set order to 1. Reduce stepsize by factor of 1/4. */ IDA_mem->ida_kk = 1; @@ -6122,9 +6289,9 @@ static int IDAHandleNFlag(IDAMem IDA_mem, int nflag, realtype err_k, realtype er /* Too many error test failures */ return(IDA_ERR_FAIL); - + } - + } } @@ -6132,7 +6299,7 @@ static int IDAHandleNFlag(IDAMem IDA_mem, int nflag, realtype err_k, realtype er /* * IDAReset * - * This routine is called only if we need to predict again at the + * This routine is called only if we need to predict again at the * very first step. In such a case, reset phi[1] and psi[0]. */ @@ -6160,7 +6327,7 @@ static void IDAReset(IDAMem IDA_mem) IDA_mem->ida_phiQS[1], IDA_mem->ida_phiQS[1]); } -/* +/* * ----------------------------------------------------------------- * Function called after a successful step * ----------------------------------------------------------------- @@ -6172,7 +6339,6 @@ static void IDAReset(IDAMem IDA_mem) * This routine completes a successful step. It increments nst, * saves the stepsize and order used, makes the final selection of * stepsize and order for the next step, and updates the phi array. - * Its return value is IDA_SUCCESS = 0. */ static void IDACompleteStep(IDAMem IDA_mem, realtype err_k, realtype err_km1) @@ -6188,18 +6354,18 @@ static void IDACompleteStep(IDAMem IDA_mem, realtype err_k, realtype err_km1) IDA_mem->ida_kused = IDA_mem->ida_kk; IDA_mem->ida_hused = IDA_mem->ida_hh; - if ( (IDA_mem->ida_knew == IDA_mem->ida_kk-1) || + if ( (IDA_mem->ida_knew == IDA_mem->ida_kk - 1) || (IDA_mem->ida_kk == IDA_mem->ida_maxord) ) IDA_mem->ida_phase = 1; - /* For the first few steps, until either a step fails, or the order is - reduced, or the order reaches its maximum, we raise the order and double + /* For the first few steps, until either a step fails, or the order is + reduced, or the order reaches its maximum, we raise the order and double the stepsize. During these steps, phase = 0. Thereafter, phase = 1, and - stepsize and order are set by the usual local error algorithm. - - Note that, after the first step, the order is not increased, as not all + stepsize and order are set by the usual local error algorithm. + + Note that, after the first step, the order is not increased, as not all of the neccessary information is available yet. */ - + if (IDA_mem->ida_phase == 0) { if(IDA_mem->ida_nst > 1) { @@ -6213,23 +6379,23 @@ static void IDACompleteStep(IDAMem IDA_mem, realtype err_k, realtype err_km1) } else { action = UNSET; - + /* Set action = LOWER/MAINTAIN/RAISE to specify order decision */ - - if (IDA_mem->ida_knew == IDA_mem->ida_kk-1) {action = LOWER; goto takeaction;} - if (IDA_mem->ida_kk == IDA_mem->ida_maxord) {action = MAINTAIN; goto takeaction;} - if ( (IDA_mem->ida_kk+1 >= IDA_mem->ida_ns ) || (kdiff == 1)) {action = MAINTAIN; goto takeaction;} - + + if (IDA_mem->ida_knew == IDA_mem->ida_kk - 1) {action = LOWER; goto takeaction;} + if (IDA_mem->ida_kk == IDA_mem->ida_maxord) {action = MAINTAIN; goto takeaction;} + if ( (IDA_mem->ida_kk + 1 >= IDA_mem->ida_ns ) || + (kdiff == 1)) {action = MAINTAIN; goto takeaction;} + /* Estimate the error at order k+1, unless already decided to reduce order, or already using maximum order, or stepsize has not been constant, or order was just raised. */ - + N_VLinearSum(ONE, IDA_mem->ida_ee, -ONE, - IDA_mem->ida_phi[IDA_mem->ida_kk+1], - IDA_mem->ida_tempv1); - enorm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_tempv1, - IDA_mem->ida_ewt, IDA_mem->ida_suppressalg); - + IDA_mem->ida_phi[IDA_mem->ida_kk + 1], IDA_mem->ida_tempv1); + enorm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_tempv1, IDA_mem->ida_ewt, + IDA_mem->ida_suppressalg); + if (IDA_mem->ida_errconQ) { tempvQ = IDA_mem->ida_ypQ; N_VLinearSum (ONE, IDA_mem->ida_eeQ, -ONE, @@ -6258,12 +6424,12 @@ static void IDACompleteStep(IDAMem IDA_mem, realtype err_k, realtype err_km1) enorm = IDAQuadSensWrmsNormUpdate(IDA_mem, enorm, IDA_mem->ida_tempvQS, IDA_mem->ida_ewtQS); } - err_kp1= enorm/(IDA_mem->ida_kk+2); + err_kp1= enorm/(IDA_mem->ida_kk + 2); /* Choose among orders k-1, k, k+1 using local truncation error norms. */ - terr_k = (IDA_mem->ida_kk+1) * err_k; - terr_kp1 = (IDA_mem->ida_kk+2) * err_kp1; + terr_k = (IDA_mem->ida_kk + 1) * err_k; + terr_kp1 = (IDA_mem->ida_kk + 2) * err_kp1; if (IDA_mem->ida_kk == 1) { if (terr_kp1 >= HALF * terr_k) {action = MAINTAIN; goto takeaction;} @@ -6271,42 +6437,40 @@ static void IDACompleteStep(IDAMem IDA_mem, realtype err_k, realtype err_km1) } else { terr_km1 = IDA_mem->ida_kk * err_km1; if (terr_km1 <= SUNMIN(terr_k, terr_kp1)) {action = LOWER; goto takeaction;} - else if (terr_kp1 >= terr_k) {action = MAINTAIN; goto takeaction;} + else if (terr_kp1 >= terr_k) {action = MAINTAIN; goto takeaction;} else {action = RAISE; goto takeaction;} } - + takeaction: - + /* Set the estimated error norm and, on change of order, reset kk. */ if (action == RAISE) { IDA_mem->ida_kk++; err_knew = err_kp1; } else if (action == LOWER) { IDA_mem->ida_kk--; err_knew = err_km1; } - else { err_knew = err_k; } + else { err_knew = err_k; } - /* Compute rr = tentative ratio hnew/hh from error norm. + /* Compute rr = tentative ratio hnew/hh from error norm estimate. Reduce hh if rr <= 1, double hh if rr >= 2, else leave hh as is. If hh is reduced, hnew/hh is restricted to be between .5 and .9. */ - + hnew = IDA_mem->ida_hh; - IDA_mem->ida_rr = SUNRpowerR( (TWO * err_knew + PT0001) , (-ONE/(IDA_mem->ida_kk+1) ) ); - + IDA_mem->ida_rr = SUNRpowerR( TWO * err_knew + PT0001, -ONE/(IDA_mem->ida_kk + 1) ); + if (IDA_mem->ida_rr >= TWO) { hnew = TWO * IDA_mem->ida_hh; if( (tmp = SUNRabs(hnew) * IDA_mem->ida_hmax_inv) > ONE ) hnew /= tmp; - } else if (IDA_mem->ida_rr <= ONE ) { + } else if (IDA_mem->ida_rr <= ONE ) { IDA_mem->ida_rr = SUNMAX(HALF, SUNMIN(PT9,IDA_mem->ida_rr)); hnew = IDA_mem->ida_hh * IDA_mem->ida_rr; } - + IDA_mem->ida_hh = hnew; - + } /* end of phase if block */ - - /* Save ee etc. for possible order increase on next step */ - - if (IDA_mem->ida_kused < IDA_mem->ida_maxord) { - N_VScale(ONE, IDA_mem->ida_ee, IDA_mem->ida_phi[IDA_mem->ida_kused+1]); + /* Save ee for possible order increase on next step */ + if (IDA_mem->ida_kused < IDA_mem->ida_maxord) { + N_VScale(ONE, IDA_mem->ida_ee, IDA_mem->ida_phi[IDA_mem->ida_kused + 1]); if (IDA_mem->ida_quadr) N_VScale(ONE, IDA_mem->ida_eeQ, IDA_mem->ida_phiQ[IDA_mem->ida_kused+1]); @@ -6401,7 +6565,85 @@ static void IDACompleteStep(IDAMem IDA_mem, realtype err_k, realtype err_km1) } -/* +/* + * ----------------------------------------------------------------- + * Interpolated output + * ----------------------------------------------------------------- + */ + +/* + * IDAGetSolution + * + * This routine evaluates y(t) and y'(t) as the value and derivative of + * the interpolating polynomial at the independent variable t, and stores + * the results in the vectors yret and ypret. It uses the current + * independent variable value, tn, and the method order last used, kused. + * This function is called by IDASolve with t = tout, t = tn, or t = tstop. + * + * If kused = 0 (no step has been taken), or if t = tn, then the order used + * here is taken to be 1, giving yret = phi[0], ypret = phi[1]/psi[0]. + * + * The return values are: + * IDA_SUCCESS if t is legal, or + * IDA_BAD_T if t is not within the interval of the last step taken. + */ + +int IDAGetSolution(void *ida_mem, realtype t, N_Vector yret, N_Vector ypret) +{ + IDAMem IDA_mem; + realtype tfuzz, tp, delt, c, d, gam; + int j, kord, retval; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSolution", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Check t for legality. Here tn - hused is t_{n-1}. */ + + tfuzz = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); + if (IDA_mem->ida_hh < ZERO) tfuzz = - tfuzz; + tp = IDA_mem->ida_tn - IDA_mem->ida_hused - tfuzz; + if ((t - tp)*IDA_mem->ida_hh < ZERO) { + IDAProcessError(IDA_mem, IDA_BAD_T, "IDAS", "IDAGetSolution", MSG_BAD_T, t, + IDA_mem->ida_tn-IDA_mem->ida_hused, IDA_mem->ida_tn); + return(IDA_BAD_T); + } + + /* Initialize kord = (kused or 1). */ + + kord = IDA_mem->ida_kused; + if (IDA_mem->ida_kused == 0) kord = 1; + + /* Accumulate multiples of columns phi[j] into yret and ypret. */ + + delt = t - IDA_mem->ida_tn; + c = ONE; d = ZERO; + gam = delt / IDA_mem->ida_psi[0]; + + IDA_mem->ida_cvals[0] = c; + for (j=1; j <= kord; j++) { + d = d*gam + c / IDA_mem->ida_psi[j-1]; + c = c*gam; + gam = (delt + IDA_mem->ida_psi[j-1]) / IDA_mem->ida_psi[j]; + + IDA_mem->ida_cvals[j] = c; + IDA_mem->ida_dvals[j-1] = d; + } + + retval = N_VLinearCombination(kord+1, IDA_mem->ida_cvals, + IDA_mem->ida_phi, yret); + if (retval != IDA_SUCCESS) return(IDA_VECTOROP_ERR); + + retval = N_VLinearCombination(kord, IDA_mem->ida_dvals, + IDA_mem->ida_phi+1, ypret); + if (retval != IDA_SUCCESS) return(IDA_VECTOROP_ERR); + + return(IDA_SUCCESS); +} + +/* * ----------------------------------------------------------------- * Norm functions * ----------------------------------------------------------------- @@ -6415,12 +6657,12 @@ static void IDACompleteStep(IDAMem IDA_mem, realtype err_k, realtype err_km1) * nrm = N_VWrmsNormMask(x,w,id); * Otherwise, * nrm = N_VWrmsNorm(x,w); - * + * * mask = SUNFALSE when the call is made from the nonlinear solver. * mask = suppressalg otherwise. */ -realtype IDAWrmsNorm(IDAMem IDA_mem, N_Vector x, N_Vector w, +realtype IDAWrmsNorm(IDAMem IDA_mem, N_Vector x, N_Vector w, booleantype mask) { realtype nrm; @@ -6434,12 +6676,12 @@ realtype IDAWrmsNorm(IDAMem IDA_mem, N_Vector x, N_Vector w, /* * IDASensWrmsNorm * - * This routine returns the maximum over the weighted root mean + * This routine returns the maximum over the weighted root mean * square norm of xS with weight vectors wS: * - * max { wrms(xS[0],wS[0]) ... wrms(xS[Ns-1],wS[Ns-1]) } + * max { wrms(xS[0],wS[0]) ... wrms(xS[Ns-1],wS[Ns-1]) } * - * Called by IDASensUpdateNorm or directly in the IDA_STAGGERED approach + * Called by IDASensUpdateNorm or directly in the IDA_STAGGERED approach * during the NLS solution and before the error test. * * Declared global for use in the computation of IC for sensitivities. @@ -6468,10 +6710,10 @@ realtype IDASensWrmsNorm(IDAMem IDA_mem, N_Vector *xS, N_Vector *wS, /* * IDAQuadSensWrmsNorm * - * This routine returns the maximum over the weighted root mean + * This routine returns the maximum over the weighted root mean * square norm of xQS with weight vectors wQS: * - * max { wrms(xQS[0],wQS[0]) ... wrms(xQS[Ns-1],wQS[Ns-1]) } + * max { wrms(xQS[0],wQS[0]) ... wrms(xQS[Ns-1],wQS[Ns-1]) } */ static realtype IDAQuadSensWrmsNorm(IDAMem IDA_mem, N_Vector *xQS, N_Vector *wQS) @@ -6510,7 +6752,7 @@ static realtype IDAQuadWrmsNormUpdate(IDAMem IDA_mem, realtype old_nrm, * * Updates the norm old_nrm to account for all sensitivities. * - * This function is declared global since it is used for finding + * This function is declared global since it is used for finding * IC for sensitivities, */ @@ -6519,13 +6761,13 @@ realtype IDASensWrmsNormUpdate(IDAMem IDA_mem, realtype old_nrm, booleantype mask) { realtype snrm; - + snrm = IDASensWrmsNorm(IDA_mem, xS, wS, mask); if (old_nrm > snrm) return(old_nrm); else return(snrm); } -static realtype IDAQuadSensWrmsNormUpdate(IDAMem IDA_mem, realtype old_nrm, +static realtype IDAQuadSensWrmsNormUpdate(IDAMem IDA_mem, realtype old_nrm, N_Vector *xQS, N_Vector *wQS) { realtype qsnrm; @@ -6535,7 +6777,7 @@ static realtype IDAQuadSensWrmsNormUpdate(IDAMem IDA_mem, realtype old_nrm, else return(qsnrm); } -/* +/* * ----------------------------------------------------------------- * Functions for rootfinding * ----------------------------------------------------------------- @@ -6562,8 +6804,8 @@ static int IDARcheck1(IDAMem IDA_mem) for (i = 0; i < IDA_mem->ida_nrtfn; i++) IDA_mem->ida_iroots[i] = 0; IDA_mem->ida_tlo = IDA_mem->ida_tn; - IDA_mem->ida_ttol = (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)) * - IDA_mem->ida_uround * HUNDRED; + IDA_mem->ida_ttol = ((SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)) * + IDA_mem->ida_uround * HUNDRED); /* Evaluate g at initial t and check for zero values. */ retval = IDA_mem->ida_gfun(IDA_mem->ida_tlo, IDA_mem->ida_phi[0], IDA_mem->ida_phi[1], @@ -6582,19 +6824,18 @@ static int IDARcheck1(IDAMem IDA_mem) /* Some g_i is zero at t0; look at g at t0+(small increment). */ hratio = SUNMAX(IDA_mem->ida_ttol / SUNRabs(IDA_mem->ida_hh), PT1); - smallh = hratio*IDA_mem->ida_hh; + smallh = hratio * IDA_mem->ida_hh; tplus = IDA_mem->ida_tlo + smallh; N_VLinearSum(ONE, IDA_mem->ida_phi[0], smallh, IDA_mem->ida_phi[1], IDA_mem->ida_yy); retval = IDA_mem->ida_gfun(tplus, IDA_mem->ida_yy, IDA_mem->ida_phi[1], - IDA_mem->ida_ghi, IDA_mem->ida_user_data); + IDA_mem->ida_ghi, IDA_mem->ida_user_data); IDA_mem->ida_nge++; if (retval != 0) return(IDA_RTFUNC_FAIL); /* We check now only the components of g which were exactly 0.0 at t0 * to see if we can 'activate' them. */ for (i = 0; i < IDA_mem->ida_nrtfn; i++) { - if (!IDA_mem->ida_gactive[i] && - SUNRabs(IDA_mem->ida_ghi[i]) != ZERO) { + if (!IDA_mem->ida_gactive[i] && SUNRabs(IDA_mem->ida_ghi[i]) != ZERO) { IDA_mem->ida_gactive[i] = SUNTRUE; IDA_mem->ida_glo[i] = IDA_mem->ida_ghi[i]; } @@ -6632,9 +6873,8 @@ static int IDARcheck2(IDAMem IDA_mem) if (IDA_mem->ida_irfnd == 0) return(IDA_SUCCESS); (void) IDAGetSolution(IDA_mem, IDA_mem->ida_tlo, IDA_mem->ida_yy, IDA_mem->ida_yp); - retval = IDA_mem->ida_gfun(IDA_mem->ida_tlo, IDA_mem->ida_yy, - IDA_mem->ida_yp, IDA_mem->ida_glo, - IDA_mem->ida_user_data); + retval = IDA_mem->ida_gfun(IDA_mem->ida_tlo, IDA_mem->ida_yy, IDA_mem->ida_yp, + IDA_mem->ida_glo, IDA_mem->ida_user_data); IDA_mem->ida_nge++; if (retval != 0) return(IDA_RTFUNC_FAIL); @@ -6651,18 +6891,19 @@ static int IDARcheck2(IDAMem IDA_mem) if (!zroot) return(IDA_SUCCESS); /* One or more g_i has a zero at tlo. Check g at tlo+smallh. */ - IDA_mem->ida_ttol = (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)) * - IDA_mem->ida_uround * HUNDRED; + IDA_mem->ida_ttol = ((SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)) * + IDA_mem->ida_uround * HUNDRED); smallh = (IDA_mem->ida_hh > ZERO) ? IDA_mem->ida_ttol : -IDA_mem->ida_ttol; tplus = IDA_mem->ida_tlo + smallh; if ( (tplus - IDA_mem->ida_tn)*IDA_mem->ida_hh >= ZERO) { hratio = smallh/IDA_mem->ida_hh; - N_VLinearSum(ONE, IDA_mem->ida_yy, hratio, IDA_mem->ida_phi[1], IDA_mem->ida_yy); + N_VLinearSum(ONE, IDA_mem->ida_yy, + hratio, IDA_mem->ida_phi[1], IDA_mem->ida_yy); } else { (void) IDAGetSolution(IDA_mem, tplus, IDA_mem->ida_yy, IDA_mem->ida_yp); } retval = IDA_mem->ida_gfun(tplus, IDA_mem->ida_yy, IDA_mem->ida_yp, - IDA_mem->ida_ghi, IDA_mem->ida_user_data); + IDA_mem->ida_ghi, IDA_mem->ida_user_data); IDA_mem->ida_nge++; if (retval != 0) return(IDA_RTFUNC_FAIL); @@ -6702,11 +6943,10 @@ static int IDARcheck3(IDAMem IDA_mem) int i, ier, retval; /* Set thi = tn or tout, whichever comes first. */ - if (IDA_mem->ida_taskc == IDA_ONE_STEP) - IDA_mem->ida_thi = IDA_mem->ida_tn; + if (IDA_mem->ida_taskc == IDA_ONE_STEP) IDA_mem->ida_thi = IDA_mem->ida_tn; if (IDA_mem->ida_taskc == IDA_NORMAL) { - IDA_mem->ida_thi = ((IDA_mem->ida_toutc - IDA_mem->ida_tn)*IDA_mem->ida_hh >= ZERO) ? - IDA_mem->ida_tn : IDA_mem->ida_toutc; + IDA_mem->ida_thi = ((IDA_mem->ida_toutc - IDA_mem->ida_tn)*IDA_mem->ida_hh >= ZERO) + ? IDA_mem->ida_tn : IDA_mem->ida_toutc; } /* Get y and y' at thi. */ @@ -6716,24 +6956,23 @@ static int IDARcheck3(IDAMem IDA_mem) /* Set ghi = g(thi) and call IDARootfind to search (tlo,thi) for roots. */ retval = IDA_mem->ida_gfun(IDA_mem->ida_thi, IDA_mem->ida_yy, IDA_mem->ida_yp, IDA_mem->ida_ghi, - IDA_mem->ida_user_data); + IDA_mem->ida_user_data); IDA_mem->ida_nge++; if (retval != 0) return(IDA_RTFUNC_FAIL); - IDA_mem->ida_ttol = (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)) * - IDA_mem->ida_uround * HUNDRED; + IDA_mem->ida_ttol = ((SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)) * + IDA_mem->ida_uround * HUNDRED); ier = IDARootfind(IDA_mem); if (ier == IDA_RTFUNC_FAIL) return(IDA_RTFUNC_FAIL); for(i=0; iida_nrtfn; i++) { - if(!IDA_mem->ida_gactive[i] && - IDA_mem->ida_grout[i] != ZERO) + if(!IDA_mem->ida_gactive[i] && IDA_mem->ida_grout[i] != ZERO) IDA_mem->ida_gactive[i] = SUNTRUE; } IDA_mem->ida_tlo = IDA_mem->ida_trout; for (i = 0; i < IDA_mem->ida_nrtfn; i++) IDA_mem->ida_glo[i] = IDA_mem->ida_grout[i]; - /* If no root found, return IDA_SUCCESS. */ + /* If no root found, return IDA_SUCCESS. */ if (ier == IDA_SUCCESS) return(IDA_SUCCESS); /* If a root was found, interpolate to get y(trout) and return. */ @@ -6774,7 +7013,7 @@ static int IDARcheck3(IDAMem IDA_mem) * set to SUNTRUE for all i=0,...,nrtfn-1, but it may be * reset to SUNFALSE if at the first step g[i] is 0.0 * both at the I.C. and at a small perturbation of them. - * gactive[i] is then set back on SUNTRUE only after the + * gactive[i] is then set back on SUNTRUE only after the * corresponding g function moves away from 0.0. * * nge = cumulative counter for gfun calls. @@ -6834,13 +7073,13 @@ static int IDARootfind(IDAMem IDA_mem) for (i = 0; i < IDA_mem->ida_nrtfn; i++) { if(!IDA_mem->ida_gactive[i]) continue; if (SUNRabs(IDA_mem->ida_ghi[i]) == ZERO) { - if(IDA_mem->ida_rootdir[i]*IDA_mem->ida_glo[i] <= ZERO) { + if(IDA_mem->ida_rootdir[i] * IDA_mem->ida_glo[i] <= ZERO) { zroot = SUNTRUE; } } else { - if ( (IDA_mem->ida_glo[i]*IDA_mem->ida_ghi[i] < ZERO) && - (IDA_mem->ida_rootdir[i]*IDA_mem->ida_glo[i] <= ZERO) ) { - gfrac = SUNRabs(IDA_mem->ida_ghi[i]/(IDA_mem->ida_ghi[i] - IDA_mem->ida_glo[i])); + if ( (IDA_mem->ida_glo[i] * IDA_mem->ida_ghi[i] < ZERO) && + (IDA_mem->ida_rootdir[i] * IDA_mem->ida_glo[i] <= ZERO) ) { + gfrac = SUNRabs(IDA_mem->ida_ghi[i] / (IDA_mem->ida_ghi[i] - IDA_mem->ida_glo[i])); if (gfrac > maxfrac) { sgnchg = SUNTRUE; maxfrac = gfrac; @@ -6851,7 +7090,7 @@ static int IDARootfind(IDAMem IDA_mem) } /* If no sign change was found, reset trout and grout. Then return - IDA_SUCCESS if no zero was found, or set iroots and return RTFOUND. */ + IDA_SUCCESS if no zero was found, or set iroots and return RTFOUND. */ if (!sgnchg) { IDA_mem->ida_trout = IDA_mem->ida_thi; for (i = 0; i < IDA_mem->ida_nrtfn; i++) @@ -6861,7 +7100,7 @@ static int IDARootfind(IDAMem IDA_mem) IDA_mem->ida_iroots[i] = 0; if(!IDA_mem->ida_gactive[i]) continue; if ( (SUNRabs(IDA_mem->ida_ghi[i]) == ZERO) && - (IDA_mem->ida_rootdir[i]*IDA_mem->ida_glo[i] <= ZERO) ) + (IDA_mem->ida_rootdir[i] * IDA_mem->ida_glo[i] <= ZERO) ) IDA_mem->ida_iroots[i] = IDA_mem->ida_glo[i] > 0 ? -1:1; } return(RTFOUND); @@ -6899,7 +7138,7 @@ static int IDARootfind(IDAMem IDA_mem) If tmid is too close to tlo or thi, adjust it inward, by a fractional distance that is between 0.1 and 0.5. */ tmid = IDA_mem->ida_thi - (IDA_mem->ida_thi - IDA_mem->ida_tlo) * - IDA_mem->ida_ghi[imax]/(IDA_mem->ida_ghi[imax] - alph*IDA_mem->ida_glo[imax]); + IDA_mem->ida_ghi[imax] / (IDA_mem->ida_ghi[imax] - alph*IDA_mem->ida_glo[imax]); if (SUNRabs(tmid - IDA_mem->ida_tlo) < HALF * IDA_mem->ida_ttol) { fracint = SUNRabs(IDA_mem->ida_thi - IDA_mem->ida_tlo) / IDA_mem->ida_ttol; fracsub = (fracint > FIVE) ? PT1 : HALF/fracint; @@ -6913,12 +7152,12 @@ static int IDARootfind(IDAMem IDA_mem) (void) IDAGetSolution(IDA_mem, tmid, IDA_mem->ida_yy, IDA_mem->ida_yp); retval = IDA_mem->ida_gfun(tmid, IDA_mem->ida_yy, IDA_mem->ida_yp, - IDA_mem->ida_grout, IDA_mem->ida_user_data); + IDA_mem->ida_grout, IDA_mem->ida_user_data); IDA_mem->ida_nge++; if (retval != 0) return(IDA_RTFUNC_FAIL); /* Check to see in which subinterval g changes sign, and reset imax. - Set side = 1 if sign change is on low side, or 2 if on high side. */ + Set side = 1 if sign change is on low side, or 2 if on high side. */ maxfrac = ZERO; zroot = SUNFALSE; sgnchg = SUNFALSE; @@ -6926,11 +7165,11 @@ static int IDARootfind(IDAMem IDA_mem) for (i = 0; i < IDA_mem->ida_nrtfn; i++) { if(!IDA_mem->ida_gactive[i]) continue; if (SUNRabs(IDA_mem->ida_grout[i]) == ZERO) { - if(IDA_mem->ida_rootdir[i]*IDA_mem->ida_glo[i] <= ZERO) + if(IDA_mem->ida_rootdir[i] * IDA_mem->ida_glo[i] <= ZERO) zroot = SUNTRUE; } else { - if ( (IDA_mem->ida_glo[i]*IDA_mem->ida_grout[i] < ZERO) && - (IDA_mem->ida_rootdir[i]*IDA_mem->ida_glo[i] <= ZERO) ) { + if ( (IDA_mem->ida_glo[i] * IDA_mem->ida_grout[i] < ZERO) && + (IDA_mem->ida_rootdir[i] * IDA_mem->ida_glo[i] <= ZERO) ) { gfrac = SUNRabs(IDA_mem->ida_grout[i] / (IDA_mem->ida_grout[i] - IDA_mem->ida_glo[i])); if (gfrac > maxfrac) { @@ -6980,16 +7219,16 @@ static int IDARootfind(IDAMem IDA_mem) IDA_mem->ida_iroots[i] = 0; if(!IDA_mem->ida_gactive[i]) continue; if ( (SUNRabs(IDA_mem->ida_ghi[i]) == ZERO) && - (IDA_mem->ida_rootdir[i]*IDA_mem->ida_glo[i] <= ZERO) ) + (IDA_mem->ida_rootdir[i] * IDA_mem->ida_glo[i] <= ZERO) ) IDA_mem->ida_iroots[i] = IDA_mem->ida_glo[i] > 0 ? -1:1; - if ( (IDA_mem->ida_glo[i]*IDA_mem->ida_ghi[i] < ZERO) && - (IDA_mem->ida_rootdir[i]*IDA_mem->ida_glo[i] <= ZERO) ) + if ( (IDA_mem->ida_glo[i] * IDA_mem->ida_ghi[i] < ZERO) && + (IDA_mem->ida_rootdir[i] * IDA_mem->ida_glo[i] <= ZERO) ) IDA_mem->ida_iroots[i] = IDA_mem->ida_glo[i] > 0 ? -1:1; } return(RTFOUND); } -/* +/* * ================================================================= * Internal DQ approximations for sensitivity RHS * ================================================================= @@ -7006,7 +7245,7 @@ static int IDARootfind(IDAMem IDA_mem) * >0 for a recoverable error. */ -int IDASensResDQ(int Ns, realtype t, +int IDASensResDQ(int Ns, realtype t, N_Vector yy, N_Vector yp, N_Vector resval, N_Vector *yyS, N_Vector *ypS, N_Vector *resvalS, void *user_dataS, @@ -7015,9 +7254,9 @@ int IDASensResDQ(int Ns, realtype t, int retval, is; for (is=0; is0 if res has a recoverable error). */ -static int IDASensRes1DQ(int Ns, realtype t, +static int IDASensRes1DQ(int Ns, realtype t, N_Vector yy, N_Vector yp, N_Vector resval, int is, N_Vector yyS, N_Vector ypS, N_Vector resvalS, @@ -7083,7 +7322,7 @@ static int IDASensRes1DQ(int Ns, realtype t, else method = (IDA_mem->ida_DQtype==IDA_CENTERED) ? CENTERED2 : FORWARD2; } - + switch (method) { case CENTERED1: @@ -7100,7 +7339,7 @@ static int IDASensRes1DQ(int Ns, realtype t, retval = IDA_mem->ida_res(t, ytemp, yptemp, resvalS, IDA_mem->ida_user_data); IDA_mem->ida_nreS++; if (retval != 0) return(retval); - + /* Backward perturb y, y' and parameter */ N_VLinearSum(-Del, yyS, ONE, yy, ytemp); N_VLinearSum(-Del, ypS, ONE, yp, yptemp); @@ -7113,7 +7352,7 @@ static int IDASensRes1DQ(int Ns, realtype t, /* Estimate the residual for the i-th sensitivity equation */ N_VLinearSum(r2Del, resvalS, -r2Del, restemp, resvalS); - + break; case CENTERED2: @@ -7124,12 +7363,12 @@ static int IDASensRes1DQ(int Ns, realtype t, /* Forward perturb y and y' */ N_VLinearSum(Dely, yyS, ONE, yy, ytemp); N_VLinearSum(Dely, ypS, ONE, yp, yptemp); - + /* Save residual in resvalS */ retval = IDA_mem->ida_res(t, ytemp, yptemp, resvalS, IDA_mem->ida_user_data); IDA_mem->ida_nreS++; if (retval != 0) return(retval); - + /* Backward perturb y and y' */ N_VLinearSum(-Dely, yyS, ONE, yy, ytemp); N_VLinearSum(-Dely, ypS, ONE, yp, yptemp); @@ -7157,13 +7396,13 @@ static int IDASensRes1DQ(int Ns, realtype t, retval = IDA_mem->ida_res(t, yy, yp, yptemp, IDA_mem->ida_user_data); IDA_mem->ida_nreS++; if (retval != 0) return(retval); - + /* Save the second difference quotient in restemp */ N_VLinearSum(r2Delp, ytemp, -r2Delp, yptemp, restemp); - + /* Add the difference quotients for the sensitivity residual */ N_VLinearSum(ONE, resvalS, ONE, restemp, resvalS); - + break; case FORWARD1: @@ -7220,7 +7459,7 @@ static int IDASensRes1DQ(int Ns, realtype t, /* Restore original value of parameter */ IDA_mem->ida_p[which] = psave; - + return(0); } @@ -7233,22 +7472,22 @@ static int IDASensRes1DQ(int Ns, realtype t, * done in IDAQuadSensRhs1InternalDQ. */ -static int IDAQuadSensRhsInternalDQ(int Ns, realtype t, +static int IDAQuadSensRhsInternalDQ(int Ns, realtype t, N_Vector yy, N_Vector yp, N_Vector *yyS, N_Vector *ypS, N_Vector rrQ, N_Vector *resvalQS, - void *ida_mem, + void *ida_mem, N_Vector yytmp, N_Vector yptmp, N_Vector tmpQS) { IDAMem IDA_mem; int is, retval; - + /* cvode_mem is passed here as user data */ IDA_mem = (IDAMem) ida_mem; for (is=0; isida_rtol, IDA_mem->ida_uround)); rdel = ONE/del; - + pbari = IDA_mem->ida_pbar[is]; which = IDA_mem->ida_plist[is]; psave = IDA_mem->ida_p[which]; - + Delp = pbari * del; norms = N_VWrmsNorm(yyS, IDA_mem->ida_ewt) * pbari; rDely = SUNMAX(norms, rdel) / pbari; Dely = ONE/rDely; - + method = (IDA_mem->ida_DQtype==IDA_CENTERED) ? CENTERED1 : FORWARD1; switch(method) { case CENTERED1: - + Del = SUNMIN(Dely, Delp); r2Del = HALF/Del; - + N_VLinearSum(ONE, yy, Del, yyS, yytmp); N_VLinearSum(ONE, yp, Del, ypS, yptmp); IDA_mem->ida_p[which] = psave + Del; @@ -7302,7 +7541,7 @@ static int IDAQuadSensRhs1InternalDQ(IDAMem IDA_mem, int is, realtype t, retval = IDA_mem->ida_rhsQ(t, yytmp, yptmp, resvalQS, IDA_mem->ida_user_data); nfel++; if (retval != 0) return(retval); - + N_VLinearSum(-Del, yyS, ONE, yy, yytmp); N_VLinearSum(-Del, ypS, ONE, yp, yptmp); @@ -7313,14 +7552,14 @@ static int IDAQuadSensRhs1InternalDQ(IDAMem IDA_mem, int is, realtype t, if (retval != 0) return(retval); N_VLinearSum(r2Del, resvalQS, -r2Del, tmpQS, resvalQS); - + break; case FORWARD1: - + Del = SUNMIN(Dely, Delp); rdel = ONE/Del; - + N_VLinearSum(ONE, yy, Del, yyS, yytmp); N_VLinearSum(ONE, yp, Del, ypS, yptmp); IDA_mem->ida_p[which] = psave + Del; @@ -7328,41 +7567,41 @@ static int IDAQuadSensRhs1InternalDQ(IDAMem IDA_mem, int is, realtype t, retval = IDA_mem->ida_rhsQ(t, yytmp, yptmp, resvalQS, IDA_mem->ida_user_data); nfel++; if (retval != 0) return(retval); - + N_VLinearSum(rdel, resvalQS, -rdel, resvalQ, resvalQS); - + break; } IDA_mem->ida_p[which] = psave; /* Increment counter nrQeS */ IDA_mem->ida_nrQeS += nfel; - + return(0); } -/* +/* * ================================================================= - * IDA Error message handling functions + * IDA error message handling functions * ================================================================= */ /* * IDAProcessError is a high level error handling function. * - If ida_mem==NULL it prints the error message to stderr. - * - Otherwise, it sets up and calls the error handling function + * - Otherwise, it sets up and calls the error handling function * pointed to by ida_ehfun. */ -void IDAProcessError(IDAMem IDA_mem, - int error_code, const char *module, const char *fname, +void IDAProcessError(IDAMem IDA_mem, + int error_code, const char *module, const char *fname, const char *msgfmt, ...) { va_list ap; char msg[256]; - /* Initialize the argument pointer variable + /* Initialize the argument pointer variable (msgfmt is the last required argument to IDAProcessError) */ va_start(ap, msgfmt); diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas_bbdpre.c b/deps/AMICI/ThirdParty/sundials/src/idas/idas_bbdpre.c index ca32f7385..551a0081c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas_bbdpre.c +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas_bbdpre.c @@ -1,10 +1,10 @@ /* - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Programmer(s): Daniel R. Reynolds @ SMU * Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -15,7 +15,7 @@ * ----------------------------------------------------------------- * This file contains implementations of routines for a * band-block-diagonal preconditioner, i.e. a block-diagonal - * matrix with banded blocks, for use with IDA, the IDASLS + * matrix with banded blocks, for use with IDA, the IDASLS * linear solver interface. * * NOTE: With only one processor in use, a banded matrix results @@ -50,11 +50,11 @@ static int IDABBDPrecFree(IDAMem ida_mem); /* Prototype for difference quotient Jacobian calculation routine */ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, - N_Vector yy, N_Vector yp, N_Vector gref, + N_Vector yy, N_Vector yp, N_Vector gref, N_Vector ytemp, N_Vector yptemp, N_Vector gtemp); /* Wrapper functions for adjoint code */ -static int IDAAglocal(sunindextype NlocalB, realtype tt, N_Vector yyB, +static int IDAAglocal(sunindextype NlocalB, realtype tt, N_Vector yyB, N_Vector ypB, N_Vector gvalB, void *user_dataB); static int IDAAgcomm(sunindextype NlocalB, realtype tt, N_Vector yyB, @@ -71,10 +71,10 @@ static int IDABBDPrecFreeB(IDABMem IDAB_mem); /*--------------------------------------------------------------- User-Callable Functions: initialization, reinit and free ---------------------------------------------------------------*/ -int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, - sunindextype mudq, sunindextype mldq, - sunindextype mukeep, sunindextype mlkeep, - realtype dq_rel_yy, +int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, + sunindextype mudq, sunindextype mldq, + sunindextype mukeep, sunindextype mlkeep, + realtype dq_rel_yy, IDABBDLocalFn Gres, IDABBDCommFn Gcomm) { IDAMem IDA_mem; @@ -132,11 +132,11 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, /* Allocate memory for preconditioner matrix. */ pdata->PP = NULL; pdata->PP = SUNBandMatrixStorage(Nlocal, muk, mlk, storage_mu); - if (pdata->PP == NULL) { + if (pdata->PP == NULL) { free(pdata); pdata = NULL; IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", "IDABBDPrecInit", MSGBBD_MEM_FAIL); - return(IDALS_MEM_FAIL); + return(IDALS_MEM_FAIL); } /* Allocate memory for temporary N_Vectors */ @@ -145,7 +145,7 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, if (pdata->zlocal == NULL) { SUNMatDestroy(pdata->PP); free(pdata); pdata = NULL; - IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", "IDABBDPrecInit", MSGBBD_MEM_FAIL); return(IDALS_MEM_FAIL); } @@ -155,12 +155,12 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, N_VDestroy(pdata->zlocal); SUNMatDestroy(pdata->PP); free(pdata); pdata = NULL; - IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", "IDABBDPrecInit", MSGBBD_MEM_FAIL); return(IDALS_MEM_FAIL); } pdata->tempv1 = NULL; - pdata->tempv1 = N_VClone(IDA_mem->ida_tempv1); + pdata->tempv1 = N_VClone(IDA_mem->ida_tempv1); if (pdata->tempv1 == NULL){ N_VDestroy(pdata->rlocal); N_VDestroy(pdata->zlocal); @@ -171,7 +171,7 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, return(IDALS_MEM_FAIL); } pdata->tempv2 = NULL; - pdata->tempv2 = N_VClone(IDA_mem->ida_tempv1); + pdata->tempv2 = N_VClone(IDA_mem->ida_tempv1); if (pdata->tempv2 == NULL){ N_VDestroy(pdata->rlocal); N_VDestroy(pdata->zlocal); @@ -183,7 +183,7 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, return(IDALS_MEM_FAIL); } pdata->tempv3 = NULL; - pdata->tempv3 = N_VClone(IDA_mem->ida_tempv1); + pdata->tempv3 = N_VClone(IDA_mem->ida_tempv1); if (pdata->tempv3 == NULL){ N_VDestroy(pdata->rlocal); N_VDestroy(pdata->zlocal); @@ -196,7 +196,7 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, return(IDALS_MEM_FAIL); } pdata->tempv4 = NULL; - pdata->tempv4 = N_VClone(IDA_mem->ida_tempv1); + pdata->tempv4 = N_VClone(IDA_mem->ida_tempv1); if (pdata->tempv4 == NULL){ N_VDestroy(pdata->rlocal); N_VDestroy(pdata->zlocal); @@ -243,14 +243,14 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, "IDABBDPrecInit", MSGBBD_SUNLS_FAIL); return(IDALS_SUNLS_FAIL); } - + /* Set rel_yy based on input value dq_rel_yy (0 implies default). */ pdata->rel_yy = (dq_rel_yy > ZERO) ? - dq_rel_yy : SUNRsqrt(IDA_mem->ida_uround); + dq_rel_yy : SUNRsqrt(IDA_mem->ida_uround); /* Store Nlocal to be used in IDABBDPrecSetup */ pdata->n_local = Nlocal; - + /* Set work space sizes and initialize nge. */ pdata->rpwsize = 0; pdata->ipwsize = 0; @@ -277,7 +277,7 @@ int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, pdata->nge = 0; /* make sure pdata is free from any previous allocations */ - if (idals_mem->pfree) + if (idals_mem->pfree) idals_mem->pfree(IDA_mem); /* Point to the new pdata field in the LS memory */ @@ -323,7 +323,7 @@ int IDABBDPrecReInit(void *ida_mem, sunindextype mudq, IDAProcessError(IDA_mem, IDALS_PMEM_NULL, "IDASBBDPRE", "IDABBDPrecReInit", MSGBBD_PMEM_NULL); return(IDALS_PMEM_NULL); - } + } pdata = (IBBDPrecData) idals_mem->pdata; /* Load half-bandwidths. */ @@ -333,7 +333,7 @@ int IDABBDPrecReInit(void *ida_mem, sunindextype mudq, /* Set rel_yy based on input value dq_rel_yy (0 implies default). */ pdata->rel_yy = (dq_rel_yy > ZERO) ? - dq_rel_yy : SUNRsqrt(IDA_mem->ida_uround); + dq_rel_yy : SUNRsqrt(IDA_mem->ida_uround); /* Re-initialize nge */ pdata->nge = 0; @@ -369,7 +369,7 @@ int IDABBDPrecGetWorkSpace(void *ida_mem, IDAProcessError(IDA_mem, IDALS_PMEM_NULL, "IDASBBDPRE", "IDABBDPrecGetWorkSpace", MSGBBD_PMEM_NULL); return(IDALS_PMEM_NULL); - } + } pdata = (IBBDPrecData) idals_mem->pdata; *lenrwBBDP = pdata->rpwsize; @@ -405,7 +405,7 @@ int IDABBDPrecGetNumGfnEvals(void *ida_mem, IDAProcessError(IDA_mem, IDALS_PMEM_NULL, "IDASBBDPRE", "IDABBDPrecGetNumGfnEvals", MSGBBD_PMEM_NULL); return(IDALS_PMEM_NULL); - } + } pdata = (IBBDPrecData) idals_mem->pdata; *ngevalsBBDP = pdata->nge; @@ -425,23 +425,23 @@ int IDABBDPrecGetNumGfnEvals(void *ida_mem, scheme via calls to the user-supplied routines glocal, gcomm. After generating the block in the band matrix PP, this routine does an LU factorization in place in PP. - + The IDABBDPrecSetup parameters used here are as follows: - + tt is the current value of the independent variable t. - + yy is the current value of the dependent variable vector, namely the predicted value of y(t). - + yp is the current value of the derivative vector y', namely the predicted value of y'(t). - + c_j is the scalar in the system Jacobian, proportional to 1/hh. - + bbd_data is the pointer to BBD memory set by IDABBDInit - + The argument rr is not used. - + Return value: The value returned by this IDABBDPrecSetup function is a int flag indicating whether it was successful. This value is @@ -452,7 +452,6 @@ int IDABBDPrecGetNumGfnEvals(void *ida_mem, static int IDABBDPrecSetup(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr, realtype c_j, void *bbd_data) { - sunindextype ier; IBBDPrecData pdata; IDAMem IDA_mem; int retval; @@ -472,11 +471,11 @@ static int IDABBDPrecSetup(realtype tt, N_Vector yy, N_Vector yp, } if (retval > 0) { return(+1); - } - + } + /* Do LU factorization of matrix and return error flag */ - ier = SUNLinSolSetup_Band(pdata->LS, pdata->PP); - return(ier); + retval = SUNLinSolSetup_Band(pdata->LS, pdata->PP); + return(retval); } @@ -486,18 +485,18 @@ static int IDABBDPrecSetup(realtype tt, N_Vector yy, N_Vector yp, The function IDABBDPrecSolve computes a solution to the linear system P z = r, where P is the left preconditioner defined by the routine IDABBDPrecSetup. - + The IDABBDPrecSolve parameters used here are as follows: - + rvec is the input right-hand side vector r. - + zvec is the computed solution vector z. - + bbd_data is the pointer to BBD data set by IDABBDInit. - + The arguments tt, yy, yp, rr, c_j and delta are NOT used. - - IDABBDPrecSolve returns the value returned from the linear + + IDABBDPrecSolve returns the value returned from the linear solver object. ---------------------------------------------------------------*/ static int IDABBDPrecSolve(realtype tt, N_Vector yy, N_Vector yp, @@ -512,9 +511,9 @@ static int IDABBDPrecSolve(realtype tt, N_Vector yy, N_Vector yp, /* Attach local data arrays for rvec and zvec to rlocal and zlocal */ N_VSetArrayPointer(N_VGetArrayPointer(rvec), pdata->rlocal); N_VSetArrayPointer(N_VGetArrayPointer(zvec), pdata->zlocal); - + /* Call banded solver object to do the work */ - retval = SUNLinSolSolve(pdata->LS, pdata->PP, pdata->zlocal, + retval = SUNLinSolSolve(pdata->LS, pdata->PP, pdata->zlocal, pdata->rlocal, ZERO); /* Detach local data arrays from rlocal and zlocal */ @@ -530,10 +529,10 @@ static int IDABBDPrecFree(IDAMem IDA_mem) { IDALsMem idals_mem; IBBDPrecData pdata; - + if (IDA_mem->ida_lmem == NULL) return(0); idals_mem = (IDALsMem) IDA_mem->ida_lmem; - + if (idals_mem->pdata == NULL) return(0); pdata = (IBBDPrecData) idals_mem->pdata; @@ -560,19 +559,19 @@ static int IDABBDPrecFree(IDAMem IDA_mem) to the local block of the Jacobian of G(t,y,y'). It assumes that a band matrix of type SUNMatrix is stored column-wise, and that elements within each column are contiguous. - + All matrix elements are generated as difference quotients, by way of calls to the user routine glocal. By virtue of the band structure, the number of these calls is bandwidth + 1, where bandwidth = mldq + mudq + 1. But the band matrix kept has bandwidth = mlkeep + mukeep + 1. This routine also assumes that the local elements of a vector are stored contiguously. - + Return values are: 0 (success), > 0 (recoverable error), or < 0 (nonrecoverable error). ----------------------------------------------------------------*/ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, - N_Vector yy, N_Vector yp, N_Vector gref, + N_Vector yy, N_Vector yp, N_Vector gref, N_Vector ytemp, N_Vector yptemp, N_Vector gtemp) { IDAMem IDA_mem; @@ -594,7 +593,7 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, ypdata = N_VGetArrayPointer(yp); gtempdata = N_VGetArrayPointer(gtemp); ewtdata = N_VGetArrayPointer(IDA_mem->ida_ewt); - if (IDA_mem->ida_constraints != NULL) + if (IDA_mem->ida_constraintsSet) cnsdata = N_VGetArrayPointer(IDA_mem->ida_constraints); ytempdata = N_VGetArrayPointer(ytemp); yptempdata= N_VGetArrayPointer(yptemp); @@ -606,7 +605,7 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, if (retval != 0) return(retval); } - retval = pdata->glocal(pdata->n_local, tt, yy, yp, gref, IDA_mem->ida_user_data); + retval = pdata->glocal(pdata->n_local, tt, yy, yp, gref, IDA_mem->ida_user_data); pdata->nge++; if (retval != 0) return(retval); @@ -616,13 +615,13 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, /* Loop over groups. */ for(group = 1; group <= ngroups; group++) { - + /* Loop over the components in this group. */ for(j = group-1; j < pdata->n_local; j += width) { yj = ydata[j]; ypj = ypdata[j]; ewtj = ewtdata[j]; - + /* Set increment inc to yj based on rel_yy*abs(yj), with adjustments using ypj and ewtj if this is small, and a further adjustment to give it the same sign as hh*ypj. */ @@ -630,9 +629,9 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, SUNMAX(SUNRabs(yj), SUNMAX( SUNRabs(IDA_mem->ida_hh*ypj), ONE/ewtj)); if (IDA_mem->ida_hh*ypj < ZERO) inc = -inc; inc = (yj + inc) - yj; - + /* Adjust sign(inc) again if yj has an inequality constraint. */ - if (IDA_mem->ida_constraints != NULL) { + if (IDA_mem->ida_constraintsSet) { conj = cnsdata[j]; if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} @@ -641,12 +640,12 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, /* Increment yj and ypj. */ ytempdata[j] += inc; yptempdata[j] += cj*inc; - + } /* Evaluate G with incremented y and yp arguments. */ retval = pdata->glocal(pdata->n_local, tt, ytemp, yptemp, - gtemp, IDA_mem->ida_user_data); + gtemp, IDA_mem->ida_user_data); pdata->nge++; if (retval != 0) return(retval); @@ -661,7 +660,7 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, SUNMAX(SUNRabs(yj), SUNMAX( SUNRabs(IDA_mem->ida_hh*ypj), ONE/ewtj)); if (IDA_mem->ida_hh*ypj < ZERO) inc = -inc; inc = (yj + inc) - yj; - if (IDA_mem->ida_constraints != NULL) { + if (IDA_mem->ida_constraintsSet) { conj = cnsdata[j]; if (SUNRabs(conj) == ONE) {if ((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if ((yj+inc)*conj <= ZERO) inc = -inc;} @@ -677,7 +676,7 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, inc_inv * (gtempdata[i] - grefdata[i]); } } - + return(0); } @@ -692,7 +691,7 @@ static int IBBDDQJac(IBBDPrecData pdata, realtype tt, realtype cj, int IDABBDPrecInitB(void *ida_mem, int which, sunindextype NlocalB, sunindextype mudqB, sunindextype mldqB, sunindextype mukeepB, sunindextype mlkeepB, - realtype dq_rel_yyB, IDABBDLocalFnB glocalB, + realtype dq_rel_yyB, IDABBDLocalFnB glocalB, IDABBDCommFnB gcommB) { IDAMem IDA_mem; @@ -701,7 +700,7 @@ int IDABBDPrecInitB(void *ida_mem, int which, sunindextype NlocalB, IDABBDPrecDataB idabbdB_mem; void *ida_memB; int flag; - + /* Check if ida_mem is allright. */ if (ida_mem == NULL) { IDAProcessError(NULL, IDALS_MEM_NULL, "IDASBBDPRE", @@ -771,7 +770,7 @@ int IDABBDPrecReInitB(void *ida_mem, int which, sunindextype mudqB, IDABMem IDAB_mem; void *ida_memB; int flag; - + /* Check if ida_mem is allright. */ if (ida_mem == NULL) { IDAProcessError(NULL, IDALS_MEM_NULL, "IDASBBDPRE", @@ -826,8 +825,8 @@ static int IDABBDPrecFreeB(IDABMem IDAB_mem) /*---------------------------------------------------------------- IDAAglocal - - This routine interfaces to the IDALocalFnB routine + + This routine interfaces to the IDALocalFnB routine provided by the user. ----------------------------------------------------------------*/ static int IDAAglocal(sunindextype NlocalB, realtype tt, N_Vector yyB, @@ -841,7 +840,7 @@ static int IDAAglocal(sunindextype NlocalB, realtype tt, N_Vector yyB, IDA_mem = (IDAMem) ida_mem; IDAADJ_mem = IDA_mem->ida_adj_mem; - + /* Get current backward problem. */ IDAB_mem = IDAADJ_mem->ia_bckpbCrt; @@ -856,7 +855,7 @@ static int IDAAglocal(sunindextype NlocalB, realtype tt, N_Vector yyB, IDAProcessError(IDA_mem, -1, "IDASBBDPRE", "IDAAglocal", MSGBBD_BAD_T); return(-1); - } + } } /* Call user's adjoint LocalFnB function. */ return idabbdB_mem->glocalB(NlocalB, tt, IDAADJ_mem->ia_yyTmp, @@ -867,8 +866,8 @@ static int IDAAglocal(sunindextype NlocalB, realtype tt, N_Vector yyB, /*---------------------------------------------------------------- IDAAgcomm - - This routine interfaces to the IDACommFnB routine + + This routine interfaces to the IDACommFnB routine provided by the user. ----------------------------------------------------------------*/ static int IDAAgcomm(sunindextype NlocalB, realtype tt, @@ -882,7 +881,7 @@ static int IDAAgcomm(sunindextype NlocalB, realtype tt, IDA_mem = (IDAMem) ida_mem; IDAADJ_mem = IDA_mem->ida_adj_mem; - + /* Get current backward problem. */ IDAB_mem = IDAADJ_mem->ia_bckpbCrt; @@ -898,11 +897,11 @@ static int IDAAgcomm(sunindextype NlocalB, realtype tt, IDAProcessError(IDA_mem, -1, "IDASBBDPRE", "IDAAgcomm", MSGBBD_BAD_T); return(-1); - } + } } /* Call user's adjoint CommFnB routine */ - return idabbdB_mem->gcommB(NlocalB, tt, IDAADJ_mem->ia_yyTmp, - IDAADJ_mem->ia_ypTmp, yyB, ypB, + return idabbdB_mem->gcommB(NlocalB, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, yyB, ypB, IDAB_mem->ida_user_data); } diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas_bbdpre_impl.h b/deps/AMICI/ThirdParty/sundials/src/idas/idas_bbdpre_impl.h index 45e409b34..70113212b 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas_bbdpre_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas_bbdpre_impl.h @@ -3,7 +3,7 @@ * Alan C. Hindmarsh and Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas_direct.c b/deps/AMICI/ThirdParty/sundials/src/idas/idas_direct.c index ee1bf7c93..bdcc64be1 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas_direct.c +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas_direct.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas_ic.c b/deps/AMICI/ThirdParty/sundials/src/idas/idas_ic.c index 0284d96bb..5c664b87a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas_ic.c +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas_ic.c @@ -6,7 +6,7 @@ * Programmers: Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas_impl.h b/deps/AMICI/ThirdParty/sundials/src/idas/idas_impl.h index c3285114e..2f65936c1 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas_impl.h @@ -2,11 +2,11 @@ * ----------------------------------------------------------------- * $Revision$ * $Date$ - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Programmer(s): Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -32,7 +32,7 @@ extern "C" { #endif -/* +/* * ================================================================= * M A I N I N T E G R A T O R M E M O R Y B L O C K * ================================================================= @@ -40,7 +40,7 @@ extern "C" { /* Basic IDA constants */ - + #define HMAX_INV_DEFAULT RCONST(0.0) /* hmax_inv default value */ #define MAXORD_DEFAULT 5 /* maxord default value */ #define MXORDP1 6 /* max. number of N_Vectors in phi */ @@ -64,7 +64,7 @@ extern "C" { #define IDA_SS 1 #define IDA_SV 2 #define IDA_WF 3 -#define IDA_EE 4 +#define IDA_EE 4 /* * ----------------------------------------------------------------- @@ -80,7 +80,7 @@ typedef struct IDAMemRec { realtype ida_uround; /* machine unit roundoff */ /*-------------------------- - Problem Specification Data + Problem Specification Data --------------------------*/ IDAResFn ida_res; /* F(t,y(t),y'(t))=0; the function F */ @@ -88,14 +88,15 @@ typedef struct IDAMemRec { int ida_itol; /* itol = IDA_SS, IDA_SV, IDA_WF, IDA_NN */ realtype ida_rtol; /* relative tolerance */ - realtype ida_Satol; /* scalar absolute tolerance */ - N_Vector ida_Vatol; /* vector absolute tolerance */ + realtype ida_Satol; /* scalar absolute tolerance */ + N_Vector ida_Vatol; /* vector absolute tolerance */ + booleantype ida_atolmin0; /* flag indicating that min(atol) = 0 */ booleantype ida_user_efun; /* SUNTRUE if user provides efun */ IDAEwtFn ida_efun; /* function to set ewt */ void *ida_edata; /* user pointer passed to efun */ - + /*----------------------- - Quadrature Related Data + Quadrature Related Data -----------------------*/ booleantype ida_quadr; @@ -109,6 +110,7 @@ typedef struct IDAMemRec { realtype ida_rtolQ; realtype ida_SatolQ; /* scalar absolute tolerance for quadratures */ N_Vector ida_VatolQ; /* vector absolute tolerance for quadratures */ + booleantype ida_atolQmin0; /* flag indicating that min(atolQ) = 0 */ /*------------------------ Sensitivity Related Data @@ -131,12 +133,13 @@ typedef struct IDAMemRec { booleantype ida_errconS; /* SUNTRUE if sensitivities in err. control */ int ida_itolS; - realtype ida_rtolS; /* relative tolerance for sensitivities */ - realtype *ida_SatolS; /* scalar absolute tolerances for sensi. */ - N_Vector *ida_VatolS; /* vector absolute tolerances for sensi. */ + realtype ida_rtolS; /* relative tolerance for sensitivities */ + realtype *ida_SatolS; /* scalar absolute tolerances for sensi. */ + N_Vector *ida_VatolS; /* vector absolute tolerances for sensi. */ + booleantype *ida_atolSmin0; /* flag indicating that min(atolS[is]) = 0 */ /*----------------------------------- - Quadrature Sensitivity Related Data + Quadrature Sensitivity Related Data -----------------------------------*/ booleantype ida_quadr_sensi; /* SUNTRUE if computing sensitivities of quadrs. */ @@ -151,6 +154,7 @@ typedef struct IDAMemRec { realtype ida_rtolQS; /* relative tolerance for yQS */ realtype *ida_SatolQS; /* scalar absolute tolerances for yQS */ N_Vector *ida_VatolQS; /* vector absolute tolerances for yQS */ + booleantype *ida_atolQSmin0; /* flag indicating that min(atolQS[is]) = 0 */ /*----------------------------------------------- Divided differences array and associated arrays @@ -180,7 +184,6 @@ typedef struct IDAMemRec { N_Vector ida_ee; /* accumulated corrections to y vector, but set equal to estimated local errors upon successful return */ - N_Vector ida_mm; /* mask vector in constraints tests (= tempv2) */ N_Vector ida_tempv1; /* work space vector */ N_Vector ida_tempv2; /* work space vector */ N_Vector ida_tempv3; /* work space vector */ @@ -191,7 +194,7 @@ typedef struct IDAMemRec { /*---------------------------- - Quadrature Related N_Vectors + Quadrature Related N_Vectors ----------------------------*/ N_Vector ida_phiQ[MXORDP1]; @@ -201,7 +204,7 @@ typedef struct IDAMemRec { N_Vector ida_eeQ; /*--------------------------- - Sensitivity Related Vectors + Sensitivity Related Vectors ---------------------------*/ N_Vector *ida_phiS[MXORDP1]; @@ -217,11 +220,11 @@ typedef struct IDAMemRec { N_Vector ida_tmpS1; /* work space vectors | tmpS1 = tempv1 */ N_Vector ida_tmpS2; /* for resS | tmpS2 = tempv2 */ - N_Vector ida_tmpS3; /* | tmpS3 = allocated */ + N_Vector ida_tmpS3; /* | tmpS3 = allocated */ + + N_Vector *ida_savresS; /* work vector in IDACalcIC for stg (= phiS[2]) */ + N_Vector *ida_delnewS; /* work vector in IDACalcIC for stg (= phiS[3]) */ - N_Vector *ida_savresS; /* work vector in IDACalcIC for stg (= phiS[2]) */ - N_Vector *ida_delnewS; /* work vector in IDACalcIC for stg (= phiS[3]) */ - N_Vector *ida_yyS0; /* initial yS, ypS vectors allocated and */ N_Vector *ida_ypS0; /* deallocated in IDACalcIC function */ @@ -229,7 +232,7 @@ typedef struct IDAMemRec { N_Vector *ida_ypS0new; /* work vector in IDASensLineSrch (= eeS) */ /*-------------------------------------- - Quadrature Sensitivity Related Vectors + Quadrature Sensitivity Related Vectors --------------------------------------*/ N_Vector *ida_phiQS[MXORDP1];/* Mod. div. diffs. for quadr. sensitivities */ @@ -241,7 +244,7 @@ typedef struct IDAMemRec { N_Vector *ida_tempvQS; /* temporary storage vector (~ tempv) */ N_Vector ida_savrhsQ; /* saved quadr. rhs (needed for rhsQS calls) */ - /*------------------------------ + /*------------------------------ Variables for use by IDACalcIC ------------------------------*/ @@ -295,7 +298,6 @@ typedef struct IDAMemRec { ------*/ int ida_maxncf; /* max numer of convergence failures */ - int ida_maxcor; /* max number of Newton corrections */ int ida_maxnef; /* max number of error test failures */ int ida_maxord; /* max value of method order k: */ @@ -303,9 +305,6 @@ typedef struct IDAMemRec { long int ida_mxstep; /* max number of internal steps for one user call */ realtype ida_hmax_inv; /* inverse of max. step size hmax (default = 0.0) */ - int ida_maxcorS; /* max number of Newton corrections for sensitivity - systems (staggered method) */ - /*-------- Counters --------*/ @@ -334,7 +333,7 @@ typedef struct IDAMemRec { long int ida_nsetups; /* number of lsetup calls */ long int ida_nsetupsS; - + /*--------------------------- Space requirements for IDAS ---------------------------*/ @@ -348,7 +347,7 @@ typedef struct IDAMemRec { /*------------------------------------------- - Error handler function and error ouput file + Error handler function and error ouput file -------------------------------------------*/ IDAErrHandlerFn ida_ehfun; /* Error messages are handled by ehfun */ @@ -356,17 +355,17 @@ typedef struct IDAMemRec { FILE *ida_errfp; /* IDA error messages are sent to errfp */ /* Flags to verify correct calling sequence */ - + booleantype ida_SetupDone; /* set to SUNFALSE by IDAInit and IDAReInit - set to SUNTRUE by IDACalcIC or IDASolve */ + set to SUNTRUE by IDACalcIC or IDASolve */ booleantype ida_VatolMallocDone; booleantype ida_constraintsMallocDone; booleantype ida_idMallocDone; booleantype ida_MallocDone; /* set to SUNFALSE by IDACreate - set to SUNTRUE by IDAInit - tested by IDAReInit and IDASolve */ + set to SUNTRUE by IDAInit + tested by IDAReInit and IDASolve */ booleantype ida_VatolQMallocDone; booleantype ida_quadMallocDone; @@ -397,16 +396,16 @@ typedef struct IDAMemRec { /* The following vectors are NVector wrappers for use with the simultaneous and staggered corrector methods: - Simult: ycor0Sim = [ida_delta, ida_deltaS] - ycorSim = [ida_ee, ida_eeS] - ewtSim = [ida_ewt, ida_ewtS] + Simult: ypredictSim = [ida_delta, ida_deltaS] + ycorSim = [ida_ee, ida_eeS] + ewtSim = [ida_ewt, ida_ewtS] - Stagger: ycor0Stg = ida_deltaS - ycorStg = ida_eeS - ewtStg = ida_ewtS + Stagger: ypredictStg = ida_deltaS + ycorStg = ida_eeS + ewtStg = ida_ewtS */ - N_Vector ycor0Sim, ycorSim, ewtSim; - N_Vector ycor0Stg, ycorStg, ewtStg; + N_Vector ypredictSim, ycorSim, ewtSim; + N_Vector ypredictStg, ycorStg, ewtStg; /* flags indicating if vector wrappers for the simultaneous and staggered correctors have been allocated */ @@ -421,12 +420,12 @@ typedef struct IDAMemRec { int (*ida_linit)(struct IDAMemRec *idamem); - int (*ida_lsetup)(struct IDAMemRec *idamem, N_Vector yyp, - N_Vector ypp, N_Vector resp, - N_Vector tempv1, N_Vector tempv2, N_Vector tempv3); + int (*ida_lsetup)(struct IDAMemRec *idamem, N_Vector yyp, + N_Vector ypp, N_Vector resp, + N_Vector tempv1, N_Vector tempv2, N_Vector tempv3); int (*ida_lsolve)(struct IDAMemRec *idamem, N_Vector b, N_Vector weight, - N_Vector ycur, N_Vector ypcur, N_Vector rescur); + N_Vector ycur, N_Vector ypcur, N_Vector rescur); int (*ida_lperf)(struct IDAMemRec *idamem, int perftask); @@ -434,10 +433,10 @@ typedef struct IDAMemRec { /* Linear Solver specific memory */ - void *ida_lmem; + void *ida_lmem; /* Flag to request a call to the setup routine */ - + booleantype ida_forceSetup; /* Flag to indicate successful ida_linit call */ @@ -450,7 +449,7 @@ typedef struct IDAMemRec { booleantype ida_constraintsSet; /* constraints vector present */ booleantype ida_suppressalg; /* SUNTRUE if suppressing algebraic vars. - in local error tests */ + in local error tests */ int ida_kused; /* method order used on last successful step */ realtype ida_h0u; /* actual initial stepsize */ realtype ida_hused; /* step size used on last successful step */ @@ -500,7 +499,7 @@ typedef struct IDAMemRec { } *IDAMem; -/* +/* * ================================================================= * A D J O I N T M O D U L E M E M O R Y B L O C K * ================================================================= @@ -508,7 +507,7 @@ typedef struct IDAMemRec { /* * ----------------------------------------------------------------- - * Forward references for pointers to various structures + * Forward references for pointers to various structures * ----------------------------------------------------------------- */ @@ -525,7 +524,7 @@ typedef struct IDABMemRec *IDABMem; * field of the structures in the dt array * IDAAMFreeFn: Type for a function that deallocates the content * field of the structures in the dt array - * IDAAGetYFn: Function type for a function that returns the + * IDAAGetYFn: Function type for a function that returns the * interpolated forward solution. * IDAAStorePnt: Function type for a function that stores a new * point in the structure d @@ -534,8 +533,8 @@ typedef struct IDABMemRec *IDABMem; typedef booleantype (*IDAAMMallocFn)(IDAMem IDA_mem); typedef void (*IDAAMFreeFn)(IDAMem IDA_mem); -typedef int (*IDAAGetYFn)(IDAMem IDA_mem, realtype t, - N_Vector yy, N_Vector yp, +typedef int (*IDAAGetYFn)(IDAMem IDA_mem, realtype t, + N_Vector yy, N_Vector yp, N_Vector *yyS, N_Vector *ypS); typedef int (*IDAAStorePntFn)(IDAMem IDA_mem, DtpntMem d); @@ -554,7 +553,7 @@ struct CkpntMemRec { /* Integration limits */ realtype ck_t0; realtype ck_t1; - + /* Modified divided difference array */ N_Vector ck_phi[MXORDP1]; @@ -563,7 +562,7 @@ struct CkpntMemRec { /* Modified divided difference array for quadratures */ N_Vector ck_phiQ[MXORDP1]; - + /* Do we need to carry sensitivities? */ booleantype ck_sensi; @@ -582,13 +581,13 @@ struct CkpntMemRec { /* Step data */ long int ck_nst; - realtype ck_tretlast; - long int ck_ns; + realtype ck_tretlast; + int ck_ns; int ck_kk; int ck_kused; int ck_knew; int ck_phase; - + realtype ck_hh; realtype ck_hused; realtype ck_rr; @@ -607,9 +606,9 @@ struct CkpntMemRec { /* How many phi, phiS, phiQ and phiQS were allocated? */ int ck_phi_alloc; - + /* Pointer to next structure in list */ - struct CkpntMemRec *ck_next; + struct CkpntMemRec *ck_next; }; /* @@ -621,7 +620,7 @@ struct CkpntMemRec { * simulations. Its content field is interpType-dependent. * ----------------------------------------------------------------- */ - + struct DtpntMemRec { realtype t; /* time */ void *content; /* interpType-dependent content */ @@ -640,9 +639,9 @@ typedef struct PolynomialDataMemRec { N_Vector y; N_Vector *yS; - /* yd and ySd store the derivative(s) only for the first dt + /* yd and ySd store the derivative(s) only for the first dt point. NULL otherwise. */ - N_Vector yd; + N_Vector yd; N_Vector *ySd; int order; } *PolynomialDataMem; @@ -679,10 +678,10 @@ struct IDABMemRec { /* Right hand side quadrature function (fQB) for backward run */ IDAQuadRhsFnB ida_rhsQ; IDAQuadRhsFnBS ida_rhsQS; - + /* User user_data */ void *ida_user_data; - + /* Linear solver's data and functions */ /* Memory block for a linear solver's interface to IDAA */ @@ -691,7 +690,7 @@ struct IDABMemRec { /* Function to free any memory allocated by the linear solver */ int (*ida_lfree)(IDABMem IDAB_mem); - /* Memory block for a preconditioner's module interface to IDAA */ + /* Memory block for a preconditioner's module interface to IDAA */ void *ida_pmem; /* Function to free any memory allocated by the preconditioner module */ @@ -720,11 +719,11 @@ struct IDABMemRec { */ struct IDAadjMemRec { - + /* -------------------- * Forward problem data * -------------------- */ - + /* Integration interval */ realtype ia_tinitial, ia_tfinal; @@ -735,6 +734,11 @@ struct IDAadjMemRec { booleantype ia_tstopIDAFcall; realtype ia_tstopIDAF; + /* Flag if IDASolveF was called in IDA_NORMAL_MODE and encountered + a root after tout */ + booleantype ia_rootret; + realtype ia_troot; + /* ---------------------- * Backward problems data * ---------------------- */ @@ -746,7 +750,7 @@ struct IDAadjMemRec { int ia_nbckpbs; /* Address of current backward problem (iterator). */ - struct IDABMemRec *ia_bckpbCrt; + struct IDABMemRec *ia_bckpbCrt; /* Flag for first call to IDASolveB */ booleantype ia_firstIDABcall; @@ -754,7 +758,7 @@ struct IDAadjMemRec { /* ---------------- * Check point data * ---------------- */ - + /* Storage for check point information */ struct CkpntMemRec *ck_mem; @@ -770,13 +774,13 @@ struct IDAadjMemRec { /* Number of steps between 2 check points */ long int ia_nsteps; - + /* Last index used in IDAAfindIndex */ long int ia_ilast; /* Storage for data from forward runs */ struct DtpntMemRec **dt_mem; - + /* Actual number of data points saved in current dt_mem */ /* Commonly, np = nsteps+1 */ long int ia_np; @@ -808,101 +812,101 @@ struct IDAadjMemRec { /* Workspace for wrapper functions */ N_Vector ia_yyTmp, ia_ypTmp; N_Vector *ia_yySTmp, *ia_ypSTmp; - + }; /* * ================================================================= - * I N T E R F A C E T O L I N E A R S O L V E R S + * I N T E R F A C E T O L I N E A R S O L V E R S * ================================================================= */ /* * ----------------------------------------------------------------- - * int (*ida_linit)(IDAMem IDA_mem); + * int (*ida_linit)(IDAMem IDA_mem); * ----------------------------------------------------------------- - * The purpose of ida_linit is to allocate memory for the - * solver-specific fields in the structure *(idamem->ida_lmem) and - * perform any needed initializations of solver-specific memory, - * such as counters/statistics. An (*ida_linit) should return - * 0 if it has successfully initialized the IDA linear solver and - * a non-zero value otherwise. If an error does occur, an + * The purpose of ida_linit is to allocate memory for the + * solver-specific fields in the structure *(idamem->ida_lmem) and + * perform any needed initializations of solver-specific memory, + * such as counters/statistics. An (*ida_linit) should return + * 0 if it has successfully initialized the IDA linear solver and + * a non-zero value otherwise. If an error does occur, an * appropriate message should be issued. * ---------------------------------------------------------------- - */ + */ /* * ----------------------------------------------------------------- - * int (*ida_lsetup)(IDAMem IDA_mem, N_Vector yyp, N_Vector ypp, - * N_Vector resp, N_Vector tempv1, - * N_Vector tempv2, N_Vector tempv3); + * int (*ida_lsetup)(IDAMem IDA_mem, N_Vector yyp, N_Vector ypp, + * N_Vector resp, N_Vector tempv1, + * N_Vector tempv2, N_Vector tempv3); * ----------------------------------------------------------------- - * The job of ida_lsetup is to prepare the linear solver for - * subsequent calls to ida_lsolve. Its parameters are as follows: - * - * idamem - problem memory pointer of type IDAMem. See the big - * typedef earlier in this file. - * - * yyp - the predicted y vector for the current IDA internal - * step. - * - * ypp - the predicted y' vector for the current IDA internal - * step. - * - * resp - F(tn, yyp, ypp). - * - * tempv1, tempv2, tempv3 - temporary N_Vectors provided for use - * by ida_lsetup. - * + * The job of ida_lsetup is to prepare the linear solver for + * subsequent calls to ida_lsolve. Its parameters are as follows: + * + * idamem - problem memory pointer of type IDAMem. See the big + * typedef earlier in this file. + * + * yyp - the predicted y vector for the current IDA internal + * step. + * + * ypp - the predicted y' vector for the current IDA internal + * step. + * + * resp - F(tn, yyp, ypp). + * + * tempv1, tempv2, tempv3 - temporary N_Vectors provided for use + * by ida_lsetup. + * * The ida_lsetup routine should return 0 if successful, - * a positive value for a recoverable error, and a negative value + * a positive value for a recoverable error, and a negative value * for an unrecoverable error. * ----------------------------------------------------------------- - */ + */ /* * ----------------------------------------------------------------- - * int (*ida_lsolve)(IDAMem IDA_mem, N_Vector b, N_Vector weight, - * N_Vector ycur, N_Vector ypcur, N_Vector rescur); + * int (*ida_lsolve)(IDAMem IDA_mem, N_Vector b, N_Vector weight, + * N_Vector ycur, N_Vector ypcur, N_Vector rescur); * ----------------------------------------------------------------- - * ida_lsolve must solve the linear equation P x = b, where - * P is some approximation to the system Jacobian - * J = (dF/dy) + cj (dF/dy') - * evaluated at (tn,ycur,ypcur) and the RHS vector b is input. - * The N-vector ycur contains the solver's current approximation - * to y(tn), ypcur contains that for y'(tn), and the vector rescur - * contains the N-vector residual F(tn,ycur,ypcur). - * The solution is to be returned in the vector b. - * + * ida_lsolve must solve the linear equation P x = b, where + * P is some approximation to the system Jacobian + * J = (dF/dy) + cj (dF/dy') + * evaluated at (tn,ycur,ypcur) and the RHS vector b is input. + * The N-vector ycur contains the solver's current approximation + * to y(tn), ypcur contains that for y'(tn), and the vector rescur + * contains the N-vector residual F(tn,ycur,ypcur). + * The solution is to be returned in the vector b. + * * The ida_lsolve routine should return 0 if successful, - * a positive value for a recoverable error, and a negative value + * a positive value for a recoverable error, and a negative value * for an unrecoverable error. * ----------------------------------------------------------------- - */ + */ /* * ----------------------------------------------------------------- - * int (*ida_lperf)(IDAMem IDA_mem, int perftask); + * int (*ida_lperf)(IDAMem IDA_mem, int perftask); * ----------------------------------------------------------------- - * ida_lperf is called two places in IDAS where linear solver - * performance data is required by IDAS. For perftask = 0, an - * initialization of performance variables is performed, while for - * perftask = 1, the performance is evaluated. + * ida_lperf is called two places in IDAS where linear solver + * performance data is required by IDAS. For perftask = 0, an + * initialization of performance variables is performed, while for + * perftask = 1, the performance is evaluated. * ----------------------------------------------------------------- - */ + */ /* * ----------------------------------------------------------------- - * int (*ida_lfree)(IDAMem IDA_mem); + * int (*ida_lfree)(IDAMem IDA_mem); * ----------------------------------------------------------------- - * ida_lfree should free up any memory allocated by the linear - * solver. This routine is called once a problem has been - * completed and the linear solver is no longer needed. It should + * ida_lfree should free up any memory allocated by the linear + * solver. This routine is called once a problem has been + * completed and the linear solver is no longer needed. It should * return 0 upon success, nonzero on failure. * ----------------------------------------------------------------- */ - + /* * ================================================================= * I D A S I N T E R N A L F U N C T I O N S @@ -915,14 +919,14 @@ int IDAEwtSet(N_Vector ycur, N_Vector weight, void *data); /* High level error handler */ -void IDAProcessError(IDAMem IDA_mem, - int error_code, const char *module, const char *fname, - const char *msgfmt, ...); +void IDAProcessError(IDAMem IDA_mem, + int error_code, const char *module, const char *fname, + const char *msgfmt, ...); /* Prototype of internal errHandler function */ -void IDAErrHandler(int error_code, const char *module, const char *function, - char *msg, void *data); +void IDAErrHandler(int error_code, const char *module, const char *function, + char *msg, void *data); /* Norm functions. Also used for IC, so they are global.*/ @@ -943,11 +947,11 @@ int idaNlsInitSensStg(IDAMem IDA_mem); /* Prototype for internal sensitivity residual DQ function */ -int IDASensResDQ(int Ns, realtype t, - N_Vector yy, N_Vector yp, N_Vector resval, - N_Vector *yyS, N_Vector *ypS, N_Vector *resvalS, - void *user_dataS, - N_Vector ytemp, N_Vector yptemp, N_Vector restemp); +int IDASensResDQ(int Ns, realtype t, + N_Vector yy, N_Vector yp, N_Vector resval, + N_Vector *yyS, N_Vector *ypS, N_Vector *resvalS, + void *user_dataS, + N_Vector ytemp, N_Vector yptemp, N_Vector restemp); /* * ================================================================= @@ -1015,14 +1019,14 @@ int IDASensResDQ(int Ns, realtype t, #define MSG_NO_TOLQ "No integration tolerances for quadrature variables have been specified." #define MSG_NULL_ATOLQ "atolQ = NULL illegal." #define MSG_BAD_RTOLQ "rtolQ < 0 illegal." -#define MSG_BAD_ATOLQ "atolQ has negative component(s) (illegal)." +#define MSG_BAD_ATOLQ "atolQ has negative component(s) (illegal)." #define MSG_NO_SENSI "Illegal attempt to call before calling IDASensInit." #define MSG_BAD_EWTS "Initial ewtS has component(s) equal to zero (illegal)." #define MSG_BAD_ITOLS "Illegal value for itolS. The legal values are IDA_SS, IDA_SV, and IDA_EE." #define MSG_NULL_ATOLS "atolS = NULL illegal." #define MSG_BAD_RTOLS "rtolS < 0 illegal." -#define MSG_BAD_ATOLS "atolS has negative component(s) (illegal)." +#define MSG_BAD_ATOLS "atolS has negative component(s) (illegal)." #define MSG_BAD_PBAR "pbar has zero component(s) (illegal)." #define MSG_BAD_PLIST "plist has negative component(s) (illegal)." #define MSG_BAD_NS "NS <= 0 illegal." @@ -1036,7 +1040,7 @@ int IDASensResDQ(int Ns, realtype t, #define MSG_NULL_ABSTOLQS "abstolQS = NULL illegal parameter." #define MSG_BAD_RELTOLQS "reltolQS < 0 illegal parameter." -#define MSG_BAD_ABSTOLQS "abstolQS has negative component(s) (illegal)." +#define MSG_BAD_ABSTOLQS "abstolQS has negative component(s) (illegal)." #define MSG_NO_QUADSENSI "Forward sensitivity analysis for quadrature variables was not activated." #define MSG_NULL_YQS0 "yQS0 = NULL illegal parameter." @@ -1068,7 +1072,7 @@ int IDASensResDQ(int Ns, realtype t, #define MSG_BAD_HINIT "Initial step is not towards tout." #define MSG_BAD_TSTOP "The value " MSG_TIME_TSTOP " is behind current " MSG_TIME "in the direction of integration." #define MSG_CLOSE_ROOTS "Root found at and very near " MSG_TIME "." -#define MSG_MAX_STEPS "At " MSG_TIME ", mxstep steps taken before reaching tout." +#define MSG_MAX_STEPS "At " MSG_TIME ", mxstep steps taken before reaching tout." #define MSG_EWT_NOW_FAIL "At " MSG_TIME "the user-provide EwtSet function failed." #define MSG_EWT_NOW_BAD "At " MSG_TIME "some ewt component has become <= 0.0." #define MSG_TOO_MUCH_ACC "At " MSG_TIME "too much accuracy requested." @@ -1080,18 +1084,20 @@ int IDASensResDQ(int Ns, realtype t, #define MSG_NULL_DKY "dky = NULL illegal." #define MSG_NULL_DKYP "dkyp = NULL illegal." -#define MSG_ERR_FAILS "At " MSG_TIME_H "the error test failed repeatedly or with |h| = hmin." -#define MSG_CONV_FAILS "At " MSG_TIME_H "the corrector convergence failed repeatedly or with |h| = hmin." -#define MSG_SETUP_FAILED "At " MSG_TIME "the linear solver setup failed unrecoverably." -#define MSG_SOLVE_FAILED "At " MSG_TIME "the linear solver solve failed unrecoverably." -#define MSG_REP_RES_ERR "At " MSG_TIME "repeated recoverable residual errors." -#define MSG_RES_NONRECOV "At " MSG_TIME "the residual function failed unrecoverably." -#define MSG_FAILED_CONSTR "At " MSG_TIME "unable to satisfy inequality constraints." -#define MSG_RTFUNC_FAILED "At " MSG_TIME ", the rootfinding routine failed in an unrecoverable manner." -#define MSG_NO_ROOT "Rootfinding was not initialized." -#define MSG_INACTIVE_ROOTS "At the end of the first step, there are still some root functions identically 0. This warning will not be issued again." -#define MSG_NLS_INPUT_NULL "At " MSG_TIME "the nonlinear solver was passed a NULL input." -#define MSG_NLS_SETUP_FAILED "At " MSG_TIME "the nonlinear solver setup failed unrecoverably." +#define MSG_ERR_FAILS "At " MSG_TIME_H "the error test failed repeatedly or with |h| = hmin." +#define MSG_CONV_FAILS "At " MSG_TIME_H "the corrector convergence failed repeatedly or with |h| = hmin." +#define MSG_SETUP_FAILED "At " MSG_TIME "the linear solver setup failed unrecoverably." +#define MSG_SOLVE_FAILED "At " MSG_TIME "the linear solver solve failed unrecoverably." +#define MSG_REP_RES_ERR "At " MSG_TIME "repeated recoverable residual errors." +#define MSG_RES_NONRECOV "At " MSG_TIME "the residual function failed unrecoverably." +#define MSG_FAILED_CONSTR "At " MSG_TIME "unable to satisfy inequality constraints." +#define MSG_RTFUNC_FAILED "At " MSG_TIME ", the rootfinding routine failed in an unrecoverable manner." +#define MSG_NO_ROOT "Rootfinding was not initialized." +#define MSG_INACTIVE_ROOTS "At the end of the first step, there are still some root functions identically 0. This warning will not be issued again." +#define MSG_NLS_INPUT_NULL "At " MSG_TIME ", the nonlinear solver was passed a NULL input." +#define MSG_NLS_SETUP_FAILED "At " MSG_TIME ", the nonlinear solver setup failed unrecoverably." +#define MSG_NLS_FAIL "At " MSG_TIME ", the nonlinear solver failed in an unrecoverable manner." + #define MSG_EWTQ_NOW_BAD "At " MSG_TIME ", a component of ewtQ has become <= 0." #define MSG_QRHSFUNC_FAILED "At " MSG_TIME ", the quadrature right-hand side routine failed in an unrecoverable manner." @@ -1101,15 +1107,16 @@ int IDASensResDQ(int Ns, realtype t, #define MSG_NULL_P "p = NULL when using internal DQ for sensitivity residual is illegal." #define MSG_EWTS_NOW_BAD "At " MSG_TIME ", a component of ewtS has become <= 0." -#define MSG_SRHSFUNC_FAILED "At " MSG_TIME ", the sensitivity residual routine failed in an unrecoverable manner." -#define MSG_SRHSFUNC_UNREC "At " MSG_TIME ", the sensitivity residual failed in a recoverable manner, but no recovery is possible." -#define MSG_SRHSFUNC_REPTD "At " MSG_TIME "repeated recoverable sensitivity residual function errors." +#define MSG_SRES_FAILED "At " MSG_TIME ", the sensitivity residual routine failed in an unrecoverable manner." +#define MSG_SRES_UNREC "At " MSG_TIME ", the sensitivity residual failed in a recoverable manner, but no recovery is possible." +#define MSG_SRES_REPTD "At " MSG_TIME "repeated recoverable sensitivity residual function errors." #define MSG_NO_TOLQS "No integration tolerances for quadrature sensitivity variables have been specified." #define MSG_NULL_RHSQ "IDAS is expected to use DQ to evaluate the RHS of quad. sensi., but quadratures were not initialized." #define MSG_BAD_EWTQS "Initial ewtQS has component(s) equal to zero (illegal)." #define MSG_EWTQS_NOW_BAD "At " MSG_TIME ", a component of ewtQS has become <= 0." #define MSG_QSRHSFUNC_FAILED "At " MSG_TIME ", the sensitivity quadrature right-hand side routine failed in an unrecoverable manner." +#define MSG_QSRHSFUNC_REPTD "At " MSG_TIME "repeated recoverable sensitivity quadrature right-hand side function errors." #define MSG_QSRHSFUNC_FIRST "The quadrature right-hand side routine failed at the first call." /* IDASet* / IDAGet* error messages */ @@ -1143,7 +1150,7 @@ int IDASensResDQ(int Ns, realtype t, #define MSGAM_BAD_SENSI "At least one backward problem requires sensitivities, but they were not stored for interpolation." #define MSGAM_BAD_ITASKB "Illegal value for itaskB. Legal values are IDA_NORMAL and IDA_ONE_STEP." #define MSGAM_BAD_TBOUT "The final time tBout is outside the interval over which the forward problem was solved." -#define MSGAM_BACK_ERROR "Error occured while integrating backward problem # %d" +#define MSGAM_BACK_ERROR "Error occured while integrating backward problem # %d" #define MSGAM_BAD_TINTERP "Bad t = %g for interpolation." #define MSGAM_BAD_T "Bad t for interpolation." #define MSGAM_WRONG_INTERP "This function cannot be called for the specified interp type." diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas_io.c b/deps/AMICI/ThirdParty/sundials/src/idas/idas_io.c index 7423676d5..b6c76d3e8 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas_io.c +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas_io.c @@ -2,11 +2,11 @@ * ----------------------------------------------------------------- * $Revision$ * $Date$ - * ----------------------------------------------------------------- + * ----------------------------------------------------------------- * Programmer(s): Radu Serban and Cosmin Petra @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -15,8 +15,8 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the optional inputs and - * outputs for the IDAS solver. + * This is the implementation file for the optional inputs and + * outputs for the IDAS solver. * ----------------------------------------------------------------- */ @@ -32,7 +32,7 @@ #define ONE RCONST(1.0) #define TWOPT5 RCONST(2.5) -/* +/* * ================================================================= * IDA optional input functions * ================================================================= @@ -59,7 +59,7 @@ int IDASetErrHandlerFn(void *ida_mem, IDAErrHandlerFn ehfun, void *eh_data) int IDASetErrFile(void *ida_mem, FILE *errfp) { IDAMem IDA_mem; - + if (ida_mem==NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetErrFile", MSG_NO_MEM); return(IDA_MEM_NULL); @@ -116,7 +116,7 @@ int IDASetMaxOrd(void *ida_mem, int maxord) if (maxord > maxord_alloc) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetMaxOrd", MSG_BAD_MAXORD); return(IDA_ILL_INPUT); - } + } IDA_mem->ida_maxord = SUNMIN(maxord,MAXORD_DEFAULT); @@ -363,7 +363,7 @@ int IDASetId(void *ida_mem, N_Vector id) IDA_mem->ida_lrw -= IDA_mem->ida_lrw1; IDA_mem->ida_liw -= IDA_mem->ida_liw1; } - IDA_mem->ida_idMallocDone = SUNFALSE; + IDA_mem->ida_idMallocDone = SUNFALSE; return(IDA_SUCCESS); } @@ -420,9 +420,9 @@ int IDASetConstraints(void *ida_mem, N_Vector constraints) /* Check the constraints vector */ temptest = N_VMaxNorm(constraints); - if((temptest > TWOPT5) || (temptest < HALF)){ + if((temptest > TWOPT5) || (temptest < HALF)){ IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetConstraints", MSG_BAD_CONSTR); - return(IDA_ILL_INPUT); + return(IDA_ILL_INPUT); } if ( !(IDA_mem->ida_constraintsMallocDone) ) { @@ -441,7 +441,7 @@ int IDASetConstraints(void *ida_mem, N_Vector constraints) return(IDA_SUCCESS); } -/* +/* * IDASetRootDirection * * Specifies the direction of zero-crossings to be monitored. @@ -463,7 +463,7 @@ int IDASetRootDirection(void *ida_mem, int *rootdir) nrt = IDA_mem->ida_nrtfn; if (nrt==0) { IDAProcessError(NULL, IDA_ILL_INPUT, "IDAS", "IDASetRootDirection", MSG_NO_ROOT); - return(IDA_ILL_INPUT); + return(IDA_ILL_INPUT); } for(i=0; iida_rootdir[i] = rootdir[i]; @@ -490,12 +490,12 @@ int IDASetNoInactiveRootWarn(void *ida_mem) IDA_mem = (IDAMem) ida_mem; IDA_mem->ida_mxgnull = 0; - + return(IDA_SUCCESS); } -/* +/* * ================================================================= * IDA IC optional input functions * ================================================================= @@ -561,7 +561,7 @@ int IDASetMaxNumJacsIC(void *ida_mem, int maxnj) if (maxnj <= 0) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetMaxNumJacsIC", MSG_BAD_MAXNJ); return(IDA_ILL_INPUT); - } + } IDA_mem->ida_maxnj = maxnj; @@ -655,7 +655,7 @@ int IDASetStepToleranceIC(void *ida_mem, realtype steptol) return(IDA_SUCCESS); } -/* +/* * ================================================================= * Quadrature optional input functions * ================================================================= @@ -668,13 +668,13 @@ int IDASetQuadErrCon(void *ida_mem, booleantype errconQ) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetQuadErrCon", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetQuadErrCon", MSG_NO_MEM); return(IDA_MEM_NULL); - } + } IDA_mem = (IDAMem) ida_mem; if (IDA_mem->ida_quadMallocDone == SUNFALSE) { - IDAProcessError(NULL, IDA_NO_QUAD, "IDAS", "IDASetQuadErrCon", MSG_NO_QUAD); + IDAProcessError(NULL, IDA_NO_QUAD, "IDAS", "IDASetQuadErrCon", MSG_NO_QUAD); return(IDA_NO_QUAD); } @@ -683,7 +683,7 @@ int IDASetQuadErrCon(void *ida_mem, booleantype errconQ) return (IDA_SUCCESS); } -/* +/* * ================================================================= * FSA optional input functions * ================================================================= @@ -694,19 +694,19 @@ int IDASetSensDQMethod(void *ida_mem, int DQtype, realtype DQrhomax) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetSensDQMethod", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetSensDQMethod", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; if ( (DQtype != IDA_CENTERED) && (DQtype != IDA_FORWARD) ) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetSensDQMethod", MSG_BAD_DQTYPE); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetSensDQMethod", MSG_BAD_DQTYPE); return(IDA_ILL_INPUT); } if (DQrhomax < ZERO ) { - IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetSensDQMethod", MSG_BAD_DQRHO); + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetSensDQMethod", MSG_BAD_DQRHO); return(IDA_ILL_INPUT); } @@ -723,7 +723,7 @@ int IDASetSensErrCon(void *ida_mem, booleantype errconS) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetSensErrCon", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetSensErrCon", MSG_NO_MEM); return(IDA_MEM_NULL); } @@ -765,7 +765,7 @@ int IDASetSensParams(void *ida_mem, realtype *p, realtype *pbar, int *plist) int Ns, is; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetSensParams", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetSensParams", MSG_NO_MEM); return(IDA_MEM_NULL); } @@ -817,7 +817,7 @@ int IDASetSensParams(void *ida_mem, realtype *p, realtype *pbar, int *plist) /* * ----------------------------------------------------------------- - * Function: IDASetQuadSensErrCon + * Function: IDASetQuadSensErrCon * ----------------------------------------------------------------- * IDASetQuadSensErrCon specifies if quadrature sensitivity variables * are considered or not in the error control. @@ -828,7 +828,7 @@ int IDASetQuadSensErrCon(void *ida_mem, booleantype errconQS) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetQuadSensErrCon", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetQuadSensErrCon", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; @@ -850,7 +850,7 @@ int IDASetQuadSensErrCon(void *ida_mem, booleantype errconQS) return(IDA_SUCCESS); } -/* +/* * ================================================================= * IDA optional output functions * ================================================================= @@ -949,13 +949,13 @@ int IDAGetNumBacktrackOps(void *ida_mem, long int *nbacktracks) int IDAGetConsistentIC(void *ida_mem, N_Vector yy0, N_Vector yp0) { IDAMem IDA_mem; - + if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetConsistentIC", MSG_NO_MEM); return (IDA_MEM_NULL); } - IDA_mem = (IDAMem) ida_mem; + IDA_mem = (IDAMem) ida_mem; if (IDA_mem->ida_kused != 0) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAGetConsistentIC", MSG_TOO_LATE); @@ -1006,6 +1006,96 @@ int IDAGetCurrentOrder(void *ida_mem, int *kcur) /*-----------------------------------------------------------------*/ +int IDAGetCurrentCj(void *ida_mem, realtype *cj) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetCurrentCjRatio", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *cj = IDA_mem->ida_cj; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetCurrentY(void *ida_mem, N_Vector *ycur) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetCurrentY", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *ycur = IDA_mem->ida_yy; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetCurrentYSens(void *ida_mem, N_Vector **yS) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetCurrentYSens", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *yS = IDA_mem->ida_yyS; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetCurrentYp(void *ida_mem, N_Vector *ypcur) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetCurrentYp", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *ypcur = IDA_mem->ida_yp; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetCurrentYpSens(void *ida_mem, N_Vector **ypS) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetCurrentYpSens", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *ypS = IDA_mem->ida_ypS; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + int IDAGetActualInitStep(void *ida_mem, realtype *hinused) { IDAMem IDA_mem; @@ -1099,13 +1189,13 @@ int IDAGetTolScaleFactor(void *ida_mem, realtype *tolsfact) int IDAGetErrWeights(void *ida_mem, N_Vector eweight) { IDAMem IDA_mem; - + if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetErrWeights", MSG_NO_MEM); return (IDA_MEM_NULL); } - IDA_mem = (IDAMem) ida_mem; + IDA_mem = (IDAMem) ida_mem; N_VScale(ONE, IDA_mem->ida_ewt, eweight); @@ -1150,9 +1240,9 @@ int IDAGetWorkSpace(void *ida_mem, long int *lenrw, long int *leniw) /*-----------------------------------------------------------------*/ -int IDAGetIntegratorStats(void *ida_mem, long int *nsteps, long int *nrevals, +int IDAGetIntegratorStats(void *ida_mem, long int *nsteps, long int *nrevals, long int *nlinsetups, long int *netfails, - int *klast, int *kcur, realtype *hinused, realtype *hlast, + int *klast, int *kcur, realtype *hinused, realtype *hlast, realtype *hcur, realtype *tcur) { IDAMem IDA_mem; @@ -1172,7 +1262,7 @@ int IDAGetIntegratorStats(void *ida_mem, long int *nsteps, long int *nrevals, *kcur = IDA_mem->ida_kk; *hinused = IDA_mem->ida_h0u; *hlast = IDA_mem->ida_hused; - *hcur = IDA_mem->ida_hh; + *hcur = IDA_mem->ida_hh; *tcur = IDA_mem->ida_tn; return(IDA_SUCCESS); @@ -1345,7 +1435,7 @@ int IDAGetNonlinSolvStats(void *ida_mem, long int *nniters, long int *nncfails) return(IDA_SUCCESS); } -/* +/* * ================================================================= * Quadrature optional output functions * ================================================================= @@ -1358,14 +1448,14 @@ int IDAGetQuadNumRhsEvals(void *ida_mem, long int *nrQevals) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadNumRhsEvals", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadNumRhsEvals", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; if (IDA_mem->ida_quadr==SUNFALSE) { - IDAProcessError(IDA_mem, IDA_NO_QUAD, "IDAS", "IDAGetQuadNumRhsEvals", MSG_NO_QUAD); + IDAProcessError(IDA_mem, IDA_NO_QUAD, "IDAS", "IDAGetQuadNumRhsEvals", MSG_NO_QUAD); return(IDA_NO_QUAD); } @@ -1381,14 +1471,14 @@ int IDAGetQuadNumErrTestFails(void *ida_mem, long int *nQetfails) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadNumErrTestFails", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadNumErrTestFails", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; if (IDA_mem->ida_quadr==SUNFALSE) { - IDAProcessError(IDA_mem, IDA_NO_QUAD, "IDAS", "IDAGetQuadNumErrTestFails", MSG_NO_QUAD); + IDAProcessError(IDA_mem, IDA_NO_QUAD, "IDAS", "IDAGetQuadNumErrTestFails", MSG_NO_QUAD); return(IDA_NO_QUAD); } @@ -1404,14 +1494,14 @@ int IDAGetQuadErrWeights(void *ida_mem, N_Vector eQweight) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadErrWeights", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadErrWeights", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; if (IDA_mem->ida_quadr==SUNFALSE) { - IDAProcessError(IDA_mem, IDA_NO_QUAD, "IDAS", "IDAGetQuadErrWeights", MSG_NO_QUAD); + IDAProcessError(IDA_mem, IDA_NO_QUAD, "IDAS", "IDAGetQuadErrWeights", MSG_NO_QUAD); return(IDA_NO_QUAD); } @@ -1428,14 +1518,14 @@ int IDAGetQuadStats(void *ida_mem, long int *nrQevals, long int *nQetfails) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadStats", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadStats", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; if (IDA_mem->ida_quadr==SUNFALSE) { - IDAProcessError(IDA_mem, IDA_NO_QUAD, "IDAS", "IDAGetQuadStats", MSG_NO_QUAD); + IDAProcessError(IDA_mem, IDA_NO_QUAD, "IDAS", "IDAGetQuadStats", MSG_NO_QUAD); return(IDA_NO_QUAD); } @@ -1446,7 +1536,7 @@ int IDAGetQuadStats(void *ida_mem, long int *nrQevals, long int *nQetfails) } -/* +/* * ================================================================= * Quadrature FSA optional output functions * ================================================================= @@ -1459,14 +1549,14 @@ int IDAGetQuadSensNumRhsEvals(void *ida_mem, long int *nrhsQSevals) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadSensNumRhsEvals", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadSensNumRhsEvals", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; if (IDA_mem->ida_quadr_sensi == SUNFALSE) { - IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAGetQuadSensNumRhsEvals", MSG_NO_QUADSENSI); + IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAGetQuadSensNumRhsEvals", MSG_NO_QUADSENSI); return(IDA_NO_QUADSENS); } @@ -1482,14 +1572,14 @@ int IDAGetQuadSensNumErrTestFails(void *ida_mem, long int *nQSetfails) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadSensNumErrTestFails", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadSensNumErrTestFails", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; if (IDA_mem->ida_quadr_sensi == SUNFALSE) { - IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAGetQuadSensNumErrTestFails", MSG_NO_QUADSENSI); + IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAGetQuadSensNumErrTestFails", MSG_NO_QUADSENSI); return(IDA_NO_QUADSENS); } @@ -1506,14 +1596,14 @@ int IDAGetQuadSensErrWeights(void *ida_mem, N_Vector *eQSweight) int is, Ns; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadSensErrWeights", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadSensErrWeights", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; if (IDA_mem->ida_quadr_sensi == SUNFALSE) { - IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAGetQuadSensErrWeights", MSG_NO_QUADSENSI); + IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAGetQuadSensErrWeights", MSG_NO_QUADSENSI); return(IDA_NO_QUADSENS); } Ns = IDA_mem->ida_Ns; @@ -1532,14 +1622,14 @@ int IDAGetQuadSensStats(void *ida_mem, long int *nrhsQSevals, long int *nQSetfai IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadSensStats", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadSensStats", MSG_NO_MEM); return(IDA_MEM_NULL); } IDA_mem = (IDAMem) ida_mem; if (IDA_mem->ida_quadr_sensi == SUNFALSE) { - IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAGetQuadSensStats", MSG_NO_QUADSENSI); + IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAGetQuadSensStats", MSG_NO_QUADSENSI); return(IDA_NO_QUADSENS); } @@ -1551,7 +1641,7 @@ int IDAGetQuadSensStats(void *ida_mem, long int *nrhsQSevals, long int *nQSetfai -/* +/* * ================================================================= * FSA optional output functions * ================================================================= @@ -1563,13 +1653,13 @@ int IDAGetSensConsistentIC(void *ida_mem, N_Vector *yyS0, N_Vector *ypS0) { IDAMem IDA_mem; int is; - + if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSensConsistentIC", MSG_NO_MEM); return (IDA_MEM_NULL); } - IDA_mem = (IDAMem) ida_mem; + IDA_mem = (IDAMem) ida_mem; if (IDA_mem->ida_sensi==SUNFALSE) { IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetSensConsistentIC", MSG_NO_SENSI); @@ -1601,7 +1691,7 @@ int IDAGetSensNumResEvals(void *ida_mem, long int *nrSevals) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGeSensNumResEvals", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGeSensNumResEvals", MSG_NO_MEM); return(IDA_MEM_NULL); } @@ -1624,7 +1714,7 @@ int IDAGetNumResEvalsSens(void *ida_mem, long int *nrevalsS) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetNumResEvalsSens", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetNumResEvalsSens", MSG_NO_MEM); return(IDA_MEM_NULL); } @@ -1647,7 +1737,7 @@ int IDAGetSensNumErrTestFails(void *ida_mem, long int *nSetfails) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSensNumErrTestFails", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSensNumErrTestFails", MSG_NO_MEM); return(IDA_MEM_NULL); } @@ -1670,7 +1760,7 @@ int IDAGetSensNumLinSolvSetups(void *ida_mem, long int *nlinsetupsS) IDAMem IDA_mem; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSensNumLinSolvSetups", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSensNumLinSolvSetups", MSG_NO_MEM); return(IDA_MEM_NULL); } @@ -1694,7 +1784,7 @@ int IDAGetSensErrWeights(void *ida_mem, N_Vector_S eSweight) int is; if (ida_mem==NULL) { - IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSensErrWeights", MSG_NO_MEM); + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSensErrWeights", MSG_NO_MEM); return(IDA_MEM_NULL); } @@ -1713,7 +1803,7 @@ int IDAGetSensErrWeights(void *ida_mem, N_Vector_S eSweight) /*-----------------------------------------------------------------*/ -int IDAGetSensStats(void *ida_mem, long int *nrSevals, long int *nrevalsS, +int IDAGetSensStats(void *ida_mem, long int *nrSevals, long int *nrevalsS, long int *nSetfails, long int *nlinsetupsS) { IDAMem IDA_mem; @@ -1951,9 +2041,18 @@ char *IDAGetReturnFlagName(long int flag) case IDA_NO_QUADSENS: sprintf(name, "IDA_NO_QUADSENS"); break; + case IDA_QRHS_FAIL: + sprintf(name,"IDA_QRHS_FAIL"); + break; + case IDA_REP_QRHS_ERR: + sprintf(name,"IDA_REP_QRHS_ERR"); + break; case IDA_QSRHS_FAIL: sprintf(name, "IDA_QSRHS_FAIL"); break; + case IDA_REP_QSRHS_ERR: + sprintf(name,"IDA_REP_QSRHS_ERR"); + break; /* IDAA flags follow below. */ case IDA_NO_ADJ: @@ -1977,10 +2076,15 @@ char *IDAGetReturnFlagName(long int flag) case IDA_NO_FWD: sprintf(name,"IDA_NO_FWD"); break; + case IDA_NLS_SETUP_FAIL: + sprintf(name,"IDA_NLS_SETUP_FAIL"); + break; + case IDA_NLS_FAIL: + sprintf(name,"IDA_NLS_FAIL"); + break; default: sprintf(name,"NONE"); } return(name); } - diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas_ls.c b/deps/AMICI/ThirdParty/sundials/src/idas/idas_ls.c index e75726689..16e5d1772 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas_ls.c +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas_ls.c @@ -3,7 +3,7 @@ * Alan C. Hindmarsh and Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -22,6 +22,7 @@ #include "idas_impl.h" #include "idas_ls_impl.h" #include +#include #include #include #include @@ -92,15 +93,15 @@ static int idaLsJacTimesVecBS(realtype tt, N_Vector yyB, /*--------------------------------------------------------------- - IDASLS Exported functions -- Required + IDASetLinearSolver specifies the linear solver ---------------------------------------------------------------*/ - -/* IDASetLinearSolver specifies the linear solver */ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) { - IDAMem IDA_mem; - IDALsMem idals_mem; - int retval, LSType; + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval, LSType; + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ /* Return immediately if any input is NULL */ if (ida_mem == NULL) { @@ -117,51 +118,61 @@ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) IDA_mem = (IDAMem) ida_mem; /* Test if solver is compatible with LS interface */ - if ( (LS->ops->gettype == NULL) || - (LS->ops->initialize == NULL) || - (LS->ops->setup == NULL) || - (LS->ops->solve == NULL) ) { + if ( (LS->ops->gettype == NULL) || (LS->ops->solve == NULL) ) { IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", "IDASetLinearSolver", "LS object is missing a required operation"); return(IDALS_ILL_INPUT); } - /* Test if vector is compatible with LS */ - if ( (IDA_mem->ida_tempv1->ops->nvdotprod == NULL) || - (IDA_mem->ida_tempv1->ops->nvconst == NULL) ) { + /* Retrieve the LS type */ + LSType = SUNLinSolGetType(LS); + + /* Set flags based on LS type */ + iterative = (LSType != SUNLINEARSOLVER_DIRECT); + matrixbased = (LSType != SUNLINEARSOLVER_ITERATIVE); + + /* Test if vector is compatible with LS interface */ + if (IDA_mem->ida_tempv1->ops->nvconst == NULL || + IDA_mem->ida_tempv1->ops->nvwrmsnorm == NULL) { IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", "IDASetLinearSolver", MSG_LS_BAD_NVECTOR); return(IDALS_ILL_INPUT); } - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(LS); + /* Check for compatible LS type, matrix and "atimes" support */ + if (iterative) { + if (IDA_mem->ida_tempv1->ops->nvgetlength == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", + "IDASetLinearSolver", MSG_LS_BAD_NVECTOR); + return(IDALS_ILL_INPUT); + } - /* Check for compatible LS type, matrix and "atimes" support */ - if ( ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) && - ( (LS->ops->resid == NULL) || - (LS->ops->numiters == NULL) ) ) { - IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", - "Iterative LS object requires 'resid' and 'numiters' routines"); - return(IDALS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_ITERATIVE) && (LS->ops->setatimes == NULL)) { - IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", - "Incompatible inputs: iterative LS must support ATimes routine"); - return(IDALS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_DIRECT) && (A == NULL)) { - IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", + if (LS->ops->resid == NULL || LS->ops->numiters == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", "IDASetLinearSolver", + "Iterative LS object requires 'resid' and 'numiters' routines"); + return(IDALS_ILL_INPUT); + } + + if (!matrixbased && LS->ops->setatimes == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", "IDASetLinearSolver", + "Incompatible inputs: iterative LS must support ATimes routine"); + return(IDALS_ILL_INPUT); + } + + if (matrixbased && A == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", "IDASetLinearSolver", + "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); + return(IDALS_ILL_INPUT); + } + + } else if (A == NULL) { + + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", "IDASetLinearSolver", "Incompatible inputs: direct LS requires non-NULL matrix"); return(IDALS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) && (A == NULL)) { - IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetLinearSolver", - "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); - return(IDALS_ILL_INPUT); + } /* free any existing system solver attached to IDA */ @@ -174,9 +185,7 @@ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) IDA_mem->ida_lfree = idaLsFree; /* Set ida_lperf if using an iterative SUNLinearSolver object */ - IDA_mem->ida_lperf = ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) ? - idaLsPerf : NULL; + IDA_mem->ida_lperf = (iterative) ? idaLsPerf : NULL; /* Allocate memory for IDALsMemRec */ idals_mem = NULL; @@ -191,6 +200,10 @@ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) /* set SUNLinearSolver pointer */ idals_mem->LS = LS; + /* Linear solver type information */ + idals_mem->iterative = iterative; + idals_mem->matrixbased = matrixbased; + /* Set defaults for Jacobian-related fields */ idals_mem->J = A; if (A != NULL) { @@ -221,7 +234,7 @@ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) idals_mem->dqincfac = ONE; idals_mem->last_flag = IDALS_SUCCESS; - /* Attach default IDALs interface routines to LS object */ + /* If LS supports ATimes, attach IDALs routine */ if (LS->ops->setatimes) { retval = SUNLinSolSetATimes(LS, IDA_mem, idaLsATimes); if (retval != SUNLS_SUCCESS) { @@ -232,6 +245,8 @@ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) return(IDALS_SUNLS_FAIL); } } + + /* If LS supports preconditioning, initialize pset/psol to NULL */ if (LS->ops->setpreconditioner) { retval = SUNLinSolSetPreconditioner(LS, IDA_mem, NULL, NULL); if (retval != SUNLS_SUCCESS) { @@ -271,10 +286,15 @@ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) return(IDALS_MEM_FAIL); } - /* Compute sqrtN from a dot product */ - N_VConst(ONE, idals_mem->ytemp); - idals_mem->sqrtN = SUNRsqrt( N_VDotProd(idals_mem->ytemp, - idals_mem->ytemp) ); + /* For iterative LS, compute sqrtN */ + if (iterative) + idals_mem->sqrtN = SUNRsqrt( N_VGetLength(idals_mem->ytemp) ); + + /* For matrix-based LS, enable soltuion scaling */ + if (matrixbased) + idals_mem->scalesol = SUNTRUE; + else + idals_mem->scalesol = SUNFALSE; /* Attach linear solver memory to integrator memory */ IDA_mem->ida_lmem = idals_mem; @@ -283,9 +303,10 @@ int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) } -/*--------------------------------------------------------------- - IDASLS Exported functions -- Optional input/output - ---------------------------------------------------------------*/ +/*=============================================================== + Optional input/output routines + ===============================================================*/ + /* IDASetJacFn specifies the Jacobian function */ int IDASetJacFn(void *ida_mem, IDALsJacFn jac) @@ -346,6 +367,29 @@ int IDASetEpsLin(void *ida_mem, realtype eplifac) } +/* IDASetLinearSolutionScaling enables or disables scaling the linear solver + solution to account for changes in cj. */ +int IDASetLinearSolutionScaling(void *ida_mem, booleantype onoff) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDASetLinearSolutionScaling", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* check for valid solver type */ + if (!(idals_mem->matrixbased)) return(IDALS_ILL_INPUT); + + /* set solution scaling flag */ + idals_mem->scalesol = onoff; + + return(IDALS_SUCCESS); +} + + /* IDASetIncrementFactor specifies increment factor for DQ approximations to Jv */ int IDASetIncrementFactor(void *ida_mem, realtype dqincfac) { @@ -688,9 +732,10 @@ char *IDAGetLinReturnFlagName(long int flag) return(name); } -/*----------------------------------------------------------------- + +/*=============================================================== IDASLS Private functions - -----------------------------------------------------------------*/ + ===============================================================*/ /*--------------------------------------------------------------- idaLsATimes: @@ -819,7 +864,6 @@ int idaLsDQJac(realtype t, realtype c_j, N_Vector y, N_Vector yp, /* Verify that N_Vector supports required operations */ if (IDA_mem->ida_tempv1->ops->nvcloneempty == NULL || - IDA_mem->ida_tempv1->ops->nvwrmsnorm == NULL || IDA_mem->ida_tempv1->ops->nvlinearsum == NULL || IDA_mem->ida_tempv1->ops->nvdestroy == NULL || IDA_mem->ida_tempv1->ops->nvscale == NULL || @@ -885,7 +929,7 @@ int idaLsDenseDQJac(realtype tt, realtype c_j, N_Vector yy, ewt_data = N_VGetArrayPointer(IDA_mem->ida_ewt); y_data = N_VGetArrayPointer(yy); yp_data = N_VGetArrayPointer(yp); - if(IDA_mem->ida_constraints!=NULL) + if(IDA_mem->ida_constraintsSet) cns_data = N_VGetArrayPointer(IDA_mem->ida_constraints); srur = SUNRsqrt(IDA_mem->ida_uround); @@ -910,7 +954,7 @@ int idaLsDenseDQJac(realtype tt, realtype c_j, N_Vector yy, inc = (yj + inc) - yj; /* Adjust sign(inc) again if y_j has an inequality constraint. */ - if (IDA_mem->ida_constraints != NULL) { + if (IDA_mem->ida_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if((yj+inc)*conj <= ZERO) inc = -inc;} @@ -989,7 +1033,7 @@ int idaLsBandDQJac(realtype tt, realtype c_j, N_Vector yy, rtemp_data = N_VGetArrayPointer(rtemp); ytemp_data = N_VGetArrayPointer(ytemp); yptemp_data = N_VGetArrayPointer(yptemp); - if (IDA_mem->ida_constraints != NULL) + if (IDA_mem->ida_constraintsSet) cns_data = N_VGetArrayPointer(IDA_mem->ida_constraints); /* Initialize ytemp and yptemp. */ @@ -1019,7 +1063,7 @@ int idaLsBandDQJac(realtype tt, realtype c_j, N_Vector yy, inc = (yj + inc) - yj; /* Adjust sign(inc) again if yj has an inequality constraint. */ - if (IDA_mem->ida_constraints != NULL) { + if (IDA_mem->ida_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if((yj+inc)*conj <= ZERO) inc = -inc;} @@ -1049,7 +1093,7 @@ int idaLsBandDQJac(realtype tt, realtype c_j, N_Vector yy, ONE/ewtj ); if (IDA_mem->ida_hh*ypj < ZERO) inc = -inc; inc = (yj + inc) - yj; - if (IDA_mem->ida_constraints != NULL) { + if (IDA_mem->ida_constraintsSet) { conj = cns_data[j]; if (SUNRabs(conj) == ONE) {if((yj+inc)*conj < ZERO) inc = -inc;} else if (SUNRabs(conj) == TWO) {if((yj+inc)*conj <= ZERO) inc = -inc;} @@ -1090,14 +1134,18 @@ int idaLsDQJtimes(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr, N_Vector y_tmp, yp_tmp; realtype sig, siginv; int iter, retval; + SUNLinearSolver_ID LSID; /* access IDALsMem structure */ retval = idaLs_AccessLMem(ida_mem, "idaLsDQJtimes", &IDA_mem, &idals_mem); if (retval != IDALS_SUCCESS) return(retval); - sig = idals_mem->sqrtN * idals_mem->dqincfac; /* GMRES */ - /*sig = idals_mem->dqincfac / N_VWrmsNorm(v, IDA_mem->ida_ewt);*/ /* BiCGStab/TFQMR */ + LSID = SUNLinSolGetID(idals_mem->LS); + if (LSID == SUNLINEARSOLVER_SPGMR || LSID == SUNLINEARSOLVER_SPFGMR) + sig = idals_mem->sqrtN * idals_mem->dqincfac; + else + sig = idals_mem->dqincfac / N_VWrmsNorm(v, IDA_mem->ida_ewt); /* Rename work1 and work2 for readibility */ y_tmp = work1; @@ -1244,13 +1292,15 @@ int idaLsSetup(IDAMem IDA_mem, N_Vector y, N_Vector yp, N_Vector r, /* Increment nje counter. */ idals_mem->nje++; - /* Zero out J; call Jacobian routine jac; return if it failed. */ - retval = SUNMatZero(idals_mem->J); - if (retval != 0) { - IDAProcessError(IDA_mem, IDALS_SUNMAT_FAIL, "IDASLS", - "idaLsSetup", MSG_LS_MATZERO_FAILED); - idals_mem->last_flag = IDALS_SUNMAT_FAIL; - return(idals_mem->last_flag); + /* Clear the linear system matrix if necessary */ + if (SUNLinSolGetType(idals_mem->LS) == SUNLINEARSOLVER_DIRECT) { + retval = SUNMatZero(idals_mem->J); + if (retval != 0) { + IDAProcessError(IDA_mem, IDALS_SUNMAT_FAIL, "IDASLS", + "idaLsSetup", MSG_LS_MATZERO_FAILED); + idals_mem->last_flag = IDALS_SUNMAT_FAIL; + return(idals_mem->last_flag); + } } /* Call Jacobian routine */ @@ -1290,7 +1340,7 @@ int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, N_Vector ycur, N_Vector ypcur, N_Vector rescur) { IDALsMem idals_mem; - int nli_inc, retval, LSType; + int nli_inc, retval; realtype tol, w_mean; /* access IDALsMem structure */ @@ -1301,16 +1351,12 @@ int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, } idals_mem = (IDALsMem) IDA_mem->ida_lmem; - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(idals_mem->LS); - /* If the linear solver is iterative: set convergence test constant tol, in terms of the Newton convergence test constant epsNewt and safety factors. The factor sqrt(Neq) assures that the convergence test is applied to the WRMS norm of the residual vector, rather than the weighted L2 norm. */ - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (idals_mem->iterative) { tol = idals_mem->sqrtN * idals_mem->eplifac * IDA_mem->ida_epsNewt; } else { tol = ZERO; @@ -1322,9 +1368,6 @@ int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, idals_mem->ypcur = ypcur; idals_mem->rcur = rescur; - /* Set initial guess x = 0 to LS */ - N_VConst(ZERO, idals_mem->x); - /* Set scaling vectors for LS to use (if applicable) */ if (idals_mem->LS->ops->setscalingvectors) { retval = SUNLinSolSetScalingVectors(idals_mem->LS, weight, weight); @@ -1348,16 +1391,18 @@ int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, <=> w_mean^2 \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 <=> \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 / w_mean^2 <=> || b - A x ||_2 < tol / w_mean - So we compute w_mean = ||w||_RMS = ||w||_2 / sqrt(n), and scale - the desired tolerance accordingly. */ - } else if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + So we compute w_mean = ||w||_RMS and scale the desired tolerance accordingly. */ + } else if (idals_mem->iterative) { - w_mean = SUNRsqrt( N_VDotProd(weight, weight) ) / idals_mem->sqrtN; + N_VConst(ONE, idals_mem->x); + w_mean = N_VWrmsNorm(weight, idals_mem->x); tol /= w_mean; } + /* Set initial guess x = 0 to LS */ + N_VConst(ZERO, idals_mem->x); + /* If a user-provided jtsetup routine is supplied, call that here */ if (idals_mem->jtsetup) { idals_mem->last_flag = idals_mem->jtsetup(IDA_mem->ida_tn, ycur, ypcur, rescur, @@ -1375,8 +1420,7 @@ int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, idals_mem->x, b, tol); /* Copy appropriate result to b (depending on solver type) */ - if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (idals_mem->iterative) { /* Retrieve solver statistics */ nli_inc = SUNLinSolNumIters(idals_mem->LS); @@ -1397,9 +1441,7 @@ int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, /* If using a direct or matrix-iterative solver, scale the correction to account for change in cj */ - if ( ((LSType == SUNLINEARSOLVER_DIRECT) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE)) && - (IDA_mem->ida_cjratio != ONE) ) + if (idals_mem->scalesol && (IDA_mem->ida_cjratio != ONE)) N_VScale(TWO/(ONE + IDA_mem->ida_cjratio), b, b); /* Increment ncfl counter */ @@ -1485,10 +1527,8 @@ int idaLsPerf(IDAMem IDA_mem, int perftask) nnid = IDA_mem->ida_nni - idals_mem->nni0; if (nstd == 0 || nnid == 0) return(0); - rcfn = (realtype) ( (IDA_mem->ida_ncfn - idals_mem->ncfn0) / - ((realtype) nstd) ); - rcfl = (realtype) ( (idals_mem->ncfl - idals_mem->ncfl0) / - ((realtype) nnid) ); + rcfn = ((realtype) (IDA_mem->ida_ncfn - idals_mem->ncfn0)) / ((realtype) nstd); + rcfl = ((realtype) (idals_mem->ncfl - idals_mem->ncfl0)) / ((realtype) nnid); lcfn = (rcfn > PT9); lcfl = (rcfl > PT9); if (!(lcfn || lcfl)) return(0); @@ -1768,6 +1808,26 @@ int IDASetEpsLinB(void *ida_mem, int which, realtype eplifacB) } +int IDASetLinearSolutionScalingB(void *ida_mem, int which, booleantype onoffB) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + IDABMem IDAB_mem; + IDALsMemB idalsB_mem; + void *ida_memB; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemB(ida_mem, which, "IDASetLinearSolutionScalingB", + &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* call corresponding routine for IDAB_mem structure */ + ida_memB = (void *) IDAB_mem->IDA_mem; + return(IDASetLinearSolutionScaling(ida_memB, onoffB)); +} + + int IDASetIncrementFactorB(void *ida_mem, int which, realtype dqincfacB) { IDAadjMem IDAADJ_mem; @@ -1926,6 +1986,10 @@ static int idaLsJacBWrapper(realtype tt, realtype c_jB, N_Vector yyB, int retval; /* access relevant memory structures */ + IDA_mem = NULL; + IDAADJ_mem = NULL; + idalsB_mem = NULL; + IDAB_mem = NULL; retval = idaLs_AccessLMemBCur(ida_mem, "idaLsJacBWrapper", &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); @@ -1961,6 +2025,10 @@ static int idaLsJacBSWrapper(realtype tt, realtype c_jB, N_Vector yyB, int retval; /* access relevant memory structures */ + IDA_mem = NULL; + IDAADJ_mem = NULL; + idalsB_mem = NULL; + IDAB_mem = NULL; retval = idaLs_AccessLMemBCur(ida_mem, "idaLsJacBSWrapper", &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); @@ -2001,6 +2069,10 @@ static int idaLsPrecSetupB(realtype tt, N_Vector yyB, N_Vector ypB, int retval; /* access relevant memory structures */ + IDA_mem = NULL; + IDAADJ_mem = NULL; + idalsB_mem = NULL; + IDAB_mem = NULL; retval = idaLs_AccessLMemBCur(ida_mem, "idaLsPrecSetupB", &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); @@ -2034,6 +2106,10 @@ static int idaLsPrecSetupBS(realtype tt, N_Vector yyB, N_Vector ypB, int retval; /* access relevant memory structures */ + IDA_mem = NULL; + IDAADJ_mem = NULL; + idalsB_mem = NULL; + IDAB_mem = NULL; retval = idaLs_AccessLMemBCur(ida_mem, "idaLsPrecSetupBS", &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); @@ -2077,6 +2153,10 @@ static int idaLsPrecSolveB(realtype tt, N_Vector yyB, N_Vector ypB, int retval; /* access relevant memory structures */ + IDA_mem = NULL; + IDAADJ_mem = NULL; + idalsB_mem = NULL; + IDAB_mem = NULL; retval = idaLs_AccessLMemBCur(ida_mem, "idaLsPrecSolveB", &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); @@ -2113,6 +2193,10 @@ static int idaLsPrecSolveBS(realtype tt, N_Vector yyB, N_Vector ypB, int retval; /* access relevant memory structures */ + IDA_mem = NULL; + IDAADJ_mem = NULL; + idalsB_mem = NULL; + IDAB_mem = NULL; retval = idaLs_AccessLMemBCur(ida_mem, "idaLsPrecSolveBS", &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); @@ -2155,6 +2239,10 @@ static int idaLsJacTimesSetupB(realtype tt, N_Vector yyB, N_Vector ypB, int retval; /* access relevant memory structures */ + IDA_mem = NULL; + IDAADJ_mem = NULL; + idalsB_mem = NULL; + IDAB_mem = NULL; retval = idaLs_AccessLMemBCur(ida_mem, "idaLsJacTimesSetupB", &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); @@ -2187,6 +2275,10 @@ static int idaLsJacTimesSetupBS(realtype tt, N_Vector yyB, N_Vector ypB, int retval; /* access relevant memory structures */ + IDA_mem = NULL; + IDAADJ_mem = NULL; + idalsB_mem = NULL; + IDAB_mem = NULL; retval = idaLs_AccessLMemBCur(ida_mem, "idaLsJacTimesSetupBS", &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); @@ -2231,6 +2323,10 @@ static int idaLsJacTimesVecB(realtype tt, N_Vector yyB, N_Vector ypB, int retval; /* access relevant memory structures */ + IDA_mem = NULL; + IDAADJ_mem = NULL; + idalsB_mem = NULL; + IDAB_mem = NULL; retval = idaLs_AccessLMemBCur(ida_mem, "idaLsJacTimesVecB", &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); @@ -2268,6 +2364,10 @@ static int idaLsJacTimesVecBS(realtype tt, N_Vector yyB, N_Vector ypB, int retval; /* access relevant memory structures */ + IDA_mem = NULL; + IDAADJ_mem = NULL; + idalsB_mem = NULL; + IDAB_mem = NULL; retval = idaLs_AccessLMemBCur(ida_mem, "idaLsJacTimesVecBS", &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas_ls_impl.h b/deps/AMICI/ThirdParty/sundials/src/idas/idas_ls_impl.h index 3cb3dc94c..9c742493a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas_ls_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas_ls_impl.h @@ -3,7 +3,7 @@ * Alan C. Hindmarsh and Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -34,6 +34,10 @@ extern "C" { -----------------------------------------------------------------*/ typedef struct IDALsMemRec { + /* Linear solver type information */ + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ + /* Jacobian construction & storage */ booleantype jacDQ; /* SUNTRUE if using internal DQ Jacobian approx. */ IDALsJacFn jac; /* Jacobian routine to be called */ @@ -49,6 +53,9 @@ typedef struct IDALsMemRec { N_Vector ypcur; /* current yp vector in Newton iteration */ N_Vector rcur; /* rcur = F(tn, ycur, ypcur) */ + /* Matrix-based solver, scale solution to account for change in cj */ + booleantype scalesol; + /* Iterative solver tolerance */ realtype sqrtN; /* sqrt(N) */ realtype eplifac; /* eplifac = linear convergence factor */ @@ -69,7 +76,7 @@ typedef struct IDALsMemRec { long int ncfl0; /* ncfl0 = saved ncfl (for performance monitor) */ long int nwarn; /* nwarn = no. of warnings (for perf. monitor) */ - long int last_flag; /* last error return flag */ + int last_flag; /* last error return flag */ /* Preconditioner computation (a) user-provided: diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas_nls.c b/deps/AMICI/ThirdParty/sundials/src/idas/idas_nls.c index 831c859d2..0ac894575 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas_nls.c +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas_nls.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -28,9 +28,8 @@ /* private functions passed to nonlinear solver */ static int idaNlsResidual(N_Vector ycor, N_Vector res, void* ida_mem); -static int idaNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, - booleantype* jcur, void* ida_mem); -static int idaNlsLSolve(N_Vector ycor, N_Vector delta, void* ida_mem); +static int idaNlsLSetup(booleantype jbad, booleantype* jcur, void* ida_mem); +static int idaNlsLSolve(N_Vector delta, void* ida_mem); static int idaNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, realtype tol, N_Vector ewt, void* ida_mem); @@ -60,11 +59,9 @@ int IDASetNonlinearSolver(void *ida_mem, SUNNonlinearSolver NLS) } /* check for required nonlinear solver functions */ - if ( NLS->ops->gettype == NULL || - NLS->ops->initialize == NULL || - NLS->ops->solve == NULL || - NLS->ops->free == NULL || - NLS->ops->setsysfn == NULL ) { + if ( NLS->ops->gettype == NULL || + NLS->ops->solve == NULL || + NLS->ops->setsysfn == NULL ) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetNonlinearSolver", "NLS does not support required operations"); @@ -100,7 +97,7 @@ int IDASetNonlinearSolver(void *ida_mem, SUNNonlinearSolver NLS) } /* set convergence test function */ - retval = SUNNonlinSolSetConvTestFn(IDA_mem->NLS, idaNlsConvTest); + retval = SUNNonlinSolSetConvTestFn(IDA_mem->NLS, idaNlsConvTest, ida_mem); if (retval != IDA_SUCCESS) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetNonlinearSolver", @@ -166,8 +163,7 @@ int idaNlsInit(IDAMem IDA_mem) } -static int idaNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, - booleantype* jcur, void* ida_mem) +static int idaNlsLSetup(booleantype jbad, booleantype* jcur, void* ida_mem) { IDAMem IDA_mem; int retval; @@ -181,17 +177,18 @@ static int idaNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, IDA_mem->ida_nsetups++; IDA_mem->ida_forceSetup = SUNFALSE; - retval = IDA_mem->ida_lsetup(IDA_mem, IDA_mem->ida_yy, IDA_mem->ida_yp, res, - IDA_mem->ida_tempv1, IDA_mem->ida_tempv2, IDA_mem->ida_tempv3); + retval = IDA_mem->ida_lsetup(IDA_mem, IDA_mem->ida_yy, IDA_mem->ida_yp, + IDA_mem->ida_savres, IDA_mem->ida_tempv1, + IDA_mem->ida_tempv2, IDA_mem->ida_tempv3); /* update Jacobian status */ *jcur = SUNTRUE; /* update convergence test constants */ - IDA_mem->ida_cjold = IDA_mem->ida_cj; + IDA_mem->ida_cjold = IDA_mem->ida_cj; IDA_mem->ida_cjratio = ONE; - IDA_mem->ida_ss = TWENTY; - IDA_mem->ida_ssS = TWENTY; + IDA_mem->ida_ss = TWENTY; + IDA_mem->ida_ssS = TWENTY; if (retval < 0) return(IDA_LSETUP_FAIL); if (retval > 0) return(IDA_LSETUP_RECVR); @@ -200,7 +197,7 @@ static int idaNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, } -static int idaNlsLSolve(N_Vector ycor, N_Vector delta, void* ida_mem) +static int idaNlsLSolve(N_Vector delta, void* ida_mem) { IDAMem IDA_mem; int retval; @@ -211,7 +208,8 @@ static int idaNlsLSolve(N_Vector ycor, N_Vector delta, void* ida_mem) } IDA_mem = (IDAMem) ida_mem; - retval = IDA_mem->ida_lsolve(IDA_mem, delta, IDA_mem->ida_ewt, IDA_mem->ida_yy, IDA_mem->ida_yp, + retval = IDA_mem->ida_lsolve(IDA_mem, delta, IDA_mem->ida_ewt, + IDA_mem->ida_yy, IDA_mem->ida_yp, IDA_mem->ida_savres); if (retval < 0) return(IDA_LSOLVE_FAIL); diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas_nls_sim.c b/deps/AMICI/ThirdParty/sundials/src/idas/idas_nls_sim.c index ce6fc5a41..10fa94b2a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas_nls_sim.c +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas_nls_sim.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -29,9 +29,9 @@ /* private functions passed to nonlinear solver */ static int idaNlsResidualSensSim(N_Vector ycor, N_Vector res, void* ida_mem); -static int idaNlsLSetupSensSim(N_Vector ycor, N_Vector res, booleantype jbad, - booleantype* jcur, void* ida_mem); -static int idaNlsLSolveSensSim(N_Vector ycor, N_Vector delta, void* ida_mem); +static int idaNlsLSetupSensSim(booleantype jbad, booleantype* jcur, + void* ida_mem); +static int idaNlsLSolveSensSim(N_Vector delta, void* ida_mem); static int idaNlsConvTestSensSim(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, realtype tol, N_Vector ewt, void* ida_mem); @@ -62,9 +62,7 @@ int IDASetNonlinearSolverSensSim(void *ida_mem, SUNNonlinearSolver NLS) /* check for required nonlinear solver functions */ if ( NLS->ops->gettype == NULL || - NLS->ops->initialize == NULL || NLS->ops->solve == NULL || - NLS->ops->free == NULL || NLS->ops->setsysfn == NULL ) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetNonlinearSolverSensSim", @@ -117,7 +115,8 @@ int IDASetNonlinearSolverSensSim(void *ida_mem, SUNNonlinearSolver NLS) } /* set convergence test function */ - retval = SUNNonlinSolSetConvTestFn(IDA_mem->NLSsim, idaNlsConvTestSensSim); + retval = SUNNonlinSolSetConvTestFn(IDA_mem->NLSsim, idaNlsConvTestSensSim, + ida_mem); if (retval != IDA_SUCCESS) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetNonlinearSolverSensSim", @@ -137,8 +136,8 @@ int IDASetNonlinearSolverSensSim(void *ida_mem, SUNNonlinearSolver NLS) /* create vector wrappers if necessary */ if (IDA_mem->simMallocDone == SUNFALSE) { - IDA_mem->ycor0Sim = N_VNewEmpty_SensWrapper(IDA_mem->ida_Ns+1); - if (IDA_mem->ycor0Sim == NULL) { + IDA_mem->ypredictSim = N_VNewEmpty_SensWrapper(IDA_mem->ida_Ns+1); + if (IDA_mem->ypredictSim == NULL) { IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDASetNonlinearSolverSensSim", MSG_MEM_FAIL); return(IDA_MEM_FAIL); @@ -146,7 +145,7 @@ int IDASetNonlinearSolverSensSim(void *ida_mem, SUNNonlinearSolver NLS) IDA_mem->ycorSim = N_VNewEmpty_SensWrapper(IDA_mem->ida_Ns+1); if (IDA_mem->ycorSim == NULL) { - N_VDestroy(IDA_mem->ycor0Sim); + N_VDestroy(IDA_mem->ypredictSim); IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDASetNonlinearSolverSensSim", MSG_MEM_FAIL); return(IDA_MEM_FAIL); @@ -154,7 +153,7 @@ int IDASetNonlinearSolverSensSim(void *ida_mem, SUNNonlinearSolver NLS) IDA_mem->ewtSim = N_VNewEmpty_SensWrapper(IDA_mem->ida_Ns+1); if (IDA_mem->ewtSim == NULL) { - N_VDestroy(IDA_mem->ycor0Sim); + N_VDestroy(IDA_mem->ypredictSim); N_VDestroy(IDA_mem->ycorSim); IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDASetNonlinearSolverSensSim", MSG_MEM_FAIL); @@ -165,14 +164,14 @@ int IDASetNonlinearSolverSensSim(void *ida_mem, SUNNonlinearSolver NLS) } /* attach vectors to vector wrappers */ - NV_VEC_SW(IDA_mem->ycor0Sim, 0) = IDA_mem->ida_delta; - NV_VEC_SW(IDA_mem->ycorSim, 0) = IDA_mem->ida_ee; - NV_VEC_SW(IDA_mem->ewtSim, 0) = IDA_mem->ida_ewt; + NV_VEC_SW(IDA_mem->ypredictSim, 0) = IDA_mem->ida_yypredict; + NV_VEC_SW(IDA_mem->ycorSim, 0) = IDA_mem->ida_ee; + NV_VEC_SW(IDA_mem->ewtSim, 0) = IDA_mem->ida_ewt; for (is=0; is < IDA_mem->ida_Ns; is++) { - NV_VEC_SW(IDA_mem->ycor0Sim, is+1) = IDA_mem->ida_deltaS[is]; - NV_VEC_SW(IDA_mem->ycorSim, is+1) = IDA_mem->ida_eeS[is]; - NV_VEC_SW(IDA_mem->ewtSim, is+1) = IDA_mem->ida_ewtS[is]; + NV_VEC_SW(IDA_mem->ypredictSim, is+1) = IDA_mem->ida_yySpredict[is]; + NV_VEC_SW(IDA_mem->ycorSim, is+1) = IDA_mem->ida_eeS[is]; + NV_VEC_SW(IDA_mem->ewtSim, is+1) = IDA_mem->ida_ewtS[is]; } return(IDA_SUCCESS); @@ -224,13 +223,11 @@ int idaNlsInitSensSim(IDAMem IDA_mem) } -static int idaNlsLSetupSensSim(N_Vector ycorSim, N_Vector resSim, - booleantype jbad, booleantype* jcur, +static int idaNlsLSetupSensSim(booleantype jbad, booleantype* jcur, void* ida_mem) { IDAMem IDA_mem; int retval; - N_Vector res; if (ida_mem == NULL) { IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", @@ -239,14 +236,12 @@ static int idaNlsLSetupSensSim(N_Vector ycorSim, N_Vector resSim, } IDA_mem = (IDAMem) ida_mem; - /* extract residual vector from the vector wrapper */ - res = NV_VEC_SW(resSim,0); - IDA_mem->ida_nsetups++; IDA_mem->ida_forceSetup = SUNFALSE; - retval = IDA_mem->ida_lsetup(IDA_mem, IDA_mem->ida_yy, IDA_mem->ida_yp, res, - IDA_mem->ida_tempv1, IDA_mem->ida_tempv2, IDA_mem->ida_tempv3); + retval = IDA_mem->ida_lsetup(IDA_mem, IDA_mem->ida_yy, IDA_mem->ida_yp, + IDA_mem->ida_savres, IDA_mem->ida_tempv1, + IDA_mem->ida_tempv2, IDA_mem->ida_tempv3); /* update Jacobian status */ *jcur = SUNTRUE; @@ -264,7 +259,7 @@ static int idaNlsLSetupSensSim(N_Vector ycorSim, N_Vector resSim, } -static int idaNlsLSolveSensSim(N_Vector ycorSim, N_Vector deltaSim, void* ida_mem) +static int idaNlsLSolveSensSim(N_Vector deltaSim, void* ida_mem) { IDAMem IDA_mem; int retval, is; diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas_nls_stg.c b/deps/AMICI/ThirdParty/sundials/src/idas/idas_nls_stg.c index 0efd6bf84..c12065f16 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas_nls_stg.c +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas_nls_stg.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -29,9 +29,9 @@ /* private functions passed to nonlinear solver */ static int idaNlsResidualSensStg(N_Vector ycor, N_Vector res, void* ida_mem); -static int idaNlsLSetupSensStg(N_Vector ycor, N_Vector res, booleantype jbad, - booleantype* jcur, void* ida_mem); -static int idaNlsLSolveSensStg(N_Vector ycor, N_Vector delta, void* ida_mem); +static int idaNlsLSetupSensStg(booleantype jbad, booleantype* jcur, + void* ida_mem); +static int idaNlsLSolveSensStg(N_Vector delta, void* ida_mem); static int idaNlsConvTestSensStg(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, realtype tol, N_Vector ewt, void* ida_mem); @@ -62,9 +62,7 @@ int IDASetNonlinearSolverSensStg(void *ida_mem, SUNNonlinearSolver NLS) /* check for required nonlinear solver functions */ if ( NLS->ops->gettype == NULL || - NLS->ops->initialize == NULL || NLS->ops->solve == NULL || - NLS->ops->free == NULL || NLS->ops->setsysfn == NULL ) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetNonlinearSolverSensStg", @@ -117,7 +115,8 @@ int IDASetNonlinearSolverSensStg(void *ida_mem, SUNNonlinearSolver NLS) } /* set convergence test function */ - retval = SUNNonlinSolSetConvTestFn(IDA_mem->NLSstg, idaNlsConvTestSensStg); + retval = SUNNonlinSolSetConvTestFn(IDA_mem->NLSstg, idaNlsConvTestSensStg, + ida_mem); if (retval != IDA_SUCCESS) { IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetNonlinearSolverSensStg", @@ -137,8 +136,8 @@ int IDASetNonlinearSolverSensStg(void *ida_mem, SUNNonlinearSolver NLS) /* create vector wrappers if necessary */ if (IDA_mem->stgMallocDone == SUNFALSE) { - IDA_mem->ycor0Stg = N_VNewEmpty_SensWrapper(IDA_mem->ida_Ns); - if (IDA_mem->ycor0Stg == NULL) { + IDA_mem->ypredictStg = N_VNewEmpty_SensWrapper(IDA_mem->ida_Ns); + if (IDA_mem->ypredictStg == NULL) { IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDASetNonlinearSolverSensStg", MSG_MEM_FAIL); return(IDA_MEM_FAIL); @@ -146,7 +145,7 @@ int IDASetNonlinearSolverSensStg(void *ida_mem, SUNNonlinearSolver NLS) IDA_mem->ycorStg = N_VNewEmpty_SensWrapper(IDA_mem->ida_Ns); if (IDA_mem->ycorStg == NULL) { - N_VDestroy(IDA_mem->ycor0Stg); + N_VDestroy(IDA_mem->ypredictStg); IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDASetNonlinearSolverSensStg", MSG_MEM_FAIL); return(IDA_MEM_FAIL); @@ -154,7 +153,7 @@ int IDASetNonlinearSolverSensStg(void *ida_mem, SUNNonlinearSolver NLS) IDA_mem->ewtStg = N_VNewEmpty_SensWrapper(IDA_mem->ida_Ns); if (IDA_mem->ewtStg == NULL) { - N_VDestroy(IDA_mem->ycor0Stg); + N_VDestroy(IDA_mem->ypredictStg); N_VDestroy(IDA_mem->ycorStg); IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDASetNonlinearSolverSensStg", MSG_MEM_FAIL); @@ -166,9 +165,9 @@ int IDASetNonlinearSolverSensStg(void *ida_mem, SUNNonlinearSolver NLS) /* attach vectors to vector wrappers */ for (is=0; is < IDA_mem->ida_Ns; is++) { - NV_VEC_SW(IDA_mem->ycor0Stg, is) = IDA_mem->ida_deltaS[is]; - NV_VEC_SW(IDA_mem->ycorStg, is) = IDA_mem->ida_eeS[is]; - NV_VEC_SW(IDA_mem->ewtStg, is) = IDA_mem->ida_ewtS[is]; + NV_VEC_SW(IDA_mem->ypredictStg, is) = IDA_mem->ida_yySpredict[is]; + NV_VEC_SW(IDA_mem->ycorStg, is) = IDA_mem->ida_eeS[is]; + NV_VEC_SW(IDA_mem->ewtStg, is) = IDA_mem->ida_ewtS[is]; } return(IDA_SUCCESS); @@ -220,8 +219,8 @@ int idaNlsInitSensStg(IDAMem IDA_mem) } -static int idaNlsLSetupSensStg(N_Vector ycorStg, N_Vector resStg, booleantype jbad, - booleantype* jcur, void* ida_mem) +static int idaNlsLSetupSensStg(booleantype jbad, booleantype* jcur, + void* ida_mem) { IDAMem IDA_mem; int retval; @@ -253,7 +252,7 @@ static int idaNlsLSetupSensStg(N_Vector ycorStg, N_Vector resStg, booleantype jb } -static int idaNlsLSolveSensStg(N_Vector ycorStg, N_Vector deltaStg, void* ida_mem) +static int idaNlsLSolveSensStg(N_Vector deltaStg, void* ida_mem) { IDAMem IDA_mem; int retval, is; diff --git a/deps/AMICI/ThirdParty/sundials/src/idas/idas_spils.c b/deps/AMICI/ThirdParty/sundials/src/idas/idas_spils.c index 26d20b1f5..da4b751a0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/idas/idas_spils.c +++ b/deps/AMICI/ThirdParty/sundials/src/idas/idas_spils.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/kinsol/CMakeLists.txt index 2853c72a4..8a278659b 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/CMakeLists.txt @@ -1,9 +1,9 @@ # --------------------------------------------------------------- -# Programmer(s): Daniel R. Reynolds @ SMU -# Radu Serban @ LLNL +# Programmer(s): Daniel R. Reynolds @ SMU +# Radu Serban @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -13,11 +13,17 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the KINSOL library +# --------------------------------------------------------------- + +install(CODE "MESSAGE(\"\nInstall KINSOL\n\")") -INSTALL(CODE "MESSAGE(\"\nInstall KINSOL\n\")") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) # Add variable kinsol_SOURCES with the sources for the KINSOL library -SET(kinsol_SOURCES +set(kinsol_SOURCES kinsol.c kinsol_bbdpre.c kinsol_direct.c @@ -28,22 +34,24 @@ SET(kinsol_SOURCES # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the KINSOL library -SET(shared_SOURCES +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_matrix.c ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c + ${sundials_SOURCE_DIR}/src/sundials/sundials_nonlinearsolver.c ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c ${sundials_SOURCE_DIR}/src/sundials/sundials_band.c ${sundials_SOURCE_DIR}/src/sundials/sundials_dense.c ${sundials_SOURCE_DIR}/src/sundials/sundials_direct.c ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c ${sundials_SOURCE_DIR}/src/sundials/sundials_version.c + ${sundials_SOURCE_DIR}/src/sundials/sundials_futils.c ${sundials_SOURCE_DIR}/src/nvector/serial/nvector_serial.c ) # Add variable sunmatrix_SOURCES with the common SUNMatrix sources which will # also be included in the KINSOL library -SET(sunmatrix_SOURCES +set(sunmatrix_SOURCES ${sundials_SOURCE_DIR}/src/sunmatrix/band/sunmatrix_band.c ${sundials_SOURCE_DIR}/src/sunmatrix/dense/sunmatrix_dense.c ${sundials_SOURCE_DIR}/src/sunmatrix/sparse/sunmatrix_sparse.c @@ -51,7 +59,7 @@ SET(sunmatrix_SOURCES # Add variable sunlinsol_SOURCES with the common SUNLinearSolver sources which will # also be included in the KINSOL library -SET(sunlinsol_SOURCES +set(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/band/sunlinsol_band.c ${sundials_SOURCE_DIR}/src/sunlinsol/dense/sunlinsol_dense.c ${sundials_SOURCE_DIR}/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c @@ -62,7 +70,7 @@ SET(sunlinsol_SOURCES ) # Add variable kinsol_HEADERS with the exported KINSOL header files -SET(kinsol_HEADERS +set(kinsol_HEADERS kinsol.h kinsol_bbdpre.h kinsol_direct.h @@ -71,58 +79,58 @@ SET(kinsol_HEADERS ) # Add prefix with complete path to the KINSOL header files -ADD_PREFIX(${sundials_SOURCE_DIR}/include/kinsol/ kinsol_HEADERS) +add_prefix(${sundials_SOURCE_DIR}/include/kinsol/ kinsol_HEADERS) # Add source directories to include directories for access to # implementation only header files. -INCLUDE_DIRECTORIES(.) -INCLUDE_DIRECTORIES(../sundials) +include_directories(.) +include_directories(../sundials) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) # Build the static library -IF(BUILD_STATIC_LIBS) +if(BUILD_STATIC_LIBS) # Add the build target for the static KINSOL library - ADD_LIBRARY(sundials_kinsol_static STATIC + add_library(sundials_kinsol_static STATIC ${kinsol_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES}) # Set the library name and make sure it is not deleted - SET_TARGET_PROPERTIES(sundials_kinsol_static + set_target_properties(sundials_kinsol_static PROPERTIES OUTPUT_NAME sundials_kinsol CLEAN_DIRECT_OUTPUT 1) # Install the KINSOL library - INSTALL(TARGETS sundials_kinsol_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS sundials_kinsol_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +endif(BUILD_STATIC_LIBS) # Build the shared library -IF(BUILD_SHARED_LIBS) +if(BUILD_SHARED_LIBS) # Add the build target for the KINSOL library - ADD_LIBRARY(sundials_kinsol_shared SHARED + add_library(sundials_kinsol_shared SHARED ${kinsol_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES}) - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_kinsol_shared m) - ENDIF() + if(UNIX) + target_link_libraries(sundials_kinsol_shared m) + endif() # Set the library name and make sure it is not deleted - SET_TARGET_PROPERTIES(sundials_kinsol_shared + set_target_properties(sundials_kinsol_shared PROPERTIES OUTPUT_NAME sundials_kinsol CLEAN_DIRECT_OUTPUT 1) # Set VERSION and SOVERSION for shared libraries - SET_TARGET_PROPERTIES(sundials_kinsol_shared + set_target_properties(sundials_kinsol_shared PROPERTIES VERSION ${kinsollib_VERSION} SOVERSION ${kinsollib_SOVERSION}) # Install the KINSOL library - INSTALL(TARGETS sundials_kinsol_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS sundials_kinsol_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) +endif(BUILD_SHARED_LIBS) # Install the KINSOL header files -INSTALL(FILES ${kinsol_HEADERS} DESTINATION include/kinsol) +install(FILES ${kinsol_HEADERS} DESTINATION include/kinsol) # -MESSAGE(STATUS "Added KINSOL module") +message(STATUS "Added KINSOL module") diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/README b/deps/AMICI/ThirdParty/sundials/src/kinsol/README deleted file mode 100644 index 834076de9..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/README +++ /dev/null @@ -1,111 +0,0 @@ - KINSOL - Release 4.1.0, Feb 2019 - Aaron Collier, Alan C. Hindmarsh, Radu Serban, and Carol S. Woodward - Center for Applied Scientific Computing, LLNL - -KINSOL is a solver for nonlinear algebraic systems which can be -described as F(u) = 0. It is written in the C language and based -on the previous Fortran package NKSOL [4], written by Peter Brown and -Youcef Saad. Nonlinear solver methods available include Newton-Krylov, -Picard, and fixed point. Both Picard and fixed point can be accelerated -with Anderson acceleration. - -KINSOL can be used both on serial and parallel computers. -The difference is only in the NVECTOR module of vector functions. -The desired version is obtained when compiling the example files -by linking with the appropriate library of NVECTOR functions. In the -parallel versions, communication between processes is done -with MPI, with OpenMP, or with Pthreads. - -When used with the serial NVECTOR module, KINSOL provides both direct (dense -and band) and preconditioned Krylov (iterative) linear solvers. Four different -iterative solvers are available: scaled preconditioned GMRES (SPGMR), scaled -preconditioned BiCGStab (SPBCG), scaled preconditioned TFQMR (SPTFQMR), and -scaled preconditioned Flexible GMRES (SPFGMR). -When used with the parallel NVECTOR module, KINSOL provides a -preconditioner module called KINBBDPRE, which provides a -band-block-diagonal preconditioner for use with the Krylov linear -solvers. However, within KINSOL any NVECTOR module may be combined -with an appropriate user-supplied preconditioning module for -acceleration of the Krylov solvers. - -KINSOL is part of a software family called SUNDIALS: SUite of Nonlinear -and DIfferential/ALgebraic equation Solvers. This suite consists of -CVODE, CVODES, ARKode, KINSOL, IDA, and IDAS. The directory -structure of the package supplied reflects this family relationship. - -For use with Fortran applications, a set of Fortran/C interface routines, -called FKINSOL, is also supplied. These are written in C, but assume that -the user calling program and all user-supplied routines are in Fortran. - -The notes below provide the location of documentation, directions for the -installation of the KINSOL package, and relevant references. Following that -is a brief history of revisions to the package. - - -A. Documentation ----------------- - -/sundials/doc/kinsol/ contains PDF files for the KINSOL User Guide [1] (kin_guide.pdf) -and the KINSOL Examples [2] (kin_examples.pdf) documents. - - -B. Installation ---------------- - -For basic installation instructions see the file /sundials/INSTALL_GUIDE.pdf. -For complete installation instructions see the "Installation Procedure" -chapter in the KINSOL User Guide [1]. - - -C. References -------------- - -[1] A. M. Collier, A. C. Hindmarsh, R. Serban, and C. S. Woodward, - "User Documentation for KINSOL v2.9.0," LLNL technical report - UCRL-SM-208116, March 2016. - -[2] A. M. Collier and R. Serban, "Example Programs for KINSOL v2.9.0," - LLNL technical report UCRL-SM-208114, March 2016. - -[3] A. C. Hindmarsh, P. N. Brown, K. E. Grant, S. L. Lee, R. Serban, - D. E. Shumaker, and C. S. Woodward, "SUNDIALS, Suite of Nonlinear and - Differential/Algebraic Equation Solvers," ACM Trans. Math. Softw., - 31(3), pp. 363-396, 2005. - -[4] Peter N. Brown and Youcef Saad, "Hybrid Krylov Methods for - Nonlinear Systems of Equations," SIAM J. Sci. Stat. Comput., - Vol 11, no 3, pp. 450-481, May 1990. - -[5] A. G. Taylor and A. C. Hindmarsh, "User Documentation for KINSOL, - A Nonlinear Solver for Sequential and Parallel Computers," LLNL - technical report UCRL-ID-131185, July 1998. - - -D. Releases ------------ - -v. 4.1.0 - Feb. 2019 -v. 4.0.2 - Jan. 2019 -v. 4.0.1 - Dec. 2018 -v. 4.0.0 - Dec. 2018 -v. 3.2.1 - Oct. 2018 -v. 3.2.0 - Sep. 2018 -v. 3.1.2 - Jul. 2018 -v. 3.1.1 - May 2018 -v. 3.1.0 - Nov. 2017 -v. 3.0.0 - Sep. 2017 -v. 2.9.0 - Sep. 2016 -v. 2.8.2 - Aug. 2015 -v. 2.8.1 - Mar. 2015 -v. 2.8.0 - Mar. 2015 -v. 2.7.0 - Mar. 2012 -v. 2.6.0 - May 2009 -v. 2.5.0 - Nov. 2006 -v. 2.4.0 - Mar. 2006 -v. 2.3.0 - Apr. 2005 -v. 2.2.2 - Mar. 2005 -v. 2.2.1 - Jan. 2005 -v. 2.2.0 - Dec. 2004 -v. 2.0 - Jul. 2002 (first SUNDIALS release) -v. 1.0 - Aug. 1998 (date written) diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/README.md b/deps/AMICI/ThirdParty/sundials/src/kinsol/README.md new file mode 100644 index 000000000..8836e369d --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/README.md @@ -0,0 +1,65 @@ +# KINSOL +### Version 5.2.0 (Mar 2020) + +**Aaron Collier, Alan C. Hindmarsh, Radu Serban, and Carol S. Woodward + Center for Applied Scientific Computing, LLNL** + +KINSOL is a package for the solution for nonlinear algebraic systems +``` +F(u) = 0. +``` +Nonlinear solver methods available include Newton-Krylov, Picard, and +fixed-point. Both Picard and fixed point can be accelerated with Anderson +acceleration. + +KINSOL is part of the SUNDIALS Suite of Nonlinear and Differential/Algebraic +equation Solvers which consists of ARKode, CVODE, CVODES, IDA, IDAS and KINSOL. +It is written in ANSI standard C, but is based on the previous Fortran package +NKSOL, written by Peter Brown and Youcef Saad. KINSOL can be used in a variety +of computing environments including serial, shared memory, distributed memory, +and accelerator-based (e.g., GPU) systems. This flexibility is obtained from a +modular design that leverages the shared vector, matrix, and linear solver APIs +used across SUNDIALS packages. + +For use with Fortran applications, a set of Fortran/C interface routines, called +FKINSOL, is also supplied. These are written in C, but assume that the user +calling program and all user-supplied routines are in Fortran. + +## Documentation + +See the [KINSOL User Guide](/doc/kinsol/kin_guide.pdf) and +[KINSOL Examples](/doc/kinsol/kin_examples.pdf) document for more information +about IDA usage and the provided example programs respectively. + +## Installation + +For installation instructions see the [INSTALL_GUIDE](/INSTALL_GUIDE.pdf) +or the "Installation Procedure" chapter in the KINSOL User Guide. + +## Release History + +Information on recent changes to KINSOL can be found in the "Introduction" +chapter of the KINSOL User Guide and a complete release history is available in +the "SUNDIALS Release History" appendix of the KINSOL User Guide. + +## References + +* A. M. Collier, A. C. Hindmarsh, R. Serban, and C. S. Woodward, + "User Documentation for KINSOL v5.2.0," LLNL technical report + UCRL-SM-208116, Mar 2020. + +* A. M. Collier and R. Serban, "Example Programs for KINSOL v5.2.0," + LLNL technical report UCRL-SM-208114, Mar 2020. + +* A. C. Hindmarsh, P. N. Brown, K. E. Grant, S. L. Lee, R. Serban, + D. E. Shumaker, and C. S. Woodward, "SUNDIALS, Suite of Nonlinear and + Differential/Algebraic Equation Solvers," ACM Trans. Math. Softw., + 31(3), pp. 363-396, 2005. + +* Peter N. Brown and Youcef Saad, "Hybrid Krylov Methods for + Nonlinear Systems of Equations," SIAM J. Sci. Stat. Comput., + Vol 11, no 3, pp. 450-481, May 1990. + +* A. G. Taylor and A. C. Hindmarsh, "User Documentation for KINSOL, + A Nonlinear Solver for Sequential and Parallel Computers," LLNL + technical report UCRL-ID-131185, July 1998. diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/CMakeLists.txt index 0c76ac56b..a617a0241 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,9 +12,10 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the FKINSOL library +# --------------------------------------------------------------- # Add variable fcvode_SOURCES with the sources for the FCVODE library -SET(fkinsol_SOURCES +set(fkinsol_SOURCES fkinband.c fkinbbd.c fkindense.c @@ -28,13 +29,13 @@ SET(fkinsol_SOURCES # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the ARKODE library -SET(shared_SOURCES +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/nvector/serial/fnvector_serial.c ) # Add variable sunmatrix_SOURCES with the common SUNMatrix sources which will # also be included in the ARKODE library -SET(sunmatrix_SOURCES +set(sunmatrix_SOURCES ${sundials_SOURCE_DIR}/src/sunmatrix/band/fsunmatrix_band.c ${sundials_SOURCE_DIR}/src/sunmatrix/dense/fsunmatrix_dense.c ${sundials_SOURCE_DIR}/src/sunmatrix/sparse/fsunmatrix_sparse.c @@ -42,7 +43,7 @@ SET(sunmatrix_SOURCES # Add variable sunlinsol_SOURCES with the common SUNLinearSolver sources which will # also be included in the ARKODE library -SET(sunlinsol_SOURCES +set(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/band/fsunlinsol_band.c ${sundials_SOURCE_DIR}/src/sunlinsol/dense/fsunlinsol_dense.c ${sundials_SOURCE_DIR}/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c @@ -52,48 +53,28 @@ SET(sunlinsol_SOURCES ${sundials_SOURCE_DIR}/src/sunlinsol/pcg/fsunlinsol_pcg.c ) -IF(KLU_FOUND) - LIST(APPEND sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/klu/fsunlinsol_klu.c - ) -ENDIF() - -IF(SUPERLUMT_FOUND) - LIST(APPEND sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/superlumt/fsunlinsol_superlumt.c - ) -ENDIF() - -IF(LAPACK_FOUND) - LIST(APPEND sunlinsol_SOURCES - ${sundials_SOURCE_DIR}/src/sunlinsol/lapackband/fsunlinsol_lapackband.c - ${sundials_SOURCE_DIR}/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.c - ) -ENDIF() - - # Add source directories to include directories for access to # implementation only header files (both for fkinsol and kinsol) -INCLUDE_DIRECTORIES(.) -INCLUDE_DIRECTORIES(..) +include_directories(.) +include_directories(..) -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY +add_definitions(-DBUILD_SUNDIALS_LIBRARY) -# Only build STATIC libraries (we cannot build shared libraries -# for the FCMIX interfaces due to unresolved symbol errors +# Only build STATIC libraries (we cannot build shared libraries +# for the FCMIX interfaces due to unresolved symbol errors # coming from inexistent user-provided functions) # Add the build target for the FKINSOL library -ADD_LIBRARY(sundials_fkinsol_static STATIC +add_library(sundials_fkinsol_static STATIC ${fkinsol_SOURCES} ${shared_SOURCES} ${sunmatrix_SOURCES} ${sunlinsol_SOURCES} ) # Set the library name and make sure it is not deleted -SET_TARGET_PROPERTIES(sundials_fkinsol_static +set_target_properties(sundials_fkinsol_static PROPERTIES OUTPUT_NAME sundials_fkinsol CLEAN_DIRECT_OUTPUT 1) # Install the FKINSOL library -INSTALL(TARGETS sundials_fkinsol_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(TARGETS sundials_fkinsol_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) # -MESSAGE(STATUS "Added KINSOL FCMIX module") +message(STATUS "Added KINSOL FCMIX module") diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinband.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinband.c index b68f90e5a..762f42dbe 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinband.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinband.c @@ -3,7 +3,7 @@ * David J. Gardner @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.c index 2ed5b4642..7ba851aa7 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.c @@ -4,7 +4,7 @@ * David J. Gardner @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -62,8 +62,15 @@ extern void FK_COMMFN(long int* NLOC, realtype* ULOC, int* IER); void FKIN_BBDINIT(long int *nlocal, long int *mudq, long int *mldq, long int *mu, long int *ml, int *ier) { - *ier = KINBBDPrecInit(KIN_kinmem, *nlocal, *mudq, *mldq, *mu, *ml, ZERO, - (KINBBDLocalFn) FKINgloc, (KINBBDCommFn) FKINgcomm); + *ier = KINBBDPrecInit(KIN_kinmem, + (sunindextype)(*nlocal), + (sunindextype)(*mudq), + (sunindextype)(*mldq), + (sunindextype)(*mu), + (sunindextype)(*ml), + ZERO, + (KINBBDLocalFn) FKINgloc, + (KINBBDCommFn) FKINgcomm); return; } @@ -126,7 +133,7 @@ int FKINgcomm(long int Nloc, N_Vector uu, void *user_data) /* Get pointers to vector data */ uloc = N_VGetArrayPointer(uu); - + /* Call user-supplied routine */ FK_COMMFN(&Nloc, uloc, &ier); @@ -137,7 +144,7 @@ int FKINgcomm(long int Nloc, N_Vector uu, void *user_data) * ---------------------------------------------------------------- * Function : FKIN_BBDOPT * ---------------------------------------------------------------- - * C function FKIN_BBDOPT is used to access optional outputs + * C function FKIN_BBDOPT is used to access optional outputs * realated to the BBD preconditioner. * ---------------------------------------------------------------- */ @@ -149,4 +156,3 @@ void FKIN_BBDOPT(long int *lenrpw, long int *lenipw, long int *nge) return; } - diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.h b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.h index fb0496595..e9a16772f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.h +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.h @@ -3,7 +3,7 @@ * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkindense.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkindense.c index b63031352..59004259f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkindense.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkindense.c @@ -3,7 +3,7 @@ * David J. Gardner @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinjtimes.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinjtimes.c index 7d8d600d6..f3259d513 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinjtimes.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinjtimes.c @@ -4,7 +4,7 @@ * David J. Gardner @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinnulllinsol.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinnulllinsol.c index 6c6d997ae..707d6d049 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinnulllinsol.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinnulllinsol.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinnullmatrix.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinnullmatrix.c index 6390ffdc3..1d17c91ea 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinnullmatrix.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinnullmatrix.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *--------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinpreco.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinpreco.c index 33352cfd3..324778c0a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinpreco.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinpreco.c @@ -3,7 +3,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.c index 6daf153a1..6c636b0e0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.c @@ -4,7 +4,7 @@ * David J. Gardner @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.h b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.h index 26ca4d40b..96349ed3f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.h +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.h @@ -5,7 +5,7 @@ * David J. Gardner @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -165,7 +165,7 @@ sparse row] matrix with storage for NNZ nonzeros, stored in the arrays JDATA (nonzero values), JRVALS (row [or column] indices for each nonzero), JCOLPTRS (indices for start of each column [or row]), with the Jacobian - matrix at the current (y) in CSC [or CSR] form (see sundials_sparse.h for + matrix at the current (y) in CSC [or CSR] form (see sunmatrix_sparse.h for more information). The arguments are: diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinsparse.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinsparse.c index 80af78f4f..d91b99215 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinsparse.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fcmix/fkinsparse.c @@ -4,7 +4,7 @@ * David J. Gardner @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fmod/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/kinsol/fmod/CMakeLists.txt new file mode 100644 index 000000000..bd2ee1338 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fmod/CMakeLists.txt @@ -0,0 +1,96 @@ +# --------------------------------------------------------------- +# Programmer(s): Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the F2003 KINSOL object library +# --------------------------------------------------------------- + +set(kinsol_SOURCES fkinsol_mod.f90 fkinsol_mod.c) + +if(BUILD_STATIC_LIBS) + sundials_add_f2003_interface_library(sundials_fkinsol_mod_static STATIC + ${kinsol_SOURCES} + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + + # include the directoy where the .mod files reside + target_include_directories(sundials_fkinsol_mod_static + PUBLIC + $ + $ + ) + + # Set the library name and make sure it is not deleted + set_target_properties(sundials_fkinsol_mod_static + PROPERTIES OUTPUT_NAME sundials_fkinsol_mod CLEAN_DIRECT_OUTPUT 1) + + # install the library + install(TARGETS sundials_fkinsol_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # install the kinsol mod file from here since it won't go into the + # top level fortran mod file directory + install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_STATIC/fkinsol_mod.mod + DESTINATION ${Fortran_INSTALL_MODDIR}) +endif() + +if(BUILD_SHARED_LIBS) + sundials_add_f2003_interface_library(sundials_fkinsol_mod_shared SHARED + ${kinsol_SOURCES} + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + + # include the directoy where the .mod files reside + target_include_directories(sundials_fkinsol_mod_shared + PUBLIC + $ + $ + ) + + # Set the library name and make sure it is not deleted + set_target_properties(sundials_fkinsol_mod_shared PROPERTIES + OUTPUT_NAME sundials_fkinsol_mod + CLEAN_DIRECT_OUTPUT 1 + VERSION ${kinsollib_VERSION} + SOVERSION ${kinsollib_SOVERSION}) + + # install the library + install(TARGETS sundials_fkinsol_mod_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # install the kinsol mod file from here since it won't go into the + # top level fortran mod file directory + install(FILES ${CMAKE_Fortran_MODULE_DIRECTORY}_SHARED/fkinsol_mod.mod + DESTINATION ${Fortran_INSTALL_MODDIR}) +endif() + +message(STATUS "Added KINSOL F2003 interface") diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fmod/fkinsol_mod.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/fmod/fkinsol_mod.c new file mode 100644 index 000000000..79ee37d8b --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fmod/fkinsol_mod.c @@ -0,0 +1,1036 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "kinsol/kinsol.h" +#include "kinsol/kinsol_bbdpre.h" +#include "kinsol/kinsol_ls.h" + + +#include +#ifdef _MSC_VER +# ifndef strtoull +# define strtoull _strtoui64 +# endif +# ifndef strtoll +# define strtoll _strtoi64 +# endif +#endif + + +typedef struct { + void* data; + size_t size; +} SwigArrayWrapper; + + +SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() { + SwigArrayWrapper result; + result.data = NULL; + result.size = 0; + return result; +} + + +#include + +SWIGEXPORT void * _wrap_FKINCreate() { + void * fresult ; + void *result = 0 ; + + result = (void *)KINCreate(); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FKINInit(void *farg1, KINSysFn farg2, N_Vector farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + KINSysFn arg2 = (KINSysFn) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (KINSysFn)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)KINInit(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSol(void *farg1, N_Vector farg2, int const *farg3, N_Vector farg4, N_Vector farg5) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (int)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + result = (int)KINSol(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetErrHandlerFn(void *farg1, KINErrHandlerFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + KINErrHandlerFn arg2 = (KINErrHandlerFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (KINErrHandlerFn)(farg2); + arg3 = (void *)(farg3); + result = (int)KINSetErrHandlerFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetErrFile(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)KINSetErrFile(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetInfoHandlerFn(void *farg1, KINInfoHandlerFn farg2, void *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + KINInfoHandlerFn arg2 = (KINInfoHandlerFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (KINInfoHandlerFn)(farg2); + arg3 = (void *)(farg3); + result = (int)KINSetInfoHandlerFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetInfoFile(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + FILE *arg2 = (FILE *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (FILE *)(farg2); + result = (int)KINSetInfoFile(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetUserData(void *farg1, void *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + void *arg2 = (void *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (void *)(farg2); + result = (int)KINSetUserData(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetPrintLevel(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)KINSetPrintLevel(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetMAA(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)KINSetMAA(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetDampingAA(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)KINSetDampingAA(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetNumMaxIters(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)KINSetNumMaxIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetNoInitSetup(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)KINSetNoInitSetup(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetNoResMon(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)KINSetNoResMon(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetMaxSetupCalls(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)KINSetMaxSetupCalls(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetMaxSubSetupCalls(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)KINSetMaxSubSetupCalls(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetEtaForm(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)KINSetEtaForm(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetEtaConstValue(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)KINSetEtaConstValue(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetEtaParams(void *farg1, double const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)KINSetEtaParams(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetResMonParams(void *farg1, double const *farg2, double const *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + realtype arg3 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (realtype)(*farg3); + result = (int)KINSetResMonParams(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetResMonConstValue(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)KINSetResMonConstValue(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetNoMinEps(void *farg1, int const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (int)(*farg2); + result = (int)KINSetNoMinEps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetMaxNewtonStep(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)KINSetMaxNewtonStep(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetMaxBetaFails(void *farg1, long const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long)(*farg2); + result = (int)KINSetMaxBetaFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetRelErrFunc(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)KINSetRelErrFunc(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetFuncNormTol(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)KINSetFuncNormTol(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetScaledStepTol(void *farg1, double const *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype arg2 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype)(*farg2); + result = (int)KINSetScaledStepTol(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetConstraints(void *farg1, N_Vector farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)KINSetConstraints(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetSysFunc(void *farg1, KINSysFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + KINSysFn arg2 = (KINSysFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (KINSysFn)(farg2); + result = (int)KINSetSysFunc(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)KINGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetNumNonlinSolvIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINGetNumNonlinSolvIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetNumFuncEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINGetNumFuncEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetNumBetaCondFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINGetNumBetaCondFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetNumBacktrackOps(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINGetNumBacktrackOps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetFuncNorm(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)KINGetFuncNorm(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetStepLength(void *farg1, double *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + realtype *arg2 = (realtype *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (realtype *)(farg2); + result = (int)KINGetStepLength(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FKINGetReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)KINGetReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FKINFree(void *farg1) { + void **arg1 = (void **) 0 ; + + arg1 = (void **)(farg1); + KINFree(arg1); +} + + +SWIGEXPORT int _wrap_FKINBBDPrecInit(void *farg1, int64_t const *farg2, int64_t const *farg3, int64_t const *farg4, int64_t const *farg5, int64_t const *farg6, double const *farg7, KINBBDLocalFn farg8, KINBBDCommFn farg9) { + int fresult ; + void *arg1 = (void *) 0 ; + sunindextype arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + sunindextype arg5 ; + sunindextype arg6 ; + realtype arg7 ; + KINBBDLocalFn arg8 = (KINBBDLocalFn) 0 ; + KINBBDCommFn arg9 = (KINBBDCommFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + arg5 = (sunindextype)(*farg5); + arg6 = (sunindextype)(*farg6); + arg7 = (realtype)(*farg7); + arg8 = (KINBBDLocalFn)(farg8); + arg9 = (KINBBDCommFn)(farg9); + result = (int)KINBBDPrecInit(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINBBDPrecGetWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)KINBBDPrecGetWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINBBDPrecGetNumGfnEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINBBDPrecGetNumGfnEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetLinearSolver(void *farg1, SUNLinearSolver farg2, SUNMatrix farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + SUNLinearSolver arg2 = (SUNLinearSolver) 0 ; + SUNMatrix arg3 = (SUNMatrix) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (SUNLinearSolver)(farg2); + arg3 = (SUNMatrix)(farg3); + result = (int)KINSetLinearSolver(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetJacFn(void *farg1, KINLsJacFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + KINLsJacFn arg2 = (KINLsJacFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (KINLsJacFn)(farg2); + result = (int)KINSetJacFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetPreconditioner(void *farg1, KINLsPrecSetupFn farg2, KINLsPrecSolveFn farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + KINLsPrecSetupFn arg2 = (KINLsPrecSetupFn) 0 ; + KINLsPrecSolveFn arg3 = (KINLsPrecSolveFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (KINLsPrecSetupFn)(farg2); + arg3 = (KINLsPrecSolveFn)(farg3); + result = (int)KINSetPreconditioner(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINSetJacTimesVecFn(void *farg1, KINLsJacTimesVecFn farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + KINLsJacTimesVecFn arg2 = (KINLsJacTimesVecFn) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (KINLsJacTimesVecFn)(farg2); + result = (int)KINSetJacTimesVecFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetLinWorkSpace(void *farg1, long *farg2, long *farg3) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)KINGetLinWorkSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetNumJacEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINGetNumJacEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetNumLinFuncEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINGetNumLinFuncEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetNumPrecEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINGetNumPrecEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetNumPrecSolves(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINGetNumPrecSolves(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetNumLinIters(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINGetNumLinIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetNumLinConvFails(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINGetNumLinConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetNumJtimesEvals(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINGetNumJtimesEvals(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FKINGetLastLinFlag(void *farg1, long *farg2) { + int fresult ; + void *arg1 = (void *) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (void *)(farg1); + arg2 = (long *)(farg2); + result = (int)KINGetLastLinFlag(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigArrayWrapper _wrap_FKINGetLinReturnFlagName(long const *farg1) { + SwigArrayWrapper fresult ; + long arg1 ; + char *result = 0 ; + + arg1 = (long)(*farg1); + result = (char *)KINGetLinReturnFlagName(arg1); + fresult.size = strlen((const char*)(result)); + fresult.data = (char *)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/fmod/fkinsol_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/kinsol/fmod/fkinsol_mod.f90 new file mode 100644 index 000000000..ff4421595 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/fmod/fkinsol_mod.f90 @@ -0,0 +1,1597 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fkinsol_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_linearsolver_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_nonlinearsolver_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: KIN_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: KIN_INITIAL_GUESS_OK = 1_C_INT + integer(C_INT), parameter, public :: KIN_STEP_LT_STPTOL = 2_C_INT + integer(C_INT), parameter, public :: KIN_WARNING = 99_C_INT + integer(C_INT), parameter, public :: KIN_MEM_NULL = -1_C_INT + integer(C_INT), parameter, public :: KIN_ILL_INPUT = -2_C_INT + integer(C_INT), parameter, public :: KIN_NO_MALLOC = -3_C_INT + integer(C_INT), parameter, public :: KIN_MEM_FAIL = -4_C_INT + integer(C_INT), parameter, public :: KIN_LINESEARCH_NONCONV = -5_C_INT + integer(C_INT), parameter, public :: KIN_MAXITER_REACHED = -6_C_INT + integer(C_INT), parameter, public :: KIN_MXNEWT_5X_EXCEEDED = -7_C_INT + integer(C_INT), parameter, public :: KIN_LINESEARCH_BCFAIL = -8_C_INT + integer(C_INT), parameter, public :: KIN_LINSOLV_NO_RECOVERY = -9_C_INT + integer(C_INT), parameter, public :: KIN_LINIT_FAIL = -10_C_INT + integer(C_INT), parameter, public :: KIN_LSETUP_FAIL = -11_C_INT + integer(C_INT), parameter, public :: KIN_LSOLVE_FAIL = -12_C_INT + integer(C_INT), parameter, public :: KIN_SYSFUNC_FAIL = -13_C_INT + integer(C_INT), parameter, public :: KIN_FIRST_SYSFUNC_ERR = -14_C_INT + integer(C_INT), parameter, public :: KIN_REPTD_SYSFUNC_ERR = -15_C_INT + integer(C_INT), parameter, public :: KIN_VECTOROP_ERR = -16_C_INT + integer(C_INT), parameter, public :: KIN_ETACHOICE1 = 1_C_INT + integer(C_INT), parameter, public :: KIN_ETACHOICE2 = 2_C_INT + integer(C_INT), parameter, public :: KIN_ETACONSTANT = 3_C_INT + integer(C_INT), parameter, public :: KIN_NONE = 0_C_INT + integer(C_INT), parameter, public :: KIN_LINESEARCH = 1_C_INT + integer(C_INT), parameter, public :: KIN_PICARD = 2_C_INT + integer(C_INT), parameter, public :: KIN_FP = 3_C_INT + public :: FKINCreate + public :: FKINInit + public :: FKINSol + public :: FKINSetErrHandlerFn + public :: FKINSetErrFile + public :: FKINSetInfoHandlerFn + public :: FKINSetInfoFile + public :: FKINSetUserData + public :: FKINSetPrintLevel + public :: FKINSetMAA + public :: FKINSetDampingAA + public :: FKINSetNumMaxIters + public :: FKINSetNoInitSetup + public :: FKINSetNoResMon + public :: FKINSetMaxSetupCalls + public :: FKINSetMaxSubSetupCalls + public :: FKINSetEtaForm + public :: FKINSetEtaConstValue + public :: FKINSetEtaParams + public :: FKINSetResMonParams + public :: FKINSetResMonConstValue + public :: FKINSetNoMinEps + public :: FKINSetMaxNewtonStep + public :: FKINSetMaxBetaFails + public :: FKINSetRelErrFunc + public :: FKINSetFuncNormTol + public :: FKINSetScaledStepTol + public :: FKINSetConstraints + public :: FKINSetSysFunc + public :: FKINGetWorkSpace + public :: FKINGetNumNonlinSolvIters + public :: FKINGetNumFuncEvals + public :: FKINGetNumBetaCondFails + public :: FKINGetNumBacktrackOps + public :: FKINGetFuncNorm + public :: FKINGetStepLength + type, bind(C) :: SwigArrayWrapper + type(C_PTR), public :: data = C_NULL_PTR + integer(C_SIZE_T), public :: size = 0 + end type + public :: FKINGetReturnFlagName + public :: FKINFree + integer(C_INT), parameter, public :: KINBBDPRE_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: KINBBDPRE_PDATA_NULL = -11_C_INT + integer(C_INT), parameter, public :: KINBBDPRE_FUNC_UNRECVR = -12_C_INT + public :: FKINBBDPrecInit + public :: FKINBBDPrecGetWorkSpace + public :: FKINBBDPrecGetNumGfnEvals + integer(C_INT), parameter, public :: KINLS_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: KINLS_MEM_NULL = -1_C_INT + integer(C_INT), parameter, public :: KINLS_LMEM_NULL = -2_C_INT + integer(C_INT), parameter, public :: KINLS_ILL_INPUT = -3_C_INT + integer(C_INT), parameter, public :: KINLS_MEM_FAIL = -4_C_INT + integer(C_INT), parameter, public :: KINLS_PMEM_NULL = -5_C_INT + integer(C_INT), parameter, public :: KINLS_JACFUNC_ERR = -6_C_INT + integer(C_INT), parameter, public :: KINLS_SUNMAT_FAIL = -7_C_INT + integer(C_INT), parameter, public :: KINLS_SUNLS_FAIL = -8_C_INT + public :: FKINSetLinearSolver + public :: FKINSetJacFn + public :: FKINSetPreconditioner + public :: FKINSetJacTimesVecFn + public :: FKINGetLinWorkSpace + public :: FKINGetNumJacEvals + public :: FKINGetNumLinFuncEvals + public :: FKINGetNumPrecEvals + public :: FKINGetNumPrecSolves + public :: FKINGetNumLinIters + public :: FKINGetNumLinConvFails + public :: FKINGetNumJtimesEvals + public :: FKINGetLastLinFlag + public :: FKINGetLinReturnFlagName + +! WRAPPER DECLARATIONS +interface +function swigc_FKINCreate() & +bind(C, name="_wrap_FKINCreate") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: fresult +end function + +function swigc_FKINInit(farg1, farg2, farg3) & +bind(C, name="_wrap_FKINInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FKINSol(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FKINSol") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetErrHandlerFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FKINSetErrHandlerFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetErrFile(farg1, farg2) & +bind(C, name="_wrap_FKINSetErrFile") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetInfoHandlerFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FKINSetInfoHandlerFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetInfoFile(farg1, farg2) & +bind(C, name="_wrap_FKINSetInfoFile") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetUserData(farg1, farg2) & +bind(C, name="_wrap_FKINSetUserData") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetPrintLevel(farg1, farg2) & +bind(C, name="_wrap_FKINSetPrintLevel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetMAA(farg1, farg2) & +bind(C, name="_wrap_FKINSetMAA") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetDampingAA(farg1, farg2) & +bind(C, name="_wrap_FKINSetDampingAA") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetNumMaxIters(farg1, farg2) & +bind(C, name="_wrap_FKINSetNumMaxIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetNoInitSetup(farg1, farg2) & +bind(C, name="_wrap_FKINSetNoInitSetup") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetNoResMon(farg1, farg2) & +bind(C, name="_wrap_FKINSetNoResMon") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetMaxSetupCalls(farg1, farg2) & +bind(C, name="_wrap_FKINSetMaxSetupCalls") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetMaxSubSetupCalls(farg1, farg2) & +bind(C, name="_wrap_FKINSetMaxSubSetupCalls") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetEtaForm(farg1, farg2) & +bind(C, name="_wrap_FKINSetEtaForm") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetEtaConstValue(farg1, farg2) & +bind(C, name="_wrap_FKINSetEtaConstValue") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetEtaParams(farg1, farg2, farg3) & +bind(C, name="_wrap_FKINSetEtaParams") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetResMonParams(farg1, farg2, farg3) & +bind(C, name="_wrap_FKINSetResMonParams") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetResMonConstValue(farg1, farg2) & +bind(C, name="_wrap_FKINSetResMonConstValue") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetNoMinEps(farg1, farg2) & +bind(C, name="_wrap_FKINSetNoMinEps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetMaxNewtonStep(farg1, farg2) & +bind(C, name="_wrap_FKINSetMaxNewtonStep") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetMaxBetaFails(farg1, farg2) & +bind(C, name="_wrap_FKINSetMaxBetaFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_LONG), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetRelErrFunc(farg1, farg2) & +bind(C, name="_wrap_FKINSetRelErrFunc") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetFuncNormTol(farg1, farg2) & +bind(C, name="_wrap_FKINSetFuncNormTol") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetScaledStepTol(farg1, farg2) & +bind(C, name="_wrap_FKINSetScaledStepTol") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetConstraints(farg1, farg2) & +bind(C, name="_wrap_FKINSetConstraints") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetSysFunc(farg1, farg2) & +bind(C, name="_wrap_FKINSetSysFunc") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FKINGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetNumNonlinSolvIters(farg1, farg2) & +bind(C, name="_wrap_FKINGetNumNonlinSolvIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetNumFuncEvals(farg1, farg2) & +bind(C, name="_wrap_FKINGetNumFuncEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetNumBetaCondFails(farg1, farg2) & +bind(C, name="_wrap_FKINGetNumBetaCondFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetNumBacktrackOps(farg1, farg2) & +bind(C, name="_wrap_FKINGetNumBacktrackOps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetFuncNorm(farg1, farg2) & +bind(C, name="_wrap_FKINGetFuncNorm") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetStepLength(farg1, farg2) & +bind(C, name="_wrap_FKINGetStepLength") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + + subroutine SWIG_free(cptr) & + bind(C, name="free") + use, intrinsic :: ISO_C_BINDING + type(C_PTR), value :: cptr +end subroutine +function swigc_FKINGetReturnFlagName(farg1) & +bind(C, name="_wrap_FKINGetReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +subroutine swigc_FKINFree(farg1) & +bind(C, name="_wrap_FKINFree") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FKINBBDPrecInit(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) & +bind(C, name="_wrap_FKINBBDPrecInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +integer(C_INT64_T), intent(in) :: farg5 +integer(C_INT64_T), intent(in) :: farg6 +real(C_DOUBLE), intent(in) :: farg7 +type(C_FUNPTR), value :: farg8 +type(C_FUNPTR), value :: farg9 +integer(C_INT) :: fresult +end function + +function swigc_FKINBBDPrecGetWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FKINBBDPrecGetWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FKINBBDPrecGetNumGfnEvals(farg1, farg2) & +bind(C, name="_wrap_FKINBBDPrecGetNumGfnEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetLinearSolver(farg1, farg2, farg3) & +bind(C, name="_wrap_FKINSetLinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetJacFn(farg1, farg2) & +bind(C, name="_wrap_FKINSetJacFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetPreconditioner(farg1, farg2, farg3) & +bind(C, name="_wrap_FKINSetPreconditioner") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FKINSetJacTimesVecFn(farg1, farg2) & +bind(C, name="_wrap_FKINSetJacTimesVecFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetLinWorkSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FKINGetLinWorkSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetNumJacEvals(farg1, farg2) & +bind(C, name="_wrap_FKINGetNumJacEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetNumLinFuncEvals(farg1, farg2) & +bind(C, name="_wrap_FKINGetNumLinFuncEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetNumPrecEvals(farg1, farg2) & +bind(C, name="_wrap_FKINGetNumPrecEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetNumPrecSolves(farg1, farg2) & +bind(C, name="_wrap_FKINGetNumPrecSolves") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetNumLinIters(farg1, farg2) & +bind(C, name="_wrap_FKINGetNumLinIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetNumLinConvFails(farg1, farg2) & +bind(C, name="_wrap_FKINGetNumLinConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetNumJtimesEvals(farg1, farg2) & +bind(C, name="_wrap_FKINGetNumJtimesEvals") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetLastLinFlag(farg1, farg2) & +bind(C, name="_wrap_FKINGetLastLinFlag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FKINGetLinReturnFlagName(farg1) & +bind(C, name="_wrap_FKINGetLinReturnFlagName") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +integer(C_LONG), intent(in) :: farg1 +type(SwigArrayWrapper) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FKINCreate() & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +type(C_PTR) :: fresult + +fresult = swigc_FKINCreate() +swig_result = fresult +end function + +function FKINInit(kinmem, func, tmpl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(C_FUNPTR), intent(in), value :: func +type(N_Vector), target, intent(inout) :: tmpl +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = kinmem +farg2 = func +farg3 = c_loc(tmpl) +fresult = swigc_FKINInit(farg1, farg2, farg3) +swig_result = fresult +end function + +function FKINSol(kinmem, uu, strategy, u_scale, f_scale) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(N_Vector), target, intent(inout) :: uu +integer(C_INT), intent(in) :: strategy +type(N_Vector), target, intent(inout) :: u_scale +type(N_Vector), target, intent(inout) :: f_scale +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = kinmem +farg2 = c_loc(uu) +farg3 = strategy +farg4 = c_loc(u_scale) +farg5 = c_loc(f_scale) +fresult = swigc_FKINSol(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FKINSetErrHandlerFn(kinmem, ehfun, eh_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(C_FUNPTR), intent(in), value :: ehfun +type(C_PTR) :: eh_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = kinmem +farg2 = ehfun +farg3 = eh_data +fresult = swigc_FKINSetErrHandlerFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FKINSetErrFile(kinmem, errfp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(C_PTR) :: errfp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = errfp +fresult = swigc_FKINSetErrFile(farg1, farg2) +swig_result = fresult +end function + +function FKINSetInfoHandlerFn(kinmem, ihfun, ih_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(C_FUNPTR), intent(in), value :: ihfun +type(C_PTR) :: ih_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = kinmem +farg2 = ihfun +farg3 = ih_data +fresult = swigc_FKINSetInfoHandlerFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FKINSetInfoFile(kinmem, infofp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(C_PTR) :: infofp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = infofp +fresult = swigc_FKINSetInfoFile(farg1, farg2) +swig_result = fresult +end function + +function FKINSetUserData(kinmem, user_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(C_PTR) :: user_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = user_data +fresult = swigc_FKINSetUserData(farg1, farg2) +swig_result = fresult +end function + +function FKINSetPrintLevel(kinmemm, printfl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmemm +integer(C_INT), intent(in) :: printfl +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = kinmemm +farg2 = printfl +fresult = swigc_FKINSetPrintLevel(farg1, farg2) +swig_result = fresult +end function + +function FKINSetMAA(kinmem, maa) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), intent(in) :: maa +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = kinmem +farg2 = maa +fresult = swigc_FKINSetMAA(farg1, farg2) +swig_result = fresult +end function + +function FKINSetDampingAA(kinmem, beta) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +real(C_DOUBLE), intent(in) :: beta +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = kinmem +farg2 = beta +fresult = swigc_FKINSetDampingAA(farg1, farg2) +swig_result = fresult +end function + +function FKINSetNumMaxIters(kinmem, mxiter) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), intent(in) :: mxiter +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = kinmem +farg2 = mxiter +fresult = swigc_FKINSetNumMaxIters(farg1, farg2) +swig_result = fresult +end function + +function FKINSetNoInitSetup(kinmem, noinitsetup) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_INT), intent(in) :: noinitsetup +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = kinmem +farg2 = noinitsetup +fresult = swigc_FKINSetNoInitSetup(farg1, farg2) +swig_result = fresult +end function + +function FKINSetNoResMon(kinmem, nonniresmon) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_INT), intent(in) :: nonniresmon +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = kinmem +farg2 = nonniresmon +fresult = swigc_FKINSetNoResMon(farg1, farg2) +swig_result = fresult +end function + +function FKINSetMaxSetupCalls(kinmem, msbset) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), intent(in) :: msbset +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = kinmem +farg2 = msbset +fresult = swigc_FKINSetMaxSetupCalls(farg1, farg2) +swig_result = fresult +end function + +function FKINSetMaxSubSetupCalls(kinmem, msbsetsub) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), intent(in) :: msbsetsub +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = kinmem +farg2 = msbsetsub +fresult = swigc_FKINSetMaxSubSetupCalls(farg1, farg2) +swig_result = fresult +end function + +function FKINSetEtaForm(kinmem, etachoice) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_INT), intent(in) :: etachoice +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = kinmem +farg2 = etachoice +fresult = swigc_FKINSetEtaForm(farg1, farg2) +swig_result = fresult +end function + +function FKINSetEtaConstValue(kinmem, eta) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +real(C_DOUBLE), intent(in) :: eta +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = kinmem +farg2 = eta +fresult = swigc_FKINSetEtaConstValue(farg1, farg2) +swig_result = fresult +end function + +function FKINSetEtaParams(kinmem, egamma, ealpha) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +real(C_DOUBLE), intent(in) :: egamma +real(C_DOUBLE), intent(in) :: ealpha +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = kinmem +farg2 = egamma +farg3 = ealpha +fresult = swigc_FKINSetEtaParams(farg1, farg2, farg3) +swig_result = fresult +end function + +function FKINSetResMonParams(kinmem, omegamin, omegamax) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +real(C_DOUBLE), intent(in) :: omegamin +real(C_DOUBLE), intent(in) :: omegamax +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +real(C_DOUBLE) :: farg3 + +farg1 = kinmem +farg2 = omegamin +farg3 = omegamax +fresult = swigc_FKINSetResMonParams(farg1, farg2, farg3) +swig_result = fresult +end function + +function FKINSetResMonConstValue(kinmem, omegaconst) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +real(C_DOUBLE), intent(in) :: omegaconst +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = kinmem +farg2 = omegaconst +fresult = swigc_FKINSetResMonConstValue(farg1, farg2) +swig_result = fresult +end function + +function FKINSetNoMinEps(kinmem, nomineps) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_INT), intent(in) :: nomineps +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = kinmem +farg2 = nomineps +fresult = swigc_FKINSetNoMinEps(farg1, farg2) +swig_result = fresult +end function + +function FKINSetMaxNewtonStep(kinmem, mxnewtstep) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +real(C_DOUBLE), intent(in) :: mxnewtstep +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = kinmem +farg2 = mxnewtstep +fresult = swigc_FKINSetMaxNewtonStep(farg1, farg2) +swig_result = fresult +end function + +function FKINSetMaxBetaFails(kinmem, mxnbcf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), intent(in) :: mxnbcf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_LONG) :: farg2 + +farg1 = kinmem +farg2 = mxnbcf +fresult = swigc_FKINSetMaxBetaFails(farg1, farg2) +swig_result = fresult +end function + +function FKINSetRelErrFunc(kinmem, relfunc) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +real(C_DOUBLE), intent(in) :: relfunc +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = kinmem +farg2 = relfunc +fresult = swigc_FKINSetRelErrFunc(farg1, farg2) +swig_result = fresult +end function + +function FKINSetFuncNormTol(kinmem, fnormtol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +real(C_DOUBLE), intent(in) :: fnormtol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = kinmem +farg2 = fnormtol +fresult = swigc_FKINSetFuncNormTol(farg1, farg2) +swig_result = fresult +end function + +function FKINSetScaledStepTol(kinmem, scsteptol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +real(C_DOUBLE), intent(in) :: scsteptol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = kinmem +farg2 = scsteptol +fresult = swigc_FKINSetScaledStepTol(farg1, farg2) +swig_result = fresult +end function + +function FKINSetConstraints(kinmem, constraints) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(N_Vector), target, intent(inout) :: constraints +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(constraints) +fresult = swigc_FKINSetConstraints(farg1, farg2) +swig_result = fresult +end function + +function FKINSetSysFunc(kinmem, func) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(C_FUNPTR), intent(in), value :: func +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = kinmem +farg2 = func +fresult = swigc_FKINSetSysFunc(farg1, farg2) +swig_result = fresult +end function + +function FKINGetWorkSpace(kinmem, lenrw, leniw) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrw +integer(C_LONG), dimension(*), target, intent(inout) :: leniw +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = kinmem +farg2 = c_loc(lenrw(1)) +farg3 = c_loc(leniw(1)) +fresult = swigc_FKINGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FKINGetNumNonlinSolvIters(kinmem, nniters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: nniters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(nniters(1)) +fresult = swigc_FKINGetNumNonlinSolvIters(farg1, farg2) +swig_result = fresult +end function + +function FKINGetNumFuncEvals(kinmem, nfevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(nfevals(1)) +fresult = swigc_FKINGetNumFuncEvals(farg1, farg2) +swig_result = fresult +end function + +function FKINGetNumBetaCondFails(kinmem, nbcfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: nbcfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(nbcfails(1)) +fresult = swigc_FKINGetNumBetaCondFails(farg1, farg2) +swig_result = fresult +end function + +function FKINGetNumBacktrackOps(kinmem, nbacktr) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: nbacktr +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(nbacktr(1)) +fresult = swigc_FKINGetNumBacktrackOps(farg1, farg2) +swig_result = fresult +end function + +function FKINGetFuncNorm(kinmem, fnorm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +real(C_DOUBLE), dimension(*), target, intent(inout) :: fnorm +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(fnorm(1)) +fresult = swigc_FKINGetFuncNorm(farg1, farg2) +swig_result = fresult +end function + +function FKINGetStepLength(kinmem, steplength) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +real(C_DOUBLE), dimension(*), target, intent(inout) :: steplength +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(steplength(1)) +fresult = swigc_FKINGetStepLength(farg1, farg2) +swig_result = fresult +end function + + +subroutine SWIG_chararray_to_string(wrap, string) + use, intrinsic :: ISO_C_BINDING + type(SwigArrayWrapper), intent(IN) :: wrap + character(kind=C_CHAR, len=:), allocatable, intent(OUT) :: string + character(kind=C_CHAR), dimension(:), pointer :: chars + integer(kind=C_SIZE_T) :: i + call c_f_pointer(wrap%data, chars, [wrap%size]) + allocate(character(kind=C_CHAR, len=wrap%size) :: string) + do i=1, wrap%size + string(i:i) = chars(i) + end do +end subroutine + +function FKINGetReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FKINGetReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + +subroutine FKINFree(kinmem) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), target, intent(inout) :: kinmem +type(C_PTR) :: farg1 + +farg1 = c_loc(kinmem) +call swigc_FKINFree(farg1) +end subroutine + +function FKINBBDPrecInit(kinmem, nlocal, mudq, mldq, mukeep, mlkeep, dq_rel_uu, gloc, gcomm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_INT64_T), intent(in) :: nlocal +integer(C_INT64_T), intent(in) :: mudq +integer(C_INT64_T), intent(in) :: mldq +integer(C_INT64_T), intent(in) :: mukeep +integer(C_INT64_T), intent(in) :: mlkeep +real(C_DOUBLE), intent(in) :: dq_rel_uu +type(C_FUNPTR), intent(in), value :: gloc +type(C_FUNPTR), intent(in), value :: gcomm +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 +integer(C_INT64_T) :: farg5 +integer(C_INT64_T) :: farg6 +real(C_DOUBLE) :: farg7 +type(C_FUNPTR) :: farg8 +type(C_FUNPTR) :: farg9 + +farg1 = kinmem +farg2 = nlocal +farg3 = mudq +farg4 = mldq +farg5 = mukeep +farg6 = mlkeep +farg7 = dq_rel_uu +farg8 = gloc +farg9 = gcomm +fresult = swigc_FKINBBDPrecInit(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) +swig_result = fresult +end function + +function FKINBBDPrecGetWorkSpace(kinmem, lenrwbbdp, leniwbbdp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwbbdp +integer(C_LONG), dimension(*), target, intent(inout) :: leniwbbdp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = kinmem +farg2 = c_loc(lenrwbbdp(1)) +farg3 = c_loc(leniwbbdp(1)) +fresult = swigc_FKINBBDPrecGetWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FKINBBDPrecGetNumGfnEvals(kinmem, ngevalsbbdp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: ngevalsbbdp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(ngevalsbbdp(1)) +fresult = swigc_FKINBBDPrecGetNumGfnEvals(farg1, farg2) +swig_result = fresult +end function + +function FKINSetLinearSolver(kinmem, ls, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(SUNLinearSolver), target, intent(inout) :: ls +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = kinmem +farg2 = c_loc(ls) +farg3 = c_loc(a) +fresult = swigc_FKINSetLinearSolver(farg1, farg2, farg3) +swig_result = fresult +end function + +function FKINSetJacFn(kinmem, jac) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(C_FUNPTR), intent(in), value :: jac +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = kinmem +farg2 = jac +fresult = swigc_FKINSetJacFn(farg1, farg2) +swig_result = fresult +end function + +function FKINSetPreconditioner(kinmem, psetup, psolve) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(C_FUNPTR), intent(in), value :: psetup +type(C_FUNPTR), intent(in), value :: psolve +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = kinmem +farg2 = psetup +farg3 = psolve +fresult = swigc_FKINSetPreconditioner(farg1, farg2, farg3) +swig_result = fresult +end function + +function FKINSetJacTimesVecFn(kinmem, jtv) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +type(C_FUNPTR), intent(in), value :: jtv +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = kinmem +farg2 = jtv +fresult = swigc_FKINSetJacTimesVecFn(farg1, farg2) +swig_result = fresult +end function + +function FKINGetLinWorkSpace(kinmem, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = kinmem +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FKINGetLinWorkSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FKINGetNumJacEvals(kinmem, njevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: njevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(njevals(1)) +fresult = swigc_FKINGetNumJacEvals(farg1, farg2) +swig_result = fresult +end function + +function FKINGetNumLinFuncEvals(kinmem, nfevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: nfevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(nfevals(1)) +fresult = swigc_FKINGetNumLinFuncEvals(farg1, farg2) +swig_result = fresult +end function + +function FKINGetNumPrecEvals(kinmem, npevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: npevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(npevals(1)) +fresult = swigc_FKINGetNumPrecEvals(farg1, farg2) +swig_result = fresult +end function + +function FKINGetNumPrecSolves(kinmem, npsolves) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: npsolves +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(npsolves(1)) +fresult = swigc_FKINGetNumPrecSolves(farg1, farg2) +swig_result = fresult +end function + +function FKINGetNumLinIters(kinmem, nliters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: nliters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(nliters(1)) +fresult = swigc_FKINGetNumLinIters(farg1, farg2) +swig_result = fresult +end function + +function FKINGetNumLinConvFails(kinmem, nlcfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: nlcfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(nlcfails(1)) +fresult = swigc_FKINGetNumLinConvFails(farg1, farg2) +swig_result = fresult +end function + +function FKINGetNumJtimesEvals(kinmem, njvevals) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: njvevals +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(njvevals(1)) +fresult = swigc_FKINGetNumJtimesEvals(farg1, farg2) +swig_result = fresult +end function + +function FKINGetLastLinFlag(kinmem, flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: kinmem +integer(C_LONG), dimension(*), target, intent(inout) :: flag +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = kinmem +farg2 = c_loc(flag(1)) +fresult = swigc_FKINGetLastLinFlag(farg1, farg2) +swig_result = fresult +end function + +function FKINGetLinReturnFlagName(flag) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +character(kind=C_CHAR, len=:), allocatable :: swig_result +integer(C_LONG), intent(in) :: flag +type(SwigArrayWrapper) :: fresult +integer(C_LONG) :: farg1 + +farg1 = flag +fresult = swigc_FKINGetLinReturnFlagName(farg1) +call SWIG_chararray_to_string(fresult, swig_result) +if (.false.) call SWIG_free(fresult%data) +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol.c index a9ad2e956..6d098a19c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol.c @@ -4,7 +4,7 @@ * John Loffeld, and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -57,7 +57,7 @@ * ----------------------------------------------------------------- */ -/* +/* * ================================================================= * IMPORTED HEADER FILES * ================================================================= @@ -73,7 +73,7 @@ #include "kinsol_impl.h" #include -/* +/* * ================================================================= * KINSOL PRIVATE CONSTANTS * ================================================================= @@ -96,14 +96,14 @@ #define POINT9 RCONST(0.9) #define POINT0001 RCONST(0.0001) -/* +/* * ================================================================= * KINSOL ROUTINE-SPECIFIC CONSTANTS * ================================================================= */ -/* - * Control constants for lower-level functions used by KINSol +/* + * Control constants for lower-level functions used by KINSol * ---------------------------------------------------------- * * KINStop return value requesting more iterations @@ -152,7 +152,7 @@ #define PRNT_ALPHABETA 11 #define PRNT_ADJ 12 -/* +/* * ================================================================= * PRIVATE FUNCTION PROTOTYPES * ================================================================= @@ -165,32 +165,31 @@ static int KINConstraint(KINMem kin_mem ); static void KINForcingTerm(KINMem kin_mem, realtype fnormp); static void KINFreeVectors(KINMem kin_mem); -static int KINFullNewton(KINMem kin_mem, realtype *fnormp, +static int KINFullNewton(KINMem kin_mem, realtype *fnormp, realtype *f1normp, booleantype *maxStepTaken); -static int KINLineSearch(KINMem kin_mem, realtype *fnormp, +static int KINLineSearch(KINMem kin_mem, realtype *fnormp, realtype *f1normp, booleantype *maxStepTaken); -static int KINPicardAA(KINMem kin_mem, long int *iter, realtype *R, - realtype *gamma, realtype *fmax); -static int KINFP(KINMem kin_mem, long int *iter, realtype *R, - realtype *gamma, realtype *fmax); +static int KINPicardAA(KINMem kin_mem, long int *iter, realtype *R, + realtype *gamma, realtype *fmax); +static int KINFP(KINMem kin_mem); static int KINLinSolDrv(KINMem kinmem); -static int KINPicardFcnEval(KINMem kin_mem, N_Vector gval, N_Vector uval, - N_Vector fval1); +static int KINPicardFcnEval(KINMem kin_mem, N_Vector gval, N_Vector uval, + N_Vector fval1); static realtype KINScFNorm(KINMem kin_mem, N_Vector v, N_Vector scale); static realtype KINScSNorm(KINMem kin_mem, N_Vector v, N_Vector u); -static int KINStop(KINMem kin_mem, booleantype maxStepTaken, - int sflag); -static int AndersonAcc(KINMem kin_mem, N_Vector gval, N_Vector fv, N_Vector x, - N_Vector x_old, int iter, realtype *R, realtype *gamma); +static int KINStop(KINMem kin_mem, booleantype maxStepTaken, + int sflag); +static int AndersonAcc(KINMem kin_mem, N_Vector gval, N_Vector fv, N_Vector x, + N_Vector x_old, long int iter, realtype *R, realtype *gamma); -/* +/* * ================================================================= * EXPORTED FUNCTIONS IMPLEMENTATION * ================================================================= */ -/* +/* * ----------------------------------------------------------------- * Creation and allocation functions * ----------------------------------------------------------------- @@ -199,18 +198,18 @@ static int AndersonAcc(KINMem kin_mem, N_Vector gval, N_Vector fv, N_Vector x, /* * Function : KINCreate * - * KINCreate creates an internal memory block for a problem to + * KINCreate creates an internal memory block for a problem to * be solved by KINSOL. If successful, KINCreate returns a pointer * to the problem memory. This pointer should be passed to * KINInit. If an initialization error occurs, KINCreate prints - * an error message to standard error and returns NULL. + * an error message to standard error and returns NULL. */ void *KINCreate(void) { KINMem kin_mem; realtype uround; - + kin_mem = NULL; kin_mem = (KINMem) malloc(sizeof(struct KINMemRec)); if (kin_mem == NULL) { @@ -224,14 +223,21 @@ void *KINCreate(void) /* set uround (unit roundoff) */ kin_mem->kin_uround = uround = UNIT_ROUNDOFF; - + /* set default values for solver optional inputs */ kin_mem->kin_func = NULL; kin_mem->kin_user_data = NULL; - kin_mem->kin_constraints = NULL; + kin_mem->kin_uu = NULL; + kin_mem->kin_unew = NULL; + kin_mem->kin_fval = NULL; + kin_mem->kin_gval = NULL; kin_mem->kin_uscale = NULL; kin_mem->kin_fscale = NULL; + kin_mem->kin_pp = NULL; + kin_mem->kin_constraints = NULL; + kin_mem->kin_vtemp1 = NULL; + kin_mem->kin_vtemp2 = NULL; kin_mem->kin_fold_aa = NULL; kin_mem->kin_gold_aa = NULL; kin_mem->kin_df_aa = NULL; @@ -239,11 +245,15 @@ void *KINCreate(void) kin_mem->kin_q_aa = NULL; kin_mem->kin_gamma_aa = NULL; kin_mem->kin_R_aa = NULL; + kin_mem->kin_ipt_map = NULL; kin_mem->kin_cv = NULL; kin_mem->kin_Xv = NULL; - kin_mem->kin_m_aa = ZERO; + kin_mem->kin_lmem = NULL; + kin_mem->kin_m_aa = 0; kin_mem->kin_aamem_aa = 0; kin_mem->kin_setstop_aa = 0; + kin_mem->kin_beta_aa = ONE; + kin_mem->kin_damping_aa = SUNFALSE; kin_mem->kin_constraintsSet = SUNFALSE; kin_mem->kin_ehfun = KINErrHandler; kin_mem->kin_eh_data = kin_mem; @@ -291,7 +301,7 @@ void *KINCreate(void) /* * Function : KINInit * - * KINInit allocates memory for a problem or execution of KINSol. + * KINInit allocates memory for a problem or execution of KINSol. * If memory is successfully allocated, KIN_SUCCESS is returned. * Otherwise, an error message is printed and an error flag * returned. @@ -302,7 +312,7 @@ int KINInit(void *kinmem, KINSysFn func, N_Vector tmpl) sunindextype liw1, lrw1; KINMem kin_mem; booleantype allocOK, nvectorOK; - + /* check kinmem */ if (kinmem == NULL) { @@ -356,7 +366,7 @@ int KINInit(void *kinmem, KINSysFn func, N_Vector tmpl) kin_mem->kin_lsolve = NULL; kin_mem->kin_lfree = NULL; kin_mem->kin_lmem = NULL; - + /* problem memory has been successfully allocated */ kin_mem->kin_MallocDone = SUNTRUE; @@ -364,7 +374,7 @@ int KINInit(void *kinmem, KINSysFn func, N_Vector tmpl) return(KIN_SUCCESS); } -/* +/* * ----------------------------------------------------------------- * Main solver function * ----------------------------------------------------------------- @@ -392,7 +402,7 @@ int KINInit(void *kinmem, KINSysFn func, N_Vector tmpl) * KINStop determines if an approximate solution has been found */ -int KINSol(void *kinmem, N_Vector u, int strategy_in, +int KINSol(void *kinmem, N_Vector u, int strategy_in, N_Vector u_scale, N_Vector f_scale) { realtype fnormp, f1normp, epsmin, fmax=ZERO; @@ -418,7 +428,7 @@ int KINSol(void *kinmem, N_Vector u, int strategy_in, kin_mem = (KINMem) kinmem; if(kin_mem->kin_MallocDone == SUNFALSE) { - KINProcessError(NULL, KIN_NO_MALLOC, "KINSOL", "KINSol", MSG_NO_MALLOC); + KINProcessError(NULL, KIN_NO_MALLOC, "KINSOL", "KINSol", MSG_NO_MALLOC); return(KIN_NO_MALLOC); } @@ -429,7 +439,7 @@ int KINSol(void *kinmem, N_Vector u, int strategy_in, kin_mem->kin_fscale = f_scale; kin_mem->kin_globalstrategy = strategy_in; - /* CSW: + /* CSW: Call fixed point solver if requested. Note that this should probably be forked off to a FPSOL solver instead of kinsol in the future. */ if ( kin_mem->kin_globalstrategy == KIN_FP ) { @@ -447,7 +457,7 @@ int KINSol(void *kinmem, N_Vector u, int strategy_in, KINPrintInfo(kin_mem, PRNT_TOL, "KINSOL", "KINSol", INFO_TOL, kin_mem->kin_scsteptol, kin_mem->kin_fnormtol); kin_mem->kin_nfe = kin_mem->kin_nnilset = kin_mem->kin_nnilset_sub = kin_mem->kin_nni = kin_mem->kin_nbcf = kin_mem->kin_nbktrk = 0; - ret = KINFP(kin_mem, &(kin_mem->kin_nni), kin_mem->kin_R_aa, kin_mem->kin_gamma_aa, &fmax); + ret = KINFP(kin_mem); switch(ret) { case KIN_SYSFUNC_FAIL: @@ -476,24 +486,32 @@ int KINSol(void *kinmem, N_Vector u, int strategy_in, /* if eps is to be bounded from below, set the bound */ - if (kin_mem->kin_inexact_ls && !(kin_mem->kin_noMinEps)) epsmin = POINT01 * kin_mem->kin_fnormtol; + if (kin_mem->kin_inexact_ls && !(kin_mem->kin_noMinEps)) + epsmin = POINT01 * kin_mem->kin_fnormtol; /* if omega is zero at this point, make sure it will be evaluated at each iteration based on the provided min/max bounds and the current function norm. */ if (kin_mem->kin_omega == ZERO) kin_mem->kin_eval_omega = SUNTRUE; - else kin_mem->kin_eval_omega = SUNFALSE; - + else kin_mem->kin_eval_omega = SUNFALSE; - /* CSW: - Call fixed point solver for Picard method if requested. - Note that this should probably be forked off to a part of an + + /* CSW: + Call fixed point solver for Picard method if requested. + Note that this should probably be forked off to a part of an FPSOL solver instead of kinsol in the future. */ if ( kin_mem->kin_globalstrategy == KIN_PICARD ) { - kin_mem->kin_gval = N_VClone(kin_mem->kin_unew); - kin_mem->kin_lrw += kin_mem->kin_lrw1; + if (kin_mem->kin_gval == NULL) { + kin_mem->kin_gval = N_VClone(kin_mem->kin_unew); + if (kin_mem->kin_gval == NULL) { + KINProcessError(kin_mem, KIN_MEM_FAIL, "KINSOL", "KINSol", MSG_MEM_FAIL); + return(KIN_MEM_FAIL); + } + kin_mem->kin_liw += kin_mem->kin_liw1; + kin_mem->kin_lrw += kin_mem->kin_lrw1; + } ret = KINPicardAA(kin_mem, &(kin_mem->kin_nni), kin_mem->kin_R_aa, kin_mem->kin_gamma_aa, &fmax); return(ret); @@ -524,7 +542,7 @@ int KINSol(void *kinmem, N_Vector u, int strategy_in, /* Full Newton Step*/ - /* call KINLinSolDrv to calculate the (approximate) Newton step, pp */ + /* call KINLinSolDrv to calculate the (approximate) Newton step, pp */ ret = KINLinSolDrv(kin_mem); if (ret != KIN_SUCCESS) break; @@ -540,7 +558,7 @@ int KINSol(void *kinmem, N_Vector u, int strategy_in, /* Line Search */ - /* call KINLinSolDrv to calculate the (approximate) Newton step, pp */ + /* call KINLinSolDrv to calculate the (approximate) Newton step, pp */ ret = KINLinSolDrv(kin_mem); if (ret != KIN_SUCCESS) break; @@ -560,19 +578,20 @@ int KINSol(void *kinmem, N_Vector u, int strategy_in, } - if ( (kin_mem->kin_globalstrategy != KIN_PICARD) && (kin_mem->kin_globalstrategy != KIN_FP) ) { - + if ( (kin_mem->kin_globalstrategy != KIN_PICARD) && + (kin_mem->kin_globalstrategy != KIN_FP) ) { + /* evaluate eta by calling the forcing term routine */ if (kin_mem->kin_callForcingTerm) KINForcingTerm(kin_mem, fnormp); kin_mem->kin_fnorm = fnormp; /* call KINStop to check if tolerances where met by this iteration */ - ret = KINStop(kin_mem, maxStepTaken, sflag); + ret = KINStop(kin_mem, maxStepTaken, sflag); if (ret == RETRY_ITERATION) { - kin_mem->kin_retry_nni = SUNTRUE; - goto repeat_nni; + kin_mem->kin_retry_nni = SUNTRUE; + goto repeat_nni; } } @@ -586,10 +605,10 @@ int KINSol(void *kinmem, N_Vector u, int strategy_in, if (kin_mem->kin_printfl > 0) KINPrintInfo(kin_mem, PRNT_NNI, "KINSOL", "KINSol", INFO_NNI, kin_mem->kin_nni, kin_mem->kin_nfe, kin_mem->kin_fnorm); - if (ret != CONTINUE_ITERATIONS) break; + if (ret != CONTINUE_ITERATIONS) break; fflush(kin_mem->kin_errfp); - + } /* end of loop; return */ @@ -626,11 +645,11 @@ int KINSol(void *kinmem, N_Vector u, int strategy_in, KINProcessError(kin_mem, KIN_MXNEWT_5X_EXCEEDED, "KINSOL", "KINSol", MSG_MXNEWT_5X_EXCEEDED); break; } - + return(ret); } -/* +/* * ----------------------------------------------------------------- * Deallocation function * ----------------------------------------------------------------- @@ -662,7 +681,7 @@ void KINFree(void **kinmem) *kinmem = NULL; } -/* +/* * ================================================================= * PRIVATE FUNCTIONS * ================================================================= @@ -693,7 +712,7 @@ static booleantype KINCheckNvector(N_Vector tmpl) else return(SUNTRUE); } -/* +/* * ----------------------------------------------------------------- * Memory allocation/deallocation * ----------------------------------------------------------------- @@ -710,202 +729,275 @@ static booleantype KINCheckNvector(N_Vector tmpl) static booleantype KINAllocVectors(KINMem kin_mem, N_Vector tmpl) { - /* allocate unew, fval, pp, vtemp1 and vtemp2. */ + /* allocate unew, fval, pp, vtemp1 and vtemp2. */ /* allocate df, dg, q, for Anderson Acceleration, Broyden and EN */ - - kin_mem->kin_unew = N_VClone(tmpl); - if (kin_mem->kin_unew == NULL) return(SUNFALSE); - kin_mem->kin_fval = N_VClone(tmpl); + if (kin_mem->kin_unew == NULL) { + kin_mem->kin_unew = N_VClone(tmpl); + if (kin_mem->kin_unew == NULL) return(SUNFALSE); + kin_mem->kin_liw += kin_mem->kin_liw1; + kin_mem->kin_lrw += kin_mem->kin_lrw1; + } + if (kin_mem->kin_fval == NULL) { - N_VDestroy(kin_mem->kin_unew); - return(SUNFALSE); + kin_mem->kin_fval = N_VClone(tmpl); + if (kin_mem->kin_fval == NULL) { + N_VDestroy(kin_mem->kin_unew); + kin_mem->kin_liw -= kin_mem->kin_liw1; + kin_mem->kin_lrw -= kin_mem->kin_lrw1; + return(SUNFALSE); + } + kin_mem->kin_liw += kin_mem->kin_liw1; + kin_mem->kin_lrw += kin_mem->kin_lrw1; } - kin_mem->kin_pp = N_VClone(tmpl); if (kin_mem->kin_pp == NULL) { - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - return(SUNFALSE); + kin_mem->kin_pp = N_VClone(tmpl); + if (kin_mem->kin_pp == NULL) { + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + kin_mem->kin_liw -= 2*kin_mem->kin_liw1; + kin_mem->kin_lrw -= 2*kin_mem->kin_lrw1; + return(SUNFALSE); + } + kin_mem->kin_liw += kin_mem->kin_liw1; + kin_mem->kin_lrw += kin_mem->kin_lrw1; } - kin_mem->kin_vtemp1 = N_VClone(tmpl); if (kin_mem->kin_vtemp1 == NULL) { - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - N_VDestroy(kin_mem->kin_pp); - return(SUNFALSE); + kin_mem->kin_vtemp1 = N_VClone(tmpl); + if (kin_mem->kin_vtemp1 == NULL) { + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + N_VDestroy(kin_mem->kin_pp); + kin_mem->kin_liw -= 3*kin_mem->kin_liw1; + kin_mem->kin_lrw -= 3*kin_mem->kin_lrw1; + return(SUNFALSE); + } + kin_mem->kin_liw += kin_mem->kin_liw1; + kin_mem->kin_lrw += kin_mem->kin_lrw1; } - kin_mem->kin_vtemp2 = N_VClone(tmpl); if (kin_mem->kin_vtemp2 == NULL) { - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - N_VDestroy(kin_mem->kin_pp); - N_VDestroy(kin_mem->kin_vtemp1); - return(SUNFALSE); + kin_mem->kin_vtemp2 = N_VClone(tmpl); + if (kin_mem->kin_vtemp2 == NULL) { + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + N_VDestroy(kin_mem->kin_pp); + N_VDestroy(kin_mem->kin_vtemp1); + kin_mem->kin_liw -= 4*kin_mem->kin_liw1; + kin_mem->kin_lrw -= 4*kin_mem->kin_lrw1; + return(SUNFALSE); + } + kin_mem->kin_liw += kin_mem->kin_liw1; + kin_mem->kin_lrw += kin_mem->kin_lrw1; } - /* update solver workspace lengths */ - - kin_mem->kin_liw += 5*kin_mem->kin_liw1; - kin_mem->kin_lrw += 5*kin_mem->kin_lrw1; + /* Vectors for Anderson acceleration */ if (kin_mem->kin_m_aa) { - kin_mem->kin_R_aa = (realtype *) malloc((kin_mem->kin_m_aa*kin_mem->kin_m_aa) * sizeof(realtype)); + if (kin_mem->kin_R_aa == NULL) { - KINProcessError(kin_mem, 0, "KINSOL", "KINAllocVectors", MSG_MEM_FAIL); - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - N_VDestroy(kin_mem->kin_pp); - N_VDestroy(kin_mem->kin_vtemp1); - N_VDestroy(kin_mem->kin_vtemp2); - return(KIN_MEM_FAIL); + kin_mem->kin_R_aa = (realtype *) malloc((kin_mem->kin_m_aa*kin_mem->kin_m_aa) * sizeof(realtype)); + if (kin_mem->kin_R_aa == NULL) { + KINProcessError(kin_mem, 0, "KINSOL", "KINAllocVectors", MSG_MEM_FAIL); + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + N_VDestroy(kin_mem->kin_pp); + N_VDestroy(kin_mem->kin_vtemp1); + N_VDestroy(kin_mem->kin_vtemp2); + kin_mem->kin_liw -= 5*kin_mem->kin_liw1; + kin_mem->kin_lrw -= 5*kin_mem->kin_lrw1; + return(KIN_MEM_FAIL); + } } - kin_mem->kin_gamma_aa = (realtype *)malloc(kin_mem->kin_m_aa * sizeof(realtype)); + if (kin_mem->kin_gamma_aa == NULL) { - KINProcessError(kin_mem, 0, "KINSOL", "KINAllocVectors", MSG_MEM_FAIL); - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - N_VDestroy(kin_mem->kin_pp); - N_VDestroy(kin_mem->kin_vtemp1); - N_VDestroy(kin_mem->kin_vtemp2); - free(kin_mem->kin_R_aa); - return(KIN_MEM_FAIL); + kin_mem->kin_gamma_aa = (realtype *) malloc(kin_mem->kin_m_aa * sizeof(realtype)); + if (kin_mem->kin_gamma_aa == NULL) { + KINProcessError(kin_mem, 0, "KINSOL", "KINAllocVectors", MSG_MEM_FAIL); + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + N_VDestroy(kin_mem->kin_pp); + N_VDestroy(kin_mem->kin_vtemp1); + N_VDestroy(kin_mem->kin_vtemp2); + free(kin_mem->kin_R_aa); + kin_mem->kin_liw -= 5*kin_mem->kin_liw1; + kin_mem->kin_lrw -= 5*kin_mem->kin_lrw1; + return(KIN_MEM_FAIL); + } } - kin_mem->kin_ipt_map = (int *)malloc(kin_mem->kin_m_aa * sizeof(int)); + if (kin_mem->kin_ipt_map == NULL) { - KINProcessError(kin_mem, 0, "KINSOL", "KINAllocVectors", MSG_MEM_FAIL); - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - N_VDestroy(kin_mem->kin_pp); - N_VDestroy(kin_mem->kin_vtemp1); - N_VDestroy(kin_mem->kin_vtemp2); - free(kin_mem->kin_R_aa); - free(kin_mem->kin_gamma_aa); - return(KIN_MEM_FAIL); + kin_mem->kin_ipt_map = (long int *) malloc(kin_mem->kin_m_aa * sizeof(long int)); + if (kin_mem->kin_ipt_map == NULL) { + KINProcessError(kin_mem, 0, "KINSOL", "KINAllocVectors", MSG_MEM_FAIL); + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + N_VDestroy(kin_mem->kin_pp); + N_VDestroy(kin_mem->kin_vtemp1); + N_VDestroy(kin_mem->kin_vtemp2); + free(kin_mem->kin_R_aa); + free(kin_mem->kin_gamma_aa); + kin_mem->kin_liw -= 5*kin_mem->kin_liw1; + kin_mem->kin_lrw -= 5*kin_mem->kin_lrw1; + return(KIN_MEM_FAIL); + } } - kin_mem->kin_cv = (realtype *)malloc((kin_mem->kin_m_aa+1) * sizeof(realtype)); + if (kin_mem->kin_cv == NULL) { - KINProcessError(kin_mem, 0, "KINSOL", "KINAllocVectors", MSG_MEM_FAIL); - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - N_VDestroy(kin_mem->kin_pp); - N_VDestroy(kin_mem->kin_vtemp1); - N_VDestroy(kin_mem->kin_vtemp2); - free(kin_mem->kin_R_aa); - free(kin_mem->kin_gamma_aa); - free(kin_mem->kin_ipt_map); - return(KIN_MEM_FAIL); + kin_mem->kin_cv = (realtype *) malloc(2 * (kin_mem->kin_m_aa+1) * sizeof(realtype)); + if (kin_mem->kin_cv == NULL) { + KINProcessError(kin_mem, 0, "KINSOL", "KINAllocVectors", MSG_MEM_FAIL); + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + N_VDestroy(kin_mem->kin_pp); + N_VDestroy(kin_mem->kin_vtemp1); + N_VDestroy(kin_mem->kin_vtemp2); + free(kin_mem->kin_R_aa); + free(kin_mem->kin_gamma_aa); + free(kin_mem->kin_ipt_map); + kin_mem->kin_liw -= 5*kin_mem->kin_liw1; + kin_mem->kin_lrw -= 5*kin_mem->kin_lrw1; + return(KIN_MEM_FAIL); + } } - kin_mem->kin_Xv = (N_Vector *)malloc((kin_mem->kin_m_aa+1) * sizeof(N_Vector)); + if (kin_mem->kin_Xv == NULL) { - KINProcessError(kin_mem, 0, "KINSOL", "KINAllocVectors", MSG_MEM_FAIL); - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - N_VDestroy(kin_mem->kin_pp); - N_VDestroy(kin_mem->kin_vtemp1); - N_VDestroy(kin_mem->kin_vtemp2); - free(kin_mem->kin_R_aa); - free(kin_mem->kin_gamma_aa); - free(kin_mem->kin_ipt_map); - free(kin_mem->kin_cv); - return(KIN_MEM_FAIL); + kin_mem->kin_Xv = (N_Vector *) malloc(2 * (kin_mem->kin_m_aa+1) * sizeof(N_Vector)); + if (kin_mem->kin_Xv == NULL) { + KINProcessError(kin_mem, 0, "KINSOL", "KINAllocVectors", MSG_MEM_FAIL); + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + N_VDestroy(kin_mem->kin_pp); + N_VDestroy(kin_mem->kin_vtemp1); + N_VDestroy(kin_mem->kin_vtemp2); + free(kin_mem->kin_R_aa); + free(kin_mem->kin_gamma_aa); + free(kin_mem->kin_ipt_map); + free(kin_mem->kin_cv); + kin_mem->kin_liw -= 5*kin_mem->kin_liw1; + kin_mem->kin_lrw -= 5*kin_mem->kin_lrw1; + return(KIN_MEM_FAIL); + } } - } - if (kin_mem->kin_m_aa) { - kin_mem->kin_fold_aa = N_VClone(tmpl); if (kin_mem->kin_fold_aa == NULL) { - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - N_VDestroy(kin_mem->kin_pp); - N_VDestroy(kin_mem->kin_vtemp1); - N_VDestroy(kin_mem->kin_vtemp2); - free(kin_mem->kin_R_aa); - free(kin_mem->kin_gamma_aa); - free(kin_mem->kin_ipt_map); - free(kin_mem->kin_cv); - free(kin_mem->kin_Xv); - return(SUNFALSE); + kin_mem->kin_fold_aa = N_VClone(tmpl); + if (kin_mem->kin_fold_aa == NULL) { + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + N_VDestroy(kin_mem->kin_pp); + N_VDestroy(kin_mem->kin_vtemp1); + N_VDestroy(kin_mem->kin_vtemp2); + free(kin_mem->kin_R_aa); + free(kin_mem->kin_gamma_aa); + free(kin_mem->kin_ipt_map); + free(kin_mem->kin_cv); + free(kin_mem->kin_Xv); + kin_mem->kin_liw -= 5*kin_mem->kin_liw1; + kin_mem->kin_lrw -= 5*kin_mem->kin_lrw1; + return(SUNFALSE); + } + kin_mem->kin_liw += kin_mem->kin_liw1; + kin_mem->kin_lrw += kin_mem->kin_lrw1; } - kin_mem->kin_gold_aa = N_VClone(tmpl); + if (kin_mem->kin_gold_aa == NULL) { - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - N_VDestroy(kin_mem->kin_pp); - N_VDestroy(kin_mem->kin_vtemp1); - N_VDestroy(kin_mem->kin_vtemp2); - free(kin_mem->kin_R_aa); - free(kin_mem->kin_gamma_aa); - free(kin_mem->kin_ipt_map); - free(kin_mem->kin_cv); - free(kin_mem->kin_Xv); - N_VDestroy(kin_mem->kin_fold_aa); - return(SUNFALSE); + kin_mem->kin_gold_aa = N_VClone(tmpl); + if (kin_mem->kin_gold_aa == NULL) { + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + N_VDestroy(kin_mem->kin_pp); + N_VDestroy(kin_mem->kin_vtemp1); + N_VDestroy(kin_mem->kin_vtemp2); + free(kin_mem->kin_R_aa); + free(kin_mem->kin_gamma_aa); + free(kin_mem->kin_ipt_map); + free(kin_mem->kin_cv); + free(kin_mem->kin_Xv); + N_VDestroy(kin_mem->kin_fold_aa); + kin_mem->kin_liw -= 6*kin_mem->kin_liw1; + kin_mem->kin_lrw -= 6*kin_mem->kin_lrw1; + return(SUNFALSE); + } + kin_mem->kin_liw += kin_mem->kin_liw1; + kin_mem->kin_lrw += kin_mem->kin_lrw1; } - kin_mem->kin_df_aa = N_VCloneVectorArray(kin_mem->kin_m_aa,tmpl); + if (kin_mem->kin_df_aa == NULL) { - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - N_VDestroy(kin_mem->kin_pp); - N_VDestroy(kin_mem->kin_vtemp1); - N_VDestroy(kin_mem->kin_vtemp2); - free(kin_mem->kin_R_aa); - free(kin_mem->kin_gamma_aa); - free(kin_mem->kin_ipt_map); - free(kin_mem->kin_cv); - free(kin_mem->kin_Xv); - N_VDestroy(kin_mem->kin_fold_aa); - N_VDestroy(kin_mem->kin_gold_aa); - return(SUNFALSE); + kin_mem->kin_df_aa = N_VCloneVectorArray((int) kin_mem->kin_m_aa,tmpl); + if (kin_mem->kin_df_aa == NULL) { + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + N_VDestroy(kin_mem->kin_pp); + N_VDestroy(kin_mem->kin_vtemp1); + N_VDestroy(kin_mem->kin_vtemp2); + free(kin_mem->kin_R_aa); + free(kin_mem->kin_gamma_aa); + free(kin_mem->kin_ipt_map); + free(kin_mem->kin_cv); + free(kin_mem->kin_Xv); + N_VDestroy(kin_mem->kin_fold_aa); + N_VDestroy(kin_mem->kin_gold_aa); + kin_mem->kin_liw -= 7*kin_mem->kin_liw1; + kin_mem->kin_lrw -= 7*kin_mem->kin_lrw1; + return(SUNFALSE); + } + kin_mem->kin_liw += kin_mem->kin_m_aa * kin_mem->kin_liw1; + kin_mem->kin_lrw += kin_mem->kin_m_aa * kin_mem->kin_lrw1; } - kin_mem->kin_dg_aa = N_VCloneVectorArray(kin_mem->kin_m_aa,tmpl); + if (kin_mem->kin_dg_aa == NULL) { - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - N_VDestroy(kin_mem->kin_pp); - N_VDestroy(kin_mem->kin_vtemp1); - N_VDestroy(kin_mem->kin_vtemp2); - free(kin_mem->kin_R_aa); - free(kin_mem->kin_gamma_aa); - free(kin_mem->kin_ipt_map); - free(kin_mem->kin_cv); - free(kin_mem->kin_Xv); - N_VDestroy(kin_mem->kin_fold_aa); - N_VDestroy(kin_mem->kin_gold_aa); - N_VDestroyVectorArray(kin_mem->kin_df_aa, kin_mem->kin_m_aa); - return(SUNFALSE); + kin_mem->kin_dg_aa = N_VCloneVectorArray((int) kin_mem->kin_m_aa,tmpl); + if (kin_mem->kin_dg_aa == NULL) { + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + N_VDestroy(kin_mem->kin_pp); + N_VDestroy(kin_mem->kin_vtemp1); + N_VDestroy(kin_mem->kin_vtemp2); + free(kin_mem->kin_R_aa); + free(kin_mem->kin_gamma_aa); + free(kin_mem->kin_ipt_map); + free(kin_mem->kin_cv); + free(kin_mem->kin_Xv); + N_VDestroy(kin_mem->kin_fold_aa); + N_VDestroy(kin_mem->kin_gold_aa); + N_VDestroyVectorArray(kin_mem->kin_df_aa, (int) kin_mem->kin_m_aa); + kin_mem->kin_liw -= (7 + kin_mem->kin_m_aa) * kin_mem->kin_liw1; + kin_mem->kin_lrw -= (7 + kin_mem->kin_m_aa) * kin_mem->kin_lrw1; + return(SUNFALSE); + } + kin_mem->kin_liw += kin_mem->kin_m_aa * kin_mem->kin_liw1; + kin_mem->kin_lrw += kin_mem->kin_m_aa * kin_mem->kin_lrw1; } - /* update solver workspace lengths */ - - kin_mem->kin_liw += 2*kin_mem->kin_m_aa*kin_mem->kin_liw1+2; - kin_mem->kin_lrw += 2*kin_mem->kin_m_aa*kin_mem->kin_lrw1+2; - - if (kin_mem->kin_aamem_aa) { - kin_mem->kin_q_aa = N_VCloneVectorArray(kin_mem->kin_m_aa,tmpl); + if (kin_mem->kin_q_aa == NULL) { + kin_mem->kin_q_aa = N_VCloneVectorArray((int) kin_mem->kin_m_aa,tmpl); if (kin_mem->kin_q_aa == NULL) { - N_VDestroy(kin_mem->kin_unew); - N_VDestroy(kin_mem->kin_fval); - N_VDestroy(kin_mem->kin_pp); - N_VDestroy(kin_mem->kin_vtemp1); - N_VDestroy(kin_mem->kin_vtemp2); - free(kin_mem->kin_R_aa); - free(kin_mem->kin_gamma_aa); - free(kin_mem->kin_ipt_map); + N_VDestroy(kin_mem->kin_unew); + N_VDestroy(kin_mem->kin_fval); + N_VDestroy(kin_mem->kin_pp); + N_VDestroy(kin_mem->kin_vtemp1); + N_VDestroy(kin_mem->kin_vtemp2); + free(kin_mem->kin_R_aa); + free(kin_mem->kin_gamma_aa); + free(kin_mem->kin_ipt_map); free(kin_mem->kin_cv); free(kin_mem->kin_Xv); - N_VDestroy(kin_mem->kin_fold_aa); - N_VDestroy(kin_mem->kin_gold_aa); - N_VDestroyVectorArray(kin_mem->kin_df_aa, kin_mem->kin_m_aa); - N_VDestroyVectorArray(kin_mem->kin_dg_aa, kin_mem->kin_m_aa); - return(SUNFALSE); + N_VDestroy(kin_mem->kin_fold_aa); + N_VDestroy(kin_mem->kin_gold_aa); + N_VDestroyVectorArray(kin_mem->kin_df_aa, (int) kin_mem->kin_m_aa); + N_VDestroyVectorArray(kin_mem->kin_dg_aa, (int) kin_mem->kin_m_aa); + kin_mem->kin_liw -= (7 + 2 * kin_mem->kin_m_aa) * kin_mem->kin_liw1; + kin_mem->kin_lrw -= (7 + 2 * kin_mem->kin_m_aa) * kin_mem->kin_lrw1; + return(SUNFALSE); } - kin_mem->kin_liw += kin_mem->kin_m_aa*kin_mem->kin_liw1; - kin_mem->kin_lrw += kin_mem->kin_m_aa*kin_mem->kin_lrw1; + kin_mem->kin_liw += kin_mem->kin_m_aa * kin_mem->kin_liw1; + kin_mem->kin_lrw += kin_mem->kin_m_aa * kin_mem->kin_lrw1; } } + return(SUNTRUE); } @@ -918,44 +1010,111 @@ static booleantype KINAllocVectors(KINMem kin_mem, N_Vector tmpl) static void KINFreeVectors(KINMem kin_mem) { - if (kin_mem->kin_unew != NULL) N_VDestroy(kin_mem->kin_unew); - if (kin_mem->kin_fval != NULL) N_VDestroy(kin_mem->kin_fval); - if (kin_mem->kin_pp != NULL) N_VDestroy(kin_mem->kin_pp); - if (kin_mem->kin_vtemp1 != NULL) N_VDestroy(kin_mem->kin_vtemp1); - if (kin_mem->kin_vtemp2 != NULL) N_VDestroy(kin_mem->kin_vtemp2); + if (kin_mem->kin_unew != NULL) { + N_VDestroy(kin_mem->kin_unew); + kin_mem->kin_unew = NULL; + kin_mem->kin_lrw -= kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_liw1; + } + + if (kin_mem->kin_fval != NULL) { + N_VDestroy(kin_mem->kin_fval); + kin_mem->kin_fval = NULL; + kin_mem->kin_lrw -= kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_liw1; + } - if ( (kin_mem->kin_globalstrategy == KIN_PICARD) && (kin_mem->kin_gval != NULL) ) + if (kin_mem->kin_pp != NULL) { + N_VDestroy(kin_mem->kin_pp); + kin_mem->kin_pp = NULL; + kin_mem->kin_lrw -= kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_liw1; + } + + if (kin_mem->kin_vtemp1 != NULL) { + N_VDestroy(kin_mem->kin_vtemp1); + kin_mem->kin_vtemp1 = NULL; + kin_mem->kin_lrw -= kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_liw1; + } + + if (kin_mem->kin_vtemp2 != NULL) { + N_VDestroy(kin_mem->kin_vtemp2); + kin_mem->kin_vtemp2 = NULL; + kin_mem->kin_lrw -= kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_liw1; + } + + if (kin_mem->kin_gval != NULL) { N_VDestroy(kin_mem->kin_gval); + kin_mem->kin_gval = NULL; + kin_mem->kin_lrw -= kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_liw1; + } - if ( ((kin_mem->kin_globalstrategy == KIN_PICARD) || (kin_mem->kin_globalstrategy == KIN_FP)) && (kin_mem->kin_m_aa > 0) ) { + if (kin_mem->kin_R_aa != NULL) { free(kin_mem->kin_R_aa); + kin_mem->kin_R_aa = NULL; + } + + if (kin_mem->kin_gamma_aa != NULL) { free(kin_mem->kin_gamma_aa); + kin_mem->kin_gamma_aa = NULL; + } + + if (kin_mem->kin_ipt_map != NULL) { free(kin_mem->kin_ipt_map); + kin_mem->kin_ipt_map = NULL; } - if (kin_mem->kin_m_aa) - { - if (kin_mem->kin_fold_aa != NULL) N_VDestroy(kin_mem->kin_fold_aa); - if (kin_mem->kin_gold_aa != NULL) N_VDestroy(kin_mem->kin_gold_aa); - N_VDestroyVectorArray(kin_mem->kin_df_aa,kin_mem->kin_m_aa); - N_VDestroyVectorArray(kin_mem->kin_dg_aa,kin_mem->kin_m_aa); - free(kin_mem->kin_cv); - free(kin_mem->kin_Xv); - kin_mem->kin_lrw -= (2*kin_mem->kin_m_aa*kin_mem->kin_lrw1+2); - kin_mem->kin_liw -= (2*kin_mem->kin_m_aa*kin_mem->kin_liw1+2); - if (kin_mem->kin_aamem_aa) - { - N_VDestroyVectorArray(kin_mem->kin_q_aa,kin_mem->kin_m_aa); - kin_mem->kin_lrw -= kin_mem->kin_m_aa*kin_mem->kin_lrw1; - kin_mem->kin_liw -= kin_mem->kin_m_aa*kin_mem->kin_liw1; - } + if (kin_mem->kin_cv != NULL) { + free(kin_mem->kin_cv); + kin_mem->kin_cv = NULL; } - kin_mem->kin_lrw -= 5*kin_mem->kin_lrw1; - kin_mem->kin_liw -= 5*kin_mem->kin_liw1; + if (kin_mem->kin_Xv != NULL) { + free(kin_mem->kin_Xv); + kin_mem->kin_Xv = NULL; + } - if (kin_mem->kin_constraintsSet) { - if (kin_mem->kin_constraints != NULL) N_VDestroy(kin_mem->kin_constraints); + if (kin_mem->kin_fold_aa != NULL) { + N_VDestroy(kin_mem->kin_fold_aa); + kin_mem->kin_fold_aa = NULL; + kin_mem->kin_lrw -= kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_liw1; + } + + if (kin_mem->kin_gold_aa != NULL) { + N_VDestroy(kin_mem->kin_gold_aa); + kin_mem->kin_gold_aa = NULL; + kin_mem->kin_lrw -= kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_liw1; + } + + if (kin_mem->kin_df_aa != NULL) { + N_VDestroyVectorArray(kin_mem->kin_df_aa, (int) kin_mem->kin_m_aa); + kin_mem->kin_df_aa = NULL; + kin_mem->kin_lrw -= kin_mem->kin_m_aa * kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_m_aa * kin_mem->kin_liw1; + } + + if (kin_mem->kin_dg_aa != NULL) { + N_VDestroyVectorArray(kin_mem->kin_dg_aa, (int) kin_mem->kin_m_aa); + kin_mem->kin_dg_aa = NULL; + kin_mem->kin_lrw -= kin_mem->kin_m_aa * kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_m_aa * kin_mem->kin_liw1; + } + + if (kin_mem->kin_q_aa != NULL) { + N_VDestroyVectorArray(kin_mem->kin_q_aa, (int) kin_mem->kin_m_aa); + kin_mem->kin_q_aa = NULL; + kin_mem->kin_lrw -= kin_mem->kin_m_aa * kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_m_aa * kin_mem->kin_liw1; + } + + if (kin_mem->kin_constraints != NULL) { + N_VDestroy(kin_mem->kin_constraints); + kin_mem->kin_constraints = NULL; kin_mem->kin_lrw -= kin_mem->kin_lrw1; kin_mem->kin_liw -= kin_mem->kin_liw1; } @@ -963,7 +1122,7 @@ static void KINFreeVectors(KINMem kin_mem) return; } -/* +/* * ----------------------------------------------------------------- * Initial setup * ----------------------------------------------------------------- @@ -992,7 +1151,7 @@ static int KINSolInit(KINMem kin_mem) { int retval; realtype fmax; - + /* check for illegal input parameters */ if (kin_mem->kin_uu == NULL) { @@ -1000,8 +1159,12 @@ static int KINSolInit(KINMem kin_mem) return(KIN_ILL_INPUT); } - if ( (kin_mem->kin_globalstrategy != KIN_NONE) && (kin_mem->kin_globalstrategy != KIN_LINESEARCH) && - (kin_mem->kin_globalstrategy != KIN_PICARD) && (kin_mem->kin_globalstrategy != KIN_FP) ) { + /* check for valid strategy */ + + if ( (kin_mem->kin_globalstrategy != KIN_NONE) && + (kin_mem->kin_globalstrategy != KIN_LINESEARCH) && + (kin_mem->kin_globalstrategy != KIN_PICARD) && + (kin_mem->kin_globalstrategy != KIN_FP) ) { KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSolInit", MSG_BAD_GLSTRAT); return(KIN_ILL_INPUT); } @@ -1026,20 +1189,22 @@ static int KINSolInit(KINMem kin_mem) return(KIN_ILL_INPUT); } - if ( (kin_mem->kin_constraints != NULL) && ( (kin_mem->kin_globalstrategy == KIN_PICARD) || (kin_mem->kin_globalstrategy == KIN_FP) ) ) { + if ( (kin_mem->kin_constraints != NULL) && + ( (kin_mem->kin_globalstrategy == KIN_PICARD) || + (kin_mem->kin_globalstrategy == KIN_FP) ) ) { KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSolInit", MSG_CONSTRAINTS_NOTOK); return(KIN_ILL_INPUT); } - + /* set the constraints flag */ - if (kin_mem->kin_constraints == NULL) + if (kin_mem->kin_constraints == NULL) kin_mem->kin_constraintsSet = SUNFALSE; else { kin_mem->kin_constraintsSet = SUNTRUE; if ((kin_mem->kin_constraints->ops->nvconstrmask == NULL) || - (kin_mem->kin_constraints->ops->nvminquotient == NULL)) { + (kin_mem->kin_constraints->ops->nvminquotient == NULL)) { KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSolInit", MSG_BAD_NVECTOR); return(KIN_ILL_INPUT); } @@ -1053,7 +1218,7 @@ static int KINSolInit(KINMem kin_mem) return(KIN_ILL_INPUT); } } - + /* all error checking is complete at this point */ if (kin_mem->kin_printfl > 0) @@ -1078,7 +1243,7 @@ static int KINSolInit(KINMem kin_mem) if (kin_mem->kin_etaflag == KIN_ETACHOICE1) kin_mem->kin_eta_alpha = (ONE + SUNRsqrt(FIVE)) * HALF; - /* initial value for eta set to 0.5 for other than the + /* initial value for eta set to 0.5 for other than the KIN_ETACONSTANT option */ if (kin_mem->kin_etaflag != KIN_ETACONSTANT) kin_mem->kin_eta = HALF; @@ -1101,12 +1266,12 @@ static int KINSolInit(KINMem kin_mem) retval = kin_mem->kin_func(kin_mem->kin_uu, kin_mem->kin_fval, kin_mem->kin_user_data); kin_mem->kin_nfe++; if (retval < 0) { - KINProcessError(kin_mem, KIN_SYSFUNC_FAIL, "KINSOL", "KINSolInit", - MSG_SYSFUNC_FAILED); + KINProcessError(kin_mem, KIN_SYSFUNC_FAIL, "KINSOL", "KINSolInit", + MSG_SYSFUNC_FAILED); return(KIN_SYSFUNC_FAIL); } else if (retval > 0) { - KINProcessError(kin_mem, KIN_FIRST_SYSFUNC_ERR, "KINSOL", "KINSolInit", - MSG_SYSFUNC_FIRST); + KINProcessError(kin_mem, KIN_FIRST_SYSFUNC_ERR, "KINSOL", "KINSolInit", + MSG_SYSFUNC_FIRST); return(KIN_FIRST_SYSFUNC_ERR); } @@ -1118,7 +1283,7 @@ static int KINSolInit(KINMem kin_mem) if (kin_mem->kin_printfl > 1) KINPrintInfo(kin_mem, PRNT_FMAX, "KINSOL", "KINSolInit", INFO_FMAX, fmax); - + /* initialize the linear solver if linit != NULL */ if (kin_mem->kin_linit != NULL) { @@ -1136,15 +1301,15 @@ static int KINSolInit(KINMem kin_mem) kin_mem->kin_fnorm_sub = kin_mem->kin_fnorm; if (kin_mem->kin_printfl > 0) - KINPrintInfo(kin_mem, PRNT_NNI, "KINSOL", "KINSolInit", - INFO_NNI, kin_mem->kin_nni, kin_mem->kin_nfe, kin_mem->kin_fnorm); + KINPrintInfo(kin_mem, PRNT_NNI, "KINSOL", "KINSolInit", + INFO_NNI, kin_mem->kin_nni, kin_mem->kin_nfe, kin_mem->kin_fnorm); /* problem has now been successfully initialized */ return(KIN_SUCCESS); } -/* +/* * ----------------------------------------------------------------- * Step functions * ----------------------------------------------------------------- @@ -1156,7 +1321,7 @@ static int KINSolInit(KINMem kin_mem) * This routine handles the process of solving for the approximate * solution of the Newton equations in the Newton iteration. * Subsequent routines handle the nonlinear aspects of its - * application. + * application. */ static int KINLinSolDrv(KINMem kin_mem) @@ -1192,13 +1357,14 @@ static int KINLinSolDrv(KINMem kin_mem) /* call the generic 'lsolve' routine to solve the system Jx = b */ - retval = kin_mem->kin_lsolve(kin_mem, x, b, &(kin_mem->kin_sJpnorm), &(kin_mem->kin_sFdotJp)); + retval = kin_mem->kin_lsolve(kin_mem, x, b, &(kin_mem->kin_sJpnorm), + &(kin_mem->kin_sFdotJp)); if (retval == 0) return(KIN_SUCCESS); else if (retval < 0) return(KIN_LSOLVE_FAIL); else if ((kin_mem->kin_lsetup == NULL) || (kin_mem->kin_jacCurrent)) return(KIN_LINSOLV_NO_RECOVERY); - /* loop back only if the linear solver setup is in use + /* loop back only if the linear solver setup is in use and Jacobian information is not current */ kin_mem->kin_sthrsh = TWO; @@ -1213,7 +1379,7 @@ static int KINLinSolDrv(KINMem kin_mem) * algorithm. Its purpose is to compute unew = uu + pp in the * direction pp from uu, taking the full Newton step. The * step may be constrained if the constraint conditions are - * violated, or if the norm of pp is greater than mxnewtstep. + * violated, or if the norm of pp is greater than mxnewtstep. */ static int KINFullNewton(KINMem kin_mem, realtype *fnormp, realtype *f1normp, @@ -1254,9 +1420,9 @@ static int KINFullNewton(KINMem kin_mem, realtype *fnormp, realtype *f1normp, return(STEP_TOO_SMALL);} } } - + /* Attempt (at most MAX_RECVR times) to evaluate function at the new iterate */ - + fOK = SUNFALSE; for (ircvr = 1; ircvr <= MAX_RECVR; ircvr++) { @@ -1293,11 +1459,11 @@ static int KINFullNewton(KINMem kin_mem, realtype *fnormp, realtype *f1normp, kin_mem->kin_sFdotJp *= ratio; kin_mem->kin_sJpnorm *= ratio; - - if (kin_mem->kin_printfl > 1) + + if (kin_mem->kin_printfl > 1) KINPrintInfo(kin_mem, PRNT_FNORM, "KINSOL", "KINFullNewton", INFO_FNORM, *fnormp); - if (pnorm > (POINT99 * kin_mem->kin_mxnewtstep)) *maxStepTaken = SUNTRUE; + if (pnorm > (POINT99 * kin_mem->kin_mxnewtstep)) *maxStepTaken = SUNTRUE; return(KIN_SUCCESS); } @@ -1333,18 +1499,18 @@ static int KINFullNewton(KINMem kin_mem, realtype *fnormp, realtype *f1normp, * || (1/uscale + SUNRabs(uu)) || * * - * If the system function fails unrecoverably at any time, KINLineSearch + * If the system function fails unrecoverably at any time, KINLineSearch * returns KIN_SYSFUNC_FAIL which will halt the solver. * - * We attempt to corect recoverable system function failures only before - * the alpha-condition loop; i.e. when the solution is updated with the - * full Newton step (possibly reduced due to constraint violations). + * We attempt to corect recoverable system function failures only before + * the alpha-condition loop; i.e. when the solution is updated with the + * full Newton step (possibly reduced due to constraint violations). * Once we find a feasible pp, we assume that any update up to pp is * feasible. - * - * If the step size is limited due to constraint violations and/or + * + * If the step size is limited due to constraint violations and/or * recoverable system function failures, we set rlmax=1 to ensure - * that the update remains feasible during the attempts to enforce + * that the update remains feasible during the attempts to enforce * the beta-condition (this is not an issue while enforcing the alpha * condition, as rl can only decrease from 1 at that stage) */ @@ -1407,7 +1573,7 @@ static int KINLineSearch(KINMem kin_mem, realtype *fnormp, realtype *f1normp, } /* Attempt (at most MAX_RECVR times) to evaluate function at the new iterate */ - + fOK = SUNFALSE; for (ircvr = 1; ircvr <= MAX_RECVR; ircvr++) { @@ -1455,13 +1621,13 @@ static int KINLineSearch(KINMem kin_mem, realtype *fnormp, realtype *f1normp, /* Loop until the ALPHA condition is satisfied. Terminate if rl becomes too small */ for(;;) { - + /* Evaluate test quantity */ alpha_cond = kin_mem->kin_f1norm + (alpha * slpi * rl); if (kin_mem->kin_printfl > 2) - KINPrintInfo(kin_mem, PRNT_ALPHA, "KINSOL", "KINLinesearch", + KINPrintInfo(kin_mem, PRNT_ALPHA, "KINSOL", "KINLinesearch", INFO_ALPHA, *fnormp, *f1normp, alpha_cond, rl); /* If ALPHA condition is satisfied, break out from loop */ @@ -1516,7 +1682,7 @@ static int KINLineSearch(KINMem kin_mem, realtype *fnormp, realtype *f1normp, if (rl < rlmin) { /* unew sufficiently distinct from uu cannot be found. - copy uu into unew (step remains unchanged) and + copy uu into unew (step remains unchanged) and return STEP_TOO_SMALL */ N_VScale(ONE, kin_mem->kin_uu, kin_mem->kin_unew); return(STEP_TOO_SMALL); @@ -1552,11 +1718,11 @@ static int KINLineSearch(KINMem kin_mem, realtype *fnormp, realtype *f1normp, beta_cond = kin_mem->kin_f1norm + (beta * slpi * rl); if (kin_mem->kin_printfl > 2) - KINPrintInfo(kin_mem, PRNT_BETA, "KINSOL", "KINLineSearch", + KINPrintInfo(kin_mem, PRNT_BETA, "KINSOL", "KINLineSearch", INFO_BETA, *f1normp, beta_cond, rl); - } while (((*f1normp) <= alpha_cond) && - ((*f1normp) < beta_cond) && (rl < rlmax)); + } while (((*f1normp) <= alpha_cond) && + ((*f1normp) < beta_cond) && (rl < rlmax)); } /* end if (rl == ONE) block */ @@ -1581,7 +1747,7 @@ static int KINLineSearch(KINMem kin_mem, realtype *fnormp, realtype *f1normp, beta_cond = kin_mem->kin_f1norm + (beta * slpi * rl); if (kin_mem->kin_printfl > 2) - KINPrintInfo(kin_mem, PRNT_ALPHABETA, "KINSOL", "KINLineSearch", + KINPrintInfo(kin_mem, PRNT_ALPHABETA, "KINSOL", "KINLineSearch", INFO_ALPHABETA, *f1normp, alpha_cond, beta_cond, rl); if ((*f1normp) > alpha_cond) rldiff = rlinc; @@ -1591,21 +1757,21 @@ static int KINLineSearch(KINMem kin_mem, realtype *fnormp, realtype *f1normp, } } while ((*f1normp > alpha_cond) || - ((*f1normp < beta_cond) && (rldiff >= rlmin))); + ((*f1normp < beta_cond) && (rldiff >= rlmin))); if ( (*f1normp < beta_cond) || ((rldiff < rlmin) && (*f1normp > alpha_cond)) ) { - /* beta condition could not be satisfied or rldiff too small - and alpha_cond not satisfied, so set unew to last u value - that satisfied the alpha condition and continue */ + /* beta condition could not be satisfied or rldiff too small + and alpha_cond not satisfied, so set unew to last u value + that satisfied the alpha condition and continue */ N_VLinearSum(ONE, kin_mem->kin_uu, rllo, kin_mem->kin_pp, kin_mem->kin_unew); retval = kin_mem->kin_func(kin_mem->kin_unew, kin_mem->kin_fval, kin_mem->kin_user_data); kin_mem->kin_nfe++; if (retval != 0) return(KIN_SYSFUNC_FAIL); *fnormp = N_VWL2Norm(kin_mem->kin_fval, kin_mem->kin_fscale); - *f1normp = HALF * (*fnormp) * (*fnormp); + *f1normp = HALF * (*fnormp) * (*fnormp); - /* increment beta-condition failures counter */ + /* increment beta-condition failures counter */ kin_mem->kin_nbcf++; @@ -1708,7 +1874,7 @@ static int KINStop(KINMem kin_mem, booleantype maxStepTaken, int sflag) fmax = KINScFNorm(kin_mem, kin_mem->kin_fval, kin_mem->kin_fscale); - if (kin_mem->kin_printfl > 1) + if (kin_mem->kin_printfl > 1) KINPrintInfo(kin_mem, PRNT_FMAX, "KINSOL", "KINStop", INFO_FMAX, fmax); if (fmax <= kin_mem->kin_fnormtol) return(KIN_SUCCESS); @@ -1739,10 +1905,10 @@ static int KINStop(KINMem kin_mem, booleantype maxStepTaken, int sflag) /* Check for consecutive number of steps taken of size mxnewtstep and if not maxStepTaken, then set ncscmx to 0 */ - + if (maxStepTaken) kin_mem->kin_ncscmx++; else kin_mem->kin_ncscmx = 0; - + if (kin_mem->kin_ncscmx == 5) return(KIN_MXNEWT_5X_EXCEEDED); /* Proceed according to the type of linear solver used */ @@ -1769,22 +1935,22 @@ static int KINStop(KINMem kin_mem, booleantype maxStepTaken, int sflag) if (kin_mem->kin_eval_omega) { omexp = SUNMAX(ZERO,((kin_mem->kin_fnorm)/(kin_mem->kin_fnormtol))-ONE); kin_mem->kin_omega = (omexp > TWELVE)? kin_mem->kin_omega_max : SUNMIN(kin_mem->kin_omega_min * SUNRexp(omexp), kin_mem->kin_omega_max); - } + } /* Check if making satisfactory progress */ if (kin_mem->kin_fnorm > kin_mem->kin_omega * kin_mem->kin_fnorm_sub) { /* Insufficient progress */ - if ((kin_mem->kin_lsetup != NULL) && !(kin_mem->kin_jacCurrent)) { + if ((kin_mem->kin_lsetup != NULL) && !(kin_mem->kin_jacCurrent)) { /* If the Jacobian is out of date, update it and retry */ - kin_mem->kin_sthrsh = TWO; + kin_mem->kin_sthrsh = TWO; return(CONTINUE_ITERATIONS); - } else { + } else { /* Otherwise, we cannot do anything, so just return. */ } } else { /* Sufficient progress */ - kin_mem->kin_fnorm_sub = kin_mem->kin_fnorm; - kin_mem->kin_sthrsh = ONE; + kin_mem->kin_fnorm_sub = kin_mem->kin_fnorm; + kin_mem->kin_sthrsh = ONE; } } else { @@ -1838,29 +2004,34 @@ static void KINForcingTerm(KINMem kin_mem, realtype fnormp) /* compute the norm of f + Jp , scaled L2 norm */ - linmodel_norm = SUNRsqrt((kin_mem->kin_fnorm * kin_mem->kin_fnorm) + (TWO * kin_mem->kin_sFdotJp) + (kin_mem->kin_sJpnorm * kin_mem->kin_sJpnorm)); + linmodel_norm = SUNRsqrt((kin_mem->kin_fnorm * kin_mem->kin_fnorm) + + (TWO * kin_mem->kin_sFdotJp) + + (kin_mem->kin_sJpnorm * kin_mem->kin_sJpnorm)); - /* form the safeguarded for choice #1 */ + /* form the safeguarded for choice #1 */ - eta_safe = SUNRpowerR(kin_mem->kin_eta, kin_mem->kin_eta_alpha); + eta_safe = SUNRpowerR(kin_mem->kin_eta, kin_mem->kin_eta_alpha); kin_mem->kin_eta = SUNRabs(fnormp - linmodel_norm) / kin_mem->kin_fnorm; } /* choice #2 forcing term */ if (kin_mem->kin_etaflag == KIN_ETACHOICE2) { - eta_safe = kin_mem->kin_eta_gamma * SUNRpowerR(kin_mem->kin_eta, kin_mem->kin_eta_alpha); - kin_mem->kin_eta = kin_mem->kin_eta_gamma * SUNRpowerR((fnormp / kin_mem->kin_fnorm), kin_mem->kin_eta_alpha); + eta_safe = kin_mem->kin_eta_gamma * + SUNRpowerR(kin_mem->kin_eta, kin_mem->kin_eta_alpha); + + kin_mem->kin_eta = kin_mem->kin_eta_gamma * + SUNRpowerR((fnormp / kin_mem->kin_fnorm), kin_mem->kin_eta_alpha); } /* apply safeguards */ - + if(eta_safe < POINT1) eta_safe = ZERO; kin_mem->kin_eta = SUNMAX(kin_mem->kin_eta, eta_safe); kin_mem->kin_eta = SUNMAX(kin_mem->kin_eta, eta_min); kin_mem->kin_eta = SUNMIN(kin_mem->kin_eta, eta_max); - return; + return; } @@ -1907,13 +2078,13 @@ static realtype KINScSNorm(KINMem kin_mem, N_Vector v, N_Vector u) return(length); } -/* +/* * ================================================================= * KINSOL Verbose output functions * ================================================================= */ -/* +/* * KINPrintInfo * * KINPrintInfo is a high level error handling function @@ -1921,11 +2092,8 @@ static realtype KINScSNorm(KINMem kin_mem, N_Vector v, N_Vector u) * passes it to the info handler function. */ -#define ihfun (kin_mem->kin_ihfun) -#define ih_data (kin_mem->kin_ih_data) - -void KINPrintInfo(KINMem kin_mem, - int info_code, const char *module, const char *fname, +void KINPrintInfo(KINMem kin_mem, + int info_code, const char *module, const char *fname, const char *msgfmt, ...) { va_list ap; @@ -1933,10 +2101,10 @@ void KINPrintInfo(KINMem kin_mem, char retstr[30]; int ret; - /* Initialize argument processing + /* Initialize argument processing (msgfrmt is the last required argument) */ - va_start(ap, msgfmt); + va_start(ap, msgfmt); if (info_code == PRNT_RETVAL) { @@ -1987,7 +2155,7 @@ void KINPrintInfo(KINMem kin_mem, } else { - + /* Compose the message */ vsprintf(msg, msgfmt, ap); @@ -1996,7 +2164,7 @@ void KINPrintInfo(KINMem kin_mem, /* call the info message handler */ - ihfun(module, fname, msg, ih_data); + kin_mem->kin_ihfun(module, fname, msg, kin_mem->kin_ih_data); /* finalize argument processing */ @@ -2007,15 +2175,13 @@ void KINPrintInfo(KINMem kin_mem, /* - * KINInfoHandler + * KINInfoHandler * * This is the default KINSOL info handling function. - * It sends the info message to the stream pointed to by kin_infofp + * It sends the info message to the stream pointed to by kin_infofp */ -#define infofp (kin_mem->kin_infofp) - -void KINInfoHandler(const char *module, const char *function, +void KINInfoHandler(const char *module, const char *function, char *msg, void *data) { KINMem kin_mem; @@ -2023,42 +2189,39 @@ void KINInfoHandler(const char *module, const char *function, /* data points to kin_mem here */ kin_mem = (KINMem) data; - + #ifndef NO_FPRINTF_OUTPUT - if (infofp != NULL) { - fprintf(infofp,"\n[%s] %s\n",module, function); - fprintf(infofp," %s\n",msg); + if (kin_mem->kin_infofp != NULL) { + fprintf(kin_mem->kin_infofp,"\n[%s] %s\n",module, function); + fprintf(kin_mem->kin_infofp," %s\n",msg); } -#endif +#endif } -/* +/* * ================================================================= * KINSOL Error Handling functions * ================================================================= */ /* - * KINProcessError + * KINProcessError * * KINProcessError is a high level error handling function. * - If cv_mem==NULL it prints the error message to stderr. - * - Otherwise, it sets up and calls the error handling function + * - Otherwise, it sets up and calls the error handling function * pointed to by cv_ehfun. */ -#define ehfun (kin_mem->kin_ehfun) -#define eh_data (kin_mem->kin_eh_data) - -void KINProcessError(KINMem kin_mem, - int error_code, const char *module, const char *fname, +void KINProcessError(KINMem kin_mem, + int error_code, const char *module, const char *fname, const char *msgfmt, ...) { va_list ap; char msg[256]; - /* Initialize the argument pointer variable + /* Initialize the argument pointer variable (msgfmt is the last required argument to KINProcessError) */ va_start(ap, msgfmt); @@ -2074,7 +2237,7 @@ void KINProcessError(KINMem kin_mem, #endif } else { /* We can call ehfun */ - ehfun(error_code, module, fname, msg, eh_data); + kin_mem->kin_ehfun(error_code, module, fname, msg, kin_mem->kin_eh_data); } /* Finalize argument processing */ @@ -2083,11 +2246,11 @@ void KINProcessError(KINMem kin_mem, return; } -/* - * KINErrHandler +/* + * KINErrHandler * * This is the default error handling function. - * It sends the error message to the stream pointed to by kin_errfp + * It sends the error message to the stream pointed to by kin_errfp */ void KINErrHandler(int error_code, const char *module, @@ -2125,18 +2288,18 @@ void KINErrHandler(int error_code, const char *module, /* * KINPicardAA * - * This routine is the main driver for the Picard iteration with - * acclerated fixed point. + * This routine is the main driver for the Picard iteration with + * acclerated fixed point. */ -static int KINPicardAA(KINMem kin_mem, long int *iterp, realtype *R, +static int KINPicardAA(KINMem kin_mem, long int *iterp, realtype *R, realtype *gamma, realtype *fmaxptr) { - int retval, ret; + int retval, ret; long int iter; realtype fmax, epsmin, fnormp; N_Vector delta, gval; - + delta = kin_mem->kin_vtemp1; gval = kin_mem->kin_gval; ret = CONTINUE_ITERATIONS; @@ -2160,8 +2323,8 @@ static int KINPicardAA(KINMem kin_mem, long int *iterp, realtype *R, if(!(kin_mem->kin_noMinEps)) kin_mem->kin_eps = SUNMAX(epsmin, kin_mem->kin_eps); } - /* evaluate g = uu - L^{-1}func(uu) and return if failed. - For Picard, assume that the fval vector has been filled + /* evaluate g = uu - L^{-1}func(uu) and return if failed. + For Picard, assume that the fval vector has been filled with an eval of the nonlinear residual prior to this call. */ retval = KINPicardFcnEval(kin_mem, gval, kin_mem->kin_uu, kin_mem->kin_fval); @@ -2170,17 +2333,17 @@ static int KINPicardAA(KINMem kin_mem, long int *iterp, realtype *R, break; } - if (kin_mem->kin_m_aa == 0) { + if (kin_mem->kin_m_aa == 0) { N_VScale(ONE, gval, kin_mem->kin_unew); } else { /* use Anderson, if desired */ N_VScale(ONE, kin_mem->kin_uu, kin_mem->kin_unew); - AndersonAcc(kin_mem, gval, delta, kin_mem->kin_unew, kin_mem->kin_uu, (int)(iter-1), R, gamma); + AndersonAcc(kin_mem, gval, delta, kin_mem->kin_unew, kin_mem->kin_uu, iter-1, R, gamma); } /* Fill the Newton residual based on the new solution iterate */ retval = kin_mem->kin_func(kin_mem->kin_unew, kin_mem->kin_fval, kin_mem->kin_user_data); kin_mem->kin_nfe++; - + if (retval < 0) { ret = KIN_SYSFUNC_FAIL; break; @@ -2191,8 +2354,8 @@ static int KINPicardAA(KINMem kin_mem, long int *iterp, realtype *R, fmax = KINScFNorm(kin_mem, kin_mem->kin_fval, kin_mem->kin_fscale); /* measure || F(x) ||_max */ kin_mem->kin_fnorm = fmax; *fmaxptr = fmax; - - if (kin_mem->kin_printfl > 1) + + if (kin_mem->kin_printfl > 1) KINPrintInfo(kin_mem, PRNT_FMAX, "KINSOL", "KINPicardAA", INFO_FMAX, fmax); /* print the current iter, fnorm, and nfe values if printfl > 0 */ @@ -2203,20 +2366,20 @@ static int KINPicardAA(KINMem kin_mem, long int *iterp, realtype *R, if (iter >= kin_mem->kin_mxiter) { ret = KIN_MAXITER_REACHED; } - if (fmax <= kin_mem->kin_fnormtol) { + if (fmax <= kin_mem->kin_fnormtol) { ret = KIN_SUCCESS; } /* Update with new iterate. */ N_VScale(ONE, kin_mem->kin_unew, kin_mem->kin_uu); - if (ret == CONTINUE_ITERATIONS) { + if (ret == CONTINUE_ITERATIONS) { /* evaluate eta by calling the forcing term routine */ if (kin_mem->kin_callForcingTerm) KINForcingTerm(kin_mem, fnormp); } fflush(kin_mem->kin_errfp); - + } /* end of loop; return */ *iterp = iter; @@ -2224,7 +2387,7 @@ static int KINPicardAA(KINMem kin_mem, long int *iterp, realtype *R, if (kin_mem->kin_printfl > 0) KINPrintInfo(kin_mem, PRNT_RETVAL, "KINSOL", "KINPicardAA", INFO_RETVAL, ret); - return(ret); + return(ret); } /* @@ -2239,7 +2402,7 @@ static int KINPicardAA(KINMem kin_mem, long int *iterp, realtype *R, * within the linear solve routines. * * This routine fills gval = uu - L^{-1}F(uu) given uu and fval = F(uu). - */ + */ static int KINPicardFcnEval(KINMem kin_mem, N_Vector gval, N_Vector uval, N_Vector fval1) { @@ -2265,7 +2428,8 @@ static int KINPicardFcnEval(KINMem kin_mem, N_Vector gval, N_Vector uval, N_Vect /* call the generic 'lsolve' routine to solve the system Lx = -fval Note that we are using gval to hold x. */ N_VScale(-ONE, fval1, fval1); - retval = kin_mem->kin_lsolve(kin_mem, gval, fval1, &(kin_mem->kin_sJpnorm), &(kin_mem->kin_sFdotJp)); + retval = kin_mem->kin_lsolve(kin_mem, gval, fval1, &(kin_mem->kin_sJpnorm), + &(kin_mem->kin_sFdotJp)); if (retval == 0) { /* Update gval = uval + gval since gval = -L^{-1}F(uu) */ @@ -2291,81 +2455,88 @@ static int KINPicardFcnEval(KINMem kin_mem, N_Vector gval, N_Vector uval, N_Vect * Anderson Acceleration. */ -static int KINFP(KINMem kin_mem, long int *iterp, - realtype *R, realtype *gamma, - realtype *fmaxptr) +static int KINFP(KINMem kin_mem) { - int retval, ret; - long int iter; - realtype fmax; - N_Vector delta; - + int retval; /* return value from user func */ + int ret; /* iteration status */ + realtype fmax; /* max norm of residual func */ + N_Vector delta; /* temporary workspace vector */ + delta = kin_mem->kin_vtemp1; - ret = CONTINUE_ITERATIONS; - fmax = kin_mem->kin_fnormtol + ONE; - iter = 0; + ret = CONTINUE_ITERATIONS; + fmax = kin_mem->kin_fnormtol + ONE; + + /* initialize iteration count */ + kin_mem->kin_nni = 0; while (ret == CONTINUE_ITERATIONS) { - iter++; + /* update iteration count */ + kin_mem->kin_nni++; /* evaluate func(uu) and return if failed */ - retval = kin_mem->kin_func(kin_mem->kin_uu, kin_mem->kin_fval, kin_mem->kin_user_data); kin_mem->kin_nfe++; + retval = kin_mem->kin_func(kin_mem->kin_uu, kin_mem->kin_fval, + kin_mem->kin_user_data); + kin_mem->kin_nfe++; if (retval < 0) { ret = KIN_SYSFUNC_FAIL; break; } - if (kin_mem->kin_m_aa == 0) { + /* compute new solution */ + if (kin_mem->kin_m_aa == 0) { + /* standard fixed point */ N_VScale(ONE, kin_mem->kin_fval, kin_mem->kin_unew); - } - else { /* use Anderson, if desired */ - AndersonAcc(kin_mem, kin_mem->kin_fval, delta, kin_mem->kin_unew, kin_mem->kin_uu, (int)(iter-1), R, gamma); + } else { + /* apply Anderson acceleration */ + AndersonAcc(kin_mem, kin_mem->kin_fval, delta, kin_mem->kin_unew, + kin_mem->kin_uu, kin_mem->kin_nni - 1, kin_mem->kin_R_aa, + kin_mem->kin_gamma_aa); } + /* compute change between iterations */ N_VLinearSum(ONE, kin_mem->kin_unew, -ONE, kin_mem->kin_uu, delta); + fmax = KINScFNorm(kin_mem, delta, kin_mem->kin_fscale); /* measure || g(x)-x || */ - - if (kin_mem->kin_printfl > 1) + + if (kin_mem->kin_printfl > 1) KINPrintInfo(kin_mem, PRNT_FMAX, "KINSOL", "KINFP", INFO_FMAX, fmax); - + kin_mem->kin_fnorm = fmax; - *fmaxptr = fmax; /* print the current iter, fnorm, and nfe values if printfl > 0 */ if (kin_mem->kin_printfl > 0) - KINPrintInfo(kin_mem, PRNT_NNI, "KINSOL", "KINFP", INFO_NNI, iter, kin_mem->kin_nfe, kin_mem->kin_fnorm); + KINPrintInfo(kin_mem, PRNT_NNI, "KINSOL", "KINFP", INFO_NNI, + kin_mem->kin_nni, kin_mem->kin_nfe, kin_mem->kin_fnorm); /* Check if the maximum number of iterations is reached */ - if (iter >= kin_mem->kin_mxiter) { + if (kin_mem->kin_nni >= kin_mem->kin_mxiter) { ret = KIN_MAXITER_REACHED; } - if (fmax <= kin_mem->kin_fnormtol) { + if (fmax <= kin_mem->kin_fnormtol) { ret = KIN_SUCCESS; } - - if (ret == CONTINUE_ITERATIONS) { + + if (ret == CONTINUE_ITERATIONS) { /* Only update solution if taking a next iteration. */ /* CSW Should put in a conditional to send back the newest iterate or - the one consistent with the fval */ + the one consistent with the fval */ N_VScale(ONE, kin_mem->kin_unew, kin_mem->kin_uu); } fflush(kin_mem->kin_errfp); - - } /* end of loop; return */ - *iterp = iter; + } /* end of loop; return */ if (kin_mem->kin_printfl > 0) KINPrintInfo(kin_mem, PRNT_RETVAL, "KINSOL", "KINFP", INFO_RETVAL, ret); - return(ret); -} + return(ret); +} - /* ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Stopping tests * ----------------------------------------------------------------- */ @@ -2377,13 +2548,15 @@ static int KINFP(KINMem kin_mem, long int *iterp, * ======================================================================== */ -static int AndersonAcc(KINMem kin_mem, N_Vector gval, N_Vector fv, - N_Vector x, N_Vector xold, - int iter, realtype *R, realtype *gamma) +static int AndersonAcc(KINMem kin_mem, N_Vector gval, N_Vector fv, + N_Vector x, N_Vector xold, + long int iter, realtype *R, realtype *gamma) { - int i_pt, i, j, lAA, retval; - int *ipt_map; + int retval; + long int i_pt, i, j, lAA; + long int *ipt_map; realtype alfa; + realtype onembeta; realtype a, b, temp, c, s; /* local shortcuts for fused vector operation */ @@ -2392,116 +2565,138 @@ static int AndersonAcc(KINMem kin_mem, N_Vector gval, N_Vector fv, N_Vector* Xv=kin_mem->kin_Xv; ipt_map = kin_mem->kin_ipt_map; - i_pt = iter-1 - ((iter-1)/kin_mem->kin_m_aa)*kin_mem->kin_m_aa; - N_VLinearSum(ONE, gval, -1.0, xold, fv); + i_pt = iter-1 - ((iter-1) / kin_mem->kin_m_aa) * kin_mem->kin_m_aa; + N_VLinearSum(ONE, gval, -ONE, xold, fv); if (iter > 0) { - /* compute dg_new = gval -gval_old*/ - N_VLinearSum(ONE, gval, -1.0, kin_mem->kin_gold_aa, kin_mem->kin_dg_aa[i_pt]); + /* compute dg_new = gval - gval_old */ + N_VLinearSum(ONE, gval, -ONE, kin_mem->kin_gold_aa, kin_mem->kin_dg_aa[i_pt]); /* compute df_new = fval - fval_old */ - N_VLinearSum(ONE, fv, -1.0, kin_mem->kin_fold_aa, kin_mem->kin_df_aa[i_pt]); + N_VLinearSum(ONE, fv, -ONE, kin_mem->kin_fold_aa, kin_mem->kin_df_aa[i_pt]); } N_VScale(ONE, gval, kin_mem->kin_gold_aa); N_VScale(ONE, fv, kin_mem->kin_fold_aa); + /* on first iteration, just do basic fixed-point update */ if (iter == 0) { N_VScale(ONE, gval, x); + return(0); } - else { - if (iter == 1) { - R[0] = sqrt(N_VDotProd(kin_mem->kin_df_aa[i_pt], kin_mem->kin_df_aa[i_pt])); - alfa = 1/R[0]; - N_VScale(alfa, kin_mem->kin_df_aa[i_pt], kin_mem->kin_q_aa[i_pt]); - ipt_map[0] = 0; - } - else if (iter <= kin_mem->kin_m_aa) { - N_VScale(ONE, kin_mem->kin_df_aa[i_pt], kin_mem->kin_vtemp2); - for (j=0; j < (iter-1); j++) { - ipt_map[j] = j; - R[(iter-1)*kin_mem->kin_m_aa+j] = N_VDotProd(kin_mem->kin_q_aa[j], kin_mem->kin_vtemp2); - N_VLinearSum(ONE,kin_mem->kin_vtemp2, -R[(iter-1)*kin_mem->kin_m_aa+j], kin_mem->kin_q_aa[j], kin_mem->kin_vtemp2); - } - R[(iter-1)*kin_mem->kin_m_aa+iter-1] = sqrt(N_VDotProd(kin_mem->kin_vtemp2, kin_mem->kin_vtemp2)); - N_VScale((1/R[(iter-1)*kin_mem->kin_m_aa+iter-1]), kin_mem->kin_vtemp2, kin_mem->kin_q_aa[i_pt]); - ipt_map[iter-1] = iter-1; + + /* update data structures based on current iteration index */ + + if (iter == 1) { + + /* second iteration */ + R[0] = SUNRsqrt(N_VDotProd(kin_mem->kin_df_aa[i_pt], kin_mem->kin_df_aa[i_pt])); + alfa = ONE/R[0]; + N_VScale(alfa, kin_mem->kin_df_aa[i_pt], kin_mem->kin_q_aa[i_pt]); + ipt_map[0] = 0; + + } else if (iter <= kin_mem->kin_m_aa) { + + /* another iteration before we've reached maa */ + N_VScale(ONE, kin_mem->kin_df_aa[i_pt], kin_mem->kin_vtemp2); + for (j=0; j < (iter-1); j++) { + ipt_map[j] = j; + R[(iter-1)*kin_mem->kin_m_aa+j] = N_VDotProd(kin_mem->kin_q_aa[j], kin_mem->kin_vtemp2); + N_VLinearSum(ONE,kin_mem->kin_vtemp2, -R[(iter-1)*kin_mem->kin_m_aa+j], kin_mem->kin_q_aa[j], kin_mem->kin_vtemp2); } - else { - /* Delete left-most column vector from QR factorization */ - for (i=0; i < kin_mem->kin_m_aa-1; i++) { - a = R[(i+1)*kin_mem->kin_m_aa + i]; - b = R[(i+1)*kin_mem->kin_m_aa + i+1]; - temp = sqrt(a*a + b*b); - c = a / temp; - s = b / temp; - R[(i+1)*kin_mem->kin_m_aa + i] = temp; - R[(i+1)*kin_mem->kin_m_aa + i+1] = 0.0; - /* OK to re-use temp */ - if (i < kin_mem->kin_m_aa-1) { - for (j = i+2; j < kin_mem->kin_m_aa; j++) { - a = R[j*kin_mem->kin_m_aa + i]; - b = R[j*kin_mem->kin_m_aa + i+1]; - temp = c * a + s * b; - R[j*kin_mem->kin_m_aa + i+1] = -s*a + c*b; - R[j*kin_mem->kin_m_aa + i] = temp; - } - } - N_VLinearSum(c, kin_mem->kin_q_aa[i], s, kin_mem->kin_q_aa[i+1], kin_mem->kin_vtemp2); - N_VLinearSum(-s, kin_mem->kin_q_aa[i], c, kin_mem->kin_q_aa[i+1], kin_mem->kin_q_aa[i+1]); - N_VScale(ONE, kin_mem->kin_vtemp2, kin_mem->kin_q_aa[i]); - } + R[(iter-1)*kin_mem->kin_m_aa+iter-1] = SUNRsqrt(N_VDotProd(kin_mem->kin_vtemp2, kin_mem->kin_vtemp2)); + N_VScale((1/R[(iter-1)*kin_mem->kin_m_aa+iter-1]), kin_mem->kin_vtemp2, kin_mem->kin_q_aa[i_pt]); + ipt_map[iter-1] = iter-1; + + } else { - /* Shift R to the left by one. */ - for (i = 1; i < kin_mem->kin_m_aa; i++) { - for (j = 0; j < kin_mem->kin_m_aa-1; j++) { - R[(i-1)*kin_mem->kin_m_aa + j] = R[i*kin_mem->kin_m_aa + j]; + /* we've filled the acceleration subspace, so start recycling */ + + /* Delete left-most column vector from QR factorization */ + for (i=0; i < kin_mem->kin_m_aa-1; i++) { + a = R[(i+1)*kin_mem->kin_m_aa + i]; + b = R[(i+1)*kin_mem->kin_m_aa + i+1]; + temp = SUNRsqrt(a*a + b*b); + c = a / temp; + s = b / temp; + R[(i+1)*kin_mem->kin_m_aa + i] = temp; + R[(i+1)*kin_mem->kin_m_aa + i+1] = ZERO; + /* OK to re-use temp */ + if (i < kin_mem->kin_m_aa-1) { + for (j = i+2; j < kin_mem->kin_m_aa; j++) { + a = R[j*kin_mem->kin_m_aa + i]; + b = R[j*kin_mem->kin_m_aa + i+1]; + temp = c * a + s * b; + R[j*kin_mem->kin_m_aa + i+1] = -s*a + c*b; + R[j*kin_mem->kin_m_aa + i] = temp; } } + N_VLinearSum(c, kin_mem->kin_q_aa[i], s, kin_mem->kin_q_aa[i+1], kin_mem->kin_vtemp2); + N_VLinearSum(-s, kin_mem->kin_q_aa[i], c, kin_mem->kin_q_aa[i+1], kin_mem->kin_q_aa[i+1]); + N_VScale(ONE, kin_mem->kin_vtemp2, kin_mem->kin_q_aa[i]); + } - /* Add the new df vector */ - N_VScale(ONE, kin_mem->kin_df_aa[i_pt], kin_mem->kin_vtemp2); - for (j=0; j < (kin_mem->kin_m_aa-1); j++) { - R[(kin_mem->kin_m_aa-1)*kin_mem->kin_m_aa+j] = N_VDotProd(kin_mem->kin_q_aa[j], kin_mem->kin_vtemp2); - N_VLinearSum(ONE, kin_mem->kin_vtemp2, -R[(kin_mem->kin_m_aa-1)*kin_mem->kin_m_aa+j], kin_mem->kin_q_aa[j],kin_mem->kin_vtemp2); + /* Shift R to the left by one. */ + for (i = 1; i < kin_mem->kin_m_aa; i++) { + for (j = 0; j < kin_mem->kin_m_aa-1; j++) { + R[(i-1)*kin_mem->kin_m_aa + j] = R[i*kin_mem->kin_m_aa + j]; } - R[(kin_mem->kin_m_aa-1)*kin_mem->kin_m_aa+kin_mem->kin_m_aa-1] = sqrt(N_VDotProd(kin_mem->kin_vtemp2, kin_mem->kin_vtemp2)); - N_VScale((1/R[(kin_mem->kin_m_aa-1)*kin_mem->kin_m_aa+kin_mem->kin_m_aa-1]), kin_mem->kin_vtemp2, kin_mem->kin_q_aa[kin_mem->kin_m_aa-1]); - - /* Update the iteration map */ - j = 0; - for (i=i_pt+1; i < kin_mem->kin_m_aa; i++) - ipt_map[j++] = i; - for (i=0; i < (i_pt+1); i++) - ipt_map[j++] = i; } - /* Solve least squares problem and update solution */ - lAA = iter; - if (kin_mem->kin_m_aa < iter) lAA = kin_mem->kin_m_aa; + /* Add the new df vector */ + N_VScale(ONE, kin_mem->kin_df_aa[i_pt], kin_mem->kin_vtemp2); + for (j=0; j < (kin_mem->kin_m_aa-1); j++) { + R[(kin_mem->kin_m_aa-1)*kin_mem->kin_m_aa+j] = N_VDotProd(kin_mem->kin_q_aa[j], kin_mem->kin_vtemp2); + N_VLinearSum(ONE, kin_mem->kin_vtemp2, -R[(kin_mem->kin_m_aa-1)*kin_mem->kin_m_aa+j], kin_mem->kin_q_aa[j],kin_mem->kin_vtemp2); + } + R[(kin_mem->kin_m_aa-1)*kin_mem->kin_m_aa+kin_mem->kin_m_aa-1] = SUNRsqrt(N_VDotProd(kin_mem->kin_vtemp2, kin_mem->kin_vtemp2)); + N_VScale((1/R[(kin_mem->kin_m_aa-1)*kin_mem->kin_m_aa+kin_mem->kin_m_aa-1]), kin_mem->kin_vtemp2, kin_mem->kin_q_aa[kin_mem->kin_m_aa-1]); + + /* Update the iteration map */ + j = 0; + for (i=i_pt+1; i < kin_mem->kin_m_aa; i++) + ipt_map[j++] = i; + for (i=0; i < (i_pt+1); i++) + ipt_map[j++] = i; + } - retval = N_VDotProdMulti(lAA, fv, kin_mem->kin_q_aa, gamma); - if (retval != KIN_SUCCESS) return(KIN_VECTOROP_ERR); + /* Solve least squares problem and update solution */ + lAA = iter; + if (kin_mem->kin_m_aa < iter) lAA = kin_mem->kin_m_aa; - /* set arrays for fused vector operation */ - cv[0] = ONE; - Xv[0] = gval; - nvec = 1; + retval = N_VDotProdMulti((int) lAA, fv, kin_mem->kin_q_aa, gamma); + if (retval != KIN_SUCCESS) return(KIN_VECTOROP_ERR); - for (i=lAA-1; i > -1; i--) { - for (j=i+1; j < lAA; j++) { - gamma[i] = gamma[i]-R[j*kin_mem->kin_m_aa+i]*gamma[j]; - } - gamma[i] = gamma[i]/R[i*kin_mem->kin_m_aa+i]; + /* set arrays for fused vector operation */ + cv[0] = ONE; + Xv[0] = gval; + nvec = 1; - cv[nvec] = -gamma[i]; - Xv[nvec] = kin_mem->kin_dg_aa[ipt_map[i]]; - nvec += 1; + for (i=lAA-1; i > -1; i--) { + for (j=i+1; j < lAA; j++) { + gamma[i] = gamma[i]-R[j*kin_mem->kin_m_aa+i]*gamma[j]; } + gamma[i] = gamma[i]/R[i*kin_mem->kin_m_aa+i]; - /* update solution */ - retval = N_VLinearCombination(nvec, cv, Xv, x); - if (retval != KIN_SUCCESS) return(KIN_VECTOROP_ERR); + cv[nvec] = -gamma[i]; + Xv[nvec] = kin_mem->kin_dg_aa[ipt_map[i]]; + nvec += 1; + } + /* if enabled, apply damping */ + if (kin_mem->kin_damping_aa) { + onembeta = (ONE - kin_mem->kin_beta_aa); + cv[nvec] = -onembeta; + Xv[nvec] = fv; + nvec += 1; + for (i = lAA - 1; i > -1; i--) { + cv[nvec] = onembeta * gamma[i]; + Xv[nvec] = kin_mem->kin_df_aa[ipt_map[i]]; + nvec += 1; + } } + /* update solution */ + retval = N_VLinearCombination(nvec, cv, Xv, x); + if (retval != KIN_SUCCESS) return(KIN_VECTOROP_ERR); + return 0; } diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_bbdpre.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_bbdpre.c index 9c6d5323d..a4683904c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_bbdpre.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_bbdpre.c @@ -4,7 +4,7 @@ * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_bbdpre_impl.h b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_bbdpre_impl.h index 5e4a3e9a7..95f1e5804 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_bbdpre_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_bbdpre_impl.h @@ -4,7 +4,7 @@ * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_direct.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_direct.c index 2d04fa67b..8f6bc1d5f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_direct.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_direct.c @@ -3,7 +3,7 @@ * Radu Serban @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_impl.h b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_impl.h index ff4b883d7..bfedf0cb7 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_impl.h @@ -4,7 +4,7 @@ * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -35,7 +35,7 @@ extern "C" { */ /* KINSOL default constants */ - + #define PRINTFL_DEFAULT 0 #define MXITER_DEFAULT 200 #define MXNBCF_DEFAULT 10 @@ -58,45 +58,45 @@ extern "C" { typedef struct KINMemRec { - realtype kin_uround; /* machine epsilon (or unit roundoff error) - (defined in sundials_types.h) */ + realtype kin_uround; /* machine epsilon (or unit roundoff error) + (defined in sundials_types.h) */ /* problem specification data */ KINSysFn kin_func; /* nonlinear system function implementation */ void *kin_user_data; /* work space available to func routine */ realtype kin_fnormtol; /* stopping tolerance on L2-norm of function - value */ + value */ realtype kin_scsteptol; /* scaled step length tolerance */ int kin_globalstrategy; /* choices are KIN_NONE, KIN_LINESEARCH - KIN_PICARD and KIN_FP */ + KIN_PICARD and KIN_FP */ int kin_printfl; /* level of verbosity of output */ long int kin_mxiter; /* maximum number of nonlinear iterations */ long int kin_msbset; /* maximum number of nonlinear iterations that - may be performed between calls to the - linear solver setup routine (lsetup) */ + may be performed between calls to the + linear solver setup routine (lsetup) */ long int kin_msbset_sub; /* subinterval length for residual monitoring */ long int kin_mxnbcf; /* maximum number of beta condition failures */ int kin_etaflag; /* choices are KIN_ETACONSTANT, KIN_ETACHOICE1 - and KIN_ETACHOICE2 */ + and KIN_ETACHOICE2 */ booleantype kin_noMinEps; /* flag controlling whether or not the value - of eps is bounded below */ + of eps is bounded below */ booleantype kin_constraintsSet; /* flag indicating if constraints are being - used */ - booleantype kin_jacCurrent; /* flag indicating if the Jacobian info. - used by the linear solver is current */ + used */ + booleantype kin_jacCurrent; /* flag indicating if the Jacobian info. + used by the linear solver is current */ booleantype kin_callForcingTerm; /* flag set if using either KIN_ETACHOICE1 - or KIN_ETACHOICE2 */ + or KIN_ETACHOICE2 */ booleantype kin_noResMon; /* flag indicating if the nonlinear - residual monitoring scheme should be - used */ + residual monitoring scheme should be + used */ booleantype kin_retry_nni; /* flag indicating if nonlinear iteration - should be retried (set by residual - monitoring algorithm) */ + should be retried (set by residual + monitoring algorithm) */ booleantype kin_update_fnorm_sub; /* flag indicating if the fnorm associated - with the subinterval needs to be - updated (set by residual monitoring - algorithm) */ + with the subinterval needs to be + updated (set by residual monitoring + algorithm) */ realtype kin_mxnewtstep; /* maximum allowable scaled step length */ realtype kin_mxnstepin; /* input (or preset) value for mxnewtstep */ @@ -106,93 +106,95 @@ typedef struct KINMemRec { realtype kin_eps; /* current value of eps */ realtype kin_eta; /* current value of eta */ realtype kin_eta_gamma; /* gamma value used in eta calculation - (choice #2) */ + (choice #2) */ realtype kin_eta_alpha; /* alpha value used in eta calculation - (choice #2) */ + (choice #2) */ booleantype kin_noInitSetup; /* flag controlling whether or not the KINSol - routine makes an initial call to the - linear solver setup routine (lsetup) */ - realtype kin_sthrsh; /* threshold value for calling the linear - solver setup routine */ + routine makes an initial call to the + linear solver setup routine (lsetup) */ + realtype kin_sthrsh; /* threshold value for calling the linear + solver setup routine */ /* counters */ long int kin_nni; /* number of nonlinear iterations */ long int kin_nfe; /* number of calls made to func routine */ long int kin_nnilset; /* value of nni counter when the linear solver - setup was last called */ + setup was last called */ long int kin_nnilset_sub; /* value of nni counter when the linear solver - setup was last called (subinterval) */ - long int kin_nbcf; /* number of times the beta-condition could not - be met in KINLineSearch */ + setup was last called (subinterval) */ + long int kin_nbcf; /* number of times the beta-condition could not + be met in KINLineSearch */ long int kin_nbktrk; /* number of backtracks performed by - KINLineSearch */ + KINLineSearch */ long int kin_ncscmx; /* number of consecutive steps of size - mxnewtstep taken */ + mxnewtstep taken */ /* vectors */ N_Vector kin_uu; /* solution vector/current iterate (initially - contains initial guess, but holds approximate - solution upon completion if no errors occurred) */ + contains initial guess, but holds approximate + solution upon completion if no errors occurred) */ N_Vector kin_unew; /* next iterate (unew = uu+pp) */ N_Vector kin_fval; /* vector containing result of nonlinear system - function evaluated at a given iterate - (fval = func(uu)) */ - N_Vector kin_gval; /* vector containing result of the fixed point - function evaluated at a given iterate; - used in KIN_PICARD strategy only. - (gval = uu - L^{-1}fval(uu)) */ + function evaluated at a given iterate + (fval = func(uu)) */ + N_Vector kin_gval; /* vector containing result of the fixed point + function evaluated at a given iterate; + used in KIN_PICARD strategy only. + (gval = uu - L^{-1}fval(uu)) */ N_Vector kin_uscale; /* iterate scaling vector */ N_Vector kin_fscale; /* fval scaling vector */ N_Vector kin_pp; /* incremental change vector (pp = unew-uu) */ - N_Vector kin_constraints; /* constraints vector */ + N_Vector kin_constraints; /* constraints vector */ N_Vector kin_vtemp1; /* scratch vector #1 */ N_Vector kin_vtemp2; /* scratch vector #2 */ - /* space requirements for AA, Broyden and NLEN */ - N_Vector kin_fold_aa; /* vector needed for AA, Broyden, and NLEN */ - N_Vector kin_gold_aa; /* vector needed for AA, Broyden, and NLEN */ - N_Vector *kin_df_aa; /* vector array needed for AA, Broyden, and NLEN */ - N_Vector *kin_dg_aa; /* vector array needed for AA, Broyden and NLEN */ - N_Vector *kin_q_aa; /* vector array needed for AA */ + /* space requirements for AA, Broyden and NLEN */ + N_Vector kin_fold_aa; /* vector needed for AA, Broyden, and NLEN */ + N_Vector kin_gold_aa; /* vector needed for AA, Broyden, and NLEN */ + N_Vector *kin_df_aa; /* vector array needed for AA, Broyden, and NLEN */ + N_Vector *kin_dg_aa; /* vector array needed for AA, Broyden and NLEN */ + N_Vector *kin_q_aa; /* vector array needed for AA */ + realtype kin_beta_aa; /* beta damping parameter for AA */ realtype *kin_gamma_aa; /* array of size maa used in AA */ realtype *kin_R_aa; /* array of size maa*maa used in AA */ - int *kin_ipt_map; /* array of size maa used in AA */ - sunindextype kin_m_aa; /* parameter for AA, Broyden or NLEN */ + long int *kin_ipt_map; /* array of size maa used in AA */ + long int kin_m_aa; /* parameter for AA, Broyden or NLEN */ booleantype kin_aamem_aa; /* sets additional memory needed for Anderson Acc */ booleantype kin_setstop_aa; /* determines whether user will set stopping criterion */ + booleantype kin_damping_aa; /* flag to apply damping in AA */ realtype *kin_cv; /* scalar array for fused vector operations */ N_Vector *kin_Xv; /* vector array for fused vector operations */ - /* space requirements for vector storage */ + /* space requirements for vector storage */ sunindextype kin_lrw1; /* number of realtype-sized memory blocks needed - for a single N_Vector */ + for a single N_Vector */ sunindextype kin_liw1; /* number of int-sized memory blocks needed for - a single N_Vecotr */ + a single N_Vecotr */ long int kin_lrw; /* total number of realtype-sized memory blocks - needed for all KINSOL work vectors */ + needed for all KINSOL work vectors */ long int kin_liw; /* total number of int-sized memory blocks needed - for all KINSOL work vectors */ + for all KINSOL work vectors */ /* linear solver data */ - + /* function prototypes (pointers) */ int (*kin_linit)(struct KINMemRec *kin_mem); int (*kin_lsetup)(struct KINMemRec *kin_mem); - int (*kin_lsolve)(struct KINMemRec *kin_mem, N_Vector xx, N_Vector bb, - realtype *sJpnorm, realtype *sFdotJp); + int (*kin_lsolve)(struct KINMemRec *kin_mem, N_Vector xx, N_Vector bb, + realtype *sJpnorm, realtype *sFdotJp); int (*kin_lfree)(struct KINMemRec *kin_mem); booleantype kin_inexact_ls; /* flag set by the linear solver module - (in linit) indicating whether this is an - iterative linear solver (SUNTRUE), or a direct - linear solver (SUNFALSE) */ + (in linit) indicating whether this is an + iterative linear solver (SUNTRUE), or a direct + linear solver (SUNFALSE) */ void *kin_lmem; /* pointer to linear solver memory block */ @@ -206,13 +208,13 @@ typedef struct KINMemRec { realtype kin_fnorm_sub; /* value of L2-norm of fscale*fval (subinterval) */ booleantype kin_eval_omega; /* flag indicating that omega must be evaluated. */ realtype kin_omega; /* constant value for real scalar used in test to - determine if reduction of norm of nonlinear - residual is sufficient. Unless a valid constant + determine if reduction of norm of nonlinear + residual is sufficient. Unless a valid constant value is specified by the user, omega is estimated from omega_min and omega_max at each iteration. */ realtype kin_omega_min; /* lower bound on omega */ realtype kin_omega_max; /* upper bound on omega */ - + /* * ----------------------------------------------------------------- * Note: The KINLineSearch subroutine scales the values of the @@ -231,11 +233,11 @@ typedef struct KINMemRec { */ booleantype kin_MallocDone; /* flag indicating if KINMalloc has been - called yet */ + called yet */ /* message files */ /*------------------------------------------- - Error handler function and error ouput file + Error handler function and error ouput file -------------------------------------------*/ KINErrHandlerFn kin_ehfun; /* Error messages are handled by ehfun */ @@ -338,7 +340,7 @@ typedef struct KINMemRec { * ----------------------------------------------------------------- * kin_lfree is called by KINFree and should free (deallocate) all * system memory resources allocated for the linear solver module - * (see KINSpgmrFree/KINSpbcgFree). It should return 0 upon + * (see KINSpgmrFree/KINSpbcgFree). It should return 0 upon * success, nonzero on failure. * * kinmem pointer to an internal memory block allocated during @@ -355,26 +357,26 @@ typedef struct KINMemRec { /* High level error handler */ -void KINProcessError(KINMem kin_mem, - int error_code, const char *module, const char *fname, - const char *msgfmt, ...); +void KINProcessError(KINMem kin_mem, + int error_code, const char *module, const char *fname, + const char *msgfmt, ...); /* Prototype of internal errHandler function */ -void KINErrHandler(int error_code, const char *module, const char *function, - char *msg, void *user_data); +void KINErrHandler(int error_code, const char *module, const char *function, + char *msg, void *user_data); /* High level info handler */ -void KINPrintInfo(KINMem kin_mem, - int info_code, const char *module, const char *fname, - const char *msgfmt, ...); +void KINPrintInfo(KINMem kin_mem, + int info_code, const char *module, const char *fname, + const char *msgfmt, ...); /* Prototype of internal infoHandler function */ -void KINInfoHandler(const char *module, const char *function, - char *msg, void *user_data); +void KINInfoHandler(const char *module, const char *function, + char *msg, void *user_data); /* * ================================================================= diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_io.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_io.c index 5a5138fb9..143aa2869 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_io.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_io.c @@ -1,13 +1,9 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Allan Taylor, Alan Hindmarsh, Radu Serban, and * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -38,18 +34,13 @@ #define TWO RCONST(2.0) #define TWOPT5 RCONST(2.5) -#define liw (kin_mem->kin_liw) -#define lrw (kin_mem->kin_lrw) -#define liw1 (kin_mem->kin_liw1) -#define lrw1 (kin_mem->kin_lrw1) - -/* +/* * ================================================================= * KINSOL optional input functions * ================================================================= */ -/* +/* * ----------------------------------------------------------------- * KINSetErrHandlerFn * ----------------------------------------------------------------- @@ -122,7 +113,7 @@ int KINSetPrintLevel(void *kinmem, int printfl) return(KIN_SUCCESS); } -/* +/* * ----------------------------------------------------------------- * KINSetInfoHandlerFn * ----------------------------------------------------------------- @@ -212,13 +203,49 @@ int KINSetMAA(void *kinmem, long int maa) if (maa > kin_mem->kin_mxiter) maa = kin_mem->kin_mxiter; - kin_mem = (KINMem) kinmem; kin_mem->kin_m_aa = maa; kin_mem->kin_aamem_aa = (maa == 0) ? SUNFALSE : SUNTRUE; return(KIN_SUCCESS); } +/* + * ----------------------------------------------------------------- + * Function : KINSetDampingAA + * ----------------------------------------------------------------- + */ + +int KINSetDampingAA(void *kinmem, realtype beta) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetMAA", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + /* check for illegal input value */ + if (beta <= ZERO) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetDampingAA", + "beta <= 0 illegal"); + return(KIN_ILL_INPUT); + } + + if (beta < ONE) { + /* enable damping */ + kin_mem->kin_beta_aa = beta; + kin_mem->kin_damping_aa = SUNTRUE; + } else { + /* disable damping */ + kin_mem->kin_beta_aa = ONE; + kin_mem->kin_damping_aa = SUNFALSE; + } + + return(KIN_SUCCESS); +} + /* * ----------------------------------------------------------------- * Function : KINSetAAStopCrit @@ -336,7 +363,7 @@ int KINSetMaxSetupCalls(void *kinmem, long int msbset) KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetMaxSetupCalls", MSG_BAD_MSBSET); return(KIN_ILL_INPUT); } - + if (msbset == 0) kin_mem->kin_msbset = MSBSET_DEFAULT; else @@ -366,7 +393,7 @@ int KINSetMaxSubSetupCalls(void *kinmem, long int msbsetsub) KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetMaxSubSetupCalls", MSG_BAD_MSBSETSUB); return(KIN_ILL_INPUT); } - + if (msbsetsub == 0) kin_mem->kin_msbset_sub = MSBSET_SUB_DEFAULT; else @@ -392,8 +419,8 @@ int KINSetEtaForm(void *kinmem, int etachoice) kin_mem = (KINMem) kinmem; - if ((etachoice != KIN_ETACONSTANT) && - (etachoice != KIN_ETACHOICE1) && + if ((etachoice != KIN_ETACONSTANT) && + (etachoice != KIN_ETACHOICE1) && (etachoice != KIN_ETACHOICE2)) { KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetEtaForm", MSG_BAD_ETACHOICE); return(KIN_ILL_INPUT); @@ -456,8 +483,8 @@ int KINSetEtaParams(void *kinmem, realtype egamma, realtype ealpha) KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetEtaParams", MSG_BAD_ALPHA); return(KIN_ILL_INPUT); } - - if (ealpha == ZERO) + + if (ealpha == ZERO) kin_mem->kin_eta_alpha = TWO; else kin_mem->kin_eta_alpha = ealpha; @@ -500,7 +527,7 @@ int KINSetResMonParams(void *kinmem, realtype omegamin, realtype omegamax) return(KIN_ILL_INPUT); } - if (omegamin == ZERO) + if (omegamin == ZERO) kin_mem->kin_omega_min = OMEGA_MIN; else kin_mem->kin_omega_min = omegamin; @@ -765,8 +792,8 @@ int KINSetConstraints(void *kinmem, N_Vector constraints) if (constraints == NULL) { if (kin_mem->kin_constraintsSet) { N_VDestroy(kin_mem->kin_constraints); - lrw -= lrw1; - liw -= liw1; + kin_mem->kin_lrw -= kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_liw1; } kin_mem->kin_constraintsSet = SUNFALSE; return(KIN_SUCCESS); @@ -775,15 +802,15 @@ int KINSetConstraints(void *kinmem, N_Vector constraints) /* Check the constraints vector */ temptest = N_VMaxNorm(constraints); - if (temptest > TWOPT5){ + if (temptest > TWOPT5){ KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetConstraints", MSG_BAD_CONSTRAINTS); - return(KIN_ILL_INPUT); + return(KIN_ILL_INPUT); } if (!kin_mem->kin_constraintsSet) { kin_mem->kin_constraints = N_VClone(constraints); - lrw += lrw1; - liw += liw1; + kin_mem->kin_lrw += kin_mem->kin_lrw1; + kin_mem->kin_liw += kin_mem->kin_liw1; kin_mem->kin_constraintsSet = SUNTRUE; } @@ -821,24 +848,10 @@ int KINSetSysFunc(void *kinmem, KINSysFn func) return(KIN_SUCCESS); } -/* - * ================================================================= - * Readability constants - * ================================================================= - */ - -#define nni (kin_mem->kin_nni) -#define nfe (kin_mem->kin_nfe) -#define nbcf (kin_mem->kin_nbcf) -#define nbktrk (kin_mem->kin_nbktrk) -#define stepl (kin_mem->kin_stepl) -#define fnorm (kin_mem->kin_fnorm) -#define liw (kin_mem->kin_liw) -#define lrw (kin_mem->kin_lrw) -/* +/* * ================================================================= - * KINSOL optional input functions + * KINSOL optional output functions * ================================================================= */ @@ -859,8 +872,8 @@ int KINGetWorkSpace(void *kinmem, long int *lenrw, long int *leniw) kin_mem = (KINMem) kinmem; - *lenrw = lrw; - *leniw = liw; + *lenrw = kin_mem->kin_lrw; + *leniw = kin_mem->kin_liw; return(KIN_SUCCESS); } @@ -881,7 +894,7 @@ int KINGetNumNonlinSolvIters(void *kinmem, long int *nniters) } kin_mem = (KINMem) kinmem; - *nniters = nni; + *nniters = kin_mem->kin_nni; return(KIN_SUCCESS); } @@ -902,7 +915,7 @@ int KINGetNumFuncEvals(void *kinmem, long int *nfevals) } kin_mem = (KINMem) kinmem; - *nfevals = nfe; + *nfevals = kin_mem->kin_nfe; return(KIN_SUCCESS); } @@ -923,7 +936,7 @@ int KINGetNumBetaCondFails(void *kinmem, long int *nbcfails) } kin_mem = (KINMem) kinmem; - *nbcfails = nbcf; + *nbcfails = kin_mem->kin_nbcf; return(KIN_SUCCESS); } @@ -944,7 +957,7 @@ int KINGetNumBacktrackOps(void *kinmem, long int *nbacktr) } kin_mem = (KINMem) kinmem; - *nbacktr = nbktrk; + *nbacktr = kin_mem->kin_nbktrk; return(KIN_SUCCESS); } @@ -986,7 +999,7 @@ int KINGetStepLength(void *kinmem, realtype *steplength) } kin_mem = (KINMem) kinmem; - *steplength = stepl; + *steplength = kin_mem->kin_stepl; return(KIN_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_ls.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_ls.c index 8f5f611ee..cd8bd2b5f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_ls.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_ls.c @@ -3,7 +3,7 @@ * David J. Gardner, Radu Serban and Aaron Collier @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -44,9 +44,11 @@ ---------------------------------------------------------------*/ int KINSetLinearSolver(void *kinmem, SUNLinearSolver LS, SUNMatrix A) { - KINMem kin_mem; - KINLsMem kinls_mem; - int retval, LSType; + KINMem kin_mem; + KINLsMem kinls_mem; + int retval, LSType; + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ /* Return immediately if either kinmem or LS inputs are NULL */ if (kinmem == NULL) { @@ -63,16 +65,20 @@ int KINSetLinearSolver(void *kinmem, SUNLinearSolver LS, SUNMatrix A) kin_mem = (KINMem) kinmem; /* Test if solver is compatible with LS interface */ - if ( (LS->ops->gettype == NULL) || - (LS->ops->initialize == NULL) || - (LS->ops->setup == NULL) || - (LS->ops->solve == NULL) ) { + if ( (LS->ops->gettype == NULL) || (LS->ops->solve == NULL) ) { KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", "KINSetLinearSolver", "LS object is missing a required operation"); return(KINLS_ILL_INPUT); } + /* Retrieve the LS type */ + LSType = SUNLinSolGetType(LS); + + /* Set flags based on LS type */ + iterative = (LSType != SUNLINEARSOLVER_DIRECT); + matrixbased = (LSType != SUNLINEARSOLVER_ITERATIVE); + /* check for required vector operations for KINLS interface */ if ( (kin_mem->kin_vtemp1->ops->nvconst == NULL) || (kin_mem->kin_vtemp1->ops->nvdotprod == NULL) ) { @@ -81,32 +87,40 @@ int KINSetLinearSolver(void *kinmem, SUNLinearSolver LS, SUNMatrix A) return(KINLS_ILL_INPUT); } - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(LS); - /* Check for compatible LS type, matrix and "atimes" support */ - if ((LSType == SUNLINEARSOLVER_ITERATIVE) && (LS->ops->setatimes == NULL)) { - KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", "KINSetLinearSolver", - "Incompatible inputs: iterative LS must support ATimes routine"); - return(KINLS_ILL_INPUT); - } - if ((LSType == SUNLINEARSOLVER_DIRECT) && (A == NULL)) { + if (iterative) { + + if ((LS->ops->setscalingvectors == NULL) && + (kin_mem->kin_vtemp1->ops->nvgetlength == NULL)) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", + "KINSetLinearSolver", MSG_LS_BAD_NVECTOR); + return(KINLS_ILL_INPUT); + } + + if (!matrixbased && (LS->ops->setatimes == NULL)) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", "KINSetLinearSolver", + "Incompatible inputs: iterative LS must support ATimes routine"); + return(KINLS_ILL_INPUT); + } + + if (matrixbased && A == NULL) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", "KINSetLinearSolver", + "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); + return(KINLS_ILL_INPUT); + } + + } else if (A == NULL) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", "KINSetLinearSolver", "Incompatible inputs: direct LS requires non-NULL matrix"); return(KINLS_ILL_INPUT); } - if ((LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) && (A == NULL)) { - KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", "KINSetLinearSolver", - "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); - return(KINLS_ILL_INPUT); - } /* free any existing system solver attached to KIN */ if (kin_mem->kin_lfree) kin_mem->kin_lfree(kin_mem); /* Determine if this is an iterative linear solver */ - kin_mem->kin_inexact_ls = ( (LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ); + kin_mem->kin_inexact_ls = iterative; /* Set four main system linear solver function fields in kin_mem */ kin_mem->kin_linit = kinLsInitialize; @@ -928,7 +942,7 @@ int kinLsDQJtimes(N_Vector v, N_Vector Jv, N_Vector u, int kinLsInitialize(KINMem kin_mem) { KINLsMem kinls_mem; - int retval, LSType; + int retval; /* Access KINLsMem structure */ if (kin_mem->kin_lmem == NULL) { @@ -938,9 +952,6 @@ int kinLsInitialize(KINMem kin_mem) } kinls_mem = (KINLsMem) kin_mem->kin_lmem; - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(kinls_mem->LS); - /* Test for valid combinations of matrix & Jacobian routines: */ if (kinls_mem->J == NULL) { @@ -1047,17 +1058,11 @@ int kinLsInitialize(KINMem kin_mem) <=> \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 / fs_mean^2 <=> || b - A x ||_2 < tol / fs_mean <=> || b - A x ||_2 < tol * tol_fac - So we compute tol_fac = 1 / ||fscale||_RMS = sqrt(n) / ||fscale||_2, - for scaling desired tolerances */ - if ( ((LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE)) && - (kinls_mem->LS->ops->setscalingvectors == NULL) ) { - - /* compute tol_fac = ||1||_2 / ||fscale||_2 */ + So we compute tol_fac = sqrt(N) / ||fscale||_L2 for scaling desired tolerances */ + if (kinls_mem->iterative && kinls_mem->LS->ops->setscalingvectors == NULL) { N_VConst(ONE, kin_mem->kin_vtemp1); - kinls_mem->tol_fac = SUNRsqrt( N_VDotProd(kin_mem->kin_vtemp1, - kin_mem->kin_vtemp1) ) - / SUNRsqrt( N_VDotProd(kin_mem->kin_fscale, kin_mem->kin_fscale) ); + kinls_mem->tol_fac = SUNRsqrt(N_VGetLength(kin_mem->kin_vtemp1)) + / N_VWL2Norm(kin_mem->kin_fscale, kin_mem->kin_vtemp1); } else { kinls_mem->tol_fac = ONE; } @@ -1084,20 +1089,21 @@ int kinLsSetup(KINMem kin_mem) } kinls_mem = (KINLsMem) kin_mem->kin_lmem; - /* recompute if J if it is non-NULL */ if (kinls_mem->J) { /* Increment nje counter. */ kinls_mem->nje++; - /* Zero out J */ - retval = SUNMatZero(kinls_mem->J); - if (retval != 0) { - KINProcessError(kin_mem, KINLS_SUNMAT_FAIL, "KINLS", - "kinLsSetup", MSG_LS_MATZERO_FAILED); - kinls_mem->last_flag = KINLS_SUNMAT_FAIL; - return(kinls_mem->last_flag); + /* Clear the linear system matrix if necessary */ + if (SUNLinSolGetType(kinls_mem->LS) == SUNLINEARSOLVER_DIRECT) { + retval = SUNMatZero(kinls_mem->J); + if (retval != 0) { + KINProcessError(kin_mem, KINLS_SUNMAT_FAIL, "KINLS", + "kinLsSetup", MSG_LS_MATZERO_FAILED); + kinls_mem->last_flag = KINLS_SUNMAT_FAIL; + return(kinls_mem->last_flag); + } } /* Call Jacobian routine */ @@ -1132,7 +1138,7 @@ int kinLsSolve(KINMem kin_mem, N_Vector xx, N_Vector bb, { KINLsMem kinls_mem; int nli_inc, retval; - realtype res_norm, tol, LSType; + realtype res_norm, tol; /* Access KINLsMem structure */ if (kin_mem->kin_lmem == NULL) { @@ -1142,9 +1148,6 @@ int kinLsSolve(KINMem kin_mem, N_Vector xx, N_Vector bb, } kinls_mem = (KINLsMem) kin_mem->kin_lmem; - /* Retrieve the LS type */ - LSType = SUNLinSolGetType(kinls_mem->LS); - /* Set linear solver tolerance as input value times scaling factor (to account for possible lack of support for left/right scaling vectors in SUNLinSol object) */ @@ -1167,9 +1170,7 @@ int kinLsSolve(KINMem kin_mem, N_Vector xx, N_Vector bb, if (kinls_mem->LS->ops->numiters) nli_inc = SUNLinSolNumIters(kinls_mem->LS); - if ( ((LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE)) && - (kin_mem->kin_printfl > 2) ) + if (kinls_mem->iterative && kin_mem->kin_printfl > 2) KINPrintInfo(kin_mem, PRNT_NLI, "KINLS", "kinLsSolve", INFO_NLI, nli_inc); @@ -1218,43 +1219,39 @@ int kinLsSolve(KINMem kin_mem, N_Vector xx, N_Vector bb, return(retval); } - /* SUNLinSolSolve returned SUNLS_SUCCESS or SUNLS_RES_REDUCED + /* SUNLinSolSolve returned SUNLS_SUCCESS or SUNLS_RES_REDUCED */ - Compute auxiliary values for use in the linesearch and in KINForcingTerm. + /* Compute auxiliary values for use in the linesearch and in KINForcingTerm. These will be subsequently corrected if the step is reduced by constraints or the linesearch. */ - - - /* sJpnorm is the norm of the scaled product (scaled by fscale) of the - current Jacobian matrix J and the step vector p (= solution vector xx). - - Only compute this if KINForcingTerm will eventually be called */ - if ( (kin_mem->kin_globalstrategy != KIN_PICARD) && - (kin_mem->kin_globalstrategy != KIN_FP) && - (kin_mem->kin_callForcingTerm) ) { - - retval = kinLsATimes(kin_mem, xx, bb); - if (retval > 0) { - kinls_mem->last_flag = SUNLS_ATIMES_FAIL_REC; - return(1); - } - else if (retval < 0) { - kinls_mem->last_flag = SUNLS_ATIMES_FAIL_UNREC; - return(-1); + if (kin_mem->kin_globalstrategy != KIN_FP) { + + /* sJpnorm is the norm of the scaled product (scaled by fscale) of the + current Jacobian matrix J and the step vector p (= solution vector xx) */ + if (kin_mem->kin_inexact_ls && kin_mem->kin_etaflag == KIN_ETACHOICE1) { + retval = kinLsATimes(kin_mem, xx, bb); + if (retval > 0) { + kinls_mem->last_flag = SUNLS_ATIMES_FAIL_REC; + return(1); + } + else if (retval < 0) { + kinls_mem->last_flag = SUNLS_ATIMES_FAIL_UNREC; + return(-1); + } + *sJpnorm = N_VWL2Norm(bb, kin_mem->kin_fscale); } - *sJpnorm = N_VWL2Norm(bb, kin_mem->kin_fscale); + /* sFdotJp is the dot product of the scaled f vector and the scaled + vector J*p, where the scaling uses fscale */ + if ((kin_mem->kin_inexact_ls && kin_mem->kin_etaflag == KIN_ETACHOICE1) || + kin_mem->kin_globalstrategy == KIN_LINESEARCH) { + N_VProd(bb, kin_mem->kin_fscale, bb); + N_VProd(bb, kin_mem->kin_fscale, bb); + *sFdotJp = N_VDotProd(kin_mem->kin_fval, bb); + } } - /* sFdotJp is the dot product of the scaled f vector and the scaled - vector J*p, where the scaling uses fscale */ - N_VProd(bb, kin_mem->kin_fscale, bb); - N_VProd(bb, kin_mem->kin_fscale, bb); - *sFdotJp = N_VDotProd(kin_mem->kin_fval, bb); - - if ( ((LSType == SUNLINEARSOLVER_ITERATIVE) || - (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE)) && - (kin_mem->kin_printfl > 2) ) + if (kin_mem->kin_inexact_ls && kin_mem->kin_printfl > 2) KINPrintInfo(kin_mem, PRNT_EPS, "KINLS", "kinLsSolve", INFO_EPS, res_norm, kin_mem->kin_eps); diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_ls_impl.h b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_ls_impl.h index bbf540da5..ffcf35ff1 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_ls_impl.h +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_ls_impl.h @@ -3,7 +3,7 @@ * David J. Gardner, Radu Serban and Aaron Collier @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -42,6 +42,10 @@ extern "C" { ------------------------------------------------------------------*/ typedef struct KINLsMemRec { + /* Linear solver type information */ + booleantype iterative; /* is the solver iterative? */ + booleantype matrixbased; /* is a matrix structure used? */ + /* Jacobian construction & storage */ booleantype jacDQ; /* SUNTRUE if using internal DQ Jacobian approx. */ KINLsJacFn jac; /* Jacobian routine to be called */ @@ -69,7 +73,7 @@ typedef struct KINLsMemRec { reevaluated (meant to be used by a user-supplied jtimes function */ - long int last_flag; /* last error return flag */ + int last_flag; /* last error return flag */ /* Preconditioner computation (a) user-provided: diff --git a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_spils.c b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_spils.c index 9e3ce8209..0ab96bce0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_spils.c +++ b/deps/AMICI/ThirdParty/sundials/src/kinsol/kinsol_spils.c @@ -4,7 +4,7 @@ * and Aaron Collier @ LLNL *----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/nvector/CMakeLists.txt index 1dc3a7f9a..81dc9ecd4 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/CMakeLists.txt @@ -2,7 +2,7 @@ # Programmer(s): Cody J. Balos @ LLNL # ------------------------------------------------------------------------------ # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -17,11 +17,18 @@ # Always add SUNDIALS serial vector add_subdirectory(serial) +# Always add SUNDIALS ManyVector +add_subdirectory(manyvector) + # Add NVECTOR modules with depedencies if(MPI_ENABLE AND MPI_C_FOUND) add_subdirectory(parallel) endif(MPI_ENABLE AND MPI_C_FOUND) +if(MPI_ENABLE AND MPI_C_FOUND) + add_subdirectory(mpiplusx) +endif(MPI_ENABLE AND MPI_C_FOUND) + if(HYPRE_ENABLE AND HYPRE_FOUND) add_subdirectory(parhyp) endif(HYPRE_ENABLE AND HYPRE_FOUND) @@ -34,23 +41,22 @@ if(OPENMP_DEVICE_ENABLE AND OPENMP_FOUND AND OPENMP_SUPPORTS_DEVICE_OFFLOADING) add_subdirectory(openmpdev) endif(OPENMP_DEVICE_ENABLE AND OPENMP_FOUND AND OPENMP_SUPPORTS_DEVICE_OFFLOADING) -if(PTHREADS_ENABLE AND PTHREADS_FOUND) +if(PTHREAD_ENABLE AND PTHREADS_FOUND) add_subdirectory(pthreads) -endif(PTHREADS_ENABLE AND PTHREADS_FOUND) +endif(PTHREAD_ENABLE AND PTHREADS_FOUND) if(PETSC_ENABLE AND PETSC_FOUND) add_subdirectory(petsc) endif(PETSC_ENABLE AND PETSC_FOUND) -if(CUDA_ENABLE AND CUDA_FOUND) +if(CUDA_ENABLE AND CMAKE_CUDA_COMPILER) add_subdirectory(cuda) -endif(CUDA_ENABLE AND CUDA_FOUND) +endif(CUDA_ENABLE AND CMAKE_CUDA_COMPILER) if(RAJA_ENABLE AND RAJA_FOUND) add_subdirectory(raja) endif(RAJA_ENABLE AND RAJA_FOUND) -IF(Trilinos_ENABLE AND Trilinos_FUNCTIONAL) - ADD_SUBDIRECTORY(trilinos) -ENDIF(Trilinos_ENABLE AND Trilinos_FUNCTIONAL) - +if(Trilinos_ENABLE AND Trilinos_FOUND) + add_subdirectory(trilinos) +endif(Trilinos_ENABLE AND Trilinos_FOUND) diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/cuda/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/nvector/cuda/CMakeLists.txt index 4a90c498b..063906f5a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/cuda/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/cuda/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Slaven Peles, and Cody J. Balos @ LLNL +# Programmer(s): Slaven Peles and Cody J. Balos @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,89 +12,59 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the cuda NVECTOR library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall NVECTOR_CUDA\n\")") - -# Add variable nveccuda_SOURCES with the sources for the NVECSERIAL lib -SET(nveccuda_SOURCES nvector_cuda.cu) +install(CODE "MESSAGE(\"\nInstall NVECTOR_CUDA\n\")") -# Tell compiler it is a CUDA source -set_source_files_properties(${nveccuda_SOURCES} PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ) +# Add variable nveccuda_SOURCES with the sources for the NVECUDA lib +set(nveccuda_SOURCES nvector_cuda.cu) # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the NVECCUDA library -SET(shared_SOURCES +set(shared_SOURCES + sundials_nvector.c sundials_math.c - sundials_mpi.c ) -ADD_PREFIX(${sundials_SOURCE_DIR}/src/sundials/ shared_SOURCES) - -# Add variable nveccuda_HEADERS with the exported NVECSERIAL header files -SET(nveccuda_HEADERS nvector_cuda.h) -IF (MPI_ENABLE) - LIST(APPEND nveccuda_HEADERS nvector_mpicuda.h) -ENDIF() -ADD_PREFIX(${sundials_SOURCE_DIR}/include/nvector/ nveccuda_HEADERS) +add_prefix(${sundials_SOURCE_DIR}/src/sundials/ shared_SOURCES) -# Add source directory to include directories -INCLUDE_DIRECTORIES(. ${MPI_CXX_INCLUDE_PATH}) +# Add variable nveccuda_HEADERS with the exported NVECUDA header files +set(nveccuda_HEADERS nvector_cuda.h) +add_prefix(${sundials_SOURCE_DIR}/include/nvector/ nveccuda_HEADERS) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) # Rules for building and installing the static library: # - Add the build target for the NVECCUDA library # - Set the library name and make sure it is not deleted -# - Install the NVECSERIAL library -IF(BUILD_STATIC_LIBS) - # ----------------------- CUDA only - # The FindCUDA module does not properly forward compile options using target_* commands. - # So as long as we use it (required in CMake < 3.8), we have to manually add compile - # options in the CUDA_ADD_* commands. - CUDA_ADD_LIBRARY(sundials_nveccuda_static STATIC ${nveccuda_SOURCES} ${shared_SOURCES} - OPTIONS -DSUNDIALS_MPI_ENABLED=0) - TARGET_COMPILE_DEFINITIONS(sundials_nveccuda_static PUBLIC -DSUNDIALS_MPI_ENABLED=0) - - SET_TARGET_PROPERTIES(sundials_nveccuda_static - PROPERTIES OUTPUT_NAME sundials_nveccuda CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_nveccuda_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - - # ----------------------- MPI+CUDA - IF(MPI_ENABLE) - CUDA_ADD_LIBRARY(sundials_nvecmpicuda_static STATIC ${nveccuda_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_nvecmpicuda_static - PROPERTIES OUTPUT_NAME sundials_nvecmpicuda CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_nvecmpicuda_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF() -ENDIF(BUILD_STATIC_LIBS) +# - Install the NVECUDA library +if(BUILD_STATIC_LIBS) + add_library(sundials_nveccuda_static STATIC ${nveccuda_SOURCES} ${shared_SOURCES}) + target_compile_features(sundials_nveccuda_static PUBLIC cxx_std_11) + set_target_properties(sundials_nveccuda_static PROPERTIES + OUTPUT_NAME sundials_nveccuda + CLEAN_DIRECT_OUTPUT 1) + install(TARGETS sundials_nveccuda_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: -# - Add the build target for the NVECSERIAL library +# - Add the build target for the NVECUDA library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries -# - Install the NVECSERIAL library -IF(BUILD_SHARED_LIBS) - # ----------------------- CUDA only - CUDA_ADD_LIBRARY(sundials_nveccuda_shared SHARED ${nveccuda_SOURCES} ${shared_SOURCES} - OPTIONS -DSUNDIALS_MPI_ENABLED=0) - TARGET_COMPILE_DEFINITIONS(sundials_nveccuda_shared PUBLIC -DSUNDIALS_MPI_ENABLED=0) - SET_TARGET_PROPERTIES(sundials_nveccuda_shared - PROPERTIES OUTPUT_NAME sundials_nveccuda CLEAN_DIRECT_OUTPUT 1 - VERSION ${nveclib_VERSION} SOVERSION ${nveclib_SOVERSION}) - INSTALL(TARGETS sundials_nveccuda_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - - # ----------------------- MPI+CUDA - IF(MPI_ENABLE) - CUDA_ADD_LIBRARY(sundials_nvecmpicuda_shared SHARED ${nveccuda_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_nvecmpicuda_shared - PROPERTIES OUTPUT_NAME sundials_nvecmpicuda CLEAN_DIRECT_OUTPUT 1 - VERSION ${nveclib_VERSION} SOVERSION ${nveclib_SOVERSION}) - INSTALL(TARGETS sundials_nvecmpicuda_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF() -ENDIF(BUILD_SHARED_LIBS) +# - Install the NVECUDA library +if(BUILD_SHARED_LIBS) + add_library(sundials_nveccuda_shared SHARED ${nveccuda_SOURCES} ${shared_SOURCES}) + target_compile_features(sundials_nveccuda_shared PUBLIC cxx_std_11) + set_target_properties(sundials_nveccuda_shared PROPERTIES + OUTPUT_NAME sundials_nveccuda + CLEAN_DIRECT_OUTPUT 1 + VERSION ${nveclib_VERSION} + SOVERSION ${nveclib_SOVERSION}) + install(TARGETS sundials_nveccuda_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_SHARED_LIBS) # Install the CUDA NVector header files -INSTALL(FILES ${nveccuda_HEADERS} DESTINATION include/nvector) -INSTALL(DIRECTORY ${sundials_SOURCE_DIR}/include/nvector/cuda DESTINATION include/nvector) +install(FILES ${nveccuda_HEADERS} DESTINATION include/nvector) +install(DIRECTORY ${sundials_SOURCE_DIR}/include/nvector/cuda DESTINATION include/nvector) -MESSAGE(STATUS "Added NVECTOR_CUDA module") +message(STATUS "Added NVECTOR_CUDA module") diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/cuda/nvector_cuda.cu b/deps/AMICI/ThirdParty/sundials/src/nvector/cuda/nvector_cuda.cu index 58b5737fc..12ea644d4 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/cuda/nvector_cuda.cu +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/cuda/nvector_cuda.cu @@ -2,7 +2,7 @@ * Programmer(s): Slaven Peles, and Cody J. Balos @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -11,7 +11,7 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for a MPI+CUDA implementation + * This is the implementation file for a CUDA implementation * of the NVECTOR package. * -----------------------------------------------------------------*/ @@ -22,7 +22,6 @@ #include #include #include -#include #define ZERO RCONST(0.0) #define HALF RCONST(0.5) @@ -38,6 +37,7 @@ using namespace suncudavec; */ typedef suncudavec::Vector vector_type; +typedef suncudavec::ThreadPartitioning part_type; /* ---------------------------------------------------------------- * Returns vector type ID. Used to identify vector implementation @@ -51,72 +51,60 @@ N_Vector_ID N_VGetVectorID_Cuda(N_Vector v) N_Vector N_VNewEmpty_Cuda() { N_Vector v; - N_Vector_Ops ops; /* Create vector */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } + /* Attach operations */ - ops->nvgetvectorid = N_VGetVectorID_Cuda; - ops->nvclone = N_VClone_Cuda; - ops->nvcloneempty = N_VCloneEmpty_Cuda; - ops->nvdestroy = N_VDestroy_Cuda; - ops->nvspace = N_VSpace_Cuda; - ops->nvgetarraypointer = NULL; - ops->nvsetarraypointer = NULL; + /* constructors, destructors, and utility operations */ + v->ops->nvgetvectorid = N_VGetVectorID_Cuda; + v->ops->nvclone = N_VClone_Cuda; + v->ops->nvcloneempty = N_VCloneEmpty_Cuda; + v->ops->nvdestroy = N_VDestroy_Cuda; + v->ops->nvspace = N_VSpace_Cuda; + v->ops->nvgetlength = N_VGetLength_Cuda; /* standard vector operations */ - ops->nvlinearsum = N_VLinearSum_Cuda; - ops->nvconst = N_VConst_Cuda; - ops->nvprod = N_VProd_Cuda; - ops->nvdiv = N_VDiv_Cuda; - ops->nvscale = N_VScale_Cuda; - ops->nvabs = N_VAbs_Cuda; - ops->nvinv = N_VInv_Cuda; - ops->nvaddconst = N_VAddConst_Cuda; - ops->nvdotprod = N_VDotProd_Cuda; - ops->nvmaxnorm = N_VMaxNorm_Cuda; - ops->nvwrmsnormmask = N_VWrmsNormMask_Cuda; - ops->nvwrmsnorm = N_VWrmsNorm_Cuda; - ops->nvmin = N_VMin_Cuda; - ops->nvwl2norm = N_VWL2Norm_Cuda; - ops->nvl1norm = N_VL1Norm_Cuda; - ops->nvcompare = N_VCompare_Cuda; - ops->nvinvtest = N_VInvTest_Cuda; - ops->nvconstrmask = N_VConstrMask_Cuda; - ops->nvminquotient = N_VMinQuotient_Cuda; - - /* fused vector operations (optional, NULL means disabled by default) */ - ops->nvlinearcombination = NULL; - ops->nvscaleaddmulti = NULL; - ops->nvdotprodmulti = NULL; - - /* vector array operations (optional, NULL means disabled by default) */ - ops->nvlinearsumvectorarray = NULL; - ops->nvscalevectorarray = NULL; - ops->nvconstvectorarray = NULL; - ops->nvwrmsnormvectorarray = NULL; - ops->nvwrmsnormmaskvectorarray = NULL; - ops->nvscaleaddmultivectorarray = NULL; - ops->nvlinearcombinationvectorarray = NULL; - - /* Attach ops and set content to NULL */ - v->content = NULL; - v->ops = ops; + v->ops->nvlinearsum = N_VLinearSum_Cuda; + v->ops->nvconst = N_VConst_Cuda; + v->ops->nvprod = N_VProd_Cuda; + v->ops->nvdiv = N_VDiv_Cuda; + v->ops->nvscale = N_VScale_Cuda; + v->ops->nvabs = N_VAbs_Cuda; + v->ops->nvinv = N_VInv_Cuda; + v->ops->nvaddconst = N_VAddConst_Cuda; + v->ops->nvdotprod = N_VDotProd_Cuda; + v->ops->nvmaxnorm = N_VMaxNorm_Cuda; + v->ops->nvmin = N_VMin_Cuda; + v->ops->nvl1norm = N_VL1Norm_Cuda; + v->ops->nvinvtest = N_VInvTest_Cuda; + v->ops->nvconstrmask = N_VConstrMask_Cuda; + v->ops->nvminquotient = N_VMinQuotient_Cuda; + v->ops->nvwrmsnormmask = N_VWrmsNormMask_Cuda; + v->ops->nvwrmsnorm = N_VWrmsNorm_Cuda; + v->ops->nvwl2norm = N_VWL2Norm_Cuda; + v->ops->nvcompare = N_VCompare_Cuda; + + /* fused and vector array operations are disabled (NULL) by default */ + + /* local reduction operations */ + v->ops->nvdotprodlocal = N_VDotProd_Cuda; + v->ops->nvmaxnormlocal = N_VMaxNorm_Cuda; + v->ops->nvminlocal = N_VMin_Cuda; + v->ops->nvl1normlocal = N_VL1Norm_Cuda; + v->ops->nvinvtestlocal = N_VInvTest_Cuda; + v->ops->nvconstrmasklocal = N_VConstrMask_Cuda; + v->ops->nvminquotientlocal = N_VMinQuotient_Cuda; + v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_Cuda; + v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_Cuda; return(v); } -#if SUNDIALS_MPI_ENABLED -N_Vector N_VNew_Cuda(MPI_Comm comm, - sunindextype local_length, - sunindextype global_length) +N_Vector N_VNew_Cuda(sunindextype length) { N_Vector v; @@ -124,14 +112,12 @@ N_Vector N_VNew_Cuda(MPI_Comm comm, v = N_VNewEmpty_Cuda(); if (v == NULL) return(NULL); - v->content = new vector_type(comm, local_length, global_length); + v->content = new vector_type(length); return(v); } -N_Vector N_VNewManaged_Cuda(MPI_Comm comm, - sunindextype local_length, - sunindextype global_length) +N_Vector N_VNewManaged_Cuda(sunindextype length) { N_Vector v; @@ -139,15 +125,17 @@ N_Vector N_VNewManaged_Cuda(MPI_Comm comm, v = N_VNewEmpty_Cuda(); if (v == NULL) return(NULL); + /* if using managed memory, we can attach an operation for + nvgetarraypointer since the host and device pointers are the same */ + v->ops->nvgetarraypointer = N_VGetHostArrayPointer_Cuda; + /* create suncudavec::Vector with managed memory */ - v->content = new vector_type(comm, local_length, global_length, true); + v->content = new vector_type(length, true); return(v); } -N_Vector N_VMake_Cuda(MPI_Comm comm, - sunindextype local_length, sunindextype global_length, - realtype *h_vdata, realtype *d_vdata) +N_Vector N_VMake_Cuda(sunindextype length, realtype *h_vdata, realtype *d_vdata) { N_Vector v; @@ -158,119 +146,60 @@ N_Vector N_VMake_Cuda(MPI_Comm comm, if (v == NULL) return(NULL); /* create suncudavec::Vector using the user-provided data arrays */ - v->content = new vector_type(comm, local_length, global_length, false, false, h_vdata, d_vdata); + v->content = new vector_type(length, false, false, h_vdata, d_vdata); return(v); } -N_Vector N_VMakeManaged_Cuda(MPI_Comm comm, - sunindextype local_length, sunindextype global_length, - realtype *vdata) +N_Vector N_VMakeManaged_Cuda(sunindextype length, realtype *vdata) { N_Vector v; if (vdata == NULL) return(NULL); - - v = NULL; - v = N_VNewEmpty_Cuda(); - if (v == NULL) return(NULL); - - /* create suncudavec::Vector with managed memory using the user-provided data arrays */ - v->content = new vector_type(comm, local_length, global_length, true, false, vdata, vdata); - - return(v); -} -#else -N_Vector N_VNew_Cuda(sunindextype length) -{ - N_Vector v; v = NULL; v = N_VNewEmpty_Cuda(); if (v == NULL) return(NULL); - v->content = new vector_type(length); - - return(v); -} - -N_Vector N_VNewManaged_Cuda(sunindextype length) -{ - N_Vector v; - - v = NULL; - v = N_VNewEmpty_Cuda(); - if (v == NULL) return(NULL); + /* if using managed memory, we can attach an operation for + nvgetarraypointer since the host and device pointers are the same */ + v->ops->nvgetarraypointer = N_VGetHostArrayPointer_Cuda; - /* create suncudavec::Vector with managed memory */ - v->content = new vector_type(length, true); + /* create suncudavec::Vector with managed memory using the user-provided data arrays */ + v->content = new vector_type(length, true, false, vdata, vdata); return(v); } -N_Vector N_VMake_Cuda(sunindextype length, realtype *h_vdata, realtype *d_vdata) +N_Vector N_VMakeWithManagedAllocator_Cuda(sunindextype length, + void* (*allocfn)(size_t), + void (*freefn)(void*)) { N_Vector v; - if (h_vdata == NULL || d_vdata == NULL) return(NULL); - v = NULL; v = N_VNewEmpty_Cuda(); if (v == NULL) return(NULL); - /* create suncudavec::Vector using the user-provided data arrays */ - v->content = new vector_type(length, false, false, h_vdata, d_vdata); - - return(v); -} - -N_Vector N_VMakeManaged_Cuda(sunindextype length, realtype *vdata) -{ - N_Vector v; - - if (vdata == NULL) return(NULL); + /* if using managed memory, we can attach an operation for + nvgetarraypointer since the host and device pointers are the same */ + v->ops->nvgetarraypointer = N_VGetHostArrayPointer_Cuda; - v = NULL; - v = N_VNewEmpty_Cuda(); - if (v == NULL) return(NULL); - - /* create suncudavec::Vector with managed memory using the user-provided data arrays */ - v->content = new vector_type(length, true, false, vdata, vdata); + /* create suncudavec::Vector with a custom allocator/deallocator */ + v->content = new vector_type(length, allocfn, freefn, true); return(v); } -#endif /* ----------------------------------------------------------------- * Function to return the global length of the vector. */ sunindextype N_VGetLength_Cuda(N_Vector v) -{ - vector_type* xd = static_cast(v->content); - return (xd->sizeGlobal()); -} - - -#if SUNDIALS_MPI_ENABLED -/* ----------------------------------------------------------------- - * Function to return the local length of the vector. - */ -sunindextype N_VGetLocalLength_Cuda(N_Vector v) { vector_type* xd = static_cast(v->content); return (xd->size()); } -/* ----------------------------------------------------------------- - * Function to return the MPI communicator for the vector. - */ -MPI_Comm N_VGetMPIComm_Cuda(N_Vector v) -{ - vector_type* xd = static_cast(v->content); - return (xd->comm()); -} -#endif - /* ---------------------------------------------------------------------------- * Return pointer to the raw host data */ @@ -373,66 +302,16 @@ void N_VPrintFile_Cuda(N_Vector x, FILE *outfile) N_Vector N_VCloneEmpty_Cuda(N_Vector w) { N_Vector v; - N_Vector_Ops ops; if (w == NULL) return(NULL); /* Create vector */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } - - ops->nvgetvectorid = w->ops->nvgetvectorid; - ops->nvclone = w->ops->nvclone; - ops->nvcloneempty = w->ops->nvcloneempty; - ops->nvdestroy = w->ops->nvdestroy; - ops->nvspace = w->ops->nvspace; - ops->nvgetarraypointer = w->ops->nvgetarraypointer; - ops->nvsetarraypointer = w->ops->nvsetarraypointer; - - /* standard vector operations */ - ops->nvlinearsum = w->ops->nvlinearsum; - ops->nvconst = w->ops->nvconst; - ops->nvprod = w->ops->nvprod; - ops->nvdiv = w->ops->nvdiv; - ops->nvscale = w->ops->nvscale; - ops->nvabs = w->ops->nvabs; - ops->nvinv = w->ops->nvinv; - ops->nvaddconst = w->ops->nvaddconst; - ops->nvdotprod = w->ops->nvdotprod; - ops->nvmaxnorm = w->ops->nvmaxnorm; - ops->nvwrmsnormmask = w->ops->nvwrmsnormmask; - ops->nvwrmsnorm = w->ops->nvwrmsnorm; - ops->nvmin = w->ops->nvmin; - ops->nvwl2norm = w->ops->nvwl2norm; - ops->nvl1norm = w->ops->nvl1norm; - ops->nvcompare = w->ops->nvcompare; - ops->nvinvtest = w->ops->nvinvtest; - ops->nvconstrmask = w->ops->nvconstrmask; - ops->nvminquotient = w->ops->nvminquotient; - - /* fused vector operations */ - ops->nvlinearcombination = w->ops->nvlinearcombination; - ops->nvscaleaddmulti = w->ops->nvscaleaddmulti; - ops->nvdotprodmulti = w->ops->nvdotprodmulti; - - /* vector array operations */ - ops->nvlinearsumvectorarray = w->ops->nvlinearsumvectorarray; - ops->nvscalevectorarray = w->ops->nvscalevectorarray; - ops->nvconstvectorarray = w->ops->nvconstvectorarray; - ops->nvwrmsnormvectorarray = w->ops->nvwrmsnormvectorarray; - ops->nvwrmsnormmaskvectorarray = w->ops->nvwrmsnormmaskvectorarray; - ops->nvscaleaddmultivectorarray = w->ops->nvscaleaddmultivectorarray; - ops->nvlinearcombinationvectorarray = w->ops->nvlinearcombinationvectorarray; - - /* Create content */ - v->content = NULL; - v->ops = ops; + /* Attach operations */ + if (N_VCopyOps(w, v)) { N_VDestroy(v); return(NULL); } return(v); } @@ -440,12 +319,13 @@ N_Vector N_VCloneEmpty_Cuda(N_Vector w) N_Vector N_VClone_Cuda(N_Vector w) { N_Vector v; - vector_type* wdat = static_cast(w->content); - vector_type* vdat = new vector_type(*wdat); v = NULL; v = N_VCloneEmpty_Cuda(w); if (v == NULL) return(NULL); + vector_type* wdat = static_cast(w->content); + vector_type* vdat = new vector_type(*wdat); + v->content = vdat; return(v); @@ -454,13 +334,16 @@ N_Vector N_VClone_Cuda(N_Vector w) void N_VDestroy_Cuda(N_Vector v) { + if (v == NULL) return; + vector_type* x = static_cast(v->content); if (x != NULL) { delete x; v->content = NULL; } - free(v->ops); v->ops = NULL; + /* free ops and vector */ + if (v->ops != NULL) { free(v->ops); v->ops = NULL; } free(v); v = NULL; return; @@ -468,13 +351,9 @@ void N_VDestroy_Cuda(N_Vector v) void N_VSpace_Cuda(N_Vector X, sunindextype *lrw, sunindextype *liw) { - int npes; vector_type* x = static_cast(X->content); - - SUNMPI_Comm_size(x->comm(), &npes); - - *lrw = x->sizeGlobal(); - *liw = 2*npes; + *lrw = x->size(); + *liw = 2; } void N_VConst_Cuda(realtype a, N_Vector X) @@ -539,84 +418,60 @@ realtype N_VDotProd_Cuda(N_Vector X, N_Vector Y) { const vector_type *xvec = static_cast(X->content); const vector_type *yvec = static_cast(Y->content); - SUNMPI_Comm comm = xvec->comm(); - - realtype sum = dotProd(*xvec, *yvec); - - realtype gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); - return gsum; + return(dotProd(*xvec, *yvec)); } realtype N_VMaxNorm_Cuda(N_Vector X) { const vector_type *xvec = static_cast(X->content); - SUNMPI_Comm comm = xvec->comm(); - - realtype locmax = maxNorm(*xvec); - - realtype globmax = SUNMPI_Allreduce_scalar(locmax, 2, comm); - return globmax; + return(maxNorm(*xvec)); } -realtype N_VWrmsNorm_Cuda(N_Vector X, N_Vector W) +realtype N_VWSqrSumLocal_Cuda(N_Vector X, N_Vector W) { const vector_type *xvec = static_cast(X->content); const vector_type *wvec = static_cast(W->content); - const sunindextype Nglob = xvec->sizeGlobal(); - SUNMPI_Comm comm = xvec->comm(); - - realtype sum = wL2NormSquare(*xvec, *wvec); + return(wL2NormSquare(*xvec, *wvec)); +} - realtype gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); - return std::sqrt(gsum/Nglob); +realtype N_VWrmsNorm_Cuda(N_Vector X, N_Vector W) +{ + const realtype sum = N_VWSqrSumLocal_Cuda(X, W); + const vector_type *xvec = static_cast(X->content); + return std::sqrt(sum/xvec->size()); } -realtype N_VWrmsNormMask_Cuda(N_Vector X, N_Vector W, N_Vector Id) +realtype N_VWSqrSumMaskLocal_Cuda(N_Vector X, N_Vector W, N_Vector Id) { const vector_type *xvec = static_cast(X->content); const vector_type *wvec = static_cast(W->content); const vector_type *ivec = static_cast(Id->content); - const sunindextype Nglob = xvec->sizeGlobal(); - SUNMPI_Comm comm = xvec->comm(); - - realtype sum = wL2NormSquareMask(*xvec, *wvec, *ivec); + return(wL2NormSquareMask(*xvec, *wvec, *ivec)); +} - realtype gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); - return std::sqrt(gsum/Nglob); +realtype N_VWrmsNormMask_Cuda(N_Vector X, N_Vector W, N_Vector Id) +{ + const realtype sum = N_VWSqrSumMaskLocal_Cuda(X, W, Id); + const vector_type *xvec = static_cast(X->content); + return std::sqrt(sum/xvec->size()); } realtype N_VMin_Cuda(N_Vector X) { const vector_type *xvec = static_cast(X->content); - SUNMPI_Comm comm = xvec->comm(); - - realtype locmin = findMin(*xvec); - - realtype globmin = SUNMPI_Allreduce_scalar(locmin, 3, comm); - return globmin; + return(findMin(*xvec)); } realtype N_VWL2Norm_Cuda(N_Vector X, N_Vector W) { - const vector_type *xvec = static_cast(X->content); - const vector_type *wvec = static_cast(W->content); - SUNMPI_Comm comm = xvec->comm(); - - realtype sum = wL2NormSquare(*xvec, *wvec); - - realtype gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); - return std::sqrt(gsum); + const realtype sum = N_VWSqrSumLocal_Cuda(X, W); + return std::sqrt(sum); } realtype N_VL1Norm_Cuda(N_Vector X) { const vector_type *xvec = static_cast(X->content); - SUNMPI_Comm comm = xvec->comm(); - - realtype sum = L1Norm(*xvec); - - realtype gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); - return gsum; + return(L1Norm(*xvec)); } void N_VCompare_Cuda(realtype c, N_Vector X, N_Vector Z) @@ -630,40 +485,24 @@ booleantype N_VInvTest_Cuda(N_Vector X, N_Vector Z) { const vector_type *xvec = static_cast(X->content); vector_type *zvec = static_cast(Z->content); - SUNMPI_Comm comm = xvec->comm(); - - realtype locmin = invTest(*xvec, *zvec); - - realtype globmin = SUNMPI_Allreduce_scalar(locmin, 3, comm); - return (globmin < HALF); + const realtype locmin = invTest(*xvec, *zvec); + return (locmin < HALF); } -/* - * Creates mask for variables violating constraints - */ booleantype N_VConstrMask_Cuda(N_Vector C, N_Vector X, N_Vector M) { const vector_type *cvec = static_cast(C->content); const vector_type *xvec = static_cast(X->content); vector_type *mvec = static_cast(M->content); - SUNMPI_Comm comm = xvec->comm(); - - realtype locsum = constrMask(*cvec, *xvec, *mvec); - - realtype globsum = SUNMPI_Allreduce_scalar(locsum, 1, comm); - return (globsum < HALF); + const realtype locsum = constrMask(*cvec, *xvec, *mvec); + return (locsum < HALF); } realtype N_VMinQuotient_Cuda(N_Vector num, N_Vector denom) { const vector_type *numvec = static_cast(num->content); const vector_type *denvec = static_cast(denom->content); - SUNMPI_Comm comm = numvec->comm(); - - realtype locmin = minQuotient(*numvec, *denvec); - - realtype globmin = SUNMPI_Allreduce_scalar(locmin, 3, comm); - return globmin; + return(minQuotient(*numvec, *denvec)); } /* @@ -721,12 +560,10 @@ int N_VScaleAddMulti_Cuda(int nvec, realtype* c, N_Vector X, N_Vector* Y, int N_VDotProdMulti_Cuda(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods) { cudaError_t err; - SUNMPI_Comm comm; vector_type* Xv; vector_type** Yv; Xv = static_cast(x->content); - comm = Xv->comm(); Yv = new vector_type*[nvec]; for (int i=0; i(X[0]->content); vector_type** Xv; vector_type** Wv; - - SUNMPI_Comm comm = xvec->comm(); - sunindextype N = xvec->sizeGlobal(); + + sunindextype N = xvec->size(); Xv = new vector_type*[nvec]; for (int k=0; kcomm(); - sunindextype N = xvec->sizeGlobal(); + + sunindextype N = xvec->size(); Xv = new vector_type*[nvec]; for (int k=0; k 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_nvector.h" + + +#include "nvector/nvector_manyvector.h" + +SWIGEXPORT N_Vector _wrap_FN_VNew_ManyVector(int64_t const *farg1, void *farg2) { + N_Vector fresult ; + sunindextype arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector result; + + arg1 = (sunindextype)(*farg1); + arg2 = (N_Vector *)(farg2); + result = (N_Vector)N_VNew_ManyVector(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VGetSubvector_ManyVector(N_Vector farg1, int64_t const *farg2) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype arg2 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + arg2 = (sunindextype)(*farg2); + result = (N_Vector)N_VGetSubvector_ManyVector(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT double * _wrap_FN_VGetSubvectorArrayPointer_ManyVector(N_Vector farg1, int64_t const *farg2) { + double * fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype arg2 ; + realtype *result = 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (sunindextype)(*farg2); + result = (realtype *)N_VGetSubvectorArrayPointer_ManyVector(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VSetSubvectorArrayPointer_ManyVector(double *farg1, N_Vector farg2, int64_t const *farg3) { + int fresult ; + realtype *arg1 = (realtype *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + sunindextype arg3 ; + int result; + + arg1 = (realtype *)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (sunindextype)(*farg3); + result = (int)N_VSetSubvectorArrayPointer_ManyVector(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FN_VGetNumSubvectors_ManyVector(N_Vector farg1) { + int64_t fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype result; + + arg1 = (N_Vector)(farg1); + result = N_VGetNumSubvectors_ManyVector(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VGetVectorID_ManyVector(N_Vector farg1) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector_ID result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector_ID)N_VGetVectorID_ManyVector(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VCloneEmpty_ManyVector(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VCloneEmpty_ManyVector(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VClone_ManyVector(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VClone_ManyVector(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VDestroy_ManyVector(N_Vector farg1) { + N_Vector arg1 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + N_VDestroy_ManyVector(arg1); +} + + +SWIGEXPORT void _wrap_FN_VSpace_ManyVector(N_Vector farg1, int64_t *farg2, int64_t *farg3) { + N_Vector arg1 = (N_Vector) 0 ; + sunindextype *arg2 = (sunindextype *) 0 ; + sunindextype *arg3 = (sunindextype *) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (sunindextype *)(farg2); + arg3 = (sunindextype *)(farg3); + N_VSpace_ManyVector(arg1,arg2,arg3); +} + + +SWIGEXPORT int64_t _wrap_FN_VGetLength_ManyVector(N_Vector farg1) { + int64_t fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype result; + + arg1 = (N_Vector)(farg1); + result = N_VGetLength_ManyVector(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VLinearSum_ManyVector(double const *farg1, N_Vector farg2, double const *farg3, N_Vector farg4, N_Vector farg5) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + N_VLinearSum_ManyVector(arg1,arg2,arg3,arg4,arg5); +} + + +SWIGEXPORT void _wrap_FN_VConst_ManyVector(double const *farg1, N_Vector farg2) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + N_VConst_ManyVector(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VProd_ManyVector(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VProd_ManyVector(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VDiv_ManyVector(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VDiv_ManyVector(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VScale_ManyVector(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VScale_ManyVector(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VAbs_ManyVector(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VAbs_ManyVector(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VInv_ManyVector(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VInv_ManyVector(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VAddConst_ManyVector(N_Vector farg1, double const *farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + N_VAddConst_ManyVector(arg1,arg2,arg3); +} + + +SWIGEXPORT double _wrap_FN_VWrmsNorm_ManyVector(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWrmsNorm_ManyVector(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNormMask_ManyVector(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWrmsNormMask_ManyVector(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWL2Norm_ManyVector(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWL2Norm_ManyVector(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VCompare_ManyVector(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VCompare_ManyVector(arg1,arg2,arg3); +} + + +SWIGEXPORT int _wrap_FN_VLinearCombination_ManyVector(int const *farg1, double *farg2, void *farg3, N_Vector farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)N_VLinearCombination_ManyVector(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleAddMulti_ManyVector(int const *farg1, double *farg2, N_Vector farg3, void *farg4, void *farg5) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + N_Vector *arg5 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector *)(farg4); + arg5 = (N_Vector *)(farg5); + result = (int)N_VScaleAddMulti_ManyVector(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VDotProdMulti_ManyVector(int const *farg1, N_Vector farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VDotProdMulti_ManyVector(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearSumVectorArray_ManyVector(int const *farg1, double const *farg2, void *farg3, double const *farg4, void *farg5, void *farg6) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype arg4 ; + N_Vector *arg5 = (N_Vector *) 0 ; + N_Vector *arg6 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype)(*farg4); + arg5 = (N_Vector *)(farg5); + arg6 = (N_Vector *)(farg6); + result = (int)N_VLinearSumVectorArray_ManyVector(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleVectorArray_ManyVector(int const *farg1, double *farg2, void *farg3, void *farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector *)(farg4); + result = (int)N_VScaleVectorArray_ManyVector(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstVectorArray_ManyVector(int const *farg1, double const *farg2, void *farg3) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (int)N_VConstVectorArray_ManyVector(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormVectorArray_ManyVector(int const *farg1, void *farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VWrmsNormVectorArray_ManyVector(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormMaskVectorArray_ManyVector(int const *farg1, void *farg2, void *farg3, N_Vector farg4, double *farg5) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype *arg5 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype *)(farg5); + result = (int)N_VWrmsNormMaskVectorArray_ManyVector(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VDotProdLocal_ManyVector(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VDotProdLocal_ManyVector(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMaxNormLocal_ManyVector(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMaxNormLocal_ManyVector(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinLocal_ManyVector(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMinLocal_ManyVector(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VL1NormLocal_ManyVector(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VL1NormLocal_ManyVector(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumLocal_ManyVector(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWSqrSumLocal_ManyVector(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumMaskLocal_ManyVector(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWSqrSumMaskLocal_ManyVector(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VInvTestLocal_ManyVector(N_Vector farg1, N_Vector farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)N_VInvTestLocal_ManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstrMaskLocal_ManyVector(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)N_VConstrMaskLocal_ManyVector(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinQuotientLocal_ManyVector(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VMinQuotientLocal_ManyVector(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableFusedOps_ManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableFusedOps_ManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableLinearCombination_ManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableLinearCombination_ManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableScaleAddMulti_ManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableScaleAddMulti_ManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableDotProdMulti_ManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableDotProdMulti_ManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableLinearSumVectorArray_ManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableLinearSumVectorArray_ManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableScaleVectorArray_ManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableScaleVectorArray_ManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableConstVectorArray_ManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableConstVectorArray_ManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableWrmsNormVectorArray_ManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableWrmsNormVectorArray_ManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableWrmsNormMaskVectorArray_ManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableWrmsNormMaskVectorArray_ManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/manyvector/fmod/fnvector_manyvector_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/nvector/manyvector/fmod/fnvector_manyvector_mod.f90 new file mode 100644 index 000000000..4e6889001 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/manyvector/fmod/fnvector_manyvector_mod.f90 @@ -0,0 +1,1338 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fnvector_manyvector_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FN_VNew_ManyVector + public :: FN_VGetSubvector_ManyVector + public :: FN_VGetSubvectorArrayPointer_ManyVector + public :: FN_VSetSubvectorArrayPointer_ManyVector + public :: FN_VGetNumSubvectors_ManyVector + public :: FN_VGetVectorID_ManyVector + public :: FN_VCloneEmpty_ManyVector + public :: FN_VClone_ManyVector + public :: FN_VDestroy_ManyVector + public :: FN_VSpace_ManyVector + public :: FN_VGetLength_ManyVector + public :: FN_VLinearSum_ManyVector + public :: FN_VConst_ManyVector + public :: FN_VProd_ManyVector + public :: FN_VDiv_ManyVector + public :: FN_VScale_ManyVector + public :: FN_VAbs_ManyVector + public :: FN_VInv_ManyVector + public :: FN_VAddConst_ManyVector + public :: FN_VWrmsNorm_ManyVector + public :: FN_VWrmsNormMask_ManyVector + public :: FN_VWL2Norm_ManyVector + public :: FN_VCompare_ManyVector + public :: FN_VLinearCombination_ManyVector + public :: FN_VScaleAddMulti_ManyVector + public :: FN_VDotProdMulti_ManyVector + public :: FN_VLinearSumVectorArray_ManyVector + public :: FN_VScaleVectorArray_ManyVector + public :: FN_VConstVectorArray_ManyVector + public :: FN_VWrmsNormVectorArray_ManyVector + public :: FN_VWrmsNormMaskVectorArray_ManyVector + public :: FN_VDotProdLocal_ManyVector + public :: FN_VMaxNormLocal_ManyVector + public :: FN_VMinLocal_ManyVector + public :: FN_VL1NormLocal_ManyVector + public :: FN_VWSqrSumLocal_ManyVector + public :: FN_VWSqrSumMaskLocal_ManyVector + public :: FN_VInvTestLocal_ManyVector + public :: FN_VConstrMaskLocal_ManyVector + public :: FN_VMinQuotientLocal_ManyVector + public :: FN_VEnableFusedOps_ManyVector + public :: FN_VEnableLinearCombination_ManyVector + public :: FN_VEnableScaleAddMulti_ManyVector + public :: FN_VEnableDotProdMulti_ManyVector + public :: FN_VEnableLinearSumVectorArray_ManyVector + public :: FN_VEnableScaleVectorArray_ManyVector + public :: FN_VEnableConstVectorArray_ManyVector + public :: FN_VEnableWrmsNormVectorArray_ManyVector + public :: FN_VEnableWrmsNormMaskVectorArray_ManyVector + +! WRAPPER DECLARATIONS +interface +function swigc_FN_VNew_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VNew_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VGetSubvector_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VGetSubvector_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VGetSubvectorArrayPointer_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VGetSubvectorArrayPointer_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VSetSubvectorArrayPointer_ManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VSetSubvectorArrayPointer_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VGetNumSubvectors_ManyVector(farg1) & +bind(C, name="_wrap_FN_VGetNumSubvectors_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FN_VGetVectorID_ManyVector(farg1) & +bind(C, name="_wrap_FN_VGetVectorID_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FN_VCloneEmpty_ManyVector(farg1) & +bind(C, name="_wrap_FN_VCloneEmpty_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VClone_ManyVector(farg1) & +bind(C, name="_wrap_FN_VClone_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VDestroy_ManyVector(farg1) & +bind(C, name="_wrap_FN_VDestroy_ManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FN_VSpace_ManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VSpace_ManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VGetLength_ManyVector(farg1) & +bind(C, name="_wrap_FN_VGetLength_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +subroutine swigc_FN_VLinearSum_ManyVector(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VLinearSum_ManyVector") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +end subroutine + +subroutine swigc_FN_VConst_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VConst_ManyVector") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VProd_ManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VProd_ManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VDiv_ManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VDiv_ManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VScale_ManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VScale_ManyVector") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VAbs_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VAbs_ManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VInv_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VInv_ManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VAddConst_ManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VAddConst_ManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VWrmsNorm_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VWrmsNorm_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNormMask_ManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWrmsNormMask_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWL2Norm_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VWL2Norm_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +subroutine swigc_FN_VCompare_ManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VCompare_ManyVector") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VLinearCombination_ManyVector(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VLinearCombination_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleAddMulti_ManyVector(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VScaleAddMulti_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VDotProdMulti_ManyVector(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VDotProdMulti_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VLinearSumVectorArray_ManyVector(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FN_VLinearSumVectorArray_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleVectorArray_ManyVector(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VScaleVectorArray_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstVectorArray_ManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstVectorArray_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormVectorArray_ManyVector(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VWrmsNormVectorArray_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormMaskVectorArray_ManyVector(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VWrmsNormMaskVectorArray_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VDotProdLocal_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VDotProdLocal_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMaxNormLocal_ManyVector(farg1) & +bind(C, name="_wrap_FN_VMaxNormLocal_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMinLocal_ManyVector(farg1) & +bind(C, name="_wrap_FN_VMinLocal_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VL1NormLocal_ManyVector(farg1) & +bind(C, name="_wrap_FN_VL1NormLocal_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWSqrSumLocal_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VWSqrSumLocal_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWSqrSumMaskLocal_ManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWSqrSumMaskLocal_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VInvTestLocal_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VInvTestLocal_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstrMaskLocal_ManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstrMaskLocal_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VMinQuotientLocal_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VMinQuotientLocal_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VEnableFusedOps_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableFusedOps_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableLinearCombination_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableLinearCombination_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableScaleAddMulti_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableScaleAddMulti_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableDotProdMulti_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableDotProdMulti_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableLinearSumVectorArray_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableLinearSumVectorArray_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableScaleVectorArray_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableScaleVectorArray_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableConstVectorArray_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableConstVectorArray_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableWrmsNormVectorArray_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableWrmsNormVectorArray_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableWrmsNormMaskVectorArray_ManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableWrmsNormMaskVectorArray_ManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FN_VNew_ManyVector(num_subvectors, vec_array) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer(C_INT64_T), intent(in) :: num_subvectors +type(C_PTR) :: vec_array +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +type(C_PTR) :: farg2 + +farg1 = num_subvectors +farg2 = vec_array +fresult = swigc_FN_VNew_ManyVector(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VGetSubvector_ManyVector(v, vec_num) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), intent(in) :: vec_num +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 + +farg1 = c_loc(v) +farg2 = vec_num +fresult = swigc_FN_VGetSubvector_ManyVector(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VGetSubvectorArrayPointer_ManyVector(v, vec_num) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), intent(in) :: vec_num +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 + +farg1 = c_loc(v) +farg2 = vec_num +fresult = swigc_FN_VGetSubvectorArrayPointer_ManyVector(farg1, farg2) +call c_f_pointer(fresult, swig_result, [1]) +end function + +function FN_VSetSubvectorArrayPointer_ManyVector(v_data, v, vec_num) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +real(C_DOUBLE), dimension(*), target, intent(inout) :: v_data +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), intent(in) :: vec_num +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT64_T) :: farg3 + +farg1 = c_loc(v_data(1)) +farg2 = c_loc(v) +farg3 = vec_num +fresult = swigc_FN_VSetSubvectorArrayPointer_ManyVector(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VGetNumSubvectors_ManyVector(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetNumSubvectors_ManyVector(farg1) +swig_result = fresult +end function + +function FN_VGetVectorID_ManyVector(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(N_Vector_ID) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetVectorID_ManyVector(farg1) +swig_result = fresult +end function + +function FN_VCloneEmpty_ManyVector(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VCloneEmpty_ManyVector(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VClone_ManyVector(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VClone_ManyVector(farg1) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FN_VDestroy_ManyVector(v) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +call swigc_FN_VDestroy_ManyVector(farg1) +end subroutine + +subroutine FN_VSpace_ManyVector(v, lrw, liw) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), dimension(*), target, intent(inout) :: lrw +integer(C_INT64_T), dimension(*), target, intent(inout) :: liw +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(v) +farg2 = c_loc(lrw(1)) +farg3 = c_loc(liw(1)) +call swigc_FN_VSpace_ManyVector(farg1, farg2, farg3) +end subroutine + +function FN_VGetLength_ManyVector(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetLength_ManyVector(farg1) +swig_result = fresult +end function + +subroutine FN_VLinearSum_ManyVector(a, x, b, y, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: a +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = a +farg2 = c_loc(x) +farg3 = b +farg4 = c_loc(y) +farg5 = c_loc(z) +call swigc_FN_VLinearSum_ManyVector(farg1, farg2, farg3, farg4, farg5) +end subroutine + +subroutine FN_VConst_ManyVector(c, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c +farg2 = c_loc(z) +call swigc_FN_VConst_ManyVector(farg1, farg2) +end subroutine + +subroutine FN_VProd_ManyVector(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VProd_ManyVector(farg1, farg2, farg3) +end subroutine + +subroutine FN_VDiv_ManyVector(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VDiv_ManyVector(farg1, farg2, farg3) +end subroutine + +subroutine FN_VScale_ManyVector(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VScale_ManyVector(farg1, farg2, farg3) +end subroutine + +subroutine FN_VAbs_ManyVector(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VAbs_ManyVector(farg1, farg2) +end subroutine + +subroutine FN_VInv_ManyVector(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VInv_ManyVector(farg1, farg2) +end subroutine + +subroutine FN_VAddConst_ManyVector(x, b, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = b +farg3 = c_loc(z) +call swigc_FN_VAddConst_ManyVector(farg1, farg2, farg3) +end subroutine + +function FN_VWrmsNorm_ManyVector(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWrmsNorm_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VWrmsNormMask_ManyVector(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWrmsNormMask_ManyVector(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VWL2Norm_ManyVector(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWL2Norm_ManyVector(farg1, farg2) +swig_result = fresult +end function + +subroutine FN_VCompare_ManyVector(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VCompare_ManyVector(farg1, farg2, farg3) +end subroutine + +function FN_VLinearCombination_ManyVector(nvec, c, v, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: v +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = v +farg4 = c_loc(z) +fresult = swigc_FN_VLinearCombination_ManyVector(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VScaleAddMulti_ManyVector(nvec, a, x, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvec +farg2 = c_loc(a(1)) +farg3 = c_loc(x) +farg4 = y +farg5 = z +fresult = swigc_FN_VScaleAddMulti_ManyVector(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VDotProdMulti_ManyVector(nvec, x, y, dotprods) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +real(C_DOUBLE), dimension(*), target, intent(inout) :: dotprods +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(x) +farg3 = y +farg4 = c_loc(dotprods(1)) +fresult = swigc_FN_VDotProdMulti_ManyVector(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VLinearSumVectorArray_ManyVector(nvec, a, x, b, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), intent(in) :: a +type(C_PTR) :: x +real(C_DOUBLE), intent(in) :: b +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = nvec +farg2 = a +farg3 = x +farg4 = b +farg5 = y +farg6 = z +fresult = swigc_FN_VLinearSumVectorArray_ManyVector(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FN_VScaleVectorArray_ManyVector(nvec, c, x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: x +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = x +farg4 = z +fresult = swigc_FN_VScaleVectorArray_ManyVector(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VConstVectorArray_ManyVector(nvecs, c, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvecs +real(C_DOUBLE), intent(in) :: c +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = nvecs +farg2 = c +farg3 = z +fresult = swigc_FN_VConstVectorArray_ManyVector(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VWrmsNormVectorArray_ManyVector(nvecs, x, w, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvecs +type(C_PTR) :: x +type(C_PTR) :: w +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvecs +farg2 = x +farg3 = w +farg4 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormVectorArray_ManyVector(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VWrmsNormMaskVectorArray_ManyVector(nvec, x, w, id, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(C_PTR) :: x +type(C_PTR) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvec +farg2 = x +farg3 = w +farg4 = c_loc(id) +farg5 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormMaskVectorArray_ManyVector(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VDotProdLocal_ManyVector(x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(y) +fresult = swigc_FN_VDotProdLocal_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VMaxNormLocal_ManyVector(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMaxNormLocal_ManyVector(farg1) +swig_result = fresult +end function + +function FN_VMinLocal_ManyVector(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMinLocal_ManyVector(farg1) +swig_result = fresult +end function + +function FN_VL1NormLocal_ManyVector(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VL1NormLocal_ManyVector(farg1) +swig_result = fresult +end function + +function FN_VWSqrSumLocal_ManyVector(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWSqrSumLocal_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VWSqrSumMaskLocal_ManyVector(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWSqrSumMaskLocal_ManyVector(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VInvTestLocal_ManyVector(x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +fresult = swigc_FN_VInvTestLocal_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VConstrMaskLocal_ManyVector(c, x, m) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: m +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(c) +farg2 = c_loc(x) +farg3 = c_loc(m) +fresult = swigc_FN_VConstrMaskLocal_ManyVector(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMinQuotientLocal_ManyVector(num, denom) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: num +type(N_Vector), target, intent(inout) :: denom +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(num) +farg2 = c_loc(denom) +fresult = swigc_FN_VMinQuotientLocal_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableFusedOps_ManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableFusedOps_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableLinearCombination_ManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableLinearCombination_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableScaleAddMulti_ManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableScaleAddMulti_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableDotProdMulti_ManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableDotProdMulti_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableLinearSumVectorArray_ManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableLinearSumVectorArray_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableScaleVectorArray_ManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableScaleVectorArray_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableConstVectorArray_ManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableConstVectorArray_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableWrmsNormVectorArray_ManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableWrmsNormVectorArray_ManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableWrmsNormMaskVectorArray_ManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableWrmsNormMaskVectorArray_ManyVector(farg1, farg2) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/manyvector/fmod/fnvector_mpimanyvector_mod.c b/deps/AMICI/ThirdParty/sundials/src/nvector/manyvector/fmod/fnvector_mpimanyvector_mod.c new file mode 100644 index 000000000..363fb03be --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/manyvector/fmod/fnvector_mpimanyvector_mod.c @@ -0,0 +1,1025 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_nvector.h" + + +#include "nvector/nvector_mpimanyvector.h" + +SWIGEXPORT N_Vector _wrap_FN_VMake_MPIManyVector(int const *farg1, int64_t const *farg2, void *farg3) { + N_Vector fresult ; + MPI_Comm arg1 ; + sunindextype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector result; + +#ifdef SUNDIALS_MPI_ENABLED + arg1 = MPI_Comm_f2c((MPI_Fint)(*farg1)); +#else + arg1 = *farg1; +#endif + arg2 = (sunindextype)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (N_Vector)N_VMake_MPIManyVector(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VNew_MPIManyVector(int64_t const *farg1, void *farg2) { + N_Vector fresult ; + sunindextype arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector result; + + arg1 = (sunindextype)(*farg1); + arg2 = (N_Vector *)(farg2); + result = (N_Vector)N_VNew_MPIManyVector(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VGetSubvector_MPIManyVector(N_Vector farg1, int64_t const *farg2) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype arg2 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + arg2 = (sunindextype)(*farg2); + result = (N_Vector)N_VGetSubvector_MPIManyVector(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT double * _wrap_FN_VGetSubvectorArrayPointer_MPIManyVector(N_Vector farg1, int64_t const *farg2) { + double * fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype arg2 ; + realtype *result = 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (sunindextype)(*farg2); + result = (realtype *)N_VGetSubvectorArrayPointer_MPIManyVector(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VSetSubvectorArrayPointer_MPIManyVector(double *farg1, N_Vector farg2, int64_t const *farg3) { + int fresult ; + realtype *arg1 = (realtype *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + sunindextype arg3 ; + int result; + + arg1 = (realtype *)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (sunindextype)(*farg3); + result = (int)N_VSetSubvectorArrayPointer_MPIManyVector(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FN_VGetNumSubvectors_MPIManyVector(N_Vector farg1) { + int64_t fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype result; + + arg1 = (N_Vector)(farg1); + result = N_VGetNumSubvectors_MPIManyVector(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VGetVectorID_MPIManyVector(N_Vector farg1) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector_ID result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector_ID)N_VGetVectorID_MPIManyVector(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VCloneEmpty_MPIManyVector(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VCloneEmpty_MPIManyVector(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VClone_MPIManyVector(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VClone_MPIManyVector(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VDestroy_MPIManyVector(N_Vector farg1) { + N_Vector arg1 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + N_VDestroy_MPIManyVector(arg1); +} + + +SWIGEXPORT void _wrap_FN_VSpace_MPIManyVector(N_Vector farg1, int64_t *farg2, int64_t *farg3) { + N_Vector arg1 = (N_Vector) 0 ; + sunindextype *arg2 = (sunindextype *) 0 ; + sunindextype *arg3 = (sunindextype *) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (sunindextype *)(farg2); + arg3 = (sunindextype *)(farg3); + N_VSpace_MPIManyVector(arg1,arg2,arg3); +} + + +SWIGEXPORT void * _wrap_FN_VGetCommunicator_MPIManyVector(N_Vector farg1) { + void * fresult ; + N_Vector arg1 = (N_Vector) 0 ; + void *result = 0 ; + + arg1 = (N_Vector)(farg1); + result = (void *)N_VGetCommunicator_MPIManyVector(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FN_VGetLength_MPIManyVector(N_Vector farg1) { + int64_t fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype result; + + arg1 = (N_Vector)(farg1); + result = N_VGetLength_MPIManyVector(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VLinearSum_MPIManyVector(double const *farg1, N_Vector farg2, double const *farg3, N_Vector farg4, N_Vector farg5) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + N_VLinearSum_MPIManyVector(arg1,arg2,arg3,arg4,arg5); +} + + +SWIGEXPORT void _wrap_FN_VConst_MPIManyVector(double const *farg1, N_Vector farg2) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + N_VConst_MPIManyVector(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VProd_MPIManyVector(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VProd_MPIManyVector(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VDiv_MPIManyVector(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VDiv_MPIManyVector(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VScale_MPIManyVector(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VScale_MPIManyVector(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VAbs_MPIManyVector(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VAbs_MPIManyVector(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VInv_MPIManyVector(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VInv_MPIManyVector(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VAddConst_MPIManyVector(N_Vector farg1, double const *farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + N_VAddConst_MPIManyVector(arg1,arg2,arg3); +} + + +SWIGEXPORT double _wrap_FN_VDotProd_MPIManyVector(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VDotProd_MPIManyVector(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMaxNorm_MPIManyVector(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMaxNorm_MPIManyVector(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNorm_MPIManyVector(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWrmsNorm_MPIManyVector(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNormMask_MPIManyVector(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWrmsNormMask_MPIManyVector(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMin_MPIManyVector(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMin_MPIManyVector(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWL2Norm_MPIManyVector(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWL2Norm_MPIManyVector(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VL1Norm_MPIManyVector(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VL1Norm_MPIManyVector(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VCompare_MPIManyVector(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VCompare_MPIManyVector(arg1,arg2,arg3); +} + + +SWIGEXPORT int _wrap_FN_VInvTest_MPIManyVector(N_Vector farg1, N_Vector farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)N_VInvTest_MPIManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstrMask_MPIManyVector(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)N_VConstrMask_MPIManyVector(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinQuotient_MPIManyVector(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VMinQuotient_MPIManyVector(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearCombination_MPIManyVector(int const *farg1, double *farg2, void *farg3, N_Vector farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)N_VLinearCombination_MPIManyVector(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleAddMulti_MPIManyVector(int const *farg1, double *farg2, N_Vector farg3, void *farg4, void *farg5) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + N_Vector *arg5 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector *)(farg4); + arg5 = (N_Vector *)(farg5); + result = (int)N_VScaleAddMulti_MPIManyVector(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VDotProdMulti_MPIManyVector(int const *farg1, N_Vector farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VDotProdMulti_MPIManyVector(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearSumVectorArray_MPIManyVector(int const *farg1, double const *farg2, void *farg3, double const *farg4, void *farg5, void *farg6) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype arg4 ; + N_Vector *arg5 = (N_Vector *) 0 ; + N_Vector *arg6 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype)(*farg4); + arg5 = (N_Vector *)(farg5); + arg6 = (N_Vector *)(farg6); + result = (int)N_VLinearSumVectorArray_MPIManyVector(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleVectorArray_MPIManyVector(int const *farg1, double *farg2, void *farg3, void *farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector *)(farg4); + result = (int)N_VScaleVectorArray_MPIManyVector(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstVectorArray_MPIManyVector(int const *farg1, double const *farg2, void *farg3) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (int)N_VConstVectorArray_MPIManyVector(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormVectorArray_MPIManyVector(int const *farg1, void *farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VWrmsNormVectorArray_MPIManyVector(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormMaskVectorArray_MPIManyVector(int const *farg1, void *farg2, void *farg3, N_Vector farg4, double *farg5) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype *arg5 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype *)(farg5); + result = (int)N_VWrmsNormMaskVectorArray_MPIManyVector(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VDotProdLocal_MPIManyVector(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VDotProdLocal_MPIManyVector(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMaxNormLocal_MPIManyVector(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMaxNormLocal_MPIManyVector(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinLocal_MPIManyVector(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMinLocal_MPIManyVector(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VL1NormLocal_MPIManyVector(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VL1NormLocal_MPIManyVector(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumLocal_MPIManyVector(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWSqrSumLocal_MPIManyVector(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumMaskLocal_MPIManyVector(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWSqrSumMaskLocal_MPIManyVector(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VInvTestLocal_MPIManyVector(N_Vector farg1, N_Vector farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)N_VInvTestLocal_MPIManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstrMaskLocal_MPIManyVector(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)N_VConstrMaskLocal_MPIManyVector(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinQuotientLocal_MPIManyVector(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VMinQuotientLocal_MPIManyVector(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableFusedOps_MPIManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableFusedOps_MPIManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableLinearCombination_MPIManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableLinearCombination_MPIManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableScaleAddMulti_MPIManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableScaleAddMulti_MPIManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableDotProdMulti_MPIManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableDotProdMulti_MPIManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableLinearSumVectorArray_MPIManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableLinearSumVectorArray_MPIManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableScaleVectorArray_MPIManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableScaleVectorArray_MPIManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableConstVectorArray_MPIManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableConstVectorArray_MPIManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableWrmsNormVectorArray_MPIManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableWrmsNormVectorArray_MPIManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableWrmsNormMaskVectorArray_MPIManyVector(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableWrmsNormMaskVectorArray_MPIManyVector(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/manyvector/fmod/fnvector_mpimanyvector_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/nvector/manyvector/fmod/fnvector_mpimanyvector_mod.f90 new file mode 100644 index 000000000..4580494f1 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/manyvector/fmod/fnvector_mpimanyvector_mod.f90 @@ -0,0 +1,1564 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fnvector_mpimanyvector_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FN_VMake_MPIManyVector + public :: FN_VNew_MPIManyVector + public :: FN_VGetSubvector_MPIManyVector + public :: FN_VGetSubvectorArrayPointer_MPIManyVector + public :: FN_VSetSubvectorArrayPointer_MPIManyVector + public :: FN_VGetNumSubvectors_MPIManyVector + public :: FN_VGetVectorID_MPIManyVector + public :: FN_VCloneEmpty_MPIManyVector + public :: FN_VClone_MPIManyVector + public :: FN_VDestroy_MPIManyVector + public :: FN_VSpace_MPIManyVector + public :: FN_VGetCommunicator_MPIManyVector + public :: FN_VGetLength_MPIManyVector + public :: FN_VLinearSum_MPIManyVector + public :: FN_VConst_MPIManyVector + public :: FN_VProd_MPIManyVector + public :: FN_VDiv_MPIManyVector + public :: FN_VScale_MPIManyVector + public :: FN_VAbs_MPIManyVector + public :: FN_VInv_MPIManyVector + public :: FN_VAddConst_MPIManyVector + public :: FN_VDotProd_MPIManyVector + public :: FN_VMaxNorm_MPIManyVector + public :: FN_VWrmsNorm_MPIManyVector + public :: FN_VWrmsNormMask_MPIManyVector + public :: FN_VMin_MPIManyVector + public :: FN_VWL2Norm_MPIManyVector + public :: FN_VL1Norm_MPIManyVector + public :: FN_VCompare_MPIManyVector + public :: FN_VInvTest_MPIManyVector + public :: FN_VConstrMask_MPIManyVector + public :: FN_VMinQuotient_MPIManyVector + public :: FN_VLinearCombination_MPIManyVector + public :: FN_VScaleAddMulti_MPIManyVector + public :: FN_VDotProdMulti_MPIManyVector + public :: FN_VLinearSumVectorArray_MPIManyVector + public :: FN_VScaleVectorArray_MPIManyVector + public :: FN_VConstVectorArray_MPIManyVector + public :: FN_VWrmsNormVectorArray_MPIManyVector + public :: FN_VWrmsNormMaskVectorArray_MPIManyVector + public :: FN_VDotProdLocal_MPIManyVector + public :: FN_VMaxNormLocal_MPIManyVector + public :: FN_VMinLocal_MPIManyVector + public :: FN_VL1NormLocal_MPIManyVector + public :: FN_VWSqrSumLocal_MPIManyVector + public :: FN_VWSqrSumMaskLocal_MPIManyVector + public :: FN_VInvTestLocal_MPIManyVector + public :: FN_VConstrMaskLocal_MPIManyVector + public :: FN_VMinQuotientLocal_MPIManyVector + public :: FN_VEnableFusedOps_MPIManyVector + public :: FN_VEnableLinearCombination_MPIManyVector + public :: FN_VEnableScaleAddMulti_MPIManyVector + public :: FN_VEnableDotProdMulti_MPIManyVector + public :: FN_VEnableLinearSumVectorArray_MPIManyVector + public :: FN_VEnableScaleVectorArray_MPIManyVector + public :: FN_VEnableConstVectorArray_MPIManyVector + public :: FN_VEnableWrmsNormVectorArray_MPIManyVector + public :: FN_VEnableWrmsNormMaskVectorArray_MPIManyVector + +! WRAPPER DECLARATIONS +interface +function swigc_FN_VMake_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VMake_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FN_VNew_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VNew_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VGetSubvector_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VGetSubvector_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VGetSubvectorArrayPointer_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VGetSubvectorArrayPointer_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VSetSubvectorArrayPointer_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VSetSubvectorArrayPointer_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VGetNumSubvectors_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VGetNumSubvectors_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FN_VGetVectorID_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VGetVectorID_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FN_VCloneEmpty_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VCloneEmpty_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VClone_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VClone_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VDestroy_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VDestroy_MPIManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FN_VSpace_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VSpace_MPIManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VGetCommunicator_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VGetCommunicator_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VGetLength_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VGetLength_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +subroutine swigc_FN_VLinearSum_MPIManyVector(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VLinearSum_MPIManyVector") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +end subroutine + +subroutine swigc_FN_VConst_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VConst_MPIManyVector") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VProd_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VProd_MPIManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VDiv_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VDiv_MPIManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VScale_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VScale_MPIManyVector") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VAbs_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VAbs_MPIManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VInv_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VInv_MPIManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VAddConst_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VAddConst_MPIManyVector") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VDotProd_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VDotProd_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMaxNorm_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VMaxNorm_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNorm_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VWrmsNorm_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNormMask_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWrmsNormMask_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMin_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VMin_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWL2Norm_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VWL2Norm_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VL1Norm_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VL1Norm_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +subroutine swigc_FN_VCompare_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VCompare_MPIManyVector") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VInvTest_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VInvTest_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstrMask_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstrMask_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VMinQuotient_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VMinQuotient_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VLinearCombination_MPIManyVector(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VLinearCombination_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleAddMulti_MPIManyVector(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VScaleAddMulti_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VDotProdMulti_MPIManyVector(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VDotProdMulti_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VLinearSumVectorArray_MPIManyVector(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FN_VLinearSumVectorArray_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleVectorArray_MPIManyVector(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VScaleVectorArray_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstVectorArray_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstVectorArray_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormVectorArray_MPIManyVector(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VWrmsNormVectorArray_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormMaskVectorArray_MPIManyVector(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VWrmsNormMaskVectorArray_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VDotProdLocal_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VDotProdLocal_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMaxNormLocal_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VMaxNormLocal_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMinLocal_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VMinLocal_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VL1NormLocal_MPIManyVector(farg1) & +bind(C, name="_wrap_FN_VL1NormLocal_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWSqrSumLocal_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VWSqrSumLocal_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWSqrSumMaskLocal_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWSqrSumMaskLocal_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VInvTestLocal_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VInvTestLocal_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstrMaskLocal_MPIManyVector(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstrMaskLocal_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VMinQuotientLocal_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VMinQuotientLocal_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VEnableFusedOps_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableFusedOps_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableLinearCombination_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableLinearCombination_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableScaleAddMulti_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableScaleAddMulti_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableDotProdMulti_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableDotProdMulti_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableLinearSumVectorArray_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableLinearSumVectorArray_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableScaleVectorArray_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableScaleVectorArray_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableConstVectorArray_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableConstVectorArray_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableWrmsNormVectorArray_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableWrmsNormVectorArray_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableWrmsNormMaskVectorArray_MPIManyVector(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableWrmsNormMaskVectorArray_MPIManyVector") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FN_VMake_MPIManyVector(comm, num_subvectors, vec_array) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer :: comm +integer(C_INT64_T), intent(in) :: num_subvectors +type(C_PTR) :: vec_array +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +integer(C_INT64_T) :: farg2 +type(C_PTR) :: farg3 + +farg1 = int(comm, C_INT) +farg2 = num_subvectors +farg3 = vec_array +fresult = swigc_FN_VMake_MPIManyVector(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VNew_MPIManyVector(num_subvectors, vec_array) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer(C_INT64_T), intent(in) :: num_subvectors +type(C_PTR) :: vec_array +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +type(C_PTR) :: farg2 + +farg1 = num_subvectors +farg2 = vec_array +fresult = swigc_FN_VNew_MPIManyVector(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VGetSubvector_MPIManyVector(v, vec_num) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), intent(in) :: vec_num +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 + +farg1 = c_loc(v) +farg2 = vec_num +fresult = swigc_FN_VGetSubvector_MPIManyVector(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VGetSubvectorArrayPointer_MPIManyVector(v, vec_num) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), intent(in) :: vec_num +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 + +farg1 = c_loc(v) +farg2 = vec_num +fresult = swigc_FN_VGetSubvectorArrayPointer_MPIManyVector(farg1, farg2) +call c_f_pointer(fresult, swig_result, [1]) +end function + +function FN_VSetSubvectorArrayPointer_MPIManyVector(v_data, v, vec_num) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +real(C_DOUBLE), dimension(*), target, intent(inout) :: v_data +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), intent(in) :: vec_num +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT64_T) :: farg3 + +farg1 = c_loc(v_data(1)) +farg2 = c_loc(v) +farg3 = vec_num +fresult = swigc_FN_VSetSubvectorArrayPointer_MPIManyVector(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VGetNumSubvectors_MPIManyVector(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetNumSubvectors_MPIManyVector(farg1) +swig_result = fresult +end function + +function FN_VGetVectorID_MPIManyVector(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(N_Vector_ID) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetVectorID_MPIManyVector(farg1) +swig_result = fresult +end function + +function FN_VCloneEmpty_MPIManyVector(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VCloneEmpty_MPIManyVector(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VClone_MPIManyVector(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VClone_MPIManyVector(farg1) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FN_VDestroy_MPIManyVector(v) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +call swigc_FN_VDestroy_MPIManyVector(farg1) +end subroutine + +subroutine FN_VSpace_MPIManyVector(v, lrw, liw) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), dimension(*), target, intent(inout) :: lrw +integer(C_INT64_T), dimension(*), target, intent(inout) :: liw +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(v) +farg2 = c_loc(lrw(1)) +farg3 = c_loc(liw(1)) +call swigc_FN_VSpace_MPIManyVector(farg1, farg2, farg3) +end subroutine + +function FN_VGetCommunicator_MPIManyVector(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetCommunicator_MPIManyVector(farg1) +swig_result = fresult +end function + +function FN_VGetLength_MPIManyVector(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetLength_MPIManyVector(farg1) +swig_result = fresult +end function + +subroutine FN_VLinearSum_MPIManyVector(a, x, b, y, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: a +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = a +farg2 = c_loc(x) +farg3 = b +farg4 = c_loc(y) +farg5 = c_loc(z) +call swigc_FN_VLinearSum_MPIManyVector(farg1, farg2, farg3, farg4, farg5) +end subroutine + +subroutine FN_VConst_MPIManyVector(c, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c +farg2 = c_loc(z) +call swigc_FN_VConst_MPIManyVector(farg1, farg2) +end subroutine + +subroutine FN_VProd_MPIManyVector(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VProd_MPIManyVector(farg1, farg2, farg3) +end subroutine + +subroutine FN_VDiv_MPIManyVector(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VDiv_MPIManyVector(farg1, farg2, farg3) +end subroutine + +subroutine FN_VScale_MPIManyVector(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VScale_MPIManyVector(farg1, farg2, farg3) +end subroutine + +subroutine FN_VAbs_MPIManyVector(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VAbs_MPIManyVector(farg1, farg2) +end subroutine + +subroutine FN_VInv_MPIManyVector(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VInv_MPIManyVector(farg1, farg2) +end subroutine + +subroutine FN_VAddConst_MPIManyVector(x, b, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = b +farg3 = c_loc(z) +call swigc_FN_VAddConst_MPIManyVector(farg1, farg2, farg3) +end subroutine + +function FN_VDotProd_MPIManyVector(x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(y) +fresult = swigc_FN_VDotProd_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VMaxNorm_MPIManyVector(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMaxNorm_MPIManyVector(farg1) +swig_result = fresult +end function + +function FN_VWrmsNorm_MPIManyVector(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWrmsNorm_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VWrmsNormMask_MPIManyVector(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWrmsNormMask_MPIManyVector(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMin_MPIManyVector(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMin_MPIManyVector(farg1) +swig_result = fresult +end function + +function FN_VWL2Norm_MPIManyVector(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWL2Norm_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VL1Norm_MPIManyVector(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VL1Norm_MPIManyVector(farg1) +swig_result = fresult +end function + +subroutine FN_VCompare_MPIManyVector(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VCompare_MPIManyVector(farg1, farg2, farg3) +end subroutine + +function FN_VInvTest_MPIManyVector(x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +fresult = swigc_FN_VInvTest_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VConstrMask_MPIManyVector(c, x, m) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: m +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(c) +farg2 = c_loc(x) +farg3 = c_loc(m) +fresult = swigc_FN_VConstrMask_MPIManyVector(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMinQuotient_MPIManyVector(num, denom) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: num +type(N_Vector), target, intent(inout) :: denom +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(num) +farg2 = c_loc(denom) +fresult = swigc_FN_VMinQuotient_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VLinearCombination_MPIManyVector(nvec, c, v, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: v +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = v +farg4 = c_loc(z) +fresult = swigc_FN_VLinearCombination_MPIManyVector(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VScaleAddMulti_MPIManyVector(nvec, a, x, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvec +farg2 = c_loc(a(1)) +farg3 = c_loc(x) +farg4 = y +farg5 = z +fresult = swigc_FN_VScaleAddMulti_MPIManyVector(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VDotProdMulti_MPIManyVector(nvec, x, y, dotprods) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +real(C_DOUBLE), dimension(*), target, intent(inout) :: dotprods +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(x) +farg3 = y +farg4 = c_loc(dotprods(1)) +fresult = swigc_FN_VDotProdMulti_MPIManyVector(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VLinearSumVectorArray_MPIManyVector(nvec, a, x, b, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), intent(in) :: a +type(C_PTR) :: x +real(C_DOUBLE), intent(in) :: b +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = nvec +farg2 = a +farg3 = x +farg4 = b +farg5 = y +farg6 = z +fresult = swigc_FN_VLinearSumVectorArray_MPIManyVector(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FN_VScaleVectorArray_MPIManyVector(nvec, c, x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: x +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = x +farg4 = z +fresult = swigc_FN_VScaleVectorArray_MPIManyVector(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VConstVectorArray_MPIManyVector(nvecs, c, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvecs +real(C_DOUBLE), intent(in) :: c +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = nvecs +farg2 = c +farg3 = z +fresult = swigc_FN_VConstVectorArray_MPIManyVector(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VWrmsNormVectorArray_MPIManyVector(nvecs, x, w, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvecs +type(C_PTR) :: x +type(C_PTR) :: w +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvecs +farg2 = x +farg3 = w +farg4 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormVectorArray_MPIManyVector(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VWrmsNormMaskVectorArray_MPIManyVector(nvec, x, w, id, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(C_PTR) :: x +type(C_PTR) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvec +farg2 = x +farg3 = w +farg4 = c_loc(id) +farg5 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormMaskVectorArray_MPIManyVector(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VDotProdLocal_MPIManyVector(x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(y) +fresult = swigc_FN_VDotProdLocal_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VMaxNormLocal_MPIManyVector(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMaxNormLocal_MPIManyVector(farg1) +swig_result = fresult +end function + +function FN_VMinLocal_MPIManyVector(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMinLocal_MPIManyVector(farg1) +swig_result = fresult +end function + +function FN_VL1NormLocal_MPIManyVector(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VL1NormLocal_MPIManyVector(farg1) +swig_result = fresult +end function + +function FN_VWSqrSumLocal_MPIManyVector(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWSqrSumLocal_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VWSqrSumMaskLocal_MPIManyVector(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWSqrSumMaskLocal_MPIManyVector(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VInvTestLocal_MPIManyVector(x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +fresult = swigc_FN_VInvTestLocal_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VConstrMaskLocal_MPIManyVector(c, x, m) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: m +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(c) +farg2 = c_loc(x) +farg3 = c_loc(m) +fresult = swigc_FN_VConstrMaskLocal_MPIManyVector(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMinQuotientLocal_MPIManyVector(num, denom) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: num +type(N_Vector), target, intent(inout) :: denom +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(num) +farg2 = c_loc(denom) +fresult = swigc_FN_VMinQuotientLocal_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableFusedOps_MPIManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableFusedOps_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableLinearCombination_MPIManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableLinearCombination_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableScaleAddMulti_MPIManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableScaleAddMulti_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableDotProdMulti_MPIManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableDotProdMulti_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableLinearSumVectorArray_MPIManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableLinearSumVectorArray_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableScaleVectorArray_MPIManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableScaleVectorArray_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableConstVectorArray_MPIManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableConstVectorArray_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableWrmsNormVectorArray_MPIManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableWrmsNormVectorArray_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableWrmsNormMaskVectorArray_MPIManyVector(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableWrmsNormMaskVectorArray_MPIManyVector(farg1, farg2) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/manyvector/nvector_manyvector.c b/deps/AMICI/ThirdParty/sundials/src/nvector/manyvector/nvector_manyvector.c new file mode 100644 index 000000000..9c72fa7b9 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/manyvector/nvector_manyvector.c @@ -0,0 +1,1837 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------- + * This is the implementation file for the ManyVector implementation + * of the NVECTOR package. + * -----------------------------------------------------------------*/ + +#include +#include +#include +#if SUNDIALS_MPI_ENABLED +#include +#else +#include +#endif + +/* Macro to handle separate MPI-aware/unaware installations */ +#if SUNDIALS_MPI_ENABLED +#define MVAPPEND(fun) fun##_MPIManyVector +#else +#define MVAPPEND(fun) fun##_ManyVector +#endif + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +/* ----------------------------------------------------------------- + ManyVector content accessor macros + -----------------------------------------------------------------*/ +#if SUNDIALS_MPI_ENABLED +#define MANYVECTOR_CONTENT(v) ( (N_VectorContent_MPIManyVector)(v->content) ) +#define MANYVECTOR_COMM(v) ( MANYVECTOR_CONTENT(v)->comm ) +#else +#define MANYVECTOR_CONTENT(v) ( (N_VectorContent_ManyVector)(v->content) ) +#endif +#define MANYVECTOR_NUM_SUBVECS(v) ( MANYVECTOR_CONTENT(v)->num_subvectors ) +#define MANYVECTOR_GLOBLENGTH(v) ( MANYVECTOR_CONTENT(v)->global_length ) +#define MANYVECTOR_SUBVECS(v) ( MANYVECTOR_CONTENT(v)->subvec_array ) +#define MANYVECTOR_SUBVEC(v,i) ( MANYVECTOR_SUBVECS(v)[i] ) +#define MANYVECTOR_OWN_DATA(v) ( MANYVECTOR_CONTENT(v)->own_data ) + +/* ----------------------------------------------------------------- + Prototypes of utility routines + -----------------------------------------------------------------*/ +static N_Vector ManyVectorClone(N_Vector w, booleantype cloneempty); +#if SUNDIALS_MPI_ENABLED +static int SubvectorMPIRank(N_Vector w); +#endif + +/* ----------------------------------------------------------------- + ManyVector API routines + -----------------------------------------------------------------*/ + +#if SUNDIALS_MPI_ENABLED + +/* This function creates an MPIManyVector from a set of existing + N_Vector objects, along with a user-created MPI (inter/intra)communicator + that couples all subvectors together. */ +N_Vector N_VMake_MPIManyVector(MPI_Comm comm, sunindextype num_subvectors, + N_Vector *vec_array) +{ + N_Vector v; + N_VectorContent_MPIManyVector content; + sunindextype i, local_length; + int rank, retval; + + /* Check that input N_Vectors are non-NULL */ + if (vec_array == NULL) return(NULL); + for (i=0; iops->nvgetvectorid = N_VGetVectorID_MPIManyVector; + v->ops->nvcloneempty = N_VCloneEmpty_MPIManyVector; + v->ops->nvclone = N_VClone_MPIManyVector; + v->ops->nvdestroy = N_VDestroy_MPIManyVector; + v->ops->nvspace = N_VSpace_MPIManyVector; + v->ops->nvgetcommunicator = N_VGetCommunicator_MPIManyVector; + v->ops->nvgetlength = N_VGetLength_MPIManyVector; + + /* standard vector operations */ + v->ops->nvlinearsum = N_VLinearSum_MPIManyVector; + v->ops->nvconst = N_VConst_MPIManyVector; + v->ops->nvprod = N_VProd_MPIManyVector; + v->ops->nvdiv = N_VDiv_MPIManyVector; + v->ops->nvscale = N_VScale_MPIManyVector; + v->ops->nvabs = N_VAbs_MPIManyVector; + v->ops->nvinv = N_VInv_MPIManyVector; + v->ops->nvaddconst = N_VAddConst_MPIManyVector; + v->ops->nvdotprod = N_VDotProd_MPIManyVector; + v->ops->nvmaxnorm = N_VMaxNorm_MPIManyVector; + v->ops->nvwrmsnorm = N_VWrmsNorm_MPIManyVector; + v->ops->nvwrmsnormmask = N_VWrmsNormMask_MPIManyVector; + v->ops->nvmin = N_VMin_MPIManyVector; + v->ops->nvwl2norm = N_VWL2Norm_MPIManyVector; + v->ops->nvl1norm = N_VL1Norm_MPIManyVector; + v->ops->nvcompare = N_VCompare_MPIManyVector; + v->ops->nvinvtest = N_VInvTest_MPIManyVector; + v->ops->nvconstrmask = N_VConstrMask_MPIManyVector; + v->ops->nvminquotient = N_VMinQuotient_MPIManyVector; + + /* fused vector operations */ + v->ops->nvlinearcombination = N_VLinearCombination_MPIManyVector; + v->ops->nvscaleaddmulti = N_VScaleAddMulti_MPIManyVector; + v->ops->nvdotprodmulti = N_VDotProdMulti_MPIManyVector; + + /* vector array operations */ + v->ops->nvwrmsnormvectorarray = N_VWrmsNormVectorArray_MPIManyVector; + v->ops->nvwrmsnormmaskvectorarray = N_VWrmsNormMaskVectorArray_MPIManyVector; + + /* local reduction operations */ + v->ops->nvdotprodlocal = N_VDotProdLocal_MPIManyVector; + v->ops->nvmaxnormlocal = N_VMaxNormLocal_MPIManyVector; + v->ops->nvminlocal = N_VMinLocal_MPIManyVector; + v->ops->nvl1normlocal = N_VL1NormLocal_MPIManyVector; + v->ops->nvinvtestlocal = N_VInvTestLocal_MPIManyVector; + v->ops->nvconstrmasklocal = N_VConstrMaskLocal_MPIManyVector; + v->ops->nvminquotientlocal = N_VMinQuotientLocal_MPIManyVector; + v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_MPIManyVector; + v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_MPIManyVector; + + /* Create content */ + content = NULL; + content = (N_VectorContent_MPIManyVector) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } + + /* Attach content */ + v->content = content; + + /* Attach content components */ + + /* set scalar content entries, and allocate/set subvector array */ + content->comm = MPI_COMM_NULL; + content->num_subvectors = num_subvectors; + content->own_data = SUNFALSE; + content->subvec_array = NULL; + content->subvec_array = (N_Vector *) malloc(num_subvectors * sizeof(N_Vector)); + if (content->subvec_array == NULL) { N_VDestroy(v); return(NULL); } + for (i=0; isubvec_array[i] = vec_array[i]; + + /* duplicate input communicator (if non-NULL) */ + if (comm != MPI_COMM_NULL) { + retval = MPI_Comm_dup(comm, &(content->comm)); + if (retval != MPI_SUCCESS) { N_VDestroy(v); return(NULL); } + } + + /* Determine overall MPIManyVector length: sum contributions from all + subvectors where this rank is the root, then perform reduction */ + local_length = 0; + for (i=0; iops->nvgetlength) { + if (rank == 0) local_length += N_VGetLength(vec_array[i]); + } else { + N_VDestroy(v); + return(NULL); + } + } + if (content->comm != MPI_COMM_NULL) { + retval = MPI_Allreduce(&local_length, &(content->global_length), 1, + MPI_SUNINDEXTYPE, MPI_SUM, content->comm); + if (retval != MPI_SUCCESS) { N_VDestroy(v); return(NULL); } + } else { + content->global_length = local_length; + } + + return(v); +} +#endif + + +#if SUNDIALS_MPI_ENABLED +/* This function creates an MPIManyVector from a set of existing + N_Vector objects, under the requirement that all MPI-aware + sub-vectors use the same MPI communicator (this is verified + internally). If no sub-vector is MPI-aware, then this may be + used to describe data partitioning within a single node, and + a NULL communicator will be created. */ +N_Vector N_VNew_MPIManyVector(sunindextype num_subvectors, + N_Vector *vec_array) +{ + sunindextype i; + booleantype nocommfound; + void* tmpcomm; + MPI_Comm comm, *vcomm; + int retval, comparison; + N_Vector v; + + /* Check that all subvectors have identical MPI communicators (if present) */ + nocommfound = SUNTRUE; + comm = MPI_COMM_NULL; + for (i=0; iops->nvgetvectorid = N_VGetVectorID_ManyVector; + v->ops->nvcloneempty = N_VCloneEmpty_ManyVector; + v->ops->nvclone = N_VClone_ManyVector; + v->ops->nvdestroy = N_VDestroy_ManyVector; + v->ops->nvspace = N_VSpace_ManyVector; + v->ops->nvgetlength = N_VGetLength_ManyVector; + + /* standard vector operations */ + v->ops->nvlinearsum = N_VLinearSum_ManyVector; + v->ops->nvconst = N_VConst_ManyVector; + v->ops->nvprod = N_VProd_ManyVector; + v->ops->nvdiv = N_VDiv_ManyVector; + v->ops->nvscale = N_VScale_ManyVector; + v->ops->nvabs = N_VAbs_ManyVector; + v->ops->nvinv = N_VInv_ManyVector; + v->ops->nvaddconst = N_VAddConst_ManyVector; + v->ops->nvdotprod = N_VDotProdLocal_ManyVector; + v->ops->nvmaxnorm = N_VMaxNormLocal_ManyVector; + v->ops->nvwrmsnorm = N_VWrmsNorm_ManyVector; + v->ops->nvwrmsnormmask = N_VWrmsNormMask_ManyVector; + v->ops->nvmin = N_VMinLocal_ManyVector; + v->ops->nvwl2norm = N_VWL2Norm_ManyVector; + v->ops->nvl1norm = N_VL1NormLocal_ManyVector; + v->ops->nvcompare = N_VCompare_ManyVector; + v->ops->nvinvtest = N_VInvTestLocal_ManyVector; + v->ops->nvconstrmask = N_VConstrMaskLocal_ManyVector; + v->ops->nvminquotient = N_VMinQuotientLocal_ManyVector; + + /* fused vector operations */ + v->ops->nvlinearcombination = N_VLinearCombination_ManyVector; + v->ops->nvscaleaddmulti = N_VScaleAddMulti_ManyVector; + v->ops->nvdotprodmulti = N_VDotProdMulti_ManyVector; + + /* vector array operations */ + v->ops->nvwrmsnormvectorarray = N_VWrmsNormVectorArray_ManyVector; + v->ops->nvwrmsnormmaskvectorarray = N_VWrmsNormMaskVectorArray_ManyVector; + + /* local reduction operations */ + v->ops->nvdotprodlocal = N_VDotProdLocal_ManyVector; + v->ops->nvmaxnormlocal = N_VMaxNormLocal_ManyVector; + v->ops->nvminlocal = N_VMinLocal_ManyVector; + v->ops->nvl1normlocal = N_VL1NormLocal_ManyVector; + v->ops->nvinvtestlocal = N_VInvTestLocal_ManyVector; + v->ops->nvconstrmasklocal = N_VConstrMaskLocal_ManyVector; + v->ops->nvminquotientlocal = N_VMinQuotientLocal_ManyVector; + v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_ManyVector; + v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_ManyVector; + + /* Create content */ + content = NULL; + content = (N_VectorContent_ManyVector) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } + + /* Attach content */ + v->content = content; + + /* Attach content components */ + + /* allocate and set subvector array */ + content->num_subvectors = num_subvectors; + content->own_data = SUNFALSE; + + content->subvec_array = NULL; + content->subvec_array = (N_Vector *) malloc(num_subvectors * sizeof(N_Vector)); + if (content->subvec_array == NULL) { N_VDestroy(v); return(NULL); } + + for (i=0; isubvec_array[i] = vec_array[i]; + + /* Determine overall ManyVector length: sum contributions from all subvectors */ + content->global_length = 0; + for (i=0; iops->nvgetlength) { + content->global_length += N_VGetLength(vec_array[i]); + } else { + N_VDestroy(v); + return(NULL); + } + } + + return(v); +} +#endif + + +/* This function returns the vec_num sub-N_Vector from the N_Vector + array. If vec_num is outside of applicable bounds, NULL is returned. */ +N_Vector MVAPPEND(N_VGetSubvector)(N_Vector v, sunindextype vec_num) +{ + if ( (vec_num < 0) || (vec_num > MANYVECTOR_NUM_SUBVECS(v)) ) + return(NULL); + return(MANYVECTOR_SUBVEC(v,vec_num)); +} + + +/* This function returns data pointer for the vec_num sub-N_Vector from + the N_Vector array. If vec_num is outside of applicable bounds, or if + the subvector does not support the N_VGetArrayPointer routine, then + NULL is returned. */ +realtype *MVAPPEND(N_VGetSubvectorArrayPointer)(N_Vector v, sunindextype vec_num) +{ + if ( (vec_num < 0) || (vec_num > MANYVECTOR_NUM_SUBVECS(v)) ) + return(NULL); + if ( MANYVECTOR_SUBVEC(v,vec_num)->ops->nvgetarraypointer == NULL ) + return(NULL); + return(N_VGetArrayPointer(MANYVECTOR_SUBVEC(v,vec_num))); +} + + +/* This function sets the data pointer for the vec_num sub-N_Vector from + the N_Vector array. If vec_num is outside of applicable bounds, or if + the subvector does not support the N_VSetArrayPointer routine, then + -1 is returned; otherwise this routine returns 0. */ +int MVAPPEND(N_VSetSubvectorArrayPointer)(realtype *v_data, N_Vector v, sunindextype vec_num) +{ + if ( (vec_num < 0) || (vec_num > MANYVECTOR_NUM_SUBVECS(v)) ) + return(-1); + if ( MANYVECTOR_SUBVEC(v,vec_num)->ops->nvsetarraypointer == NULL ) + return(-1); + N_VSetArrayPointer(v_data, MANYVECTOR_SUBVEC(v,vec_num)); + return(0); +} + + +/* This function returns the overall number of sub-vectors. + It returns a locally stored integer, and is therefore a local call. */ +sunindextype MVAPPEND(N_VGetNumSubvectors)(N_Vector v) +{ + return(MANYVECTOR_NUM_SUBVECS(v)); +} + + +/* ----------------------------------------------------------------- + ManyVector implementations of generic NVector routines + -----------------------------------------------------------------*/ + +/* Returns vector type ID. Used to identify vector implementation + from abstract N_Vector interface. */ +N_Vector_ID MVAPPEND(N_VGetVectorID)(N_Vector v) +{ +#if SUNDIALS_MPI_ENABLED + return(SUNDIALS_NVEC_MPIMANYVECTOR); +#else + return(SUNDIALS_NVEC_MANYVECTOR); +#endif +} + + +/* Clones a ManyVector, calling CloneEmpty on subvectors. */ +N_Vector MVAPPEND(N_VCloneEmpty)(N_Vector w) +{ + return(ManyVectorClone(w, SUNTRUE)); +} + + +/* Clones a ManyVector, calling Clone on subvectors. */ +N_Vector MVAPPEND(N_VClone)(N_Vector w) +{ + return(ManyVectorClone(w, SUNFALSE)); +} + + +/* Destroys a ManyVector */ +void MVAPPEND(N_VDestroy)(N_Vector v) +{ + sunindextype i; + + if (v == NULL) return; + + /* free content */ + if (v->content != NULL) { + /* if subvectors are owned by v, then Destroy those */ + if ((MANYVECTOR_OWN_DATA(v) == SUNTRUE) && (MANYVECTOR_SUBVECS(v) != NULL)) { + for (i=0; icontent); + v->content = NULL; + } + + /* free ops and vector */ + if (v->ops != NULL) { free(v->ops); v->ops = NULL; } + free(v); v = NULL; + + return; +} + + +/* Returns the space requirements for the ManyVector, by accumulating this + information from all subvectors. */ +void MVAPPEND(N_VSpace)(N_Vector v, sunindextype *lrw, sunindextype *liw) +{ + sunindextype i, lrw1, liw1; + *lrw = 0; + *liw = 0; + for (i=0; iops->nvspace != NULL) { + N_VSpace(MANYVECTOR_SUBVEC(v,i), &lrw1, &liw1); + *lrw += lrw1; + *liw += liw1; + } + } + return; +} + + +#if SUNDIALS_MPI_ENABLED +/* This function retrieves the MPI Communicator from an MPIManyVector object. */ +void *N_VGetCommunicator_MPIManyVector(N_Vector v) +{ + if (MANYVECTOR_COMM(v) == MPI_COMM_NULL) + return NULL; + else + return((void *) &MANYVECTOR_COMM(v)); +} +#else +/* This function retrieves the MPI Communicator from a ManyVector object. */ +void *N_VGetCommunicator_ManyVector(N_Vector v) +{ + return NULL; +} +#endif + + +/* This function retrieves the global length of a ManyVector object. */ +sunindextype MVAPPEND(N_VGetLength)(N_Vector v) +{ + return(MANYVECTOR_GLOBLENGTH(v)); +} + + +/* Performs the linear sum z = a*x + b*y by calling N_VLinearSum on all subvectors; + this routine does not check that x, y and z are ManyVectors, if they have the + same number of subvectors, or if these subvectors are compatible. */ +void MVAPPEND(N_VLinearSum)(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) +{ + sunindextype i; + for (i=0; iops->nvdotprodlocal) { + + sum += N_VDotProdLocal(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(y,i)); + + /* otherwise, call nvdotprod and root tasks accumulate to overall sum */ + } else { + + contrib = N_VDotProd(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(y,i)); + + /* get this task's rank in subvector communicator (note: serial + subvectors will result in rank==0) */ + rank = SubvectorMPIRank(MANYVECTOR_SUBVEC(x,i)); + if (rank < 0) return(ZERO); + if (rank == 0) sum += contrib; + + } + +#else + + /* add subvector contribution */ + sum += N_VDotProd(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(y,i)); + +#endif + + } + + return(sum); +} + + +#if SUNDIALS_MPI_ENABLED +/* Performs the dot product of two ManyVectors by calling N_VDotProdLocal and + combining the results. This routine does not check that x and y are + ManyVectors, if they have the same number of subvectors, or if these + subvectors are compatible. */ +realtype N_VDotProd_MPIManyVector(N_Vector x, N_Vector y) +{ + realtype lsum, gsum; + lsum = gsum = N_VDotProdLocal_MPIManyVector(x,y); + if (MANYVECTOR_COMM(x) != MPI_COMM_NULL) + MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, MANYVECTOR_COMM(x)); + return(gsum); +} +#endif + + +/* Performs the MPI task-local maximum norm of a ManyVector by calling + N_VMaxNormLocal on all subvectors. + + If any subvector does not implement the N_VMaxNormLocal routine (NULL + function pointer), then this routine will call N_VMaxNorm instead. */ +realtype MVAPPEND(N_VMaxNormLocal)(N_Vector x) +{ + sunindextype i; + realtype max, lmax; + + /* initialize output*/ + max = ZERO; + + for (i=0; iops->nvmaxnormlocal) { + + lmax = N_VMaxNormLocal(MANYVECTOR_SUBVEC(x,i)); + max = (max > lmax) ? max : lmax; + + /* otherwise, call nvmaxnorm and accumulate to overall max */ + } else { + + lmax = N_VMaxNorm(MANYVECTOR_SUBVEC(x,i)); + max = (max > lmax) ? max : lmax; + + } + } + + return(max); +} + + +#if SUNDIALS_MPI_ENABLED +/* Performs the maximum norm of a ManyVector by calling N_VMaxNormLocal and + combining the results. */ +realtype N_VMaxNorm_MPIManyVector(N_Vector x) +{ + realtype lmax, gmax; + lmax = gmax = N_VMaxNormLocal_MPIManyVector(x); + if (MANYVECTOR_COMM(x) != MPI_COMM_NULL) + MPI_Allreduce(&lmax, &gmax, 1, MPI_SUNREALTYPE, MPI_MAX, MANYVECTOR_COMM(x)); + return(gmax); +} +#endif + + +/* Performs the MPI task-local weighted squared sum of a ManyVector by calling + N_VWSqrSumLocal on all subvectors; this routine does not check that x and + w are ManyVectors, if they have the same number of subvectors, or if these + subvectors are compatible. + + If any subvector does not implement the N_VWSqrSumLocal routine (NULL + function pointer), then this routine will call N_VWrmsNorm and N_VGetLength + to unravel the squared sum of the subvector components. It will then only + accumulate this to the overall sum if this is the root task for that + subvector's communicator (note: serial vectors are always root task). */ +realtype MVAPPEND(N_VWSqrSumLocal)(N_Vector x, N_Vector w) +{ + sunindextype i, N; + realtype sum, contrib; +#if SUNDIALS_MPI_ENABLED + int rank; +#endif + + /* initialize output*/ + sum = ZERO; + + for (i=0; iops->nvwsqrsumlocal) { + + sum += N_VWSqrSumLocal(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(w,i)); + + /* otherwise, call nvwrmsnorm, and accumulate to overall sum on root task */ + } else { + + contrib = N_VWrmsNorm(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(w,i)); + + /* get this task's rank in subvector communicator (note: serial + subvectors will result in rank==0) */ + rank = SubvectorMPIRank(MANYVECTOR_SUBVEC(x,i)); + if (rank < 0) return(ZERO); + if (rank == 0) { + N = N_VGetLength(MANYVECTOR_SUBVEC(x,i)); + sum += (contrib*contrib*N); + } + } + +#else + + /* accumulate subvector contribution to overall sum */ + contrib = N_VWrmsNorm(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(w,i)); + N = N_VGetLength(MANYVECTOR_SUBVEC(x,i)); + sum += (contrib*contrib*N); + +#endif + + } + + return(sum); +} + + +/* Performs the WRMS norm of a ManyVector by calling N_VWSqrSumLocal and + combining the results; this routine does not check that x and + w are ManyVectors, if they have the same number of subvectors, or if these + subvectors are compatible. */ +realtype MVAPPEND(N_VWrmsNorm)(N_Vector x, N_Vector w) +{ + realtype gsum; +#if SUNDIALS_MPI_ENABLED + realtype lsum; + lsum = gsum = N_VWSqrSumLocal_MPIManyVector(x, w); + if (MANYVECTOR_COMM(x) != MPI_COMM_NULL) + MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, MANYVECTOR_COMM(x)); +#else + gsum = N_VWSqrSumLocal_ManyVector(x, w); +#endif + return(SUNRsqrt(gsum/(MANYVECTOR_GLOBLENGTH(x)))); +} + + +/* Performs the MPI task-local masked weighted squared sum of a ManyVector by + calling N_VWSqrSumMaskLocal on all subvectors; this routine does not check + that x, w and id are ManyVectors, if they have the same number of + subvectors, or if these subvectors are compatible. + + If any subvector does not implement the N_VWSqrSumLocal routine (NULL + function pointer), then this routine will call N_VWrmsNormMask and + N_VGetLength to unravel the masked squared sum of the subvector components. + It will then only accumulate this to the overall sum if this is the root + task for that subvector's communicator (note: serial vectors are always + root task). */ +realtype MVAPPEND(N_VWSqrSumMaskLocal)(N_Vector x, N_Vector w, N_Vector id) +{ + sunindextype i, N; + realtype sum, contrib; +#if SUNDIALS_MPI_ENABLED + int rank; +#endif + + /* initialize output*/ + sum = ZERO; + + for (i=0; iops->nvwsqrsummasklocal) { + + sum += N_VWSqrSumMaskLocal(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(w,i), + MANYVECTOR_SUBVEC(id,i)); + + /* otherwise, call nvwrmsnormmask, and accumulate to overall sum on root task */ + } else { + + contrib = N_VWrmsNormMask(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(w,i), + MANYVECTOR_SUBVEC(id,i)); + + /* get this task's rank in subvector communicator (note: serial + subvectors will result in rank==0) */ + rank = SubvectorMPIRank(MANYVECTOR_SUBVEC(x,i)); + if (rank < 0) return(ZERO); + if (rank == 0) { + N = N_VGetLength(MANYVECTOR_SUBVEC(x,i)); + sum += (contrib*contrib*N); + } + } + +#else + + /* accumulate subvector contribution to overall sum */ + contrib = N_VWrmsNormMask(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(w,i), + MANYVECTOR_SUBVEC(id,i)); + N = N_VGetLength(MANYVECTOR_SUBVEC(x,i)); + sum += (contrib*contrib*N); + +#endif + + } + + return(sum); +} + + +/* Performs the masked WRMS norm of a ManyVector by calling N_VWSqrSumMaskLocal + and combining the results; this routine does not check that x, w and id are + ManyVectors, if they have the same number of subvectors, or if these subvectors + are compatible. */ +realtype MVAPPEND(N_VWrmsNormMask)(N_Vector x, N_Vector w, N_Vector id) +{ + realtype gsum; +#if SUNDIALS_MPI_ENABLED + realtype lsum; + lsum = gsum = N_VWSqrSumMaskLocal_MPIManyVector(x, w, id); + if (MANYVECTOR_COMM(x) != MPI_COMM_NULL) + MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, MANYVECTOR_COMM(x)); +#else + gsum = N_VWSqrSumMaskLocal_ManyVector(x, w, id); +#endif + return(SUNRsqrt(gsum/(MANYVECTOR_GLOBLENGTH(x)))); +} + + +/* Computes the MPI task-local minimum entry of a ManyVector by calling + N_VMinLocal on all subvectors. + + If any subvector does not implement the N_VMinLocal routine (NULL + function pointer), then this routine will call N_VMin instead. */ +realtype MVAPPEND(N_VMinLocal)(N_Vector x) +{ + sunindextype i; + realtype min, lmin; + + /* initialize output*/ + min = BIG_REAL; + + for (i=0; iops->nvminlocal) { + + lmin = N_VMinLocal(MANYVECTOR_SUBVEC(x,i)); + min = (min < lmin) ? min : lmin; + + /* otherwise, call nvmin and accumulate to overall min */ + } else { + + lmin = N_VMin(MANYVECTOR_SUBVEC(x,i)); + min = (min < lmin) ? min : lmin; + + } + } + + return(min); +} + + +#if SUNDIALS_MPI_ENABLED +/* Computes the minimum entry of a ManyVector by calling N_VMinLocal and + combining the results. */ +realtype N_VMin_MPIManyVector(N_Vector x) +{ + realtype lmin, gmin; + lmin = gmin = N_VMinLocal_MPIManyVector(x); + if (MANYVECTOR_COMM(x) != MPI_COMM_NULL) + MPI_Allreduce(&lmin, &gmin, 1, MPI_SUNREALTYPE, MPI_MIN, MANYVECTOR_COMM(x)); + return(gmin); +} +#endif + + +/* Performs the WL2 norm of a ManyVector by calling N_VSqrSumLocal and + 'massaging' the result. This routine does not check that x and w are + ManyVectors, if they have the same number of subvectors, or if these + subvectors are compatible. */ +realtype MVAPPEND(N_VWL2Norm)(N_Vector x, N_Vector w) +{ + realtype gsum; +#if SUNDIALS_MPI_ENABLED + realtype lsum; + lsum = gsum = N_VWSqrSumLocal_MPIManyVector(x, w); + if (MANYVECTOR_COMM(x) != MPI_COMM_NULL) + MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, MANYVECTOR_COMM(x)); +#else + gsum = N_VWSqrSumLocal_ManyVector(x, w); +#endif + return(SUNRsqrt(gsum)); +} + + +/* Performs the MPI task-local L1 norm of a ManyVector by calling N_VL1NormLocal on + all subvectors. If any subvector does not implement the N_VL1NormLocal routine + (NULL function pointer), then this routine will call N_VL1Norm, but only + accumulate the sum if this is the root task for that subvector's + communicator (note: serial vectors are always root task). */ +realtype MVAPPEND(N_VL1NormLocal)(N_Vector x) +{ + sunindextype i; + realtype sum; +#if SUNDIALS_MPI_ENABLED + realtype contrib; + int rank; +#endif + + /* initialize output*/ + sum = ZERO; + + for (i=0; iops->nvl1normlocal) { + + sum += N_VL1NormLocal(MANYVECTOR_SUBVEC(x,i)); + + /* otherwise, call nvl1norm and root tasks accumulate to overall sum */ + } else { + + contrib = N_VL1Norm(MANYVECTOR_SUBVEC(x,i)); + + /* get this task's rank in subvector communicator (note: serial + subvectors will result in rank==0) */ + rank = SubvectorMPIRank(MANYVECTOR_SUBVEC(x,i)); + if (rank < 0) return(ZERO); + if (rank == 0) sum += contrib; + + } + +#else + + /* accumulate subvector contribution to overall sum */ + sum += N_VL1Norm(MANYVECTOR_SUBVEC(x,i)); + +#endif + + } + + return(sum); +} + + +#if SUNDIALS_MPI_ENABLED +/* Performs the L1 norm of a ManyVector by calling N_VL1NormLocal and + combining the results. */ +realtype N_VL1Norm_MPIManyVector(N_Vector x) +{ + realtype lsum, gsum; + lsum = gsum = N_VL1NormLocal_MPIManyVector(x); + if (MANYVECTOR_COMM(x) != MPI_COMM_NULL) + MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, MANYVECTOR_COMM(x)); + return(gsum); +} +#endif + + +/* Performs N_VCompare on all subvectors; this routine does not check that x and z are + ManyVectors, if they have the same number of subvectors, or if these subvectors are + compatible. */ +void MVAPPEND(N_VCompare)(realtype c, N_Vector x, N_Vector z) +{ + sunindextype i; + for (i=0; iops->nvinvtestlocal) { + + subval = N_VInvTestLocal(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(z,i)); + val = (val && subval); + + /* otherwise, call nvinvtest and accumulate to overall val */ + } else { + + subval = N_VInvTest(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(z,i)); + val = (val && subval); + + } + } + + return(val); +} + + +#if SUNDIALS_MPI_ENABLED +/* Performs the InvTest for a ManyVector by calling N_VInvTestLocal and + combining the results. This routine does not check that x and z + are ManyVectors, if they have the same number of subvectors, or if these + subvectors are compatible. */ +booleantype N_VInvTest_MPIManyVector(N_Vector x, N_Vector z) +{ + realtype val, gval; + val = gval = (N_VInvTestLocal_MPIManyVector(x, z)) ? ONE : ZERO; + if (MANYVECTOR_COMM(x) != MPI_COMM_NULL) + MPI_Allreduce(&val, &gval, 1, MPI_SUNREALTYPE, MPI_MIN, MANYVECTOR_COMM(x)); + return (gval != ZERO); +} +#endif + + +/* Performs the MPI task-local ConstrMask for a ManyVector by calling N_VConstrMaskLocal + on all subvectors and combining the results appropriately. This routine does not + check that c, x and m are ManyVectors, if they have the same number of subvectors, + or if these subvectors are compatible. + + If any subvector does not implement the N_VConstrMaskLocal routine (NULL + function pointer), then this routine will call N_VConstrMask instead. */ +booleantype MVAPPEND(N_VConstrMaskLocal)(N_Vector c, N_Vector x, N_Vector m) +{ + sunindextype i; + booleantype val, subval; + + /* initialize output*/ + val = SUNTRUE; + + for (i=0; iops->nvconstrmasklocal) { + + subval = N_VConstrMaskLocal(MANYVECTOR_SUBVEC(c,i), MANYVECTOR_SUBVEC(x,i), + MANYVECTOR_SUBVEC(m,i)); + val = (val && subval); + + /* otherwise, call nvconstrmask and accumulate to overall val */ + } else { + + subval = N_VConstrMask(MANYVECTOR_SUBVEC(c,i), MANYVECTOR_SUBVEC(x,i), + MANYVECTOR_SUBVEC(m,i)); + val = (val && subval); + + } + } + + return(val); +} + + +#if SUNDIALS_MPI_ENABLED +/* Performs the ConstrMask for a ManyVector by calling N_VConstrMaskLocal and + combining the results. This routine does not check that c, x and m + are ManyVectors, if they have the same number of subvectors, or if these + subvectors are compatible. */ +booleantype N_VConstrMask_MPIManyVector(N_Vector c, N_Vector x, N_Vector m) +{ + realtype val, gval; + val = gval = (N_VConstrMaskLocal_MPIManyVector(c, x, m)) ? ONE : ZERO; + if (MANYVECTOR_COMM(x) != MPI_COMM_NULL) + MPI_Allreduce(&val, &gval, 1, MPI_SUNREALTYPE, MPI_MIN, MANYVECTOR_COMM(x)); + return (gval != ZERO); +} +#endif + + +/* Performs the MPI task-local MinQuotient for a ManyVector by calling N_VMinQuotientLocal + on all subvectors and combining the results appropriately. This routine does not check + that num and denom are ManyVectors, if they have the same number of subvectors, or if + these subvectors are compatible. + + If any subvector does not implement the N_VMinQuotientLocal routine (NULL + function pointer), then this routine will call N_VMinQuotient instead. */ +realtype MVAPPEND(N_VMinQuotientLocal)(N_Vector num, N_Vector denom) +{ + sunindextype i; + realtype min, lmin; + + /* initialize output*/ + min = BIG_REAL; + + for (i=0; iops->nvminquotientlocal) { + + lmin = N_VMinQuotientLocal(MANYVECTOR_SUBVEC(num,i), + MANYVECTOR_SUBVEC(denom,i)); + min = (min < lmin) ? min : lmin; + + /* otherwise, call nvmin and accumulate to overall min */ + } else { + + lmin = N_VMinQuotient(MANYVECTOR_SUBVEC(num,i), + MANYVECTOR_SUBVEC(denom,i)); + min = (min < lmin) ? min : lmin; + + } + } + + return(min); +} + + +#if SUNDIALS_MPI_ENABLED +/* Performs the MinQuotient for a ManyVector by calling N_VMinQuotientLocal + and combining the results. This routine does not check that num and + denom are ManyVectors, if they have the same number of subvectors, or if + these subvectors are compatible. */ +realtype N_VMinQuotient_MPIManyVector(N_Vector num, N_Vector denom) +{ + realtype lmin, gmin; + lmin = gmin = N_VMinQuotientLocal_MPIManyVector(num, denom); + if (MANYVECTOR_COMM(num) != MPI_COMM_NULL) + MPI_Allreduce(&lmin, &gmin, 1, MPI_SUNREALTYPE, MPI_MIN, MANYVECTOR_COMM(num)); + return(gmin); +} +#endif + + + +/* ----------------------------------------------------------------- + Fused vector operations + ----------------------------------------------------------------- */ + +/* Performs the linear combination z = sum_j c[j]*X[j] by calling + N_VLinearCombination on all subvectors; this routine does not check that z + or the components of X are ManyVectors, if they have the same number of + subvectors, or if these subvectors are compatible. + + NOTE: implementation of this routine is more challenging, due to the + array-of-arrays of N_Vectors that comprise X. This routine will be + passed an array of ManyVectors, so to call the subvector-specific routines + we must unravel the subvectors while retaining an array of outer vectors. */ +int MVAPPEND(N_VLinearCombination)(int nvec, realtype* c, N_Vector* X, N_Vector z) +{ + sunindextype i, j; + int retval; + N_Vector *Xsub; + + /* create array of nvec N_Vector pointers for reuse within loop */ + Xsub = NULL; + Xsub = (N_Vector *) malloc( nvec * sizeof(N_Vector) ); + if (Xsub == NULL) return(1); + + /* perform operation by calling N_VLinearCombination for each subvector */ + for (i=0; i pair */ + for (i=0; iops == NULL) return(-1); + + if (tf) { + /* enable all fused vector operations */ + v->ops->nvlinearcombination = MVAPPEND(N_VLinearCombination); + v->ops->nvscaleaddmulti = MVAPPEND(N_VScaleAddMulti); + v->ops->nvdotprodmulti = MVAPPEND(N_VDotProdMulti); + /* enable all vector array operations */ + v->ops->nvlinearsumvectorarray = MVAPPEND(N_VLinearSumVectorArray); + v->ops->nvscalevectorarray = MVAPPEND(N_VScaleVectorArray); + v->ops->nvconstvectorarray = MVAPPEND(N_VConstVectorArray); + v->ops->nvwrmsnormvectorarray = MVAPPEND(N_VWrmsNormVectorArray); + v->ops->nvwrmsnormmaskvectorarray = MVAPPEND(N_VWrmsNormMaskVectorArray); + v->ops->nvscaleaddmultivectorarray = NULL; + v->ops->nvlinearcombinationvectorarray = NULL; + } else { + /* disable all fused vector operations */ + v->ops->nvlinearcombination = NULL; + v->ops->nvscaleaddmulti = NULL; + v->ops->nvdotprodmulti = NULL; + /* disable all vector array operations */ + v->ops->nvlinearsumvectorarray = NULL; + v->ops->nvscalevectorarray = NULL; + v->ops->nvconstvectorarray = NULL; + v->ops->nvwrmsnormvectorarray = NULL; + v->ops->nvwrmsnormmaskvectorarray = NULL; + v->ops->nvscaleaddmultivectorarray = NULL; + v->ops->nvlinearcombinationvectorarray = NULL; + } + + /* return success */ + return(0); +} + + +int MVAPPEND(N_VEnableLinearCombination)(N_Vector v, booleantype tf) +{ + /* check that vector is non-NULL */ + if (v == NULL) return(-1); + + /* check that ops structure is non-NULL */ + if (v->ops == NULL) return(-1); + + /* enable/disable operation */ + if (tf) + v->ops->nvlinearcombination = MVAPPEND(N_VLinearCombination); + else + v->ops->nvlinearcombination = NULL; + + /* return success */ + return(0); +} + +int MVAPPEND(N_VEnableScaleAddMulti)(N_Vector v, booleantype tf) +{ + /* check that vector is non-NULL */ + if (v == NULL) return(-1); + + /* check that ops structure is non-NULL */ + if (v->ops == NULL) return(-1); + + /* enable/disable operation */ + if (tf) + v->ops->nvscaleaddmulti = MVAPPEND(N_VScaleAddMulti); + else + v->ops->nvscaleaddmulti = NULL; + + /* return success */ + return(0); +} + +int MVAPPEND(N_VEnableDotProdMulti)(N_Vector v, booleantype tf) +{ + /* check that vector is non-NULL */ + if (v == NULL) return(-1); + + /* check that ops structure is non-NULL */ + if (v->ops == NULL) return(-1); + + /* enable/disable operation */ + if (tf) + v->ops->nvdotprodmulti = MVAPPEND(N_VDotProdMulti); + else + v->ops->nvdotprodmulti = NULL; + + /* return success */ + return(0); +} + +int MVAPPEND(N_VEnableLinearSumVectorArray)(N_Vector v, booleantype tf) +{ + /* check that vector is non-NULL */ + if (v == NULL) return(-1); + + /* check that ops structure is non-NULL */ + if (v->ops == NULL) return(-1); + + /* enable/disable operation */ + if (tf) + v->ops->nvlinearsumvectorarray = MVAPPEND(N_VLinearSumVectorArray); + else + v->ops->nvlinearsumvectorarray = NULL; + + /* return success */ + return(0); +} + +int MVAPPEND(N_VEnableScaleVectorArray)(N_Vector v, booleantype tf) +{ + /* check that vector is non-NULL */ + if (v == NULL) return(-1); + + /* check that ops structure is non-NULL */ + if (v->ops == NULL) return(-1); + + /* enable/disable operation */ + if (tf) + v->ops->nvscalevectorarray = MVAPPEND(N_VScaleVectorArray); + else + v->ops->nvscalevectorarray = NULL; + + /* return success */ + return(0); +} + +int MVAPPEND(N_VEnableConstVectorArray)(N_Vector v, booleantype tf) +{ + /* check that vector is non-NULL */ + if (v == NULL) return(-1); + + /* check that ops structure is non-NULL */ + if (v->ops == NULL) return(-1); + + /* enable/disable operation */ + if (tf) + v->ops->nvconstvectorarray = MVAPPEND(N_VConstVectorArray); + else + v->ops->nvconstvectorarray = NULL; + + /* return success */ + return(0); +} + +int MVAPPEND(N_VEnableWrmsNormVectorArray)(N_Vector v, booleantype tf) +{ + /* check that vector is non-NULL */ + if (v == NULL) return(-1); + + /* check that ops structure is non-NULL */ + if (v->ops == NULL) return(-1); + + /* enable/disable operation */ + if (tf) + v->ops->nvwrmsnormvectorarray = MVAPPEND(N_VWrmsNormVectorArray); + else + v->ops->nvwrmsnormvectorarray = NULL; + + /* return success */ + return(0); +} + +int MVAPPEND(N_VEnableWrmsNormMaskVectorArray)(N_Vector v, booleantype tf) +{ + /* check that vector is non-NULL */ + if (v == NULL) return(-1); + + /* check that ops structure is non-NULL */ + if (v->ops == NULL) return(-1); + + /* enable/disable operation */ + if (tf) + v->ops->nvwrmsnormmaskvectorarray = MVAPPEND(N_VWrmsNormMaskVectorArray); + else + v->ops->nvwrmsnormmaskvectorarray = NULL; + + /* return success */ + return(0); +} + + +/* ----------------------------------------------------------------- + Implementation of utility routines + -----------------------------------------------------------------*/ + +/* This function performs a generic clone operation on an input N_Vector. + Based on the 'cloneempty' flag it will either call "nvclone" or + "nvcloneempty" when creating subvectors in the cloned vector. */ +static N_Vector ManyVectorClone(N_Vector w, booleantype cloneempty) +{ + N_Vector v; + MVAPPEND(N_VectorContent) content; + sunindextype i; + + if (w == NULL) return(NULL); + + /* Create vector */ + v = NULL; + v = N_VNewEmpty(); + if (v == NULL) return(NULL); + + /* Attach operations */ + if (N_VCopyOps(w, v)) { N_VDestroy(v); return(NULL); } + + /* Create content */ + content = NULL; + content = (MVAPPEND(N_VectorContent)) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } + + /* Attach content and ops to new vector, and return */ + v->content = content; + + /* Attach content components */ + + /* Set scalar components */ +#if SUNDIALS_MPI_ENABLED + content->comm = MPI_COMM_NULL; +#endif + content->num_subvectors = MANYVECTOR_NUM_SUBVECS(w); + content->global_length = MANYVECTOR_GLOBLENGTH(w); + content->own_data = SUNTRUE; + + /* Allocate the subvector array */ + content->subvec_array = NULL; + content->subvec_array = (N_Vector *) malloc(content->num_subvectors * sizeof(N_Vector)); + if (content->subvec_array == NULL) { N_VDestroy(v); return(NULL); } + + /* Initialize the subvector array to NULL */ + for (i=0; inum_subvectors; i++) + content->subvec_array[i] = NULL; + + /* Duplicate the input communicator (if applicable) */ +#if SUNDIALS_MPI_ENABLED + if (MANYVECTOR_COMM(w) != MPI_COMM_NULL) { + if (MPI_Comm_dup(MANYVECTOR_COMM(w), &(content->comm)) != MPI_SUCCESS) + { N_VDestroy(v); return(NULL); } + } +#endif + + /* Clone vectors into the subvector array */ + for (i=0; inum_subvectors; i++) { + if (cloneempty) { + content->subvec_array[i] = N_VCloneEmpty(MANYVECTOR_SUBVEC(w,i)); + } else { + content->subvec_array[i] = N_VClone(MANYVECTOR_SUBVEC(w,i)); + } + if (content->subvec_array[i] == NULL) { + N_VDestroy(v); + return(NULL); + } + } + + return(v); +} + + +#if SUNDIALS_MPI_ENABLED +/* This function returns the rank of this task in the MPI communicator + associated with the input N_Vector. If the input N_Vector is MPI-unaware, it + returns 0. If an error occurs in the call to MPI_Comm_Rank, it returns -1. */ +static int SubvectorMPIRank(N_Vector x) +{ + void* tmpcomm; + MPI_Comm *comm; + int rank, retval; + tmpcomm = N_VGetCommunicator(x); + if (tmpcomm == NULL) return(0); + comm = (MPI_Comm *) tmpcomm; + if ((*comm) == MPI_COMM_NULL) return(0); + retval = MPI_Comm_rank(*comm, &rank); + if (retval != MPI_SUCCESS) return(-1); + return(rank); +} +#endif diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/CMakeLists.txt new file mode 100644 index 000000000..4562e6216 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/CMakeLists.txt @@ -0,0 +1,97 @@ +# --------------------------------------------------------------- +# Programmer(s): Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the MPIPlusX NVECTOR library +# --------------------------------------------------------------- + +install(CODE "MESSAGE(\"\nInstall NVECTOR_MPIPLUSX\n\")") + +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) + +if(MPI_C_FOUND AND MPI_C_COMPILER) + # use MPI wrapper as the compiler + set(CMAKE_C_COMPILER ${MPI_C_COMPILER}) +elseif(MPI_C_FOUND) + # add MPI_INCLUDE_PATH to include directories + include_directories(${MPI_INCLUDE_PATH}) +endif() + +# Add variable nvecmpiplusx_SOURCES with the sources for the NVECMPIPLUSX lib +set(nvecmpiplusx_SOURCES + nvector_mpiplusx.c + ${sundials_SOURCE_DIR}/src/nvector/manyvector/nvector_manyvector.c + ) + +# Add variable shared_SOURCES with the common SUNDIALS sources which will +# also be included in the NVECMPIPLUSX library +set(shared_SOURCES + ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c + ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c + ) + +# Add variable nvecmpiplusx_HEADERS with the exported NVECMPIPLUSX header files +set(nvecmpiplusx_HEADERS ${sundials_SOURCE_DIR}/include/nvector/nvector_manyvector.h) +if(MPI_ENABLE AND MPI_C_FOUND) + list(APPEND nvecmpiplusx_HEADERS + ${sundials_SOURCE_DIR}/include/nvector/nvector_mpimanyvector.h + ${sundials_SOURCE_DIR}/include/nvector/nvector_mpiplusx.h) +endif() + +# Add source directory to include directories +include_directories(.) + +# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY +add_definitions(-DBUILD_SUNDIALS_LIBRARY) + +# Rules for building and installing the static library: +# - Add the build target for the NVECMPIPLUSX library +# - Set the library name and make sure it is not deleted +# - Install the NVECMPIPLUSX library +if(BUILD_STATIC_LIBS) + add_library(sundials_nvecmpiplusx_static STATIC ${nvecmpiplusx_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_nvecmpiplusx_static PROPERTIES + OUTPUT_NAME sundials_nvecmpiplusx + CLEAN_DIRECT_OUTPUT 1) + + install(TARGETS sundials_nvecmpiplusx_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_STATIC_LIBS) + +# Rules for building and installing the shared library: +# - Add the build target for the NVECMPIPLUSX library +# - Set the library name and make sure it is not deleted +# - Set VERSION and SOVERSION for shared libraries +# - Install the NVECMPIPLUSX library +if(BUILD_SHARED_LIBS) + add_library(sundials_nvecmpiplusx_shared SHARED ${nvecmpiplusx_SOURCES} ${shared_SOURCES}) + + if(UNIX) + target_link_libraries(sundials_nvecmpiplusx_shared m) + endif() + + set_target_properties(sundials_nvecmpiplusx_shared PROPERTIES + OUTPUT_NAME sundials_nvecmpiplusx + VERSION ${nveclib_VERSION} + SOVERSION ${nveclib_SOVERSION} + CLEAN_DIRECT_OUTPUT 1) + + install(TARGETS sundials_nvecmpiplusx_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_SHARED_LIBS) + +# Install the NVECMPIPLUSX header files +install(FILES ${nvecmpiplusx_HEADERS} DESTINATION include/nvector) + +message(STATUS "Added NVECTOR_MPIPLUSX module") diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/fmod/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/fmod/CMakeLists.txt new file mode 100644 index 000000000..f0f30125e --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/fmod/CMakeLists.txt @@ -0,0 +1,57 @@ +# --------------------------------------------------------------- +# Programmer(s): Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the F2003 MPIPlusX NVECTOR object library +# --------------------------------------------------------------- + +set(nvecmpiplusx_SOURCES fnvector_mpiplusx_mod.f90 fnvector_mpiplusx_mod.c) + +if(MPI_ENABLE AND MPI_C_FOUND) + if(MPI_C_COMPILER) + # use MPI wrapper as the compiler + set(CMAKE_C_COMPILER ${MPI_C_COMPILER}) + elseif() + # add MPI_INCLUDE_PATH to include directories + include_directories(${MPI_INCLUDE_PATH}) + endif() + if(MPI_Fortran_COMPILER) + # use MPI wrapper as the compiler + set(CMAKE_Fortran_COMPILER ${MPI_Fortran_COMPILER}) + endif() +endif() + +if(BUILD_STATIC_LIBS) + if(MPI_ENABLE AND MPI_C_FOUND) + sundials_add_f2003_interface_library(sundials_fnvecmpiplusx_mod_static STATIC_OBJECT + ${nvecmpiplusx_SOURCES}) + add_dependencies(sundials_fnvecmpiplusx_mod_static_obj sundials_fgeneric_static_obj) + set_target_properties(sundials_fnvecmpiplusx_mod_static PROPERTIES + OUTPUT_NAME sundials_fnvecmpiplusx_mod + CLEAN_DIRECT_OUTPUT 1) + install(TARGETS sundials_fnvecmpiplusx_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() +endif(BUILD_STATIC_LIBS) + +if(BUILD_SHARED_LIBS) + if(MPI_ENABLE AND MPI_C_FOUND) + sundials_add_f2003_interface_library(sundials_fnvecmpiplusx_mod_shared SHARED_OBJECT + ${nvecmpiplusx_SOURCES}) + add_dependencies(sundials_fnvecmpiplusx_mod_shared_obj sundials_fgeneric_shared_obj) + set_target_properties(sundials_fnvecmpiplusx_mod_shared PROPERTIES + OUTPUT_NAME sundials_fnvecmpiplusx_mod + CLEAN_DIRECT_OUTPUT 1) + install(TARGETS sundials_fnvecmpiplusx_mod_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() +endif(BUILD_SHARED_LIBS) + +message(STATUS "Added NVECTOR_MPIPLUSX F2003 interface") diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/fmod/fnvector_mpiplusx_mod.c b/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/fmod/fnvector_mpiplusx_mod.c new file mode 100644 index 000000000..98e270214 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/fmod/fnvector_mpiplusx_mod.c @@ -0,0 +1,287 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_nvector.h" + + +#include "nvector/nvector_mpiplusx.h" + +SWIGEXPORT N_Vector _wrap_FN_VMake_MPIPlusX(int const *farg1, N_Vector farg2) { + N_Vector fresult ; + MPI_Comm arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector result; + +#ifdef SUNDIALS_MPI_ENABLED + arg1 = MPI_Comm_f2c((MPI_Fint)(*farg1)); +#else + arg1 = *farg1; +#endif + arg2 = (N_Vector)(farg2); + result = (N_Vector)N_VMake_MPIPlusX(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VGetVectorID_MPIPlusX(N_Vector farg1) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector_ID result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector_ID)N_VGetVectorID_MPIPlusX(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double * _wrap_FN_VGetArrayPointer_MPIPlusX(N_Vector farg1) { + double * fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype *result = 0 ; + + arg1 = (N_Vector)(farg1); + result = (realtype *)N_VGetArrayPointer_MPIPlusX(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VSetArrayPointer_MPIPlusX(double *farg1, N_Vector farg2) { + realtype *arg1 = (realtype *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype *)(farg1); + arg2 = (N_Vector)(farg2); + N_VSetArrayPointer_MPIPlusX(arg1,arg2); +} + + +SWIGEXPORT N_Vector _wrap_FN_VGetLocalVector_MPIPlusX(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VGetLocalVector_MPIPlusX(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FN_VGetLocalLength_MPIPlusX(N_Vector farg1) { + int64_t fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype result; + + arg1 = (N_Vector)(farg1); + result = N_VGetLocalLength_MPIPlusX(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/fmod/fnvector_mpiplusx_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/fmod/fnvector_mpiplusx_mod.f90 new file mode 100644 index 000000000..d81d933c1 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/fmod/fnvector_mpiplusx_mod.f90 @@ -0,0 +1,172 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fnvector_mpiplusx_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FN_VMake_MPIPlusX + public :: FN_VGetVectorID_MPIPlusX + public :: FN_VGetArrayPointer_MPIPlusX + public :: FN_VSetArrayPointer_MPIPlusX + public :: FN_VGetLocalVector_MPIPlusX + public :: FN_VGetLocalLength_MPIPlusX + +! WRAPPER DECLARATIONS +interface +function swigc_FN_VMake_MPIPlusX(farg1, farg2) & +bind(C, name="_wrap_FN_VMake_MPIPlusX") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VGetVectorID_MPIPlusX(farg1) & +bind(C, name="_wrap_FN_VGetVectorID_MPIPlusX") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FN_VGetArrayPointer_MPIPlusX(farg1) & +bind(C, name="_wrap_FN_VGetArrayPointer_MPIPlusX") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VSetArrayPointer_MPIPlusX(farg1, farg2) & +bind(C, name="_wrap_FN_VSetArrayPointer_MPIPlusX") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_FN_VGetLocalVector_MPIPlusX(farg1) & +bind(C, name="_wrap_FN_VGetLocalVector_MPIPlusX") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VGetLocalLength_MPIPlusX(farg1) & +bind(C, name="_wrap_FN_VGetLocalLength_MPIPlusX") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FN_VMake_MPIPlusX(comm, x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer :: comm +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 + +farg1 = int(comm, C_INT) +farg2 = c_loc(x) +fresult = swigc_FN_VMake_MPIPlusX(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VGetVectorID_MPIPlusX(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(N_Vector_ID) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetVectorID_MPIPlusX(farg1) +swig_result = fresult +end function + +function FN_VGetArrayPointer_MPIPlusX(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetArrayPointer_MPIPlusX(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +subroutine FN_VSetArrayPointer_MPIPlusX(vdata, v) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(*), target, intent(inout) :: vdata +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(vdata(1)) +farg2 = c_loc(v) +call swigc_FN_VSetArrayPointer_MPIPlusX(farg1, farg2) +end subroutine + +function FN_VGetLocalVector_MPIPlusX(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetLocalVector_MPIPlusX(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VGetLocalLength_MPIPlusX(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetLocalLength_MPIPlusX(farg1) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/nvector_mpiplusx.c b/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/nvector_mpiplusx.c new file mode 100644 index 000000000..9fc087468 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/mpiplusx/nvector_mpiplusx.c @@ -0,0 +1,66 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Cody J. Balos @ LLNL + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------- + * This is the implementation file for the MPIPlusX NVECTOR. + * -----------------------------------------------------------------*/ + +#include +#include +#include +#include +#include + +#define MPIPLUSX_LOCAL_VECTOR(v) ( N_VGetSubvector_MPIManyVector(v, 0) ) + +N_Vector N_VMake_MPIPlusX(MPI_Comm comm, N_Vector X) +{ + N_Vector v; + + if (X == NULL) return NULL; + + v = NULL; + v = N_VMake_MPIManyVector(comm, 1, &X); + if (v == NULL) return NULL; + + /* override certain ops */ + v->ops->nvgetvectorid = N_VGetVectorID_MPIPlusX; + v->ops->nvgetarraypointer = N_VGetArrayPointer_MPIPlusX; + v->ops->nvsetarraypointer = N_VSetArrayPointer_MPIPlusX; + + return v; +} + +N_Vector_ID N_VGetVectorID_MPIPlusX(N_Vector v) +{ + return SUNDIALS_NVEC_MPIPLUSX; +} + +realtype* N_VGetArrayPointer_MPIPlusX(N_Vector v) +{ + return N_VGetSubvectorArrayPointer_MPIManyVector(v, 0); +} + +void N_VSetArrayPointer_MPIPlusX(realtype *vdata, N_Vector v) +{ + N_VSetSubvectorArrayPointer_MPIManyVector(vdata, v, 0); +} + +N_Vector N_VGetLocalVector_MPIPlusX(N_Vector v) +{ + return MPIPLUSX_LOCAL_VECTOR(v); +} + +sunindextype N_VGetLocalLength_MPIPlusX(N_Vector v) +{ + return N_VGetLength(MPIPLUSX_LOCAL_VECTOR(v)); +} diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/CMakeLists.txt index b98e84041..81ebd2721 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Steve Smith, and Cody J. Balos @ LLNL +# Programmer(s): Steve Smith and Cody J. Balos @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,98 +12,100 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the openmp NVECTOR library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall NVECTOR_OPENMP\n\")") +install(CODE "MESSAGE(\"\nInstall NVECTOR_OPENMP\n\")") # Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF(F90_FOUND AND F2003_INTERFACE_ENABLE) +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) # Add variable nvecopenmp_SOURCES with the sources for the NVECOPENMP lib -SET(nvecopenmp_SOURCES nvector_openmp.c) +set(nvecopenmp_SOURCES nvector_openmp.c) # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the NVECOPENMP library -SET(shared_SOURCES +set(shared_SOURCES + ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c ) # Add variable nvecopenmp_HEADERS with the exported NVECOPENMP header files -SET(nvecopenmp_HEADERS +set(nvecopenmp_HEADERS ${sundials_SOURCE_DIR}/include/nvector/nvector_openmp.h ) # Add source directory to include directories -INCLUDE_DIRECTORIES(.) +include_directories(.) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") # Use C flags for linker as well. -SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_C_FLAGS}") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_C_FLAGS}") # Rules for building and installing the static library: # - Add the build target for the NVECOPENMP library # - Set the library name and make sure it is not deleted # - Install the NVECOPENMP library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_nvecopenmp_static STATIC ${nvecopenmp_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_nvecopenmp_static +if(BUILD_STATIC_LIBS) + add_library(sundials_nvecopenmp_static STATIC ${nvecopenmp_SOURCES} ${shared_SOURCES}) + set_target_properties(sundials_nvecopenmp_static PROPERTIES OUTPUT_NAME sundials_nvecopenmp CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_nvecopenmp_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) + install(TARGETS sundials_nvecopenmp_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: # - Add the build target for the NVECOPENMP library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries # - Install the NVECOPENMP library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_nvecopenmp_shared SHARED ${nvecopenmp_SOURCES} ${shared_SOURCES}) +if(BUILD_SHARED_LIBS) + add_library(sundials_nvecopenmp_shared SHARED ${nvecopenmp_SOURCES} ${shared_SOURCES}) - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_nvecopenmp_shared m) - ENDIF() + if(UNIX) + target_link_libraries(sundials_nvecopenmp_shared m) + endif() - SET_TARGET_PROPERTIES(sundials_nvecopenmp_shared + set_target_properties(sundials_nvecopenmp_shared PROPERTIES OUTPUT_NAME sundials_nvecopenmp CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_nvecopenmp_shared + set_target_properties(sundials_nvecopenmp_shared PROPERTIES VERSION ${nveclib_VERSION} SOVERSION ${nveclib_SOVERSION}) - INSTALL(TARGETS sundials_nvecopenmp_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) + install(TARGETS sundials_nvecopenmp_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_SHARED_LIBS) # Install the NVECOPENMP header files -INSTALL(FILES ${nvecopenmp_HEADERS} DESTINATION include/nvector) +install(FILES ${nvecopenmp_HEADERS} DESTINATION include/nvector) # If FCMIX is enabled, build and install the FNVECOPENMP library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fnvecopenmp_SOURCES fnvector_openmp.c) +if(F77_INTERFACE_ENABLE AND F77_FOUND) + set(fnvecopenmp_SOURCES fnvector_openmp.c) - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fnvecopenmp_static STATIC ${fnvecopenmp_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fnvecopenmp_static + if(BUILD_STATIC_LIBS) + add_library(sundials_fnvecopenmp_static STATIC ${fnvecopenmp_SOURCES}) + set_target_properties(sundials_fnvecopenmp_static PROPERTIES OUTPUT_NAME sundials_fnvecopenmp CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fnvecopenmp_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) + install(TARGETS sundials_fnvecopenmp_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fnvecopenmp_shared ${fnvecopenmp_SOURCES}) + if(BUILD_SHARED_LIBS) + add_library(sundials_fnvecopenmp_shared ${fnvecopenmp_SOURCES}) # fnvecopenmp depends on nvecopenmp - TARGET_LINK_LIBRARIES(sundials_fnvecopenmp_shared sundials_nvecopenmp_shared) + target_link_libraries(sundials_fnvecopenmp_shared sundials_nvecopenmp_shared) - SET_TARGET_PROPERTIES(sundials_fnvecopenmp_shared + set_target_properties(sundials_fnvecopenmp_shared PROPERTIES OUTPUT_NAME sundials_fnvecopenmp CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fnvecopenmp_shared + set_target_properties(sundials_fnvecopenmp_shared PROPERTIES VERSION ${nveclib_VERSION} SOVERSION ${nveclib_SOVERSION}) - INSTALL(TARGETS sundials_fnvecopenmp_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + install(TARGETS sundials_fnvecopenmp_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(F77_INTERFACE_ENABLE AND F77_FOUND) # -MESSAGE(STATUS "Added NVECTOR_OPENMP module") +message(STATUS "Added NVECTOR_OPENMP module") diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/F90/fnvector_openmp.f90 b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/F90/fnvector_openmp.f90 deleted file mode 100644 index 87d2b3031..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/F90/fnvector_openmp.f90 +++ /dev/null @@ -1,480 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): Cody J. Balos @ LLNL -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS OpenMP NVector using the ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fnvector_openmp_mod - - !======= Interfaces ========= - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - ! ----------------------------------------------------------------- - ! N_VNew_OpenMP - ! ----------------------------------------------------------------- - - type(c_ptr) function FN_VNew_OpenMP(vec_length, num_threads) & - bind(C,name='N_VNew_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - integer(c_long), value :: vec_length - integer(c_int), value :: num_threads - end function FN_VNew_OpenMP - - ! ----------------------------------------------------------------- - ! N_VNewEmpty_OpenMP - ! ----------------------------------------------------------------- - - type(c_ptr) function FN_VNewEmpty_OpenMP(vec_length, num_threads) & - bind(C,name='N_VNewEmpty_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - integer(c_long), value :: vec_length - integer(c_int), value :: num_threads - end function FN_VNewEmpty_OpenMP - - ! ----------------------------------------------------------------- - ! N_VMake_OpenMP - ! ----------------------------------------------------------------- - - type(c_ptr) function FN_VMake_OpenMP(length, v_data, num_threads) & - bind(C,name='N_VMake_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - integer(c_long), value :: length - real(c_double) :: v_data(length) - integer(c_int), value :: num_threads - end function FN_VMake_OpenMP - - ! ----------------------------------------------------------------- - ! N_VCloneVectorArray_OpenMP: NOT INTERFACED - ! ----------------------------------------------------------------- - - ! ----------------------------------------------------------------- - ! N_VCloneVectorArrayEmpty_OpenMP: NOT INTERFACED - ! ----------------------------------------------------------------- - - ! ================================================================= - ! Destructors - ! ================================================================= - - ! ----------------------------------------------------------------- - ! N_VDestroy_OpenMP - ! ----------------------------------------------------------------- - - subroutine FN_VDestroy_OpenMP(v) & - bind(C,name='N_VDestroy_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: v - end subroutine FN_VDestroy_OpenMP - - ! ----------------------------------------------------------------- - ! N_VDestroyVectorArray_OpenMP: NOT INTERFACED - ! ----------------------------------------------------------------- - - ! ================================================================= - ! Other routines - ! ================================================================= - - ! ----------------------------------------------------------------- - ! N_VGetLength_OpenMP - ! ----------------------------------------------------------------- - - integer(c_long) function FN_VGetLength_OpenMP(v) & - bind(C,name='N_VGetLength_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: v - end function FN_VGetLength_OpenMP - - ! ----------------------------------------------------------------- - ! N_VPrint_OpenMP - ! ----------------------------------------------------------------- - - subroutine FN_VPrint_OpenMP(v) & - bind(C,name='N_VPrint_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: v - end subroutine FN_VPrint_OpenMP - - ! ----------------------------------------------------------------- - ! NOT INTERFACED: N_VPrintFile_OpenMP - ! ----------------------------------------------------------------- - - ! ================================================================= - ! Operations - ! ================================================================= - - ! ----------------------------------------------------------------- - ! N_VGetVectorID_OpenMP - ! ----------------------------------------------------------------- - - integer(c_int) function FN_VGetVectorID_OpenMP(v) & - bind(C,name='N_VGetVectorID_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: v - end function FN_VGetVectorID_OpenMP - - ! ----------------------------------------------------------------- - ! N_VCloneEmpty_OpenMP - ! ----------------------------------------------------------------- - - type(c_ptr) function FN_VCloneEmpty_OpenMP(w) & - bind(C,name='N_VCloneEmpty_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: w - end function FN_VCloneEmpty_OpenMP - - ! ----------------------------------------------------------------- - ! N_VClone_OpenMP - ! ----------------------------------------------------------------- - - type(c_ptr) function FN_VClone_OpenMP(w) & - bind(C,name='N_VClone_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: w - end function FN_VClone_OpenMP - - ! ----------------------------------------------------------------- - ! N_VSpace_OpenMP - ! ----------------------------------------------------------------- - - subroutine FN_VSpace_OpenMP(v, lrw, liw) & - bind(C,name='N_VSpace_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: v - integer(c_long) :: lrw - integer(c_long) :: liw - end subroutine FN_VSpace_OpenMP - - ! ----------------------------------------------------------------- - ! N_VGetArrayPointer_OpenMP - ! ----------------------------------------------------------------- - - type(c_ptr) function FN_VGetArrayPointer_OpenMP(vec) & - bind(C,name='N_VGetArrayPointer_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: vec - end function FN_VGetArrayPointer_OpenMP - - ! ----------------------------------------------------------------- - ! N_VSetArrayPointer_OpenMP - ! ----------------------------------------------------------------- - - subroutine FN_VSetArrayPointer_OpenMP(v_data, v) & - bind(C,name='N_VSetArrayPointer_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: v_data - type(c_ptr), value :: v - end subroutine FN_VSetArrayPointer_OpenMP - - ! ----------------------------------------------------------------- - ! N_VLinearSum_OpenMP - ! ----------------------------------------------------------------- - - subroutine FN_VLinearSum_OpenMP(a, x, b, y, z) & - bind(C,name='N_VLinearSum_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - real(c_double), value :: a - type(c_ptr), value :: x - real(c_double), value :: b - type(c_ptr), value :: y - type(c_ptr), value :: z - end subroutine FN_VLinearSum_OpenMP - - ! ----------------------------------------------------------------- - ! N_VConst_OpenMP - ! ----------------------------------------------------------------- - - subroutine FN_VConst_OpenMP(c, z) & - bind(C,name='N_VConst_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - real(c_double), value :: c - type(c_ptr), value :: z - end subroutine FN_VConst_OpenMP - - ! ----------------------------------------------------------------- - ! N_VProd_OpenMP - ! ----------------------------------------------------------------- - - subroutine FN_VProd_OpenMP(x, y, z) & - bind(C,name='N_VProd_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: y - type(c_ptr), value :: z - end subroutine FN_VProd_OpenMP - - ! ----------------------------------------------------------------- - ! N_VDiv_OpenMP - ! ----------------------------------------------------------------- - - subroutine FN_VDiv_OpenMP(x, y, z) & - bind(C,name='N_VDiv_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: y - type(c_ptr), value :: z - end subroutine FN_VDiv_OpenMP - - ! ----------------------------------------------------------------- - ! N_VScale_OpenMP - ! ----------------------------------------------------------------- - - subroutine FN_VScale_OpenMP(c, x, z) & - bind(C,name='N_VScale_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - real(c_double), value :: c - type(c_ptr), value :: x - type(c_ptr), value :: z - end subroutine FN_VScale_OpenMP - - ! ----------------------------------------------------------------- - ! N_VAbs_OpenMP - ! ----------------------------------------------------------------- - - subroutine FN_VAbs_OpenMP(x, z) & - bind(C,name='N_VAbs_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: z - end subroutine FN_VAbs_OpenMP - - ! ----------------------------------------------------------------- - ! N_VInv_OpenMP - ! ----------------------------------------------------------------- - - subroutine FN_VInv_OpenMP(x, z) & - bind(C,name='N_VInv_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: z - end subroutine FN_VInv_OpenMP - - ! ----------------------------------------------------------------- - ! N_VAddConst - ! ----------------------------------------------------------------- - - subroutine FN_VAddConst_OpenMP(x, b, z) & - bind(C,name='N_VAddConst_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - real(c_double), value :: b - type(c_ptr), value :: z - end subroutine FN_VAddConst_OpenMP - - ! ----------------------------------------------------------------- - ! N_VDotProd_OpenMP - ! ----------------------------------------------------------------- - - real(c_double) function FN_VDotProd_OpenMP(x, y) & - bind(C,name='N_VDotProd_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: y - end function FN_VDotProd_OpenMP - - ! ----------------------------------------------------------------- - ! N_VMaxNorm_OpenMP - ! ----------------------------------------------------------------- - - real(c_double) function FN_VMaxNorm_OpenMP(x) & - bind(C,name='N_VMaxNorm_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - end function FN_VMaxNorm_OpenMP - - ! ----------------------------------------------------------------- - ! N_VWrmsNorm_OpenMP - ! ----------------------------------------------------------------- - - real(c_double) function FN_VWrmsNorm_OpenMP(x, w) & - bind(C,name='N_VWrmsNorm_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: w - end function FN_VWrmsNorm_OpenMP - - ! ----------------------------------------------------------------- - ! N_VWrmsNormMask_OpenMP - ! ----------------------------------------------------------------- - - real(c_double) function FN_VWrmsNormMask_OpenMP(x, w, id) & - bind(C,name='N_VWrmsNormMask_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: w - type(c_ptr), value :: id - end function FN_VWrmsNormMask_OpenMP - - ! ----------------------------------------------------------------- - ! N_VMin_OpenMP - ! ----------------------------------------------------------------- - - real(c_double) function FN_VMin_OpenMP(x) & - bind(C,name='N_VMin_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - end function FN_VMin_OpenMP - - ! ----------------------------------------------------------------- - ! N_VWL2Norm_OpenMP - ! ----------------------------------------------------------------- - - real(c_double) function FN_VWL2Norm_OpenMP(x, w) & - bind(C,name='N_VWL2Norm_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: w - end function FN_VWL2Norm_OpenMP - - ! ----------------------------------------------------------------- - ! N_VL1Norm_OpenMP - ! ----------------------------------------------------------------- - - real(c_double) function FN_VL1Norm_OpenMP(x) & - bind(C,name='N_VL1Norm_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - end function FN_VL1Norm_OpenMP - - ! ----------------------------------------------------------------- - ! N_VCompare_OpenMP - ! ----------------------------------------------------------------- - - subroutine FN_VCompare_OpenMP(c, x, z) & - bind(C,name='N_VCompare_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - real(c_double), value :: c - type(c_ptr), value :: x - type(c_ptr), value :: z - end subroutine FN_VCompare_OpenMP - - ! ----------------------------------------------------------------- - ! N_VInvTest_OpenMP - ! ----------------------------------------------------------------- - - integer(c_int) function FN_VInvTest_OpenMP(x, z) & - bind(C,name='N_VInvTest_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: z - end function FN_VInvTest_OpenMP - - ! ----------------------------------------------------------------- - ! N_VConstrMask_OpenMP - ! ----------------------------------------------------------------- - - integer(c_int) function FN_VConstrMask_OpenMP(c, x, m) & - bind(C,name='N_VConstrMask_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: c - type(c_ptr), value :: x - type(c_ptr), value :: m - end function FN_VConstrMask_OpenMP - - ! ----------------------------------------------------------------- - ! N_VMinQuotient_OpenMP - ! ----------------------------------------------------------------- - - real(c_double) function FN_VMinQuotient_OpenMP(num, denom) & - bind(C,name='N_VMinQuotient_OpenMP') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: num - type(c_ptr), value :: denom - end function FN_VMinQuotient_OpenMP - - ! ================================================================ - ! Fused vector operations: NOT INTERFACED - ! ================================================================ - - ! ================================================================ - ! Vector array operations: NOT INTERFACED - ! ================================================================ - - end interface - -contains - - ! ================================================================ - ! Helpful routines - ! ================================================================ - - ! ---------------------------------------------------------------- - ! FN_VGetData_OpenMP - ! - ! Extracts data array from a OpenMP SUNDIALS N_Vector - ! ---------------------------------------------------------------- - - subroutine FN_VGetData_OpenMP(vec, f_array) - - !======= Inclusions =========== - use, intrinsic :: iso_c_binding - - !======= Declarations ========= - implicit none - - ! calling variables - type(c_ptr) :: vec - integer(c_long) :: length - real(c_double), pointer :: f_array(:) - - ! C pointer for N_Vector interal data array - type(c_ptr) :: c_array - - !======= Internals ============ - - ! get data pointer from N_Vector - c_array = FN_VGetArrayPointer_OpenMP(vec) - - ! get vector length - length = FN_VGetLength_OpenMP(vec) - - ! convert c pointer to f pointer - call c_f_pointer(c_array, f_array, (/length/)) - - end subroutine FN_VGetData_OpenMP - -end module fnvector_openmp_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fmod/CMakeLists.txt similarity index 75% rename from deps/AMICI/ThirdParty/sundials/src/nvector/openmp/F90/CMakeLists.txt rename to deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fmod/CMakeLists.txt index 1b27dc60a..25dddc902 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/F90/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fmod/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Cody J. Balos @ LLNL +# Programmer(s): Cody J. Balos @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,22 +12,25 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the F2003 openmp NVECTOR object library +# --------------------------------------------------------------- -set(nvecopenmp_SOURCES fnvector_openmp.f90) +set(nvecopenmp_SOURCES fnvector_openmp_mod.f90 fnvector_openmp_mod.c) if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fnvecopenmp_mod_static STATIC + sundials_add_f2003_interface_library(sundials_fnvecopenmp_mod_static STATIC_OBJECT ${nvecopenmp_SOURCES} ) + add_dependencies(sundials_fnvecopenmp_mod_static_obj sundials_fgeneric_static_obj) set_target_properties(sundials_fnvecopenmp_mod_static PROPERTIES OUTPUT_NAME sundials_fnvecopenmp_mod CLEAN_DIRECT_OUTPUT 1) install(TARGETS sundials_fnvecopenmp_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif(BUILD_STATIC_LIBS) if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fnvecopenmp_mod_shared SHARED + sundials_add_f2003_interface_library(sundials_fnvecopenmp_mod_shared SHARED_OBJECT ${nvecopenmp_SOURCES} ) + add_dependencies(sundials_fnvecopenmp_mod_shared_obj sundials_fgeneric_shared_obj) set_target_properties(sundials_fnvecopenmp_mod_shared PROPERTIES OUTPUT_NAME sundials_fnvecopenmp_mod CLEAN_DIRECT_OUTPUT 1) set_target_properties(sundials_fnvecopenmp_mod_shared diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fmod/fnvector_openmp_mod.c b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fmod/fnvector_openmp_mod.c new file mode 100644 index 000000000..0705e2f8d --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fmod/fnvector_openmp_mod.c @@ -0,0 +1,951 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_nvector.h" + + +#include "nvector/nvector_openmp.h" + +SWIGEXPORT N_Vector _wrap_FN_VNew_OpenMP(int64_t const *farg1, int const *farg2) { + N_Vector fresult ; + sunindextype arg1 ; + int arg2 ; + N_Vector result; + + arg1 = (sunindextype)(*farg1); + arg2 = (int)(*farg2); + result = (N_Vector)N_VNew_OpenMP(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VNewEmpty_OpenMP(int64_t const *farg1, int const *farg2) { + N_Vector fresult ; + sunindextype arg1 ; + int arg2 ; + N_Vector result; + + arg1 = (sunindextype)(*farg1); + arg2 = (int)(*farg2); + result = (N_Vector)N_VNewEmpty_OpenMP(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VMake_OpenMP(int64_t const *farg1, double *farg2, int const *farg3) { + N_Vector fresult ; + sunindextype arg1 ; + realtype *arg2 = (realtype *) 0 ; + int arg3 ; + N_Vector result; + + arg1 = (sunindextype)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (int)(*farg3); + result = (N_Vector)N_VMake_OpenMP(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FN_VCloneVectorArray_OpenMP(int const *farg1, N_Vector farg2) { + void * fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *result = 0 ; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + result = (N_Vector *)N_VCloneVectorArray_OpenMP(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FN_VCloneVectorArrayEmpty_OpenMP(int const *farg1, N_Vector farg2) { + void * fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *result = 0 ; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + result = (N_Vector *)N_VCloneVectorArrayEmpty_OpenMP(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VDestroyVectorArray_OpenMP(void *farg1, int const *farg2) { + N_Vector *arg1 = (N_Vector *) 0 ; + int arg2 ; + + arg1 = (N_Vector *)(farg1); + arg2 = (int)(*farg2); + N_VDestroyVectorArray_OpenMP(arg1,arg2); +} + + +SWIGEXPORT int64_t _wrap_FN_VGetLength_OpenMP(N_Vector farg1) { + int64_t fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype result; + + arg1 = (N_Vector)(farg1); + result = N_VGetLength_OpenMP(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VPrint_OpenMP(N_Vector farg1) { + N_Vector arg1 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + N_VPrint_OpenMP(arg1); +} + + +SWIGEXPORT void _wrap_FN_VPrintFile_OpenMP(N_Vector farg1, void *farg2) { + N_Vector arg1 = (N_Vector) 0 ; + FILE *arg2 = (FILE *) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (FILE *)(farg2); + N_VPrintFile_OpenMP(arg1,arg2); +} + + +SWIGEXPORT int _wrap_FN_VGetVectorID_OpenMP(N_Vector farg1) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector_ID result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector_ID)N_VGetVectorID_OpenMP(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VCloneEmpty_OpenMP(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VCloneEmpty_OpenMP(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VClone_OpenMP(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VClone_OpenMP(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VDestroy_OpenMP(N_Vector farg1) { + N_Vector arg1 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + N_VDestroy_OpenMP(arg1); +} + + +SWIGEXPORT void _wrap_FN_VSpace_OpenMP(N_Vector farg1, int64_t *farg2, int64_t *farg3) { + N_Vector arg1 = (N_Vector) 0 ; + sunindextype *arg2 = (sunindextype *) 0 ; + sunindextype *arg3 = (sunindextype *) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (sunindextype *)(farg2); + arg3 = (sunindextype *)(farg3); + N_VSpace_OpenMP(arg1,arg2,arg3); +} + + +SWIGEXPORT double * _wrap_FN_VGetArrayPointer_OpenMP(N_Vector farg1) { + double * fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype *result = 0 ; + + arg1 = (N_Vector)(farg1); + result = (realtype *)N_VGetArrayPointer_OpenMP(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VSetArrayPointer_OpenMP(double *farg1, N_Vector farg2) { + realtype *arg1 = (realtype *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype *)(farg1); + arg2 = (N_Vector)(farg2); + N_VSetArrayPointer_OpenMP(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VLinearSum_OpenMP(double const *farg1, N_Vector farg2, double const *farg3, N_Vector farg4, N_Vector farg5) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + N_VLinearSum_OpenMP(arg1,arg2,arg3,arg4,arg5); +} + + +SWIGEXPORT void _wrap_FN_VConst_OpenMP(double const *farg1, N_Vector farg2) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + N_VConst_OpenMP(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VProd_OpenMP(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VProd_OpenMP(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VDiv_OpenMP(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VDiv_OpenMP(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VScale_OpenMP(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VScale_OpenMP(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VAbs_OpenMP(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VAbs_OpenMP(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VInv_OpenMP(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VInv_OpenMP(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VAddConst_OpenMP(N_Vector farg1, double const *farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + N_VAddConst_OpenMP(arg1,arg2,arg3); +} + + +SWIGEXPORT double _wrap_FN_VDotProd_OpenMP(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VDotProd_OpenMP(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMaxNorm_OpenMP(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMaxNorm_OpenMP(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNorm_OpenMP(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWrmsNorm_OpenMP(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNormMask_OpenMP(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWrmsNormMask_OpenMP(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMin_OpenMP(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMin_OpenMP(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWL2Norm_OpenMP(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWL2Norm_OpenMP(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VL1Norm_OpenMP(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VL1Norm_OpenMP(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VCompare_OpenMP(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VCompare_OpenMP(arg1,arg2,arg3); +} + + +SWIGEXPORT int _wrap_FN_VInvTest_OpenMP(N_Vector farg1, N_Vector farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)N_VInvTest_OpenMP(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstrMask_OpenMP(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)N_VConstrMask_OpenMP(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinQuotient_OpenMP(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VMinQuotient_OpenMP(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearCombination_OpenMP(int const *farg1, double *farg2, void *farg3, N_Vector farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)N_VLinearCombination_OpenMP(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleAddMulti_OpenMP(int const *farg1, double *farg2, N_Vector farg3, void *farg4, void *farg5) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + N_Vector *arg5 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector *)(farg4); + arg5 = (N_Vector *)(farg5); + result = (int)N_VScaleAddMulti_OpenMP(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VDotProdMulti_OpenMP(int const *farg1, N_Vector farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VDotProdMulti_OpenMP(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearSumVectorArray_OpenMP(int const *farg1, double const *farg2, void *farg3, double const *farg4, void *farg5, void *farg6) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype arg4 ; + N_Vector *arg5 = (N_Vector *) 0 ; + N_Vector *arg6 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype)(*farg4); + arg5 = (N_Vector *)(farg5); + arg6 = (N_Vector *)(farg6); + result = (int)N_VLinearSumVectorArray_OpenMP(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleVectorArray_OpenMP(int const *farg1, double *farg2, void *farg3, void *farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector *)(farg4); + result = (int)N_VScaleVectorArray_OpenMP(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstVectorArray_OpenMP(int const *farg1, double const *farg2, void *farg3) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (int)N_VConstVectorArray_OpenMP(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormVectorArray_OpenMP(int const *farg1, void *farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VWrmsNormVectorArray_OpenMP(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormMaskVectorArray_OpenMP(int const *farg1, void *farg2, void *farg3, N_Vector farg4, double *farg5) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype *arg5 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype *)(farg5); + result = (int)N_VWrmsNormMaskVectorArray_OpenMP(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumLocal_OpenMP(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWSqrSumLocal_OpenMP(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumMaskLocal_OpenMP(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWSqrSumMaskLocal_OpenMP(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableFusedOps_OpenMP(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableFusedOps_OpenMP(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableLinearCombination_OpenMP(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableLinearCombination_OpenMP(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableScaleAddMulti_OpenMP(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableScaleAddMulti_OpenMP(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableDotProdMulti_OpenMP(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableDotProdMulti_OpenMP(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableLinearSumVectorArray_OpenMP(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableLinearSumVectorArray_OpenMP(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableScaleVectorArray_OpenMP(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableScaleVectorArray_OpenMP(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableConstVectorArray_OpenMP(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableConstVectorArray_OpenMP(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableWrmsNormVectorArray_OpenMP(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableWrmsNormVectorArray_OpenMP(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableWrmsNormMaskVectorArray_OpenMP(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableWrmsNormMaskVectorArray_OpenMP(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fmod/fnvector_openmp_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fmod/fnvector_openmp_mod.f90 new file mode 100644 index 000000000..2d5e08bc3 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fmod/fnvector_openmp_mod.f90 @@ -0,0 +1,1440 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fnvector_openmp_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FN_VNew_OpenMP + public :: FN_VNewEmpty_OpenMP + public :: FN_VMake_OpenMP + public :: FN_VCloneVectorArray_OpenMP + public :: FN_VCloneVectorArrayEmpty_OpenMP + public :: FN_VDestroyVectorArray_OpenMP + public :: FN_VGetLength_OpenMP + public :: FN_VPrint_OpenMP + public :: FN_VPrintFile_OpenMP + public :: FN_VGetVectorID_OpenMP + public :: FN_VCloneEmpty_OpenMP + public :: FN_VClone_OpenMP + public :: FN_VDestroy_OpenMP + public :: FN_VSpace_OpenMP + public :: FN_VGetArrayPointer_OpenMP + public :: FN_VSetArrayPointer_OpenMP + public :: FN_VLinearSum_OpenMP + public :: FN_VConst_OpenMP + public :: FN_VProd_OpenMP + public :: FN_VDiv_OpenMP + public :: FN_VScale_OpenMP + public :: FN_VAbs_OpenMP + public :: FN_VInv_OpenMP + public :: FN_VAddConst_OpenMP + public :: FN_VDotProd_OpenMP + public :: FN_VMaxNorm_OpenMP + public :: FN_VWrmsNorm_OpenMP + public :: FN_VWrmsNormMask_OpenMP + public :: FN_VMin_OpenMP + public :: FN_VWL2Norm_OpenMP + public :: FN_VL1Norm_OpenMP + public :: FN_VCompare_OpenMP + public :: FN_VInvTest_OpenMP + public :: FN_VConstrMask_OpenMP + public :: FN_VMinQuotient_OpenMP + public :: FN_VLinearCombination_OpenMP + public :: FN_VScaleAddMulti_OpenMP + public :: FN_VDotProdMulti_OpenMP + public :: FN_VLinearSumVectorArray_OpenMP + public :: FN_VScaleVectorArray_OpenMP + public :: FN_VConstVectorArray_OpenMP + public :: FN_VWrmsNormVectorArray_OpenMP + public :: FN_VWrmsNormMaskVectorArray_OpenMP + public :: FN_VWSqrSumLocal_OpenMP + public :: FN_VWSqrSumMaskLocal_OpenMP + public :: FN_VEnableFusedOps_OpenMP + public :: FN_VEnableLinearCombination_OpenMP + public :: FN_VEnableScaleAddMulti_OpenMP + public :: FN_VEnableDotProdMulti_OpenMP + public :: FN_VEnableLinearSumVectorArray_OpenMP + public :: FN_VEnableScaleVectorArray_OpenMP + public :: FN_VEnableConstVectorArray_OpenMP + public :: FN_VEnableWrmsNormVectorArray_OpenMP + public :: FN_VEnableWrmsNormMaskVectorArray_OpenMP + +! WRAPPER DECLARATIONS +interface +function swigc_FN_VNew_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VNew_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VNewEmpty_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VNewEmpty_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VMake_OpenMP(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VMake_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FN_VCloneVectorArray_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VCloneVectorArray_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VCloneVectorArrayEmpty_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VCloneVectorArrayEmpty_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VDestroyVectorArray_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VDestroyVectorArray_OpenMP") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +end subroutine + +function swigc_FN_VGetLength_OpenMP(farg1) & +bind(C, name="_wrap_FN_VGetLength_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +subroutine swigc_FN_VPrint_OpenMP(farg1) & +bind(C, name="_wrap_FN_VPrint_OpenMP") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FN_VPrintFile_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VPrintFile_OpenMP") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_FN_VGetVectorID_OpenMP(farg1) & +bind(C, name="_wrap_FN_VGetVectorID_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FN_VCloneEmpty_OpenMP(farg1) & +bind(C, name="_wrap_FN_VCloneEmpty_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VClone_OpenMP(farg1) & +bind(C, name="_wrap_FN_VClone_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VDestroy_OpenMP(farg1) & +bind(C, name="_wrap_FN_VDestroy_OpenMP") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FN_VSpace_OpenMP(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VSpace_OpenMP") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VGetArrayPointer_OpenMP(farg1) & +bind(C, name="_wrap_FN_VGetArrayPointer_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VSetArrayPointer_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VSetArrayPointer_OpenMP") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VLinearSum_OpenMP(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VLinearSum_OpenMP") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +end subroutine + +subroutine swigc_FN_VConst_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VConst_OpenMP") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VProd_OpenMP(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VProd_OpenMP") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VDiv_OpenMP(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VDiv_OpenMP") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VScale_OpenMP(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VScale_OpenMP") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VAbs_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VAbs_OpenMP") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VInv_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VInv_OpenMP") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VAddConst_OpenMP(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VAddConst_OpenMP") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VDotProd_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VDotProd_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMaxNorm_OpenMP(farg1) & +bind(C, name="_wrap_FN_VMaxNorm_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNorm_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VWrmsNorm_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNormMask_OpenMP(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWrmsNormMask_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMin_OpenMP(farg1) & +bind(C, name="_wrap_FN_VMin_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWL2Norm_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VWL2Norm_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VL1Norm_OpenMP(farg1) & +bind(C, name="_wrap_FN_VL1Norm_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +subroutine swigc_FN_VCompare_OpenMP(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VCompare_OpenMP") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VInvTest_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VInvTest_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstrMask_OpenMP(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstrMask_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VMinQuotient_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VMinQuotient_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VLinearCombination_OpenMP(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VLinearCombination_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleAddMulti_OpenMP(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VScaleAddMulti_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VDotProdMulti_OpenMP(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VDotProdMulti_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VLinearSumVectorArray_OpenMP(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FN_VLinearSumVectorArray_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleVectorArray_OpenMP(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VScaleVectorArray_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstVectorArray_OpenMP(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstVectorArray_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormVectorArray_OpenMP(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VWrmsNormVectorArray_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormMaskVectorArray_OpenMP(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VWrmsNormMaskVectorArray_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWSqrSumLocal_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VWSqrSumLocal_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWSqrSumMaskLocal_OpenMP(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWSqrSumMaskLocal_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VEnableFusedOps_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableFusedOps_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableLinearCombination_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableLinearCombination_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableScaleAddMulti_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableScaleAddMulti_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableDotProdMulti_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableDotProdMulti_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableLinearSumVectorArray_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableLinearSumVectorArray_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableScaleVectorArray_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableScaleVectorArray_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableConstVectorArray_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableConstVectorArray_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableWrmsNormVectorArray_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableWrmsNormVectorArray_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableWrmsNormMaskVectorArray_OpenMP(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableWrmsNormMaskVectorArray_OpenMP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FN_VNew_OpenMP(vec_length, num_threads) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer(C_INT64_T), intent(in) :: vec_length +integer(C_INT), intent(in) :: num_threads +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +integer(C_INT) :: farg2 + +farg1 = vec_length +farg2 = num_threads +fresult = swigc_FN_VNew_OpenMP(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VNewEmpty_OpenMP(vec_length, num_threads) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer(C_INT64_T), intent(in) :: vec_length +integer(C_INT), intent(in) :: num_threads +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +integer(C_INT) :: farg2 + +farg1 = vec_length +farg2 = num_threads +fresult = swigc_FN_VNewEmpty_OpenMP(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VMake_OpenMP(vec_length, v_data, num_threads) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer(C_INT64_T), intent(in) :: vec_length +real(C_DOUBLE), dimension(*), target, intent(inout) :: v_data +integer(C_INT), intent(in) :: num_threads +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT) :: farg3 + +farg1 = vec_length +farg2 = c_loc(v_data(1)) +farg3 = num_threads +fresult = swigc_FN_VMake_OpenMP(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VCloneVectorArray_OpenMP(count, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: count +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 + +farg1 = count +farg2 = c_loc(w) +fresult = swigc_FN_VCloneVectorArray_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VCloneVectorArrayEmpty_OpenMP(count, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: count +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 + +farg1 = count +farg2 = c_loc(w) +fresult = swigc_FN_VCloneVectorArrayEmpty_OpenMP(farg1, farg2) +swig_result = fresult +end function + +subroutine FN_VDestroyVectorArray_OpenMP(vs, count) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: vs +integer(C_INT), intent(in) :: count +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = vs +farg2 = count +call swigc_FN_VDestroyVectorArray_OpenMP(farg1, farg2) +end subroutine + +function FN_VGetLength_OpenMP(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetLength_OpenMP(farg1) +swig_result = fresult +end function + +subroutine FN_VPrint_OpenMP(v) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +call swigc_FN_VPrint_OpenMP(farg1) +end subroutine + +subroutine FN_VPrintFile_OpenMP(v, outfile) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: outfile +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(v) +farg2 = outfile +call swigc_FN_VPrintFile_OpenMP(farg1, farg2) +end subroutine + +function FN_VGetVectorID_OpenMP(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(N_Vector_ID) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetVectorID_OpenMP(farg1) +swig_result = fresult +end function + +function FN_VCloneEmpty_OpenMP(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VCloneEmpty_OpenMP(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VClone_OpenMP(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VClone_OpenMP(farg1) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FN_VDestroy_OpenMP(v) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +call swigc_FN_VDestroy_OpenMP(farg1) +end subroutine + +subroutine FN_VSpace_OpenMP(v, lrw, liw) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), dimension(*), target, intent(inout) :: lrw +integer(C_INT64_T), dimension(*), target, intent(inout) :: liw +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(v) +farg2 = c_loc(lrw(1)) +farg3 = c_loc(liw(1)) +call swigc_FN_VSpace_OpenMP(farg1, farg2, farg3) +end subroutine + +function FN_VGetArrayPointer_OpenMP(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetArrayPointer_OpenMP(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +subroutine FN_VSetArrayPointer_OpenMP(v_data, v) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(*), target, intent(inout) :: v_data +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(v_data(1)) +farg2 = c_loc(v) +call swigc_FN_VSetArrayPointer_OpenMP(farg1, farg2) +end subroutine + +subroutine FN_VLinearSum_OpenMP(a, x, b, y, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: a +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = a +farg2 = c_loc(x) +farg3 = b +farg4 = c_loc(y) +farg5 = c_loc(z) +call swigc_FN_VLinearSum_OpenMP(farg1, farg2, farg3, farg4, farg5) +end subroutine + +subroutine FN_VConst_OpenMP(c, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c +farg2 = c_loc(z) +call swigc_FN_VConst_OpenMP(farg1, farg2) +end subroutine + +subroutine FN_VProd_OpenMP(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VProd_OpenMP(farg1, farg2, farg3) +end subroutine + +subroutine FN_VDiv_OpenMP(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VDiv_OpenMP(farg1, farg2, farg3) +end subroutine + +subroutine FN_VScale_OpenMP(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VScale_OpenMP(farg1, farg2, farg3) +end subroutine + +subroutine FN_VAbs_OpenMP(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VAbs_OpenMP(farg1, farg2) +end subroutine + +subroutine FN_VInv_OpenMP(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VInv_OpenMP(farg1, farg2) +end subroutine + +subroutine FN_VAddConst_OpenMP(x, b, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = b +farg3 = c_loc(z) +call swigc_FN_VAddConst_OpenMP(farg1, farg2, farg3) +end subroutine + +function FN_VDotProd_OpenMP(x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(y) +fresult = swigc_FN_VDotProd_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VMaxNorm_OpenMP(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMaxNorm_OpenMP(farg1) +swig_result = fresult +end function + +function FN_VWrmsNorm_OpenMP(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWrmsNorm_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VWrmsNormMask_OpenMP(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWrmsNormMask_OpenMP(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMin_OpenMP(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMin_OpenMP(farg1) +swig_result = fresult +end function + +function FN_VWL2Norm_OpenMP(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWL2Norm_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VL1Norm_OpenMP(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VL1Norm_OpenMP(farg1) +swig_result = fresult +end function + +subroutine FN_VCompare_OpenMP(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VCompare_OpenMP(farg1, farg2, farg3) +end subroutine + +function FN_VInvTest_OpenMP(x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +fresult = swigc_FN_VInvTest_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VConstrMask_OpenMP(c, x, m) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: m +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(c) +farg2 = c_loc(x) +farg3 = c_loc(m) +fresult = swigc_FN_VConstrMask_OpenMP(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMinQuotient_OpenMP(num, denom) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: num +type(N_Vector), target, intent(inout) :: denom +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(num) +farg2 = c_loc(denom) +fresult = swigc_FN_VMinQuotient_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VLinearCombination_OpenMP(nvec, c, v, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: v +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = v +farg4 = c_loc(z) +fresult = swigc_FN_VLinearCombination_OpenMP(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VScaleAddMulti_OpenMP(nvec, a, x, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvec +farg2 = c_loc(a(1)) +farg3 = c_loc(x) +farg4 = y +farg5 = z +fresult = swigc_FN_VScaleAddMulti_OpenMP(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VDotProdMulti_OpenMP(nvec, x, y, dotprods) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +real(C_DOUBLE), dimension(*), target, intent(inout) :: dotprods +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(x) +farg3 = y +farg4 = c_loc(dotprods(1)) +fresult = swigc_FN_VDotProdMulti_OpenMP(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VLinearSumVectorArray_OpenMP(nvec, a, x, b, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), intent(in) :: a +type(C_PTR) :: x +real(C_DOUBLE), intent(in) :: b +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = nvec +farg2 = a +farg3 = x +farg4 = b +farg5 = y +farg6 = z +fresult = swigc_FN_VLinearSumVectorArray_OpenMP(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FN_VScaleVectorArray_OpenMP(nvec, c, x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: x +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = x +farg4 = z +fresult = swigc_FN_VScaleVectorArray_OpenMP(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VConstVectorArray_OpenMP(nvecs, c, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvecs +real(C_DOUBLE), intent(in) :: c +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = nvecs +farg2 = c +farg3 = z +fresult = swigc_FN_VConstVectorArray_OpenMP(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VWrmsNormVectorArray_OpenMP(nvecs, x, w, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvecs +type(C_PTR) :: x +type(C_PTR) :: w +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvecs +farg2 = x +farg3 = w +farg4 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormVectorArray_OpenMP(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VWrmsNormMaskVectorArray_OpenMP(nvecs, x, w, id, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvecs +type(C_PTR) :: x +type(C_PTR) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvecs +farg2 = x +farg3 = w +farg4 = c_loc(id) +farg5 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormMaskVectorArray_OpenMP(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VWSqrSumLocal_OpenMP(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWSqrSumLocal_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VWSqrSumMaskLocal_OpenMP(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWSqrSumMaskLocal_OpenMP(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VEnableFusedOps_OpenMP(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableFusedOps_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableLinearCombination_OpenMP(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableLinearCombination_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableScaleAddMulti_OpenMP(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableScaleAddMulti_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableDotProdMulti_OpenMP(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableDotProdMulti_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableLinearSumVectorArray_OpenMP(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableLinearSumVectorArray_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableScaleVectorArray_OpenMP(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableScaleVectorArray_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableConstVectorArray_OpenMP(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableConstVectorArray_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableWrmsNormVectorArray_OpenMP(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableWrmsNormVectorArray_OpenMP(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableWrmsNormMaskVectorArray_OpenMP(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableWrmsNormMaskVectorArray_OpenMP(farg1, farg2) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.c b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.c index b54f6cb44..3dfd51ee0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.c +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.c @@ -3,7 +3,7 @@ * Programmer(s): Steven Smith @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -50,22 +50,22 @@ void FNV_INITOMP(int *code, long int *N, int *num_threads, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vec = NULL; - F2C_CVODE_vec = N_VNewEmpty_OpenMP(*N, *num_threads); + F2C_CVODE_vec = N_VNewEmpty_OpenMP((sunindextype)(*N), *num_threads); if (F2C_CVODE_vec == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vec = NULL; - F2C_IDA_vec = N_VNewEmpty_OpenMP(*N, *num_threads); + F2C_IDA_vec = N_VNewEmpty_OpenMP((sunindextype)(*N), *num_threads); if (F2C_IDA_vec == NULL) *ier = -1; break; case FCMIX_KINSOL: F2C_KINSOL_vec = NULL; - F2C_KINSOL_vec = N_VNewEmpty_OpenMP(*N, *num_threads); + F2C_KINSOL_vec = N_VNewEmpty_OpenMP((sunindextype)(*N), *num_threads); if (F2C_KINSOL_vec == NULL) *ier = -1; break; case FCMIX_ARKODE: F2C_ARKODE_vec = NULL; - F2C_ARKODE_vec = N_VNewEmpty_OpenMP(*N, *num_threads); + F2C_ARKODE_vec = N_VNewEmpty_OpenMP((sunindextype)(*N), *num_threads); if (F2C_ARKODE_vec == NULL) *ier = -1; break; default: @@ -80,12 +80,12 @@ void FNV_INITOMP_Q(int *code, long int *Nq, int *num_threads, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vecQ = NULL; - F2C_CVODE_vecQ = N_VNewEmpty_OpenMP(*Nq, *num_threads); + F2C_CVODE_vecQ = N_VNewEmpty_OpenMP((sunindextype)(*Nq), *num_threads); if (F2C_CVODE_vecQ == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vecQ = NULL; - F2C_IDA_vecQ = N_VNewEmpty_OpenMP(*Nq, *num_threads); + F2C_IDA_vecQ = N_VNewEmpty_OpenMP((sunindextype)(*Nq), *num_threads); if (F2C_IDA_vecQ == NULL) *ier = -1; break; default: @@ -100,12 +100,12 @@ void FNV_INITOMP_B(int *code, long int *NB, int *num_threads, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vecB = NULL; - F2C_CVODE_vecB = N_VNewEmpty_OpenMP(*NB, *num_threads); + F2C_CVODE_vecB = N_VNewEmpty_OpenMP((sunindextype)(*NB), *num_threads); if (F2C_CVODE_vecB == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vecB = NULL; - F2C_IDA_vecB = N_VNewEmpty_OpenMP(*NB, *num_threads); + F2C_IDA_vecB = N_VNewEmpty_OpenMP((sunindextype)(*NB), *num_threads); if (F2C_IDA_vecB == NULL) *ier = -1; break; default: @@ -120,12 +120,12 @@ void FNV_INITOMP_QB(int *code, long int *NqB, int *num_threads, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vecQB = NULL; - F2C_CVODE_vecQB = N_VNewEmpty_OpenMP(*NqB, *num_threads); + F2C_CVODE_vecQB = N_VNewEmpty_OpenMP((sunindextype)(*NqB), *num_threads); if (F2C_CVODE_vecQB == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vecQB = NULL; - F2C_IDA_vecQB = N_VNewEmpty_OpenMP(*NqB, *num_threads); + F2C_IDA_vecQB = N_VNewEmpty_OpenMP((sunindextype)(*NqB), *num_threads); if (F2C_IDA_vecQB == NULL) *ier = -1; break; default: diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.h b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.h index aa354de97..334a6d985 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.h +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.h @@ -3,7 +3,7 @@ * Programmer(s): Steven Smith @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/nvector_openmp.c b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/nvector_openmp.c index e278029e4..3cb16892a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/nvector_openmp.c +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/openmp/nvector_openmp.c @@ -7,7 +7,7 @@ * @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -76,75 +76,72 @@ N_Vector_ID N_VGetVectorID_OpenMP(N_Vector v) N_Vector N_VNewEmpty_OpenMP(sunindextype length, int num_threads) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_OpenMP content; /* Create vector */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } + /* Attach operations */ - ops->nvgetvectorid = N_VGetVectorID_OpenMP; - ops->nvclone = N_VClone_OpenMP; - ops->nvcloneempty = N_VCloneEmpty_OpenMP; - ops->nvdestroy = N_VDestroy_OpenMP; - ops->nvspace = N_VSpace_OpenMP; - ops->nvgetarraypointer = N_VGetArrayPointer_OpenMP; - ops->nvsetarraypointer = N_VSetArrayPointer_OpenMP; + /* constructors, destructors, and utility operations */ + v->ops->nvgetvectorid = N_VGetVectorID_OpenMP; + v->ops->nvclone = N_VClone_OpenMP; + v->ops->nvcloneempty = N_VCloneEmpty_OpenMP; + v->ops->nvdestroy = N_VDestroy_OpenMP; + v->ops->nvspace = N_VSpace_OpenMP; + v->ops->nvgetarraypointer = N_VGetArrayPointer_OpenMP; + v->ops->nvsetarraypointer = N_VSetArrayPointer_OpenMP; + v->ops->nvgetlength = N_VGetLength_OpenMP; /* standard vector operations */ - ops->nvlinearsum = N_VLinearSum_OpenMP; - ops->nvconst = N_VConst_OpenMP; - ops->nvprod = N_VProd_OpenMP; - ops->nvdiv = N_VDiv_OpenMP; - ops->nvscale = N_VScale_OpenMP; - ops->nvabs = N_VAbs_OpenMP; - ops->nvinv = N_VInv_OpenMP; - ops->nvaddconst = N_VAddConst_OpenMP; - ops->nvdotprod = N_VDotProd_OpenMP; - ops->nvmaxnorm = N_VMaxNorm_OpenMP; - ops->nvwrmsnormmask = N_VWrmsNormMask_OpenMP; - ops->nvwrmsnorm = N_VWrmsNorm_OpenMP; - ops->nvmin = N_VMin_OpenMP; - ops->nvwl2norm = N_VWL2Norm_OpenMP; - ops->nvl1norm = N_VL1Norm_OpenMP; - ops->nvcompare = N_VCompare_OpenMP; - ops->nvinvtest = N_VInvTest_OpenMP; - ops->nvconstrmask = N_VConstrMask_OpenMP; - ops->nvminquotient = N_VMinQuotient_OpenMP; - - /* fused vector operations (optional, NULL means disabled by default) */ - ops->nvlinearcombination = NULL; - ops->nvscaleaddmulti = NULL; - ops->nvdotprodmulti = NULL; - - /* vector array operations (optional, NULL means disabled by default) */ - ops->nvlinearsumvectorarray = NULL; - ops->nvscalevectorarray = NULL; - ops->nvconstvectorarray = NULL; - ops->nvwrmsnormvectorarray = NULL; - ops->nvwrmsnormmaskvectorarray = NULL; - ops->nvscaleaddmultivectorarray = NULL; - ops->nvlinearcombinationvectorarray = NULL; + v->ops->nvlinearsum = N_VLinearSum_OpenMP; + v->ops->nvconst = N_VConst_OpenMP; + v->ops->nvprod = N_VProd_OpenMP; + v->ops->nvdiv = N_VDiv_OpenMP; + v->ops->nvscale = N_VScale_OpenMP; + v->ops->nvabs = N_VAbs_OpenMP; + v->ops->nvinv = N_VInv_OpenMP; + v->ops->nvaddconst = N_VAddConst_OpenMP; + v->ops->nvdotprod = N_VDotProd_OpenMP; + v->ops->nvmaxnorm = N_VMaxNorm_OpenMP; + v->ops->nvwrmsnormmask = N_VWrmsNormMask_OpenMP; + v->ops->nvwrmsnorm = N_VWrmsNorm_OpenMP; + v->ops->nvmin = N_VMin_OpenMP; + v->ops->nvwl2norm = N_VWL2Norm_OpenMP; + v->ops->nvl1norm = N_VL1Norm_OpenMP; + v->ops->nvcompare = N_VCompare_OpenMP; + v->ops->nvinvtest = N_VInvTest_OpenMP; + v->ops->nvconstrmask = N_VConstrMask_OpenMP; + v->ops->nvminquotient = N_VMinQuotient_OpenMP; + + /* fused and vector array operations are disabled (NULL) by default */ + + /* local reduction kernels */ + v->ops->nvdotprodlocal = N_VDotProd_OpenMP; + v->ops->nvmaxnormlocal = N_VMaxNorm_OpenMP; + v->ops->nvminlocal = N_VMin_OpenMP; + v->ops->nvl1normlocal = N_VL1Norm_OpenMP; + v->ops->nvinvtestlocal = N_VInvTest_OpenMP; + v->ops->nvconstrmasklocal = N_VConstrMask_OpenMP; + v->ops->nvminquotientlocal = N_VMinQuotient_OpenMP; + v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_OpenMP; + v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_OpenMP; /* Create content */ content = NULL; - content = (N_VectorContent_OpenMP) malloc(sizeof(struct _N_VectorContent_OpenMP)); - if (content == NULL) { free(ops); free(v); return(NULL); } + content = (N_VectorContent_OpenMP) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } - content->length = length; - content->num_threads = num_threads; - content->own_data = SUNFALSE; - content->data = NULL; - - /* Attach content and ops */ + /* Attach content */ v->content = content; - v->ops = ops; + + /* Initialize content */ + content->length = length; + content->num_threads = num_threads; + content->own_data = SUNFALSE; + content->data = NULL; return(v); } @@ -204,15 +201,15 @@ N_Vector N_VMake_OpenMP(sunindextype length, realtype *v_data, int num_threads) * Function to create an array of new vectors. */ -N_Vector *N_VCloneVectorArray_OpenMP(int count, N_Vector w) +N_Vector* N_VCloneVectorArray_OpenMP(int count, N_Vector w) { - N_Vector *vs; + N_Vector* vs; int j; if (count <= 0) return(NULL); vs = NULL; - vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + vs = (N_Vector*) malloc(count * sizeof(N_Vector)); if(vs == NULL) return(NULL); for (j = 0; j < count; j++) { @@ -231,15 +228,15 @@ N_Vector *N_VCloneVectorArray_OpenMP(int count, N_Vector w) * Function to create an array of new vectors with NULL data array. */ -N_Vector *N_VCloneVectorArrayEmpty_OpenMP(int count, N_Vector w) +N_Vector* N_VCloneVectorArrayEmpty_OpenMP(int count, N_Vector w) { - N_Vector *vs; + N_Vector* vs; int j; if (count <= 0) return(NULL); vs = NULL; - vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + vs = (N_Vector*) malloc(count * sizeof(N_Vector)); if(vs == NULL) return(NULL); for (j = 0; j < count; j++) { @@ -258,7 +255,7 @@ N_Vector *N_VCloneVectorArrayEmpty_OpenMP(int count, N_Vector w) * Function to free an array created with N_VCloneVectorArray_OpenMP */ -void N_VDestroyVectorArray_OpenMP(N_Vector *vs, int count) +void N_VDestroyVectorArray_OpenMP(N_Vector* vs, int count) { int j; @@ -327,77 +324,31 @@ void N_VPrintFile_OpenMP(N_Vector x, FILE *outfile) N_Vector N_VCloneEmpty_OpenMP(N_Vector w) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_OpenMP content; if (w == NULL) return(NULL); /* Create vector */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } - - ops->nvgetvectorid = w->ops->nvgetvectorid; - ops->nvclone = w->ops->nvclone; - ops->nvcloneempty = w->ops->nvcloneempty; - ops->nvdestroy = w->ops->nvdestroy; - ops->nvspace = w->ops->nvspace; - ops->nvgetarraypointer = w->ops->nvgetarraypointer; - ops->nvsetarraypointer = w->ops->nvsetarraypointer; - - /* standard vector operations */ - ops->nvlinearsum = w->ops->nvlinearsum; - ops->nvconst = w->ops->nvconst; - ops->nvprod = w->ops->nvprod; - ops->nvdiv = w->ops->nvdiv; - ops->nvscale = w->ops->nvscale; - ops->nvabs = w->ops->nvabs; - ops->nvinv = w->ops->nvinv; - ops->nvaddconst = w->ops->nvaddconst; - ops->nvdotprod = w->ops->nvdotprod; - ops->nvmaxnorm = w->ops->nvmaxnorm; - ops->nvwrmsnormmask = w->ops->nvwrmsnormmask; - ops->nvwrmsnorm = w->ops->nvwrmsnorm; - ops->nvmin = w->ops->nvmin; - ops->nvwl2norm = w->ops->nvwl2norm; - ops->nvl1norm = w->ops->nvl1norm; - ops->nvcompare = w->ops->nvcompare; - ops->nvinvtest = w->ops->nvinvtest; - ops->nvconstrmask = w->ops->nvconstrmask; - ops->nvminquotient = w->ops->nvminquotient; - - /* fused vector operations */ - ops->nvlinearcombination = w->ops->nvlinearcombination; - ops->nvscaleaddmulti = w->ops->nvscaleaddmulti; - ops->nvdotprodmulti = w->ops->nvdotprodmulti; - - /* vector array operations */ - ops->nvlinearsumvectorarray = w->ops->nvlinearsumvectorarray; - ops->nvscalevectorarray = w->ops->nvscalevectorarray; - ops->nvconstvectorarray = w->ops->nvconstvectorarray; - ops->nvwrmsnormvectorarray = w->ops->nvwrmsnormvectorarray; - ops->nvwrmsnormmaskvectorarray = w->ops->nvwrmsnormmaskvectorarray; - ops->nvscaleaddmultivectorarray = w->ops->nvscaleaddmultivectorarray; - ops->nvlinearcombinationvectorarray = w->ops->nvlinearcombinationvectorarray; + /* Attach operations */ + if (N_VCopyOps(w, v)) { N_VDestroy(v); return(NULL); } /* Create content */ content = NULL; - content = (N_VectorContent_OpenMP) malloc(sizeof(struct _N_VectorContent_OpenMP)); - if (content == NULL) { free(ops); free(v); return(NULL); } - - content->length = NV_LENGTH_OMP(w); - content->num_threads = NV_NUM_THREADS_OMP(w); - content->own_data = SUNFALSE; - content->data = NULL; + content = (N_VectorContent_OpenMP) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } - /* Attach content and ops */ + /* Attach content */ v->content = content; - v->ops = ops; + + /* Initialize content */ + content->length = NV_LENGTH_OMP(w); + content->num_threads = NV_NUM_THREADS_OMP(w); + content->own_data = SUNFALSE; + content->data = NULL; return(v); } @@ -443,12 +394,21 @@ N_Vector N_VClone_OpenMP(N_Vector w) void N_VDestroy_OpenMP(N_Vector v) { - if (NV_OWN_DATA_OMP(v) == SUNTRUE) { - free(NV_DATA_OMP(v)); - NV_DATA_OMP(v) = NULL; + if (v == NULL) return; + + /* free content */ + if (v->content != NULL) { + /* free data array if it's owned by the vector */ + if (NV_OWN_DATA_OMP(v) && NV_DATA_OMP(v) != NULL) { + free(NV_DATA_OMP(v)); + NV_DATA_OMP(v) = NULL; + } + free(v->content); + v->content = NULL; } - free(v->content); v->content = NULL; - free(v->ops); v->ops = NULL; + + /* free ops and vector */ + if (v->ops != NULL) { free(v->ops); v->ops = NULL; } free(v); v = NULL; return; @@ -501,6 +461,7 @@ void N_VLinearSum_OpenMP(realtype a, N_Vector x, realtype b, N_Vector y, N_Vecto N_Vector v1, v2; booleantype test; + i = 0; /* initialize to suppress clang warning */ xd = yd = zd = NULL; if ((b == ONE) && (z == y)) { /* BLAS usage: axpy y <- ax+y */ @@ -593,6 +554,7 @@ void N_VConst_OpenMP(realtype c, N_Vector z) sunindextype i, N; realtype *zd; + i = 0; /* initialize to suppress clang warning */ zd = NULL; N = NV_LENGTH_OMP(z); @@ -615,6 +577,7 @@ void N_VProd_OpenMP(N_Vector x, N_Vector y, N_Vector z) sunindextype i, N; realtype *xd, *yd, *zd; + i = 0; /* initialize to suppress clang warning */ xd = yd = zd = NULL; N = NV_LENGTH_OMP(x); @@ -640,6 +603,7 @@ void N_VDiv_OpenMP(N_Vector x, N_Vector y, N_Vector z) sunindextype i, N; realtype *xd, *yd, *zd; + i = 0; /* initialize to suppress clang warning */ xd = yd = zd = NULL; N = NV_LENGTH_OMP(x); @@ -665,6 +629,7 @@ void N_VScale_OpenMP(realtype c, N_Vector x, N_Vector z) sunindextype i, N; realtype *xd, *zd; + i = 0; /* initialize to suppress clang warning */ xd = zd = NULL; if (z == x) { /* BLAS usage: scale x <- cx */ @@ -700,6 +665,7 @@ void N_VAbs_OpenMP(N_Vector x, N_Vector z) sunindextype i, N; realtype *xd, *zd; + i = 0; /* initialize to suppress clang warning */ xd = zd = NULL; N = NV_LENGTH_OMP(x); @@ -723,6 +689,7 @@ void N_VInv_OpenMP(N_Vector x, N_Vector z) sunindextype i, N; realtype *xd, *zd; + i = 0; /* initialize to suppress clang warning */ xd = zd = NULL; N = NV_LENGTH_OMP(x); @@ -747,6 +714,7 @@ void N_VAddConst_OpenMP(N_Vector x, realtype b, N_Vector z) sunindextype i, N; realtype *xd, *zd; + i = 0; /* initialize to suppress clang warning */ xd = zd = NULL; N = NV_LENGTH_OMP(x); @@ -771,8 +739,9 @@ realtype N_VDotProd_OpenMP(N_Vector x, N_Vector y) sunindextype i, N; realtype sum, *xd, *yd; + i = 0; /* initialize to suppress clang warning */ sum = ZERO; - xd = yd = NULL; + xd = yd = NULL; N = NV_LENGTH_OMP(x); xd = NV_DATA_OMP(x); @@ -797,8 +766,9 @@ realtype N_VMaxNorm_OpenMP(N_Vector x) sunindextype i, N; realtype tmax, max, *xd; + i = 0; /* initialize to suppress clang warning */ max = ZERO; - xd = NULL; + xd = NULL; N = NV_LENGTH_OMP(x); xd = NV_DATA_OMP(x); @@ -827,23 +797,7 @@ realtype N_VMaxNorm_OpenMP(N_Vector x) realtype N_VWrmsNorm_OpenMP(N_Vector x, N_Vector w) { - sunindextype i, N; - realtype sum, *xd, *wd; - - sum = ZERO; - xd = wd = NULL; - - N = NV_LENGTH_OMP(x); - xd = NV_DATA_OMP(x); - wd = NV_DATA_OMP(w); - -#pragma omp parallel for default(none) private(i) shared(N,xd,wd) \ - reduction(+:sum) schedule(static) num_threads(NV_NUM_THREADS_OMP(x)) - for (i = 0; i < N; i++) { - sum += SUNSQR(xd[i]*wd[i]); - } - - return(SUNRsqrt(sum/N)); + return(SUNRsqrt(N_VWSqrSumLocal_OpenMP(x, w)/(NV_LENGTH_OMP(x)))); } @@ -853,26 +807,7 @@ realtype N_VWrmsNorm_OpenMP(N_Vector x, N_Vector w) realtype N_VWrmsNormMask_OpenMP(N_Vector x, N_Vector w, N_Vector id) { - sunindextype i, N; - realtype sum, *xd, *wd, *idd; - - sum = ZERO; - xd = wd = idd = NULL; - - N = NV_LENGTH_OMP(x); - xd = NV_DATA_OMP(x); - wd = NV_DATA_OMP(w); - idd = NV_DATA_OMP(id); - -#pragma omp parallel for default(none) private(i) shared(N,xd,wd,idd) \ - reduction(+:sum) schedule(static) num_threads(NV_NUM_THREADS_OMP(x)) - for (i = 0; i < N; i++) { - if (idd[i] > ZERO) { - sum += SUNSQR(xd[i]*wd[i]); - } - } - - return(SUNRsqrt(sum / N)); + return(SUNRsqrt(N_VWSqrSumMaskLocal_OpenMP(x, w, id)/(NV_LENGTH_OMP(x)))); } @@ -886,6 +821,7 @@ realtype N_VMin_OpenMP(N_Vector x) realtype min, *xd; realtype tmin; + i = 0; /* initialize to suppress clang warning */ xd = NULL; N = NV_LENGTH_OMP(x); @@ -922,8 +858,9 @@ realtype N_VWL2Norm_OpenMP(N_Vector x, N_Vector w) sunindextype i, N; realtype sum, *xd, *wd; + i = 0; /* initialize to suppress clang warning */ sum = ZERO; - xd = wd = NULL; + xd = wd = NULL; N = NV_LENGTH_OMP(x); xd = NV_DATA_OMP(x); @@ -948,8 +885,9 @@ realtype N_VL1Norm_OpenMP(N_Vector x) sunindextype i, N; realtype sum, *xd; + i = 0; /* initialize to suppress clang warning */ sum = ZERO; - xd = NULL; + xd = NULL; N = NV_LENGTH_OMP(x); xd = NV_DATA_OMP(x); @@ -972,6 +910,7 @@ void N_VCompare_OpenMP(realtype c, N_Vector x, N_Vector z) sunindextype i, N; realtype *xd, *zd; + i = 0; /* initialize to suppress clang warning */ xd = zd = NULL; N = NV_LENGTH_OMP(x); @@ -997,6 +936,7 @@ booleantype N_VInvTest_OpenMP(N_Vector x, N_Vector z) sunindextype i, N; realtype *xd, *zd, val; + i = 0; /* initialize to suppress clang warning */ xd = zd = NULL; N = NV_LENGTH_OMP(x); @@ -1032,6 +972,7 @@ booleantype N_VConstrMask_OpenMP(N_Vector c, N_Vector x, N_Vector m) realtype *cd, *xd, *md; booleantype test; + i = 0; /* initialize to suppress clang warning */ cd = xd = md = NULL; N = NV_LENGTH_OMP(x); @@ -1071,6 +1012,7 @@ realtype N_VMinQuotient_OpenMP(N_Vector num, N_Vector denom) sunindextype i, N; realtype *nd, *dd, min, tmin, val; + i = 0; /* initialize to suppress clang warning */ nd = dd = NULL; N = NV_LENGTH_OMP(num); @@ -1102,6 +1044,63 @@ realtype N_VMinQuotient_OpenMP(N_Vector num, N_Vector denom) } +/* ---------------------------------------------------------------------------- + * Computes weighted square sum of a vector + */ + +realtype N_VWSqrSumLocal_OpenMP(N_Vector x, N_Vector w) +{ + sunindextype i, N; + realtype sum, *xd, *wd; + + i = 0; /* initialize to suppress clang warning */ + sum = ZERO; + xd = wd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + wd = NV_DATA_OMP(w); + +#pragma omp parallel for default(none) private(i) shared(N,xd,wd) \ + reduction(+:sum) schedule(static) num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) { + sum += SUNSQR(xd[i]*wd[i]); + } + + return(sum); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted square sum of a masked vector + */ + +realtype N_VWSqrSumMaskLocal_OpenMP(N_Vector x, N_Vector w, N_Vector id) +{ + sunindextype i, N; + realtype sum, *xd, *wd, *idd; + + i = 0; /* initialize to suppress clang warning */ + sum = ZERO; + xd = wd = idd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + wd = NV_DATA_OMP(w); + idd = NV_DATA_OMP(id); + +#pragma omp parallel for default(none) private(i) shared(N,xd,wd,idd) \ + reduction(+:sum) schedule(static) num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) { + if (idd[i] > ZERO) { + sum += SUNSQR(xd[i]*wd[i]); + } + } + + return(sum); +} + + /* * ----------------------------------------------------------------- * fused vector operations @@ -1115,6 +1114,9 @@ int N_VLinearCombination_OpenMP(int nvec, realtype* c, N_Vector* X, N_Vector z) realtype* zd=NULL; realtype* xd=NULL; + i = 0; /* initialize to suppress clang warning */ + j = 0; + /* invalid number of vectors */ if (nvec < 1) return(-1); @@ -1208,6 +1210,9 @@ int N_VScaleAddMulti_OpenMP(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Ve realtype* yd=NULL; realtype* zd=NULL; + i = 0; /* initialize to suppress clang warning */ + j = 0; + /* invalid number of vectors */ if (nvec < 1) return(-1); @@ -1266,6 +1271,9 @@ int N_VDotProdMulti_OpenMP(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods realtype* xd=NULL; realtype* yd=NULL; + i = 0; /* initialize to suppress clang warning */ + j = 0; + /* invalid number of vectors */ if (nvec < 1) return(-1); @@ -1323,10 +1331,13 @@ int N_VLinearSumVectorArray_OpenMP(int nvec, realtype* yd=NULL; realtype* zd=NULL; realtype c; - N_Vector* V1; - N_Vector* V2; + N_Vector* V1; + N_Vector* V2; booleantype test; + i = 0; /* initialize to suppress clang warning */ + j = 0; + /* invalid number of vectors */ if (nvec < 1) return(-1); @@ -1372,7 +1383,7 @@ int N_VLinearSumVectorArray_OpenMP(int nvec, /* (1) a == -1.0, b != 1.0, */ /* (2) a != 1.0, b == -1.0 */ if ((test = (a == -ONE)) || (b == -ONE)) { - c = test ? b : a; + c = test ? b : a; V1 = test ? Y : X; V2 = test ? X : Y; return(VLin2VectorArray_OpenMP(nvec, c, V1, V2, Z)); @@ -1421,6 +1432,9 @@ int N_VScaleVectorArray_OpenMP(int nvec, realtype* c, N_Vector* X, N_Vector* Z) realtype* xd=NULL; realtype* zd=NULL; + i = 0; /* initialize to suppress clang warning */ + j = 0; + /* invalid number of vectors */ if (nvec < 1) return(-1); @@ -1476,6 +1490,9 @@ int N_VConstVectorArray_OpenMP(int nvec, realtype c, N_Vector* Z) sunindextype j, N; realtype* zd=NULL; + i = 0; /* initialize to suppress clang warning */ + j = 0; + /* invalid number of vectors */ if (nvec < 1) return(-1); @@ -1513,6 +1530,9 @@ int N_VWrmsNormVectorArray_OpenMP(int nvec, N_Vector* X, N_Vector* W, realtype* realtype* wd=NULL; realtype* xd=NULL; + i = 0; /* initialize to suppress clang warning */ + j = 0; + /* invalid number of vectors */ if (nvec < 1) return(-1); @@ -1567,6 +1587,9 @@ int N_VWrmsNormMaskVectorArray_OpenMP(int nvec, N_Vector* X, N_Vector* W, realtype* xd=NULL; realtype* idd=NULL; + i = 0; /* initialize to suppress clang warning */ + j = 0; + /* invalid number of vectors */ if (nvec < 1) return(-1); @@ -1623,8 +1646,11 @@ int N_VScaleAddMultiVectorArray_OpenMP(int nvec, int nsum, realtype* a, realtype* zd=NULL; int retval; - N_Vector* YY; - N_Vector* ZZ; + N_Vector* YY; + N_Vector* ZZ; + + i = 0; /* initialize to suppress clang warning */ + k = 0; /* invalid number of vectors */ if (nvec < 1) return(-1); @@ -1643,8 +1669,8 @@ int N_VScaleAddMultiVectorArray_OpenMP(int nvec, int nsum, realtype* a, } /* should have called N_VScaleAddMulti */ - YY = (N_Vector *) malloc(nsum * sizeof(N_Vector)); - ZZ = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + YY = (N_Vector*) malloc(nsum * sizeof(N_Vector)); + ZZ = (N_Vector*) malloc(nsum * sizeof(N_Vector)); for (j=0; jnvgetvectorid = N_VGetVectorID_OpenMPDEV; - ops->nvclone = N_VClone_OpenMPDEV; - ops->nvcloneempty = N_VCloneEmpty_OpenMPDEV; - ops->nvdestroy = N_VDestroy_OpenMPDEV; - ops->nvspace = N_VSpace_OpenMPDEV; - ops->nvgetarraypointer = NULL; - ops->nvsetarraypointer = NULL; + /* constructors, destructors, and utility operations */ + v->ops->nvgetvectorid = N_VGetVectorID_OpenMPDEV; + v->ops->nvclone = N_VClone_OpenMPDEV; + v->ops->nvcloneempty = N_VCloneEmpty_OpenMPDEV; + v->ops->nvdestroy = N_VDestroy_OpenMPDEV; + v->ops->nvspace = N_VSpace_OpenMPDEV; + v->ops->nvgetlength = N_VGetLength_OpenMPDEV; /* standard vector operations */ - ops->nvlinearsum = N_VLinearSum_OpenMPDEV; - ops->nvconst = N_VConst_OpenMPDEV; - ops->nvprod = N_VProd_OpenMPDEV; - ops->nvdiv = N_VDiv_OpenMPDEV; - ops->nvscale = N_VScale_OpenMPDEV; - ops->nvabs = N_VAbs_OpenMPDEV; - ops->nvinv = N_VInv_OpenMPDEV; - ops->nvaddconst = N_VAddConst_OpenMPDEV; - ops->nvdotprod = N_VDotProd_OpenMPDEV; - ops->nvmaxnorm = N_VMaxNorm_OpenMPDEV; - ops->nvwrmsnormmask = N_VWrmsNormMask_OpenMPDEV; - ops->nvwrmsnorm = N_VWrmsNorm_OpenMPDEV; - ops->nvmin = N_VMin_OpenMPDEV; - ops->nvwl2norm = N_VWL2Norm_OpenMPDEV; - ops->nvl1norm = N_VL1Norm_OpenMPDEV; - ops->nvcompare = N_VCompare_OpenMPDEV; - ops->nvinvtest = N_VInvTest_OpenMPDEV; - ops->nvconstrmask = N_VConstrMask_OpenMPDEV; - ops->nvminquotient = N_VMinQuotient_OpenMPDEV; - - /* fused vector operations (optional, NULL means disabled by default) */ - ops->nvlinearcombination = NULL; - ops->nvscaleaddmulti = NULL; - ops->nvdotprodmulti = NULL; - - /* vector array operations (optional, NULL means disabled by default) */ - ops->nvlinearsumvectorarray = NULL; - ops->nvscalevectorarray = NULL; - ops->nvconstvectorarray = NULL; - ops->nvwrmsnormvectorarray = NULL; - ops->nvwrmsnormmaskvectorarray = NULL; - ops->nvscaleaddmultivectorarray = NULL; - ops->nvlinearcombinationvectorarray = NULL; + v->ops->nvlinearsum = N_VLinearSum_OpenMPDEV; + v->ops->nvconst = N_VConst_OpenMPDEV; + v->ops->nvprod = N_VProd_OpenMPDEV; + v->ops->nvdiv = N_VDiv_OpenMPDEV; + v->ops->nvscale = N_VScale_OpenMPDEV; + v->ops->nvabs = N_VAbs_OpenMPDEV; + v->ops->nvinv = N_VInv_OpenMPDEV; + v->ops->nvaddconst = N_VAddConst_OpenMPDEV; + v->ops->nvdotprod = N_VDotProd_OpenMPDEV; + v->ops->nvmaxnorm = N_VMaxNorm_OpenMPDEV; + v->ops->nvwrmsnormmask = N_VWrmsNormMask_OpenMPDEV; + v->ops->nvwrmsnorm = N_VWrmsNorm_OpenMPDEV; + v->ops->nvmin = N_VMin_OpenMPDEV; + v->ops->nvwl2norm = N_VWL2Norm_OpenMPDEV; + v->ops->nvl1norm = N_VL1Norm_OpenMPDEV; + v->ops->nvcompare = N_VCompare_OpenMPDEV; + v->ops->nvinvtest = N_VInvTest_OpenMPDEV; + v->ops->nvconstrmask = N_VConstrMask_OpenMPDEV; + v->ops->nvminquotient = N_VMinQuotient_OpenMPDEV; + + /* fused and vector array operations are disabled (NULL) by default */ + + /* local reduction operations */ + v->ops->nvdotprodlocal = N_VDotProd_OpenMPDEV; + v->ops->nvmaxnormlocal = N_VMaxNorm_OpenMPDEV; + v->ops->nvminlocal = N_VMin_OpenMPDEV; + v->ops->nvl1normlocal = N_VL1Norm_OpenMPDEV; + v->ops->nvinvtestlocal = N_VInvTest_OpenMPDEV; + v->ops->nvconstrmasklocal = N_VConstrMask_OpenMPDEV; + v->ops->nvminquotientlocal = N_VMinQuotient_OpenMPDEV; + v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_OpenMPDEV; + v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_OpenMPDEV; /* Create content */ content = NULL; - content = (N_VectorContent_OpenMPDEV) malloc(sizeof(struct _N_VectorContent_OpenMPDEV)); - if (content == NULL) { free(ops); free(v); return(NULL); } + content = (N_VectorContent_OpenMPDEV) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } + + /* Attach content */ + v->content = content; + /* Initialize content */ content->length = length; content->own_data = SUNFALSE; content->host_data = NULL; content->dev_data = NULL; - /* Attach content and ops */ - v->content = content; - v->ops = ops; - return(v); } @@ -167,18 +162,20 @@ N_Vector N_VNew_OpenMPDEV(sunindextype length) /* Create data */ if (length > 0) { + /* Update ownership */ + NV_OWN_DATA_OMPDEV(v) = SUNTRUE; + /* Allocate memory on host */ data = NULL; data = (realtype *) malloc(length * sizeof(realtype)); + if (data == NULL) { N_VDestroy(v); return(NULL); } /* Allocate memory on device */ dev = omp_get_default_device(); dev_data = omp_target_alloc(length * sizeof(realtype), dev); - - if(data == NULL) { N_VDestroy_OpenMPDEV(v); return(NULL); } + if (dev_data == NULL) { N_VDestroy(v); return(NULL); } /* Attach data */ - NV_OWN_DATA_OMPDEV(v) = SUNTRUE; NV_DATA_HOST_OMPDEV(v) = data; NV_DATA_DEV_OMPDEV(v) = dev_data; @@ -191,7 +188,8 @@ N_Vector N_VNew_OpenMPDEV(sunindextype length) * Function to create a vector with user data component */ -N_Vector N_VMake_OpenMPDEV(sunindextype length, realtype *h_vdata, realtype *d_vdata) +N_Vector N_VMake_OpenMPDEV(sunindextype length, realtype *h_vdata, + realtype *d_vdata) { N_Vector v; int dev, host; @@ -411,78 +409,32 @@ void N_VCopyFromDevice_OpenMPDEV(N_Vector x) N_Vector N_VCloneEmpty_OpenMPDEV(N_Vector w) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_OpenMPDEV content; if (w == NULL) return(NULL); /* Create vector */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } - - ops->nvgetvectorid = w->ops->nvgetvectorid; - ops->nvclone = w->ops->nvclone; - ops->nvcloneempty = w->ops->nvcloneempty; - ops->nvdestroy = w->ops->nvdestroy; - ops->nvspace = w->ops->nvspace; - ops->nvgetarraypointer = w->ops->nvgetarraypointer; - ops->nvsetarraypointer = w->ops->nvsetarraypointer; - - /* standard vector operations */ - ops->nvlinearsum = w->ops->nvlinearsum; - ops->nvconst = w->ops->nvconst; - ops->nvprod = w->ops->nvprod; - ops->nvdiv = w->ops->nvdiv; - ops->nvscale = w->ops->nvscale; - ops->nvabs = w->ops->nvabs; - ops->nvinv = w->ops->nvinv; - ops->nvaddconst = w->ops->nvaddconst; - ops->nvdotprod = w->ops->nvdotprod; - ops->nvmaxnorm = w->ops->nvmaxnorm; - ops->nvwrmsnormmask = w->ops->nvwrmsnormmask; - ops->nvwrmsnorm = w->ops->nvwrmsnorm; - ops->nvmin = w->ops->nvmin; - ops->nvwl2norm = w->ops->nvwl2norm; - ops->nvl1norm = w->ops->nvl1norm; - ops->nvcompare = w->ops->nvcompare; - ops->nvinvtest = w->ops->nvinvtest; - ops->nvconstrmask = w->ops->nvconstrmask; - ops->nvminquotient = w->ops->nvminquotient; - - /* fused vector operations */ - ops->nvlinearcombination = w->ops->nvlinearcombination; - ops->nvscaleaddmulti = w->ops->nvscaleaddmulti; - ops->nvdotprodmulti = w->ops->nvdotprodmulti; - - /* vector array operations */ - ops->nvlinearsumvectorarray = w->ops->nvlinearsumvectorarray; - ops->nvscalevectorarray = w->ops->nvscalevectorarray; - ops->nvconstvectorarray = w->ops->nvconstvectorarray; - ops->nvwrmsnormvectorarray = w->ops->nvwrmsnormvectorarray; - ops->nvwrmsnormmaskvectorarray = w->ops->nvwrmsnormmaskvectorarray; - ops->nvscaleaddmultivectorarray = w->ops->nvscaleaddmultivectorarray; - ops->nvlinearcombinationvectorarray = w->ops->nvlinearcombinationvectorarray; - + /* Attach operations */ + if (N_VCopyOps(w, v)) { N_VDestroy(v); return(NULL); } + /* Create content */ content = NULL; - content = (N_VectorContent_OpenMPDEV) malloc(sizeof(struct _N_VectorContent_OpenMPDEV)); - if (content == NULL) { free(ops); free(v); return(NULL); } + content = (N_VectorContent_OpenMPDEV) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } + /* Attach content */ + v->content = content; + + /* Initialize content */ content->length = NV_LENGTH_OMPDEV(w); content->own_data = SUNFALSE; content->host_data = NULL; content->dev_data = NULL; - /* Attach content and ops */ - v->content = content; - v->ops = ops; - return(v); } @@ -508,18 +460,20 @@ N_Vector N_VClone_OpenMPDEV(N_Vector w) /* Create data */ if (length > 0) { + /* Update ownership flag */ + NV_OWN_DATA_OMPDEV(v) = SUNTRUE; + /* Allocate memory on host */ data = NULL; data = (realtype *) malloc(length * sizeof(realtype)); + if (data == NULL) { N_VDestroy(v); return(NULL); } /* Allocate memory on device */ dev = omp_get_default_device(); dev_data = omp_target_alloc(length * sizeof(realtype), dev); - - if(data == NULL) { N_VDestroy_OpenMPDEV(v); return(NULL); } + if (dev_data == NULL) { N_VDestroy(v); return(NULL); } /* Attach data */ - NV_OWN_DATA_OMPDEV(v) = SUNTRUE; NV_DATA_HOST_OMPDEV(v)= data; NV_DATA_DEV_OMPDEV(v) = dev_data; @@ -537,19 +491,30 @@ void N_VDestroy_OpenMPDEV(N_Vector v) { int dev; - if (NV_OWN_DATA_OMPDEV(v) == SUNTRUE) { - /* Free host memory */ - free(NV_DATA_HOST_OMPDEV(v)); - NV_DATA_HOST_OMPDEV(v) = NULL; - - /* Free device memory */ - dev = omp_get_default_device(); - omp_target_free(NV_DATA_DEV_OMPDEV(v), dev); - NV_DATA_DEV_OMPDEV(v) = NULL; + if (v == NULL) return; + + /* free content */ + if (v->content != NULL) { + /* free data arrays if they are owned by the vector */ + if (NV_OWN_DATA_OMPDEV(v)) { + + if (NV_DATA_HOST_OMPDEV(v) != NULL) { + free(NV_DATA_HOST_OMPDEV(v)); + NV_DATA_HOST_OMPDEV(v) = NULL; + } + + if (NV_DATA_DEV_OMPDEV(v) != NULL) { + dev = omp_get_default_device(); + omp_target_free(NV_DATA_DEV_OMPDEV(v), dev); + NV_DATA_DEV_OMPDEV(v) = NULL; + } + } + free(v->content); + v->content = NULL; } - free(v->content); v->content = NULL; - free(v->ops); v->ops = NULL; + /* free ops and vector */ + if (v->ops != NULL) { free(v->ops); v->ops = NULL; } free(v); v = NULL; return; @@ -937,6 +902,26 @@ realtype N_VMaxNorm_OpenMPDEV(N_Vector x) */ realtype N_VWrmsNorm_OpenMPDEV(N_Vector x, N_Vector w) +{ + return(SUNRsqrt(N_VWSqrSumLocal_OpenMPDEV(x, w)/(NV_LENGTH_OMPDEV(x)))); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted root mean square norm of a masked vector + */ + +realtype N_VWrmsNormMask_OpenMPDEV(N_Vector x, N_Vector w, N_Vector id) +{ + return(SUNRsqrt(N_VWSqrSumMaskLocal_OpenMPDEV(x, w, id) / (NV_LENGTH_OMPDEV(x)))); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted square sum of a vector + */ + +realtype N_VWSqrSumLocal_OpenMPDEV(N_Vector x, N_Vector w) { sunindextype i, N; realtype sum, *xd_dev, *wd_dev; @@ -958,15 +943,15 @@ realtype N_VWrmsNorm_OpenMPDEV(N_Vector x, N_Vector w) sum += SUNSQR(xd_dev[i]*wd_dev[i]); } - return(SUNRsqrt(sum/N)); + return(sum); } /* ---------------------------------------------------------------------------- - * Computes weighted root mean square norm of a masked vector + * Computes weighted square sum of a masked vector */ -realtype N_VWrmsNormMask_OpenMPDEV(N_Vector x, N_Vector w, N_Vector id) +realtype N_VWSqrSumMaskLocal_OpenMPDEV(N_Vector x, N_Vector w, N_Vector id) { sunindextype i, N; realtype sum, *xd_dev, *wd_dev, *idd_dev; @@ -991,7 +976,7 @@ realtype N_VWrmsNormMask_OpenMPDEV(N_Vector x, N_Vector w, N_Vector id) } } - return(SUNRsqrt(sum / N)); + return(sum); } diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/CMakeLists.txt index f2617c8b4..f0b385dee 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Radu Serban @ LLNL +# Programmer(s): Radu Serban @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,95 +12,101 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the parallel NVECTOR library +# --------------------------------------------------------------- + +install(CODE "MESSAGE(\"\nInstall NVECTOR_PARALLEL\n\")") -INSTALL(CODE "MESSAGE(\"\nInstall NVECTOR_PARALLEL\n\")") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) -IF(MPI_C_COMPILER) +if(MPI_C_COMPILER) # use MPI wrapper as the compiler - SET(CMAKE_C_COMPILER ${MPI_C_COMPILER}) -ELSE() + set(CMAKE_C_COMPILER ${MPI_C_COMPILER}) +else() # add MPI_INCLUDE_PATH to include directories - INCLUDE_DIRECTORIES(${MPI_INCLUDE_PATH}) -ENDIF() + include_directories(${MPI_INCLUDE_PATH}) +endif() # Add variable nvecparallel_SOURCES with the sources for the NVECPARALLEL lib -SET(nvecparallel_SOURCES nvector_parallel.c) +set(nvecparallel_SOURCES nvector_parallel.c) # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the NVECPARALLEL library -SET(shared_SOURCES +set(shared_SOURCES + ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c - ${sundials_SOURCE_DIR}/src/sundials/sundials_mpi.c ) # Add variable nvecparallel_HEADERS with the exported NVECPARALLEL header files -SET(nvecparallel_HEADERS +set(nvecparallel_HEADERS ${sundials_SOURCE_DIR}/include/nvector/nvector_parallel.h ) # Add source directory to include directories -INCLUDE_DIRECTORIES(.) +include_directories(.) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) # Rules for building and installing the static library: # - Add the build target for the NVECPARALLEL library # - Set the library name and make sure it is not deleted # - Install the NVECPARALLEL library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_nvecparallel_static STATIC ${nvecparallel_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_nvecparallel_static +if(BUILD_STATIC_LIBS) + add_library(sundials_nvecparallel_static STATIC ${nvecparallel_SOURCES} ${shared_SOURCES}) + set_target_properties(sundials_nvecparallel_static PROPERTIES OUTPUT_NAME sundials_nvecparallel CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_nvecparallel_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) + install(TARGETS sundials_nvecparallel_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: # - Add the build target for the NVECPARALLEL library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries # - Install the NVECPARALLEL library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_nvecparallel_shared SHARED ${nvecparallel_SOURCES} ${shared_SOURCES}) +if(BUILD_SHARED_LIBS) + add_library(sundials_nvecparallel_shared SHARED ${nvecparallel_SOURCES} ${shared_SOURCES}) - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_nvecparallel_shared m) - ENDIF() + if(UNIX) + target_link_libraries(sundials_nvecparallel_shared m) + endif() - SET_TARGET_PROPERTIES(sundials_nvecparallel_shared + set_target_properties(sundials_nvecparallel_shared PROPERTIES OUTPUT_NAME sundials_nvecparallel CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_nvecparallel_shared + set_target_properties(sundials_nvecparallel_shared PROPERTIES VERSION ${nveclib_VERSION} SOVERSION ${nveclib_SOVERSION}) - INSTALL(TARGETS sundials_nvecparallel_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) + install(TARGETS sundials_nvecparallel_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_SHARED_LIBS) # Install the NVECPARALLEL header files -INSTALL(FILES ${nvecparallel_HEADERS} DESTINATION include/nvector) +install(FILES ${nvecparallel_HEADERS} DESTINATION include/nvector) # If FCMIX is enabled and MPI works, build and install the FNVECPARALLEL library -IF(F77_INTERFACE_ENABLE AND MPI_Fortran_FOUND) - SET(fnvecparallel_SOURCES fnvector_parallel.c) +if(F77_INTERFACE_ENABLE AND MPI_Fortran_FOUND) + set(fnvecparallel_SOURCES fnvector_parallel.c) - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fnvecparallel_static STATIC ${fnvecparallel_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fnvecparallel_static + if(BUILD_STATIC_LIBS) + add_library(sundials_fnvecparallel_static STATIC ${fnvecparallel_SOURCES}) + set_target_properties(sundials_fnvecparallel_static PROPERTIES OUTPUT_NAME sundials_fnvecparallel CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fnvecparallel_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) + install(TARGETS sundials_fnvecparallel_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fnvecparallel_shared SHARED ${fnvecparallel_SOURCES}) + if(BUILD_SHARED_LIBS) + add_library(sundials_fnvecparallel_shared SHARED ${fnvecparallel_SOURCES}) # fnvecparallel depends on nvecparallel - TARGET_LINK_LIBRARIES(sundials_fnvecparallel_shared sundials_nvecparallel_shared) + target_link_libraries(sundials_fnvecparallel_shared sundials_nvecparallel_shared) - SET_TARGET_PROPERTIES(sundials_fnvecparallel_shared + set_target_properties(sundials_fnvecparallel_shared PROPERTIES OUTPUT_NAME sundials_fnvecparallel CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fnvecparallel_shared + set_target_properties(sundials_fnvecparallel_shared PROPERTIES VERSION ${nveclib_VERSION} SOVERSION ${nveclib_SOVERSION}) - INSTALL(TARGETS sundials_fnvecparallel_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + install(TARGETS sundials_fnvecparallel_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) -ENDIF() +endif() # -MESSAGE(STATUS "Added NVECTOR_PARALLEL module") +message(STATUS "Added NVECTOR_PARALLEL module") diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fmod/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fmod/CMakeLists.txt new file mode 100644 index 000000000..bb8595047 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fmod/CMakeLists.txt @@ -0,0 +1,57 @@ +# --------------------------------------------------------------- +# Programmer(s): Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the F2003 parallel NVECTOR object library +# --------------------------------------------------------------- + +set(nvecparallel_SOURCES fnvector_parallel_mod.f90 fnvector_parallel_mod.c) + +if(MPI_C_COMPILER) + # use MPI wrapper as the compiler + set(CMAKE_C_COMPILER ${MPI_C_COMPILER}) +else() + # add MPI_INCLUDE_PATH to include directories + include_directories(${MPI_INCLUDE_PATH}) +endif() + +if(MPI_Fortran_COMPILER) + # use MPI wrapper as the compiler + set(CMAKE_Fortran_COMPILER ${MPI_Fortran_COMPILER}) +else() + # add MPI_INCLUDE_PATH to include directories + include_directories(${MPI_INCLUDE_PATH}) +endif() + +if(BUILD_STATIC_LIBS) + sundials_add_f2003_interface_library(sundials_fnvecparallel_mod_static STATIC_OBJECT + ${nvecparallel_SOURCES}) + add_dependencies(sundials_fnvecparallel_mod_static_obj sundials_fgeneric_static_obj) + set_target_properties(sundials_fnvecparallel_mod_static PROPERTIES + OUTPUT_NAME sundials_fnvecparallel_mod + CLEAN_DIRECT_OUTPUT 1) + install(TARGETS sundials_fnvecparallel_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_STATIC_LIBS) + +if(BUILD_SHARED_LIBS) + sundials_add_f2003_interface_library(sundials_fnvecparallel_mod_shared SHARED_OBJECT + ${nvecparallel_SOURCES}) + add_dependencies(sundials_fnvecparallel_mod_shared_obj sundials_fgeneric_shared_obj) + set_target_properties(sundials_fnvecparallel_mod_shared PROPERTIES + OUTPUT_NAME sundials_fnvecparallel_mod + CLEAN_DIRECT_OUTPUT 1 + VERSION ${nveclib_VERSION} + SOVERSION ${nveclib_SOVERSION}) + install(TARGETS sundials_fnvecparallel_mod_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_SHARED_LIBS) + +message(STATUS "Added NVECTOR_PARALLEL F2003 interface") diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fmod/fnvector_parallel_mod.c b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fmod/fnvector_parallel_mod.c new file mode 100644 index 000000000..278a51add --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fmod/fnvector_parallel_mod.c @@ -0,0 +1,1087 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_nvector.h" + + +#include "nvector/nvector_parallel.h" + +SWIGEXPORT N_Vector _wrap_FN_VNew_Parallel(int const *farg1, int64_t const *farg2, int64_t const *farg3) { + N_Vector fresult ; + MPI_Comm arg1 ; + sunindextype arg2 ; + sunindextype arg3 ; + N_Vector result; + +#ifdef SUNDIALS_MPI_ENABLED + arg1 = MPI_Comm_f2c((MPI_Fint)(*farg1)); +#else + arg1 = *farg1; +#endif + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + result = (N_Vector)N_VNew_Parallel(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VNewEmpty_Parallel(int const *farg1, int64_t const *farg2, int64_t const *farg3) { + N_Vector fresult ; + MPI_Comm arg1 ; + sunindextype arg2 ; + sunindextype arg3 ; + N_Vector result; + +#ifdef SUNDIALS_MPI_ENABLED + arg1 = MPI_Comm_f2c((MPI_Fint)(*farg1)); +#else + arg1 = *farg1; +#endif + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + result = (N_Vector)N_VNewEmpty_Parallel(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VMake_Parallel(int const *farg1, int64_t const *farg2, int64_t const *farg3, double *farg4) { + N_Vector fresult ; + MPI_Comm arg1 ; + sunindextype arg2 ; + sunindextype arg3 ; + realtype *arg4 = (realtype *) 0 ; + N_Vector result; + +#ifdef SUNDIALS_MPI_ENABLED + arg1 = MPI_Comm_f2c((MPI_Fint)(*farg1)); +#else + arg1 = *farg1; +#endif + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (realtype *)(farg4); + result = (N_Vector)N_VMake_Parallel(arg1,arg2,arg3,arg4); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FN_VCloneVectorArray_Parallel(int const *farg1, N_Vector farg2) { + void * fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *result = 0 ; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + result = (N_Vector *)N_VCloneVectorArray_Parallel(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FN_VCloneVectorArrayEmpty_Parallel(int const *farg1, N_Vector farg2) { + void * fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *result = 0 ; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + result = (N_Vector *)N_VCloneVectorArrayEmpty_Parallel(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VDestroyVectorArray_Parallel(void *farg1, int const *farg2) { + N_Vector *arg1 = (N_Vector *) 0 ; + int arg2 ; + + arg1 = (N_Vector *)(farg1); + arg2 = (int)(*farg2); + N_VDestroyVectorArray_Parallel(arg1,arg2); +} + + +SWIGEXPORT int64_t _wrap_FN_VGetLength_Parallel(N_Vector farg1) { + int64_t fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype result; + + arg1 = (N_Vector)(farg1); + result = N_VGetLength_Parallel(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FN_VGetLocalLength_Parallel(N_Vector farg1) { + int64_t fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype result; + + arg1 = (N_Vector)(farg1); + result = N_VGetLocalLength_Parallel(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VPrint_Parallel(N_Vector farg1) { + N_Vector arg1 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + N_VPrint_Parallel(arg1); +} + + +SWIGEXPORT void _wrap_FN_VPrintFile_Parallel(N_Vector farg1, void *farg2) { + N_Vector arg1 = (N_Vector) 0 ; + FILE *arg2 = (FILE *) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (FILE *)(farg2); + N_VPrintFile_Parallel(arg1,arg2); +} + + +SWIGEXPORT int _wrap_FN_VGetVectorID_Parallel(N_Vector farg1) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector_ID result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector_ID)N_VGetVectorID_Parallel(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VCloneEmpty_Parallel(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VCloneEmpty_Parallel(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VClone_Parallel(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VClone_Parallel(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VDestroy_Parallel(N_Vector farg1) { + N_Vector arg1 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + N_VDestroy_Parallel(arg1); +} + + +SWIGEXPORT void _wrap_FN_VSpace_Parallel(N_Vector farg1, int64_t *farg2, int64_t *farg3) { + N_Vector arg1 = (N_Vector) 0 ; + sunindextype *arg2 = (sunindextype *) 0 ; + sunindextype *arg3 = (sunindextype *) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (sunindextype *)(farg2); + arg3 = (sunindextype *)(farg3); + N_VSpace_Parallel(arg1,arg2,arg3); +} + + +SWIGEXPORT double * _wrap_FN_VGetArrayPointer_Parallel(N_Vector farg1) { + double * fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype *result = 0 ; + + arg1 = (N_Vector)(farg1); + result = (realtype *)N_VGetArrayPointer_Parallel(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VSetArrayPointer_Parallel(double *farg1, N_Vector farg2) { + realtype *arg1 = (realtype *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype *)(farg1); + arg2 = (N_Vector)(farg2); + N_VSetArrayPointer_Parallel(arg1,arg2); +} + + +SWIGEXPORT void * _wrap_FN_VGetCommunicator_Parallel(N_Vector farg1) { + void * fresult ; + N_Vector arg1 = (N_Vector) 0 ; + void *result = 0 ; + + arg1 = (N_Vector)(farg1); + result = (void *)N_VGetCommunicator_Parallel(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VLinearSum_Parallel(double const *farg1, N_Vector farg2, double const *farg3, N_Vector farg4, N_Vector farg5) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + N_VLinearSum_Parallel(arg1,arg2,arg3,arg4,arg5); +} + + +SWIGEXPORT void _wrap_FN_VConst_Parallel(double const *farg1, N_Vector farg2) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + N_VConst_Parallel(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VProd_Parallel(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VProd_Parallel(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VDiv_Parallel(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VDiv_Parallel(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VScale_Parallel(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VScale_Parallel(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VAbs_Parallel(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VAbs_Parallel(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VInv_Parallel(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VInv_Parallel(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VAddConst_Parallel(N_Vector farg1, double const *farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + N_VAddConst_Parallel(arg1,arg2,arg3); +} + + +SWIGEXPORT double _wrap_FN_VDotProd_Parallel(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VDotProd_Parallel(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMaxNorm_Parallel(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMaxNorm_Parallel(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNorm_Parallel(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWrmsNorm_Parallel(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNormMask_Parallel(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWrmsNormMask_Parallel(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMin_Parallel(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMin_Parallel(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWL2Norm_Parallel(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWL2Norm_Parallel(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VL1Norm_Parallel(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VL1Norm_Parallel(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VCompare_Parallel(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VCompare_Parallel(arg1,arg2,arg3); +} + + +SWIGEXPORT int _wrap_FN_VInvTest_Parallel(N_Vector farg1, N_Vector farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)N_VInvTest_Parallel(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstrMask_Parallel(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)N_VConstrMask_Parallel(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinQuotient_Parallel(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VMinQuotient_Parallel(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearCombination_Parallel(int const *farg1, double *farg2, void *farg3, N_Vector farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)N_VLinearCombination_Parallel(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleAddMulti_Parallel(int const *farg1, double *farg2, N_Vector farg3, void *farg4, void *farg5) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + N_Vector *arg5 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector *)(farg4); + arg5 = (N_Vector *)(farg5); + result = (int)N_VScaleAddMulti_Parallel(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VDotProdMulti_Parallel(int const *farg1, N_Vector farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VDotProdMulti_Parallel(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearSumVectorArray_Parallel(int const *farg1, double const *farg2, void *farg3, double const *farg4, void *farg5, void *farg6) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype arg4 ; + N_Vector *arg5 = (N_Vector *) 0 ; + N_Vector *arg6 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype)(*farg4); + arg5 = (N_Vector *)(farg5); + arg6 = (N_Vector *)(farg6); + result = (int)N_VLinearSumVectorArray_Parallel(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleVectorArray_Parallel(int const *farg1, double *farg2, void *farg3, void *farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector *)(farg4); + result = (int)N_VScaleVectorArray_Parallel(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstVectorArray_Parallel(int const *farg1, double const *farg2, void *farg3) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (int)N_VConstVectorArray_Parallel(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormVectorArray_Parallel(int const *farg1, void *farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VWrmsNormVectorArray_Parallel(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormMaskVectorArray_Parallel(int const *farg1, void *farg2, void *farg3, N_Vector farg4, double *farg5) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype *arg5 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype *)(farg5); + result = (int)N_VWrmsNormMaskVectorArray_Parallel(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VDotProdLocal_Parallel(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VDotProdLocal_Parallel(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMaxNormLocal_Parallel(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMaxNormLocal_Parallel(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinLocal_Parallel(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMinLocal_Parallel(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VL1NormLocal_Parallel(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VL1NormLocal_Parallel(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumLocal_Parallel(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWSqrSumLocal_Parallel(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumMaskLocal_Parallel(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWSqrSumMaskLocal_Parallel(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VInvTestLocal_Parallel(N_Vector farg1, N_Vector farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)N_VInvTestLocal_Parallel(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstrMaskLocal_Parallel(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)N_VConstrMaskLocal_Parallel(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinQuotientLocal_Parallel(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VMinQuotientLocal_Parallel(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableFusedOps_Parallel(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableFusedOps_Parallel(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableLinearCombination_Parallel(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableLinearCombination_Parallel(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableScaleAddMulti_Parallel(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableScaleAddMulti_Parallel(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableDotProdMulti_Parallel(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableDotProdMulti_Parallel(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableLinearSumVectorArray_Parallel(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableLinearSumVectorArray_Parallel(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableScaleVectorArray_Parallel(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableScaleVectorArray_Parallel(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableConstVectorArray_Parallel(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableConstVectorArray_Parallel(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableWrmsNormVectorArray_Parallel(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableWrmsNormVectorArray_Parallel(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableWrmsNormMaskVectorArray_Parallel(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableWrmsNormMaskVectorArray_Parallel(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fmod/fnvector_parallel_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fmod/fnvector_parallel_mod.f90 new file mode 100644 index 000000000..b1857b240 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fmod/fnvector_parallel_mod.f90 @@ -0,0 +1,1670 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fnvector_parallel_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FN_VNew_Parallel + public :: FN_VNewEmpty_Parallel + public :: FN_VMake_Parallel + public :: FN_VCloneVectorArray_Parallel + public :: FN_VCloneVectorArrayEmpty_Parallel + public :: FN_VDestroyVectorArray_Parallel + public :: FN_VGetLength_Parallel + public :: FN_VGetLocalLength_Parallel + public :: FN_VPrint_Parallel + public :: FN_VPrintFile_Parallel + public :: FN_VGetVectorID_Parallel + public :: FN_VCloneEmpty_Parallel + public :: FN_VClone_Parallel + public :: FN_VDestroy_Parallel + public :: FN_VSpace_Parallel + public :: FN_VGetArrayPointer_Parallel + public :: FN_VSetArrayPointer_Parallel + public :: FN_VGetCommunicator_Parallel + public :: FN_VLinearSum_Parallel + public :: FN_VConst_Parallel + public :: FN_VProd_Parallel + public :: FN_VDiv_Parallel + public :: FN_VScale_Parallel + public :: FN_VAbs_Parallel + public :: FN_VInv_Parallel + public :: FN_VAddConst_Parallel + public :: FN_VDotProd_Parallel + public :: FN_VMaxNorm_Parallel + public :: FN_VWrmsNorm_Parallel + public :: FN_VWrmsNormMask_Parallel + public :: FN_VMin_Parallel + public :: FN_VWL2Norm_Parallel + public :: FN_VL1Norm_Parallel + public :: FN_VCompare_Parallel + public :: FN_VInvTest_Parallel + public :: FN_VConstrMask_Parallel + public :: FN_VMinQuotient_Parallel + public :: FN_VLinearCombination_Parallel + public :: FN_VScaleAddMulti_Parallel + public :: FN_VDotProdMulti_Parallel + public :: FN_VLinearSumVectorArray_Parallel + public :: FN_VScaleVectorArray_Parallel + public :: FN_VConstVectorArray_Parallel + public :: FN_VWrmsNormVectorArray_Parallel + public :: FN_VWrmsNormMaskVectorArray_Parallel + public :: FN_VDotProdLocal_Parallel + public :: FN_VMaxNormLocal_Parallel + public :: FN_VMinLocal_Parallel + public :: FN_VL1NormLocal_Parallel + public :: FN_VWSqrSumLocal_Parallel + public :: FN_VWSqrSumMaskLocal_Parallel + public :: FN_VInvTestLocal_Parallel + public :: FN_VConstrMaskLocal_Parallel + public :: FN_VMinQuotientLocal_Parallel + public :: FN_VEnableFusedOps_Parallel + public :: FN_VEnableLinearCombination_Parallel + public :: FN_VEnableScaleAddMulti_Parallel + public :: FN_VEnableDotProdMulti_Parallel + public :: FN_VEnableLinearSumVectorArray_Parallel + public :: FN_VEnableScaleVectorArray_Parallel + public :: FN_VEnableConstVectorArray_Parallel + public :: FN_VEnableWrmsNormVectorArray_Parallel + public :: FN_VEnableWrmsNormMaskVectorArray_Parallel + +! WRAPPER DECLARATIONS +interface +function swigc_FN_VNew_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VNew_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FN_VNewEmpty_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VNewEmpty_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FN_VMake_Parallel(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VMake_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR) :: fresult +end function + +function swigc_FN_VCloneVectorArray_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VCloneVectorArray_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VCloneVectorArrayEmpty_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VCloneVectorArrayEmpty_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VDestroyVectorArray_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VDestroyVectorArray_Parallel") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +end subroutine + +function swigc_FN_VGetLength_Parallel(farg1) & +bind(C, name="_wrap_FN_VGetLength_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FN_VGetLocalLength_Parallel(farg1) & +bind(C, name="_wrap_FN_VGetLocalLength_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +subroutine swigc_FN_VPrint_Parallel(farg1) & +bind(C, name="_wrap_FN_VPrint_Parallel") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FN_VPrintFile_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VPrintFile_Parallel") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_FN_VGetVectorID_Parallel(farg1) & +bind(C, name="_wrap_FN_VGetVectorID_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FN_VCloneEmpty_Parallel(farg1) & +bind(C, name="_wrap_FN_VCloneEmpty_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VClone_Parallel(farg1) & +bind(C, name="_wrap_FN_VClone_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VDestroy_Parallel(farg1) & +bind(C, name="_wrap_FN_VDestroy_Parallel") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FN_VSpace_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VSpace_Parallel") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VGetArrayPointer_Parallel(farg1) & +bind(C, name="_wrap_FN_VGetArrayPointer_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VSetArrayPointer_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VSetArrayPointer_Parallel") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_FN_VGetCommunicator_Parallel(farg1) & +bind(C, name="_wrap_FN_VGetCommunicator_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VLinearSum_Parallel(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VLinearSum_Parallel") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +end subroutine + +subroutine swigc_FN_VConst_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VConst_Parallel") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VProd_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VProd_Parallel") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VDiv_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VDiv_Parallel") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VScale_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VScale_Parallel") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VAbs_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VAbs_Parallel") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VInv_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VInv_Parallel") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VAddConst_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VAddConst_Parallel") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VDotProd_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VDotProd_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMaxNorm_Parallel(farg1) & +bind(C, name="_wrap_FN_VMaxNorm_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNorm_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VWrmsNorm_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNormMask_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWrmsNormMask_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMin_Parallel(farg1) & +bind(C, name="_wrap_FN_VMin_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWL2Norm_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VWL2Norm_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VL1Norm_Parallel(farg1) & +bind(C, name="_wrap_FN_VL1Norm_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +subroutine swigc_FN_VCompare_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VCompare_Parallel") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VInvTest_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VInvTest_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstrMask_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstrMask_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VMinQuotient_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VMinQuotient_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VLinearCombination_Parallel(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VLinearCombination_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleAddMulti_Parallel(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VScaleAddMulti_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VDotProdMulti_Parallel(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VDotProdMulti_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VLinearSumVectorArray_Parallel(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FN_VLinearSumVectorArray_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleVectorArray_Parallel(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VScaleVectorArray_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstVectorArray_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstVectorArray_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormVectorArray_Parallel(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VWrmsNormVectorArray_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormMaskVectorArray_Parallel(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VWrmsNormMaskVectorArray_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VDotProdLocal_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VDotProdLocal_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMaxNormLocal_Parallel(farg1) & +bind(C, name="_wrap_FN_VMaxNormLocal_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMinLocal_Parallel(farg1) & +bind(C, name="_wrap_FN_VMinLocal_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VL1NormLocal_Parallel(farg1) & +bind(C, name="_wrap_FN_VL1NormLocal_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWSqrSumLocal_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VWSqrSumLocal_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWSqrSumMaskLocal_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWSqrSumMaskLocal_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VInvTestLocal_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VInvTestLocal_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstrMaskLocal_Parallel(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstrMaskLocal_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VMinQuotientLocal_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VMinQuotientLocal_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VEnableFusedOps_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableFusedOps_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableLinearCombination_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableLinearCombination_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableScaleAddMulti_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableScaleAddMulti_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableDotProdMulti_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableDotProdMulti_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableLinearSumVectorArray_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableLinearSumVectorArray_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableScaleVectorArray_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableScaleVectorArray_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableConstVectorArray_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableConstVectorArray_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableWrmsNormVectorArray_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableWrmsNormVectorArray_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableWrmsNormMaskVectorArray_Parallel(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableWrmsNormMaskVectorArray_Parallel") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FN_VNew_Parallel(comm, local_length, global_length) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer :: comm +integer(C_INT64_T), intent(in) :: local_length +integer(C_INT64_T), intent(in) :: global_length +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 + +farg1 = int(comm, C_INT) +farg2 = local_length +farg3 = global_length +fresult = swigc_FN_VNew_Parallel(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VNewEmpty_Parallel(comm, local_length, global_length) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer :: comm +integer(C_INT64_T), intent(in) :: local_length +integer(C_INT64_T), intent(in) :: global_length +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 + +farg1 = int(comm, C_INT) +farg2 = local_length +farg3 = global_length +fresult = swigc_FN_VNewEmpty_Parallel(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VMake_Parallel(comm, local_length, global_length, v_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer :: comm +integer(C_INT64_T), intent(in) :: local_length +integer(C_INT64_T), intent(in) :: global_length +real(C_DOUBLE), dimension(*), target, intent(inout) :: v_data +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +type(C_PTR) :: farg4 + +farg1 = int(comm, C_INT) +farg2 = local_length +farg3 = global_length +farg4 = c_loc(v_data(1)) +fresult = swigc_FN_VMake_Parallel(farg1, farg2, farg3, farg4) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VCloneVectorArray_Parallel(count, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: count +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 + +farg1 = count +farg2 = c_loc(w) +fresult = swigc_FN_VCloneVectorArray_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VCloneVectorArrayEmpty_Parallel(count, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: count +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 + +farg1 = count +farg2 = c_loc(w) +fresult = swigc_FN_VCloneVectorArrayEmpty_Parallel(farg1, farg2) +swig_result = fresult +end function + +subroutine FN_VDestroyVectorArray_Parallel(vs, count) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: vs +integer(C_INT), intent(in) :: count +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = vs +farg2 = count +call swigc_FN_VDestroyVectorArray_Parallel(farg1, farg2) +end subroutine + +function FN_VGetLength_Parallel(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetLength_Parallel(farg1) +swig_result = fresult +end function + +function FN_VGetLocalLength_Parallel(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetLocalLength_Parallel(farg1) +swig_result = fresult +end function + +subroutine FN_VPrint_Parallel(v) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +call swigc_FN_VPrint_Parallel(farg1) +end subroutine + +subroutine FN_VPrintFile_Parallel(v, outfile) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: outfile +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(v) +farg2 = outfile +call swigc_FN_VPrintFile_Parallel(farg1, farg2) +end subroutine + +function FN_VGetVectorID_Parallel(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(N_Vector_ID) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetVectorID_Parallel(farg1) +swig_result = fresult +end function + +function FN_VCloneEmpty_Parallel(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VCloneEmpty_Parallel(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VClone_Parallel(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VClone_Parallel(farg1) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FN_VDestroy_Parallel(v) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +call swigc_FN_VDestroy_Parallel(farg1) +end subroutine + +subroutine FN_VSpace_Parallel(v, lrw, liw) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), dimension(*), target, intent(inout) :: lrw +integer(C_INT64_T), dimension(*), target, intent(inout) :: liw +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(v) +farg2 = c_loc(lrw(1)) +farg3 = c_loc(liw(1)) +call swigc_FN_VSpace_Parallel(farg1, farg2, farg3) +end subroutine + +function FN_VGetArrayPointer_Parallel(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetArrayPointer_Parallel(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +subroutine FN_VSetArrayPointer_Parallel(v_data, v) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(*), target, intent(inout) :: v_data +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(v_data(1)) +farg2 = c_loc(v) +call swigc_FN_VSetArrayPointer_Parallel(farg1, farg2) +end subroutine + +function FN_VGetCommunicator_Parallel(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetCommunicator_Parallel(farg1) +swig_result = fresult +end function + +subroutine FN_VLinearSum_Parallel(a, x, b, y, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: a +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = a +farg2 = c_loc(x) +farg3 = b +farg4 = c_loc(y) +farg5 = c_loc(z) +call swigc_FN_VLinearSum_Parallel(farg1, farg2, farg3, farg4, farg5) +end subroutine + +subroutine FN_VConst_Parallel(c, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c +farg2 = c_loc(z) +call swigc_FN_VConst_Parallel(farg1, farg2) +end subroutine + +subroutine FN_VProd_Parallel(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VProd_Parallel(farg1, farg2, farg3) +end subroutine + +subroutine FN_VDiv_Parallel(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VDiv_Parallel(farg1, farg2, farg3) +end subroutine + +subroutine FN_VScale_Parallel(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VScale_Parallel(farg1, farg2, farg3) +end subroutine + +subroutine FN_VAbs_Parallel(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VAbs_Parallel(farg1, farg2) +end subroutine + +subroutine FN_VInv_Parallel(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VInv_Parallel(farg1, farg2) +end subroutine + +subroutine FN_VAddConst_Parallel(x, b, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = b +farg3 = c_loc(z) +call swigc_FN_VAddConst_Parallel(farg1, farg2, farg3) +end subroutine + +function FN_VDotProd_Parallel(x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(y) +fresult = swigc_FN_VDotProd_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VMaxNorm_Parallel(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMaxNorm_Parallel(farg1) +swig_result = fresult +end function + +function FN_VWrmsNorm_Parallel(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWrmsNorm_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VWrmsNormMask_Parallel(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWrmsNormMask_Parallel(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMin_Parallel(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMin_Parallel(farg1) +swig_result = fresult +end function + +function FN_VWL2Norm_Parallel(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWL2Norm_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VL1Norm_Parallel(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VL1Norm_Parallel(farg1) +swig_result = fresult +end function + +subroutine FN_VCompare_Parallel(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VCompare_Parallel(farg1, farg2, farg3) +end subroutine + +function FN_VInvTest_Parallel(x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +fresult = swigc_FN_VInvTest_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VConstrMask_Parallel(c, x, m) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: m +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(c) +farg2 = c_loc(x) +farg3 = c_loc(m) +fresult = swigc_FN_VConstrMask_Parallel(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMinQuotient_Parallel(num, denom) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: num +type(N_Vector), target, intent(inout) :: denom +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(num) +farg2 = c_loc(denom) +fresult = swigc_FN_VMinQuotient_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VLinearCombination_Parallel(nvec, c, v, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: v +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = v +farg4 = c_loc(z) +fresult = swigc_FN_VLinearCombination_Parallel(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VScaleAddMulti_Parallel(nvec, a, x, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvec +farg2 = c_loc(a(1)) +farg3 = c_loc(x) +farg4 = y +farg5 = z +fresult = swigc_FN_VScaleAddMulti_Parallel(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VDotProdMulti_Parallel(nvec, x, y, dotprods) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +real(C_DOUBLE), dimension(*), target, intent(inout) :: dotprods +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(x) +farg3 = y +farg4 = c_loc(dotprods(1)) +fresult = swigc_FN_VDotProdMulti_Parallel(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VLinearSumVectorArray_Parallel(nvec, a, x, b, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), intent(in) :: a +type(C_PTR) :: x +real(C_DOUBLE), intent(in) :: b +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = nvec +farg2 = a +farg3 = x +farg4 = b +farg5 = y +farg6 = z +fresult = swigc_FN_VLinearSumVectorArray_Parallel(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FN_VScaleVectorArray_Parallel(nvec, c, x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: x +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = x +farg4 = z +fresult = swigc_FN_VScaleVectorArray_Parallel(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VConstVectorArray_Parallel(nvecs, c, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvecs +real(C_DOUBLE), intent(in) :: c +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = nvecs +farg2 = c +farg3 = z +fresult = swigc_FN_VConstVectorArray_Parallel(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VWrmsNormVectorArray_Parallel(nvecs, x, w, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvecs +type(C_PTR) :: x +type(C_PTR) :: w +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvecs +farg2 = x +farg3 = w +farg4 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormVectorArray_Parallel(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VWrmsNormMaskVectorArray_Parallel(nvec, x, w, id, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(C_PTR) :: x +type(C_PTR) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvec +farg2 = x +farg3 = w +farg4 = c_loc(id) +farg5 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormMaskVectorArray_Parallel(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VDotProdLocal_Parallel(x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(y) +fresult = swigc_FN_VDotProdLocal_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VMaxNormLocal_Parallel(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMaxNormLocal_Parallel(farg1) +swig_result = fresult +end function + +function FN_VMinLocal_Parallel(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMinLocal_Parallel(farg1) +swig_result = fresult +end function + +function FN_VL1NormLocal_Parallel(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VL1NormLocal_Parallel(farg1) +swig_result = fresult +end function + +function FN_VWSqrSumLocal_Parallel(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWSqrSumLocal_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VWSqrSumMaskLocal_Parallel(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWSqrSumMaskLocal_Parallel(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VInvTestLocal_Parallel(x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +fresult = swigc_FN_VInvTestLocal_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VConstrMaskLocal_Parallel(c, x, m) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: m +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(c) +farg2 = c_loc(x) +farg3 = c_loc(m) +fresult = swigc_FN_VConstrMaskLocal_Parallel(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMinQuotientLocal_Parallel(num, denom) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: num +type(N_Vector), target, intent(inout) :: denom +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(num) +farg2 = c_loc(denom) +fresult = swigc_FN_VMinQuotientLocal_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableFusedOps_Parallel(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableFusedOps_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableLinearCombination_Parallel(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableLinearCombination_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableScaleAddMulti_Parallel(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableScaleAddMulti_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableDotProdMulti_Parallel(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableDotProdMulti_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableLinearSumVectorArray_Parallel(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableLinearSumVectorArray_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableScaleVectorArray_Parallel(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableScaleVectorArray_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableConstVectorArray_Parallel(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableConstVectorArray_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableWrmsNormVectorArray_Parallel(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableWrmsNormVectorArray_Parallel(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableWrmsNormMaskVectorArray_Parallel(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableWrmsNormMaskVectorArray_Parallel(farg1, farg2) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.c b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.c index b8812f5c8..80a8edff3 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.c +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.c @@ -3,7 +3,7 @@ * Programmer(s): Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -62,22 +62,30 @@ void FNV_INITP(MPI_Fint *comm, int *code, long int *L, long int *N, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vec = NULL; - F2C_CVODE_vec = N_VNewEmpty_Parallel(F2C_comm, *L, *N); + F2C_CVODE_vec = N_VNewEmpty_Parallel(F2C_comm, + (sunindextype)(*L), + (sunindextype)(*N)); if (F2C_CVODE_vec == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vec = NULL; - F2C_IDA_vec = N_VNewEmpty_Parallel(F2C_comm, *L, *N); + F2C_IDA_vec = N_VNewEmpty_Parallel(F2C_comm, + (sunindextype)(*L), + (sunindextype)(*N)); if (F2C_IDA_vec == NULL) *ier = -1; break; case FCMIX_KINSOL: F2C_KINSOL_vec = NULL; - F2C_KINSOL_vec = N_VNewEmpty_Parallel(F2C_comm, *L, *N); + F2C_KINSOL_vec = N_VNewEmpty_Parallel(F2C_comm, + (sunindextype)(*L), + (sunindextype)(*N)); if (F2C_KINSOL_vec == NULL) *ier = -1; break; case FCMIX_ARKODE: F2C_ARKODE_vec = NULL; - F2C_ARKODE_vec = N_VNewEmpty_Parallel(F2C_comm, *L, *N); + F2C_ARKODE_vec = N_VNewEmpty_Parallel(F2C_comm, + (sunindextype)(*L), + (sunindextype)(*N)); if (F2C_ARKODE_vec == NULL) *ier = -1; break; default: @@ -100,12 +108,16 @@ void FNV_INITP_Q(MPI_Fint *comm, int *code, long int *Lq, long int *Nq, int *ier switch(*code) { case FCMIX_CVODE: F2C_CVODE_vecQ = NULL; - F2C_CVODE_vecQ = N_VNewEmpty_Parallel(F2C_comm, *Lq, *Nq); + F2C_CVODE_vecQ = N_VNewEmpty_Parallel(F2C_comm, + (sunindextype)(*Lq), + (sunindextype)(*Nq)); if (F2C_CVODE_vecQ == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vecQ = NULL; - F2C_IDA_vecQ = N_VNewEmpty_Parallel(F2C_comm, *Lq, *Nq); + F2C_IDA_vecQ = N_VNewEmpty_Parallel(F2C_comm, + (sunindextype)(*Lq), + (sunindextype)(*Nq)); if (F2C_IDA_vecQ == NULL) *ier = -1; break; default: @@ -128,12 +140,16 @@ void FNV_INITP_B(MPI_Fint *comm, int *code, long int *LB, long int *NB, int *ier switch(*code) { case FCMIX_CVODE: F2C_CVODE_vecB = NULL; - F2C_CVODE_vecB = N_VNewEmpty_Parallel(F2C_comm, *LB, *NB); + F2C_CVODE_vecB = N_VNewEmpty_Parallel(F2C_comm, + (sunindextype)(*LB), + (sunindextype)(*NB)); if (F2C_CVODE_vecB == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vecB = NULL; - F2C_IDA_vecB = N_VNewEmpty_Parallel(F2C_comm, *LB, *NB); + F2C_IDA_vecB = N_VNewEmpty_Parallel(F2C_comm, + (sunindextype)(*LB), + (sunindextype)(*NB)); if (F2C_IDA_vecB == NULL) *ier = -1; break; default: @@ -157,12 +173,16 @@ void FNV_INITP_QB(MPI_Fint *comm, int *code, long int *LqB, long int *NqB, int * switch(*code) { case FCMIX_CVODE: F2C_CVODE_vecQB = NULL; - F2C_CVODE_vecQB = N_VNewEmpty_Parallel(F2C_comm, *LqB, *NqB); + F2C_CVODE_vecQB = N_VNewEmpty_Parallel(F2C_comm, + (sunindextype)(*LqB), + (sunindextype)(*NqB)); if (F2C_CVODE_vecQB == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vecQB = NULL; - F2C_IDA_vecQB = N_VNewEmpty_Parallel(F2C_comm, *LqB, *NqB); + F2C_IDA_vecQB = N_VNewEmpty_Parallel(F2C_comm, + (sunindextype)(*LqB), + (sunindextype)(*NqB)); if (F2C_IDA_vecQB == NULL) *ier = -1; break; default: diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.h b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.h index 3e3db9d87..1871caa9c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.h +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.h @@ -3,7 +3,7 @@ * Programmer(s): Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/nvector_parallel.c b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/nvector_parallel.c index 441b08e46..cc93aa384 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/nvector_parallel.c +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/parallel/nvector_parallel.c @@ -3,7 +3,7 @@ * and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -21,7 +21,6 @@ #include #include -#include #define ZERO RCONST(0.0) #define HALF RCONST(0.5) @@ -79,87 +78,84 @@ N_Vector N_VNewEmpty_Parallel(MPI_Comm comm, sunindextype global_length) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_Parallel content; sunindextype n, Nsum; /* Compute global length as sum of local lengths */ n = local_length; - MPI_Allreduce(&n, &Nsum, 1, PVEC_INTEGER_MPI_TYPE, MPI_SUM, comm); + MPI_Allreduce(&n, &Nsum, 1, MPI_SUNINDEXTYPE, MPI_SUM, comm); if (Nsum != global_length) { fprintf(stderr, BAD_N); return(NULL); } - /* Create vector */ + /* Create an empty vector object */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } + /* Attach operations */ - ops->nvgetvectorid = N_VGetVectorID_Parallel; - ops->nvclone = N_VClone_Parallel; - ops->nvcloneempty = N_VCloneEmpty_Parallel; - ops->nvdestroy = N_VDestroy_Parallel; - ops->nvspace = N_VSpace_Parallel; - ops->nvgetarraypointer = N_VGetArrayPointer_Parallel; - ops->nvsetarraypointer = N_VSetArrayPointer_Parallel; + /* constructors, destructors, and utility operations */ + v->ops->nvgetvectorid = N_VGetVectorID_Parallel; + v->ops->nvclone = N_VClone_Parallel; + v->ops->nvcloneempty = N_VCloneEmpty_Parallel; + v->ops->nvdestroy = N_VDestroy_Parallel; + v->ops->nvspace = N_VSpace_Parallel; + v->ops->nvgetarraypointer = N_VGetArrayPointer_Parallel; + v->ops->nvsetarraypointer = N_VSetArrayPointer_Parallel; + v->ops->nvgetcommunicator = N_VGetCommunicator_Parallel; + v->ops->nvgetlength = N_VGetLength_Parallel; /* standard vector operations */ - ops->nvlinearsum = N_VLinearSum_Parallel; - ops->nvconst = N_VConst_Parallel; - ops->nvprod = N_VProd_Parallel; - ops->nvdiv = N_VDiv_Parallel; - ops->nvscale = N_VScale_Parallel; - ops->nvabs = N_VAbs_Parallel; - ops->nvinv = N_VInv_Parallel; - ops->nvaddconst = N_VAddConst_Parallel; - ops->nvdotprod = N_VDotProd_Parallel; - ops->nvmaxnorm = N_VMaxNorm_Parallel; - ops->nvwrmsnormmask = N_VWrmsNormMask_Parallel; - ops->nvwrmsnorm = N_VWrmsNorm_Parallel; - ops->nvmin = N_VMin_Parallel; - ops->nvwl2norm = N_VWL2Norm_Parallel; - ops->nvl1norm = N_VL1Norm_Parallel; - ops->nvcompare = N_VCompare_Parallel; - ops->nvinvtest = N_VInvTest_Parallel; - ops->nvconstrmask = N_VConstrMask_Parallel; - ops->nvminquotient = N_VMinQuotient_Parallel; - - /* fused vector operations (optional, NULL means disabled by default) */ - ops->nvlinearcombination = NULL; - ops->nvscaleaddmulti = NULL; - ops->nvdotprodmulti = NULL; - - /* vector array operations (optional, NULL means disabled by default) */ - ops->nvlinearsumvectorarray = NULL; - ops->nvscalevectorarray = NULL; - ops->nvconstvectorarray = NULL; - ops->nvwrmsnormvectorarray = NULL; - ops->nvwrmsnormmaskvectorarray = NULL; - ops->nvscaleaddmultivectorarray = NULL; - ops->nvlinearcombinationvectorarray = NULL; - + v->ops->nvlinearsum = N_VLinearSum_Parallel; + v->ops->nvconst = N_VConst_Parallel; + v->ops->nvprod = N_VProd_Parallel; + v->ops->nvdiv = N_VDiv_Parallel; + v->ops->nvscale = N_VScale_Parallel; + v->ops->nvabs = N_VAbs_Parallel; + v->ops->nvinv = N_VInv_Parallel; + v->ops->nvaddconst = N_VAddConst_Parallel; + v->ops->nvdotprod = N_VDotProd_Parallel; + v->ops->nvmaxnorm = N_VMaxNorm_Parallel; + v->ops->nvwrmsnormmask = N_VWrmsNormMask_Parallel; + v->ops->nvwrmsnorm = N_VWrmsNorm_Parallel; + v->ops->nvmin = N_VMin_Parallel; + v->ops->nvwl2norm = N_VWL2Norm_Parallel; + v->ops->nvl1norm = N_VL1Norm_Parallel; + v->ops->nvcompare = N_VCompare_Parallel; + v->ops->nvinvtest = N_VInvTest_Parallel; + v->ops->nvconstrmask = N_VConstrMask_Parallel; + v->ops->nvminquotient = N_VMinQuotient_Parallel; + + /* fused and vector array operations are disabled (NULL) by default */ + + /* local reduction operations */ + v->ops->nvdotprodlocal = N_VDotProdLocal_Parallel; + v->ops->nvmaxnormlocal = N_VMaxNormLocal_Parallel; + v->ops->nvminlocal = N_VMinLocal_Parallel; + v->ops->nvl1normlocal = N_VL1NormLocal_Parallel; + v->ops->nvinvtestlocal = N_VInvTestLocal_Parallel; + v->ops->nvconstrmasklocal = N_VConstrMaskLocal_Parallel; + v->ops->nvminquotientlocal = N_VMinQuotientLocal_Parallel; + v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_Parallel; + v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_Parallel; + /* Create content */ content = NULL; - content = (N_VectorContent_Parallel) malloc(sizeof(struct _N_VectorContent_Parallel)); - if (content == NULL) { free(ops); free(v); return(NULL); } + content = (N_VectorContent_Parallel) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } + + /* Attach content */ + v->content = content; - /* Attach lengths and communicator */ + /* Initialize content */ content->local_length = local_length; content->global_length = global_length; content->comm = comm; content->own_data = SUNFALSE; content->data = NULL; - /* Attach content and ops */ - v->content = content; - v->ops = ops; - return(v); } @@ -223,15 +219,15 @@ N_Vector N_VMake_Parallel(MPI_Comm comm, * Function to create an array of new parallel vectors. */ -N_Vector *N_VCloneVectorArray_Parallel(int count, N_Vector w) +N_Vector* N_VCloneVectorArray_Parallel(int count, N_Vector w) { - N_Vector *vs; + N_Vector* vs; int j; if (count <= 0) return(NULL); vs = NULL; - vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + vs = (N_Vector*) malloc(count * sizeof(N_Vector)); if(vs == NULL) return(NULL); for (j = 0; j < count; j++) { @@ -251,15 +247,15 @@ N_Vector *N_VCloneVectorArray_Parallel(int count, N_Vector w) * (NULL) data array. */ -N_Vector *N_VCloneVectorArrayEmpty_Parallel(int count, N_Vector w) +N_Vector* N_VCloneVectorArrayEmpty_Parallel(int count, N_Vector w) { - N_Vector *vs; + N_Vector* vs; int j; if (count <= 0) return(NULL); vs = NULL; - vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + vs = (N_Vector*) malloc(count * sizeof(N_Vector)); if(vs == NULL) return(NULL); for (j = 0; j < count; j++) { @@ -278,7 +274,7 @@ N_Vector *N_VCloneVectorArrayEmpty_Parallel(int count, N_Vector w) * Function to free an array created with N_VCloneVectorArray_Parallel */ -void N_VDestroyVectorArray_Parallel(N_Vector *vs, int count) +void N_VDestroyVectorArray_Parallel(N_Vector* vs, int count) { int j; @@ -353,80 +349,33 @@ void N_VPrintFile_Parallel(N_Vector x, FILE* outfile) N_Vector N_VCloneEmpty_Parallel(N_Vector w) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_Parallel content; if (w == NULL) return(NULL); /* Create vector */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } - - ops->nvgetvectorid = w->ops->nvgetvectorid; - ops->nvclone = w->ops->nvclone; - ops->nvcloneempty = w->ops->nvcloneempty; - ops->nvdestroy = w->ops->nvdestroy; - ops->nvspace = w->ops->nvspace; - ops->nvgetarraypointer = w->ops->nvgetarraypointer; - ops->nvsetarraypointer = w->ops->nvsetarraypointer; - - /* standard vector operations */ - ops->nvlinearsum = w->ops->nvlinearsum; - ops->nvconst = w->ops->nvconst; - ops->nvprod = w->ops->nvprod; - ops->nvdiv = w->ops->nvdiv; - ops->nvscale = w->ops->nvscale; - ops->nvabs = w->ops->nvabs; - ops->nvinv = w->ops->nvinv; - ops->nvaddconst = w->ops->nvaddconst; - ops->nvdotprod = w->ops->nvdotprod; - ops->nvmaxnorm = w->ops->nvmaxnorm; - ops->nvwrmsnormmask = w->ops->nvwrmsnormmask; - ops->nvwrmsnorm = w->ops->nvwrmsnorm; - ops->nvmin = w->ops->nvmin; - ops->nvwl2norm = w->ops->nvwl2norm; - ops->nvl1norm = w->ops->nvl1norm; - ops->nvcompare = w->ops->nvcompare; - ops->nvinvtest = w->ops->nvinvtest; - ops->nvconstrmask = w->ops->nvconstrmask; - ops->nvminquotient = w->ops->nvminquotient; - - /* fused vector operations */ - ops->nvlinearcombination = w->ops->nvlinearcombination; - ops->nvscaleaddmulti = w->ops->nvscaleaddmulti; - ops->nvdotprodmulti = w->ops->nvdotprodmulti; - - /* vector array operations */ - ops->nvlinearsumvectorarray = w->ops->nvlinearsumvectorarray; - ops->nvscalevectorarray = w->ops->nvscalevectorarray; - ops->nvconstvectorarray = w->ops->nvconstvectorarray; - ops->nvwrmsnormvectorarray = w->ops->nvwrmsnormvectorarray; - ops->nvwrmsnormmaskvectorarray = w->ops->nvwrmsnormmaskvectorarray; - ops->nvscaleaddmultivectorarray = w->ops->nvscaleaddmultivectorarray; - ops->nvlinearcombinationvectorarray = w->ops->nvlinearcombinationvectorarray; - + /* Attach operations */ + if (N_VCopyOps(w, v)) { N_VDestroy(v); return(NULL); } + /* Create content */ content = NULL; - content = (N_VectorContent_Parallel) malloc(sizeof(struct _N_VectorContent_Parallel)); - if (content == NULL) { free(ops); free(v); return(NULL); } + content = (N_VectorContent_Parallel) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } - /* Attach lengths and communicator */ + /* Attach content */ + v->content = content; + + /* Initialize content */ content->local_length = NV_LOCLENGTH_P(w); content->global_length = NV_GLOBLENGTH_P(w); content->comm = NV_COMM_P(w); content->own_data = SUNFALSE; content->data = NULL; - /* Attach content and ops */ - v->content = content; - v->ops = ops; - return(v); } @@ -460,12 +409,20 @@ N_Vector N_VClone_Parallel(N_Vector w) void N_VDestroy_Parallel(N_Vector v) { - if ((NV_OWN_DATA_P(v) == SUNTRUE) && (NV_DATA_P(v) != NULL)) { - free(NV_DATA_P(v)); - NV_DATA_P(v) = NULL; + if (v == NULL) return; + + /* free content */ + if (v->content != NULL) { + if (NV_OWN_DATA_P(v) && NV_DATA_P(v) != NULL) { + free(NV_DATA_P(v)); + NV_DATA_P(v) = NULL; + } + free(v->content); + v->content = NULL; } - free(v->content); v->content = NULL; - free(v->ops); v->ops = NULL; + + /* free ops and vector */ + if (v->ops != NULL) { free(v->ops); v->ops = NULL; } free(v); v = NULL; return; @@ -497,6 +454,11 @@ void N_VSetArrayPointer_Parallel(realtype *v_data, N_Vector v) return; } +void *N_VGetCommunicator_Parallel(N_Vector v) +{ + return((void *) &(NV_COMM_P(v))); +} + void N_VLinearSum_Parallel(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) { sunindextype i, N; @@ -712,11 +674,10 @@ void N_VAddConst_Parallel(N_Vector x, realtype b, N_Vector z) return; } -realtype N_VDotProd_Parallel(N_Vector x, N_Vector y) +realtype N_VDotProdLocal_Parallel(N_Vector x, N_Vector y) { sunindextype i, N; - realtype sum, *xd, *yd, gsum; - MPI_Comm comm; + realtype sum, *xd, *yd; sum = ZERO; xd = yd = NULL; @@ -724,78 +685,85 @@ realtype N_VDotProd_Parallel(N_Vector x, N_Vector y) N = NV_LOCLENGTH_P(x); xd = NV_DATA_P(x); yd = NV_DATA_P(y); - comm = NV_COMM_P(x); for (i = 0; i < N; i++) sum += xd[i]*yd[i]; + return(sum); +} - gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); - +realtype N_VDotProd_Parallel(N_Vector x, N_Vector y) +{ + realtype lsum, gsum; + lsum = N_VDotProdLocal_Parallel(x,y); + MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, NV_COMM_P(x)); return(gsum); } -realtype N_VMaxNorm_Parallel(N_Vector x) +realtype N_VMaxNormLocal_Parallel(N_Vector x) { sunindextype i, N; - realtype max, *xd, gmax; - MPI_Comm comm; + realtype max, *xd; xd = NULL; N = NV_LOCLENGTH_P(x); xd = NV_DATA_P(x); - comm = NV_COMM_P(x); max = ZERO; - for (i = 0; i < N; i++) { + for (i = 0; i < N; i++) if (SUNRabs(xd[i]) > max) max = SUNRabs(xd[i]); - } - gmax = SUNMPI_Allreduce_scalar(max, 2, comm); + return(max); +} +realtype N_VMaxNorm_Parallel(N_Vector x) +{ + realtype lmax, gmax; + lmax = N_VMaxNormLocal_Parallel(x); + MPI_Allreduce(&lmax, &gmax, 1, MPI_SUNREALTYPE, MPI_MAX, NV_COMM_P(x)); return(gmax); } -realtype N_VWrmsNorm_Parallel(N_Vector x, N_Vector w) +realtype N_VWSqrSumLocal_Parallel(N_Vector x, N_Vector w) { - sunindextype i, N, N_global; - realtype sum, prodi, *xd, *wd, gsum; - MPI_Comm comm; + sunindextype i, N; + realtype sum, prodi, *xd, *wd; sum = ZERO; xd = wd = NULL; - N = NV_LOCLENGTH_P(x); - N_global = NV_GLOBLENGTH_P(x); - xd = NV_DATA_P(x); - wd = NV_DATA_P(w); - comm = NV_COMM_P(x); + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + wd = NV_DATA_P(w); for (i = 0; i < N; i++) { prodi = xd[i]*wd[i]; sum += SUNSQR(prodi); } - gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); + return(sum); +} - return(SUNRsqrt(gsum/N_global)); +realtype N_VWrmsNorm_Parallel(N_Vector x, N_Vector w) +{ + realtype lsum, gsum; + lsum = N_VWSqrSumLocal_Parallel(x, w); + MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, NV_COMM_P(x)); + return(SUNRsqrt(gsum/(NV_GLOBLENGTH_P(x)))); } -realtype N_VWrmsNormMask_Parallel(N_Vector x, N_Vector w, N_Vector id) +realtype N_VWSqrSumMaskLocal_Parallel(N_Vector x, N_Vector w, N_Vector id) { - sunindextype i, N, N_global; - realtype sum, prodi, *xd, *wd, *idd, gsum; - MPI_Comm comm; + sunindextype i, N; + realtype sum, prodi, *xd, *wd, *idd; sum = ZERO; xd = wd = idd = NULL; - N = NV_LOCLENGTH_P(x); - N_global = NV_GLOBLENGTH_P(x); - xd = NV_DATA_P(x); - wd = NV_DATA_P(w); - idd = NV_DATA_P(id); - comm = NV_COMM_P(x); + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + wd = NV_DATA_P(w); + idd = NV_DATA_P(id); for (i = 0; i < N; i++) { if (idd[i] > ZERO) { @@ -803,84 +771,72 @@ realtype N_VWrmsNormMask_Parallel(N_Vector x, N_Vector w, N_Vector id) sum += SUNSQR(prodi); } } + return(sum); +} - gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); - - return(SUNRsqrt(gsum/N_global)); +realtype N_VWrmsNormMask_Parallel(N_Vector x, N_Vector w, N_Vector id) +{ + realtype lsum, gsum; + lsum = N_VWSqrSumMaskLocal_Parallel(x, w, id); + MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, NV_COMM_P(x)); + return(SUNRsqrt(gsum/(NV_GLOBLENGTH_P(x)))); } -realtype N_VMin_Parallel(N_Vector x) +realtype N_VMinLocal_Parallel(N_Vector x) { sunindextype i, N; - realtype min, *xd, gmin; - MPI_Comm comm; - - xd = NULL; - - N = NV_LOCLENGTH_P(x); - comm = NV_COMM_P(x); + realtype min, *xd; + xd = NULL; + N = NV_LOCLENGTH_P(x); min = BIG_REAL; if (N > 0) { - xd = NV_DATA_P(x); - min = xd[0]; - - for (i = 1; i < N; i++) { + for (i = 1; i < N; i++) if (xd[i] < min) min = xd[i]; - } - } + return(min); +} - gmin = SUNMPI_Allreduce_scalar(min, 3, comm); - +realtype N_VMin_Parallel(N_Vector x) +{ + realtype lmin, gmin; + lmin = N_VMinLocal_Parallel(x); + MPI_Allreduce(&lmin, &gmin, 1, MPI_SUNREALTYPE, MPI_MIN, NV_COMM_P(x)); return(gmin); } realtype N_VWL2Norm_Parallel(N_Vector x, N_Vector w) { - sunindextype i, N; - realtype sum, prodi, *xd, *wd, gsum; - MPI_Comm comm; - - sum = ZERO; - xd = wd = NULL; - - N = NV_LOCLENGTH_P(x); - xd = NV_DATA_P(x); - wd = NV_DATA_P(w); - comm = NV_COMM_P(x); - - for (i = 0; i < N; i++) { - prodi = xd[i]*wd[i]; - sum += SUNSQR(prodi); - } - - gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); - + realtype lsum, gsum; + lsum = N_VWSqrSumLocal_Parallel(x, w); + MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, NV_COMM_P(x)); return(SUNRsqrt(gsum)); } -realtype N_VL1Norm_Parallel(N_Vector x) +realtype N_VL1NormLocal_Parallel(N_Vector x) { sunindextype i, N; - realtype sum, gsum, *xd; - MPI_Comm comm; + realtype sum, *xd; sum = ZERO; - xd = NULL; - - N = NV_LOCLENGTH_P(x); - xd = NV_DATA_P(x); - comm = NV_COMM_P(x); + xd = NULL; + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); for (i = 0; i #include -#include #define ZERO RCONST(0.0) #define HALF RCONST(0.5) #define ONE RCONST(1.0) #define ONEPT5 RCONST(1.5) -/* Error Message */ -#define BAD_N1 "N_VNew_ParHyp -- Sum of local vector lengths differs from " -#define BAD_N2 "input global length. \n\n" -#define BAD_N BAD_N1 BAD_N2 - /* * ----------------------------------------------------------------- * Simplifying macros NV_CONTENT_PH, NV_DATA_PH, NV_LOCLENGTH_PH, @@ -153,66 +147,67 @@ N_Vector N_VNewEmpty_ParHyp(MPI_Comm comm, sunindextype global_length) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_ParHyp content; - /* Create vector */ + /* Create an empty vector object */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } + /* Attach operations */ - ops->nvgetvectorid = N_VGetVectorID_ParHyp; - ops->nvclone = N_VClone_ParHyp; - ops->nvcloneempty = N_VCloneEmpty_ParHyp; - ops->nvdestroy = N_VDestroy_ParHyp; - ops->nvspace = N_VSpace_ParHyp; - ops->nvgetarraypointer = N_VGetArrayPointer_ParHyp; - ops->nvsetarraypointer = N_VSetArrayPointer_ParHyp; + /* constructors, destructors, and utility operations */ + v->ops->nvgetvectorid = N_VGetVectorID_ParHyp; + v->ops->nvclone = N_VClone_ParHyp; + v->ops->nvcloneempty = N_VCloneEmpty_ParHyp; + v->ops->nvdestroy = N_VDestroy_ParHyp; + v->ops->nvspace = N_VSpace_ParHyp; + v->ops->nvgetarraypointer = N_VGetArrayPointer_ParHyp; + v->ops->nvsetarraypointer = N_VSetArrayPointer_ParHyp; + v->ops->nvgetcommunicator = N_VGetCommunicator_ParHyp; + v->ops->nvgetlength = N_VGetLength_ParHyp; /* standard vector operations */ - ops->nvlinearsum = N_VLinearSum_ParHyp; - ops->nvconst = N_VConst_ParHyp; - ops->nvprod = N_VProd_ParHyp; - ops->nvdiv = N_VDiv_ParHyp; - ops->nvscale = N_VScale_ParHyp; - ops->nvabs = N_VAbs_ParHyp; - ops->nvinv = N_VInv_ParHyp; - ops->nvaddconst = N_VAddConst_ParHyp; - ops->nvdotprod = N_VDotProd_ParHyp; - ops->nvmaxnorm = N_VMaxNorm_ParHyp; - ops->nvwrmsnormmask = N_VWrmsNormMask_ParHyp; - ops->nvwrmsnorm = N_VWrmsNorm_ParHyp; - ops->nvmin = N_VMin_ParHyp; - ops->nvwl2norm = N_VWL2Norm_ParHyp; - ops->nvl1norm = N_VL1Norm_ParHyp; - ops->nvcompare = N_VCompare_ParHyp; - ops->nvinvtest = N_VInvTest_ParHyp; - ops->nvconstrmask = N_VConstrMask_ParHyp; - ops->nvminquotient = N_VMinQuotient_ParHyp; - - /* fused vector operations (optional, NULL means disabled by default) */ - ops->nvlinearcombination = NULL; - ops->nvscaleaddmulti = NULL; - ops->nvdotprodmulti = NULL; - - /* vector array operations (optional, NULL means disabled by default) */ - ops->nvlinearsumvectorarray = NULL; - ops->nvscalevectorarray = NULL; - ops->nvconstvectorarray = NULL; - ops->nvwrmsnormvectorarray = NULL; - ops->nvwrmsnormmaskvectorarray = NULL; - ops->nvscaleaddmultivectorarray = NULL; - ops->nvlinearcombinationvectorarray = NULL; + v->ops->nvlinearsum = N_VLinearSum_ParHyp; + v->ops->nvconst = N_VConst_ParHyp; + v->ops->nvprod = N_VProd_ParHyp; + v->ops->nvdiv = N_VDiv_ParHyp; + v->ops->nvscale = N_VScale_ParHyp; + v->ops->nvabs = N_VAbs_ParHyp; + v->ops->nvinv = N_VInv_ParHyp; + v->ops->nvaddconst = N_VAddConst_ParHyp; + v->ops->nvdotprod = N_VDotProd_ParHyp; + v->ops->nvmaxnorm = N_VMaxNorm_ParHyp; + v->ops->nvwrmsnormmask = N_VWrmsNormMask_ParHyp; + v->ops->nvwrmsnorm = N_VWrmsNorm_ParHyp; + v->ops->nvmin = N_VMin_ParHyp; + v->ops->nvwl2norm = N_VWL2Norm_ParHyp; + v->ops->nvl1norm = N_VL1Norm_ParHyp; + v->ops->nvcompare = N_VCompare_ParHyp; + v->ops->nvinvtest = N_VInvTest_ParHyp; + v->ops->nvconstrmask = N_VConstrMask_ParHyp; + v->ops->nvminquotient = N_VMinQuotient_ParHyp; + + /* fused and vector array operations are disabled (NULL) by default */ + + /* local reduction operations */ + v->ops->nvdotprodlocal = N_VDotProdLocal_ParHyp; + v->ops->nvmaxnormlocal = N_VMaxNormLocal_ParHyp; + v->ops->nvminlocal = N_VMinLocal_ParHyp; + v->ops->nvl1normlocal = N_VL1NormLocal_ParHyp; + v->ops->nvinvtestlocal = N_VInvTestLocal_ParHyp; + v->ops->nvconstrmasklocal = N_VConstrMaskLocal_ParHyp; + v->ops->nvminquotientlocal = N_VMinQuotientLocal_ParHyp; + v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_ParHyp; + v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_ParHyp; /* Create content */ content = NULL; - content = (N_VectorContent_ParHyp) malloc(sizeof(struct _N_VectorContent_ParHyp)); - if (content == NULL) { free(ops); free(v); return(NULL); } + content = (N_VectorContent_ParHyp) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } + + /* Attach content */ + v->content = content; /* Attach lengths and communicator */ content->local_length = local_length; @@ -221,10 +216,6 @@ N_Vector N_VNewEmpty_ParHyp(MPI_Comm comm, content->own_parvector = SUNFALSE; content->x = NULL; - /* Attach content and ops */ - v->content = content; - v->ops = ops; - return(v); } @@ -238,10 +229,10 @@ N_Vector N_VMake_ParHyp(HYPRE_ParVector x) { N_Vector v; MPI_Comm comm = hypre_ParVectorComm(x); - HYPRE_Int global_length = hypre_ParVectorGlobalSize(x); - HYPRE_Int local_begin = hypre_ParVectorFirstIndex(x); - HYPRE_Int local_end = hypre_ParVectorLastIndex(x); - HYPRE_Int local_length = local_end - local_begin + 1; + sunindextype global_length = (sunindextype) hypre_ParVectorGlobalSize(x); + sunindextype local_begin = (sunindextype) hypre_ParVectorFirstIndex(x); + sunindextype local_end = (sunindextype) hypre_ParVectorLastIndex(x); + sunindextype local_length = local_end - local_begin + 1; v = NULL; v = N_VNewEmpty_ParHyp(comm, local_length, global_length); @@ -385,85 +376,33 @@ void N_VPrintFile_ParHyp(N_Vector x, FILE *outfile) N_Vector N_VCloneEmpty_ParHyp(N_Vector w) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_ParHyp content; if (w == NULL) return(NULL); /* Create vector */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Added variables for hypre_parhyp intialization */ - int nprocs, myid; - MPI_Comm_size(NV_COMM_PH(w), &nprocs); - MPI_Comm_rank(NV_COMM_PH(w), &myid); - - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } - - ops->nvgetvectorid = w->ops->nvgetvectorid; - ops->nvclone = w->ops->nvclone; - ops->nvcloneempty = w->ops->nvcloneempty; - ops->nvdestroy = w->ops->nvdestroy; - ops->nvspace = w->ops->nvspace; - ops->nvgetarraypointer = w->ops->nvgetarraypointer; - ops->nvsetarraypointer = w->ops->nvsetarraypointer; - - /* standard vector operations */ - ops->nvlinearsum = w->ops->nvlinearsum; - ops->nvconst = w->ops->nvconst; - ops->nvprod = w->ops->nvprod; - ops->nvdiv = w->ops->nvdiv; - ops->nvscale = w->ops->nvscale; - ops->nvabs = w->ops->nvabs; - ops->nvinv = w->ops->nvinv; - ops->nvaddconst = w->ops->nvaddconst; - ops->nvdotprod = w->ops->nvdotprod; - ops->nvmaxnorm = w->ops->nvmaxnorm; - ops->nvwrmsnormmask = w->ops->nvwrmsnormmask; - ops->nvwrmsnorm = w->ops->nvwrmsnorm; - ops->nvmin = w->ops->nvmin; - ops->nvwl2norm = w->ops->nvwl2norm; - ops->nvl1norm = w->ops->nvl1norm; - ops->nvcompare = w->ops->nvcompare; - ops->nvinvtest = w->ops->nvinvtest; - ops->nvconstrmask = w->ops->nvconstrmask; - ops->nvminquotient = w->ops->nvminquotient; - - /* fused vector operations */ - ops->nvlinearcombination = w->ops->nvlinearcombination; - ops->nvscaleaddmulti = w->ops->nvscaleaddmulti; - ops->nvdotprodmulti = w->ops->nvdotprodmulti; - - /* vector array operations */ - ops->nvlinearsumvectorarray = w->ops->nvlinearsumvectorarray; - ops->nvscalevectorarray = w->ops->nvscalevectorarray; - ops->nvconstvectorarray = w->ops->nvconstvectorarray; - ops->nvwrmsnormvectorarray = w->ops->nvwrmsnormvectorarray; - ops->nvwrmsnormmaskvectorarray = w->ops->nvwrmsnormmaskvectorarray; - ops->nvscaleaddmultivectorarray = w->ops->nvscaleaddmultivectorarray; - ops->nvlinearcombinationvectorarray = w->ops->nvlinearcombinationvectorarray; + /* Attach operations */ + if (N_VCopyOps(w, v)) { N_VDestroy(v); return(NULL); } /* Create content */ content = NULL; - content = (N_VectorContent_ParHyp) malloc(sizeof(struct _N_VectorContent_ParHyp)); - if (content == NULL) { free(ops); free(v); return(NULL); } + content = (N_VectorContent_ParHyp) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } - /* Attach lengths and communicator */ + /* Attach content */ + v->content = content; + + /* Initialize content */ content->local_length = NV_LOCLENGTH_PH(w); content->global_length = NV_GLOBLENGTH_PH(w); content->comm = NV_COMM_PH(w); content->own_parvector = SUNFALSE; content->x = NULL; - /* Attach content and ops */ - v->content = content; - v->ops = ops; - return(v); } @@ -479,8 +418,7 @@ N_Vector N_VClone_ParHyp(N_Vector w) v = NULL; v = N_VCloneEmpty_ParHyp(w); - if (v==NULL) - return(NULL); + if (v==NULL) return(NULL); vx = hypre_ParVectorCreate(wx->comm, wx->global_size, wx->partitioning); hypre_ParVectorInitialize(vx); @@ -490,19 +428,28 @@ N_Vector N_VClone_ParHyp(N_Vector w) hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(vx), 1); NV_HYPRE_PARVEC_PH(v) = vx; - NV_OWN_PARVEC_PH(v) = SUNTRUE; + NV_OWN_PARVEC_PH(v) = SUNTRUE; return(v); } void N_VDestroy_ParHyp(N_Vector v) { - if ((NV_OWN_PARVEC_PH(v) == SUNTRUE)) { - hypre_ParVectorDestroy(NV_HYPRE_PARVEC_PH(v)); + if (v == NULL) return; + + /* free content */ + if (v->content != NULL) { + /* free the hypre parvector if it's owned by the vector wrapper */ + if (NV_OWN_PARVEC_PH(v) && NV_HYPRE_PARVEC_PH(v) != NULL) { + hypre_ParVectorDestroy(NV_HYPRE_PARVEC_PH(v)); + NV_HYPRE_PARVEC_PH(v) = NULL; + } + free(v->content); + v->content = NULL; } - free(v->content); v->content = NULL; - free(v->ops); v->ops = NULL; + /* free ops and vector */ + if (v->ops != NULL) { free(v->ops); v->ops = NULL; } free(v); v = NULL; return; @@ -545,6 +492,17 @@ void N_VSetArrayPointer_ParHyp(realtype *v_data, N_Vector v) /* Not implemented for Hypre vector */ } + +void *N_VGetCommunicator_ParHyp(N_Vector v) +{ + return((void *) &(NV_COMM_PH(v))); +} + +sunindextype N_VGetLength_ParHyp(N_Vector v) +{ + return(NV_GLOBLENGTH_PH(v)); +} + /* * Computes z[i] = a*x[i] + b*y[i] * @@ -757,9 +715,22 @@ void N_VAddConst_ParHyp(N_Vector x, realtype b, N_Vector z) return; } -realtype N_VDotProd_ParHyp(N_Vector x, N_Vector y) +realtype N_VDotProdLocal_ParHyp(N_Vector x, N_Vector y) { + sunindextype i, N; + realtype sum, *xd, *yd; + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + yd = NV_DATA_PH(y); + + sum = ZERO; + for (i = 0; i < N; i++) + sum += xd[i]*yd[i]; + return(sum); +} +realtype N_VDotProd_ParHyp(N_Vector x, N_Vector y) +{ HYPRE_Real gsum; HYPRE_ParVectorInnerProd( (HYPRE_ParVector) NV_HYPRE_PARVEC_PH(x), (HYPRE_ParVector) NV_HYPRE_PARVEC_PH(y), &gsum); @@ -767,155 +738,133 @@ realtype N_VDotProd_ParHyp(N_Vector x, N_Vector y) return(gsum); } -realtype N_VMaxNorm_ParHyp(N_Vector x) +realtype N_VMaxNormLocal_ParHyp(N_Vector x) { sunindextype i, N; - realtype max, *xd, gmax; - MPI_Comm comm; - - xd = NULL; + realtype max, *xd; N = NV_LOCLENGTH_PH(x); xd = NV_DATA_PH(x); - comm = NV_COMM_PH(x); max = ZERO; - - for (i = 0; i < N; i++) { + for (i = 0; i < N; i++) if (SUNRabs(xd[i]) > max) max = SUNRabs(xd[i]); - } - - gmax = SUNMPI_Allreduce_scalar(max, 2, comm); + return(max); +} +realtype N_VMaxNorm_ParHyp(N_Vector x) +{ + realtype lmax, gmax; + lmax = N_VMaxNormLocal_ParHyp(x); + MPI_Allreduce(&lmax, &gmax, 1, MPI_SUNREALTYPE, MPI_MAX, NV_COMM_PH(x)); return(gmax); } -realtype N_VWrmsNorm_ParHyp(N_Vector x, N_Vector w) +realtype N_VWSqrSumLocal_ParHyp(N_Vector x, N_Vector w) { - sunindextype i, N, N_global; - realtype sum, prodi, *xd, *wd, gsum; - MPI_Comm comm; - - sum = ZERO; - xd = wd = NULL; + sunindextype i, N; + realtype sum, prodi, *xd, *wd; - N = NV_LOCLENGTH_PH(x); - N_global = NV_GLOBLENGTH_PH(x); - xd = NV_DATA_PH(x); - wd = NV_DATA_PH(w); - comm = NV_COMM_PH(x); + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + wd = NV_DATA_PH(w); + sum = ZERO; for (i = 0; i < N; i++) { prodi = xd[i]*wd[i]; sum += SUNSQR(prodi); } - - gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); - - return(SUNRsqrt(gsum/N_global)); + return(sum); } -realtype N_VWrmsNormMask_ParHyp(N_Vector x, N_Vector w, N_Vector id) +realtype N_VWrmsNorm_ParHyp(N_Vector x, N_Vector w) { - sunindextype i, N, N_global; - realtype sum, prodi, *xd, *wd, *idd, gsum; - MPI_Comm comm; + realtype lsum, gsum; + lsum = N_VWSqrSumLocal_ParHyp(x, w); + MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, NV_COMM_PH(x)); + return(SUNRsqrt(gsum/(NV_GLOBLENGTH_PH(x)))); +} - sum = ZERO; - xd = wd = idd = NULL; +realtype N_VWSqrSumMaskLocal_ParHyp(N_Vector x, N_Vector w, N_Vector id) +{ + sunindextype i, N; + realtype sum, prodi, *xd, *wd, *idd; - N = NV_LOCLENGTH_PH(x); - N_global = NV_GLOBLENGTH_PH(x); - xd = NV_DATA_PH(x); - wd = NV_DATA_PH(w); - idd = NV_DATA_PH(id); - comm = NV_COMM_PH(x); + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + wd = NV_DATA_PH(w); + idd = NV_DATA_PH(id); + sum = ZERO; for (i = 0; i < N; i++) { if (idd[i] > ZERO) { prodi = xd[i]*wd[i]; sum += SUNSQR(prodi); } } + return(sum); +} - gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); - - return(SUNRsqrt(gsum/N_global)); +realtype N_VWrmsNormMask_ParHyp(N_Vector x, N_Vector w, N_Vector id) +{ + realtype lsum, gsum; + lsum = N_VWSqrSumMaskLocal_ParHyp(x, w, id); + MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, NV_COMM_PH(x)); + return(SUNRsqrt(gsum/(NV_GLOBLENGTH_PH(x)))); } -realtype N_VMin_ParHyp(N_Vector x) +realtype N_VMinLocal_ParHyp(N_Vector x) { sunindextype i, N; - realtype min, *xd, gmin; - MPI_Comm comm; - - xd = NULL; - - N = NV_LOCLENGTH_PH(x); - comm = NV_COMM_PH(x); + realtype min, *xd; + xd = NULL; + N = NV_LOCLENGTH_PH(x); min = BIG_REAL; if (N > 0) { - xd = NV_DATA_PH(x); - min = xd[0]; - - for (i = 1; i < N; i++) { - if (xd[i] < min) - min = xd[i]; - } - + for (i = 1; i < N; i++) + if (xd[i] < min) min = xd[i]; } + return(min); +} - gmin = SUNMPI_Allreduce_scalar(min, 3, comm); - +realtype N_VMin_ParHyp(N_Vector x) +{ + realtype lmin, gmin; + lmin = N_VMinLocal_ParHyp(x); + MPI_Allreduce(&lmin, &gmin, 1, MPI_SUNREALTYPE, MPI_MIN, NV_COMM_PH(x)); return(gmin); } realtype N_VWL2Norm_ParHyp(N_Vector x, N_Vector w) { - sunindextype i, N; - realtype sum, prodi, *xd, *wd, gsum; - MPI_Comm comm; - - sum = ZERO; - xd = wd = NULL; - - N = NV_LOCLENGTH_PH(x); - xd = NV_DATA_PH(x); - wd = NV_DATA_PH(w); - comm = NV_COMM_PH(x); - - for (i = 0; i < N; i++) { - prodi = xd[i]*wd[i]; - sum += SUNSQR(prodi); - } - - gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); - + realtype lsum, gsum; + lsum = N_VWSqrSumLocal_ParHyp(x, w); + MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, NV_COMM_PH(x)); return(SUNRsqrt(gsum)); } -realtype N_VL1Norm_ParHyp(N_Vector x) +realtype N_VL1NormLocal_ParHyp(N_Vector x) { sunindextype i, N; - realtype sum, gsum, *xd; - MPI_Comm comm; + realtype sum, *xd; + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); sum = ZERO; - xd = NULL; - - N = NV_LOCLENGTH_PH(x); - xd = NV_DATA_PH(x); - comm = NV_COMM_PH(x); - for (i = 0; i #include -#include #define ZERO RCONST(0.0) #define HALF RCONST(0.5) @@ -119,93 +118,86 @@ N_Vector N_VNewEmpty_Petsc(MPI_Comm comm, sunindextype global_length) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_Petsc content; sunindextype n, Nsum; PetscErrorCode ierr; /* Compute global length as sum of local lengths */ n = local_length; - ierr = MPI_Allreduce(&n, &Nsum, 1, PVEC_INTEGER_MPI_TYPE, MPI_SUM, comm); + ierr = MPI_Allreduce(&n, &Nsum, 1, MPI_SUNINDEXTYPE, MPI_SUM, comm); CHKERRABORT(comm,ierr); if (Nsum != global_length) { fprintf(stderr, BAD_N); return(NULL); } - /* Create vector */ + /* Create an empty vector object */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } + /* Attach operations */ - ops->nvgetvectorid = N_VGetVectorID_Petsc; - ops->nvclone = N_VClone_Petsc; - ops->nvcloneempty = N_VCloneEmpty_Petsc; - ops->nvdestroy = N_VDestroy_Petsc; - ops->nvspace = N_VSpace_Petsc; - ops->nvgetarraypointer = N_VGetArrayPointer_Petsc; - ops->nvsetarraypointer = N_VSetArrayPointer_Petsc; + /* constructors, destructors, and utility operations */ + v->ops->nvgetvectorid = N_VGetVectorID_Petsc; + v->ops->nvclone = N_VClone_Petsc; + v->ops->nvcloneempty = N_VCloneEmpty_Petsc; + v->ops->nvdestroy = N_VDestroy_Petsc; + v->ops->nvspace = N_VSpace_Petsc; + v->ops->nvgetarraypointer = N_VGetArrayPointer_Petsc; + v->ops->nvsetarraypointer = N_VSetArrayPointer_Petsc; + v->ops->nvgetcommunicator = N_VGetCommunicator_Petsc; + v->ops->nvgetlength = N_VGetLength_Petsc; /* standard vector operations */ - ops->nvlinearsum = N_VLinearSum_Petsc; - ops->nvconst = N_VConst_Petsc; - ops->nvprod = N_VProd_Petsc; - ops->nvdiv = N_VDiv_Petsc; - ops->nvscale = N_VScale_Petsc; - ops->nvabs = N_VAbs_Petsc; - ops->nvinv = N_VInv_Petsc; - ops->nvaddconst = N_VAddConst_Petsc; - ops->nvdotprod = N_VDotProd_Petsc; - ops->nvmaxnorm = N_VMaxNorm_Petsc; - ops->nvwrmsnormmask = N_VWrmsNormMask_Petsc; - ops->nvwrmsnorm = N_VWrmsNorm_Petsc; - ops->nvmin = N_VMin_Petsc; - ops->nvwl2norm = N_VWL2Norm_Petsc; - ops->nvl1norm = N_VL1Norm_Petsc; - ops->nvcompare = N_VCompare_Petsc; - ops->nvinvtest = N_VInvTest_Petsc; - ops->nvconstrmask = N_VConstrMask_Petsc; - ops->nvminquotient = N_VMinQuotient_Petsc; - - /* fused vector operations (optional, NULL means disabled by default) */ - ops->nvlinearcombination = NULL; - ops->nvscaleaddmulti = NULL; - ops->nvdotprodmulti = NULL; - - /* vector array operations (optional, NULL means disabled by default) */ - ops->nvlinearsumvectorarray = NULL; - ops->nvscalevectorarray = NULL; - ops->nvconstvectorarray = NULL; - ops->nvwrmsnormvectorarray = NULL; - ops->nvwrmsnormmaskvectorarray = NULL; - ops->nvscaleaddmultivectorarray = NULL; - ops->nvlinearcombinationvectorarray = NULL; - + v->ops->nvlinearsum = N_VLinearSum_Petsc; + v->ops->nvconst = N_VConst_Petsc; + v->ops->nvprod = N_VProd_Petsc; + v->ops->nvdiv = N_VDiv_Petsc; + v->ops->nvscale = N_VScale_Petsc; + v->ops->nvabs = N_VAbs_Petsc; + v->ops->nvinv = N_VInv_Petsc; + v->ops->nvaddconst = N_VAddConst_Petsc; + v->ops->nvdotprod = N_VDotProd_Petsc; + v->ops->nvmaxnorm = N_VMaxNorm_Petsc; + v->ops->nvwrmsnormmask = N_VWrmsNormMask_Petsc; + v->ops->nvwrmsnorm = N_VWrmsNorm_Petsc; + v->ops->nvmin = N_VMin_Petsc; + v->ops->nvwl2norm = N_VWL2Norm_Petsc; + v->ops->nvl1norm = N_VL1Norm_Petsc; + v->ops->nvcompare = N_VCompare_Petsc; + v->ops->nvinvtest = N_VInvTest_Petsc; + v->ops->nvconstrmask = N_VConstrMask_Petsc; + v->ops->nvminquotient = N_VMinQuotient_Petsc; + + /* fused and vector array operations are disabled (NULL) by default */ + + /* local reduction operations */ + v->ops->nvdotprodlocal = N_VDotProdLocal_Petsc; + v->ops->nvmaxnormlocal = N_VMaxNormLocal_Petsc; + v->ops->nvminlocal = N_VMinLocal_Petsc; + v->ops->nvl1normlocal = N_VL1NormLocal_Petsc; + v->ops->nvinvtestlocal = N_VInvTestLocal_Petsc; + v->ops->nvconstrmasklocal = N_VConstrMaskLocal_Petsc; + v->ops->nvminquotientlocal = N_VMinQuotientLocal_Petsc; + v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_Petsc; + v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_Petsc; + /* Create content */ content = NULL; - content = (N_VectorContent_Petsc) malloc(sizeof(struct _N_VectorContent_Petsc)); - if (content == NULL) { - free(ops); - free(v); - return(NULL); - } + content = (N_VectorContent_Petsc) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } - /* Attach lengths and communicator */ + /* Attach content */ + v->content = content; + + /* Initialize content */ content->local_length = local_length; content->global_length = global_length; content->comm = comm; content->own_data = SUNFALSE; content->pvec = NULL; - /* Attach content and ops */ - v->content = content; - v->ops = ops; - return(v); } @@ -317,6 +309,15 @@ Vec N_VGetVector_Petsc(N_Vector v) return NV_PVEC_PTC(v); } +/* ---------------------------------------------------------------- + * Function to set the PETSc vector + */ + +void N_VSetVector_Petsc(N_Vector v, Vec p) +{ + NV_PVEC_PTC(v) = p; +} + /* ---------------------------------------------------------------- * Function to print the global data in a PETSc vector to stdout */ @@ -359,87 +360,33 @@ void N_VPrintFile_Petsc(N_Vector x, const char fname[]) N_Vector N_VCloneEmpty_Petsc(N_Vector w) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_Petsc content; if (w == NULL) return(NULL); /* Create vector */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { - free(v); - return(NULL); - } - - ops->nvgetvectorid = w->ops->nvgetvectorid; - ops->nvclone = w->ops->nvclone; - ops->nvcloneempty = w->ops->nvcloneempty; - ops->nvdestroy = w->ops->nvdestroy; - ops->nvspace = w->ops->nvspace; - ops->nvgetarraypointer = w->ops->nvgetarraypointer; - ops->nvsetarraypointer = w->ops->nvsetarraypointer; - - /* standard vector operations */ - ops->nvlinearsum = w->ops->nvlinearsum; - ops->nvconst = w->ops->nvconst; - ops->nvprod = w->ops->nvprod; - ops->nvdiv = w->ops->nvdiv; - ops->nvscale = w->ops->nvscale; - ops->nvabs = w->ops->nvabs; - ops->nvinv = w->ops->nvinv; - ops->nvaddconst = w->ops->nvaddconst; - ops->nvdotprod = w->ops->nvdotprod; - ops->nvmaxnorm = w->ops->nvmaxnorm; - ops->nvwrmsnormmask = w->ops->nvwrmsnormmask; - ops->nvwrmsnorm = w->ops->nvwrmsnorm; - ops->nvmin = w->ops->nvmin; - ops->nvwl2norm = w->ops->nvwl2norm; - ops->nvl1norm = w->ops->nvl1norm; - ops->nvcompare = w->ops->nvcompare; - ops->nvinvtest = w->ops->nvinvtest; - ops->nvconstrmask = w->ops->nvconstrmask; - ops->nvminquotient = w->ops->nvminquotient; - - /* fused vector operations */ - ops->nvlinearcombination = w->ops->nvlinearcombination; - ops->nvscaleaddmulti = w->ops->nvscaleaddmulti; - ops->nvdotprodmulti = w->ops->nvdotprodmulti; - - /* vector array operations */ - ops->nvlinearsumvectorarray = w->ops->nvlinearsumvectorarray; - ops->nvscalevectorarray = w->ops->nvscalevectorarray; - ops->nvconstvectorarray = w->ops->nvconstvectorarray; - ops->nvwrmsnormvectorarray = w->ops->nvwrmsnormvectorarray; - ops->nvwrmsnormmaskvectorarray = w->ops->nvwrmsnormmaskvectorarray; - ops->nvscaleaddmultivectorarray = w->ops->nvscaleaddmultivectorarray; - ops->nvlinearcombinationvectorarray = w->ops->nvlinearcombinationvectorarray; + /* Attach operations */ + if (N_VCopyOps(w, v)) { N_VDestroy(v); return(NULL); } /* Create content */ content = NULL; - content = (N_VectorContent_Petsc) malloc(sizeof(struct _N_VectorContent_Petsc)); - if (content == NULL) { - free(ops); - free(v); - return(NULL); - } + content = (N_VectorContent_Petsc) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } - /* Attach lengths and communicator */ + /* Attach content */ + v->content = content; + + /* Initialize content */ content->local_length = NV_LOCLENGTH_PTC(w); content->global_length = NV_GLOBLENGTH_PTC(w); content->comm = NV_COMM_PTC(w); content->own_data = SUNFALSE; content->pvec = NULL; - /* Attach content and ops */ - v->content = content; - v->ops = ops; - return(v); } @@ -455,18 +402,9 @@ N_Vector N_VClone_Petsc(N_Vector w) if (v == NULL) return(NULL); - /* Create data */ - - /* Allocate empty PETSc vector */ - pvec = (Vec) malloc(sizeof(Vec)); - if(pvec == NULL) { - N_VDestroy_Petsc(v); - return(NULL); - } - - /* ierr = */ + /* Duplicate vector */ VecDuplicate(wvec, &pvec); - if(pvec == NULL) { + if (pvec == NULL) { N_VDestroy_Petsc(v); return(NULL); } @@ -480,17 +418,21 @@ N_Vector N_VClone_Petsc(N_Vector w) void N_VDestroy_Petsc(N_Vector v) { - if (NV_OWN_DATA_PTC(v) == SUNTRUE) { - VecDestroy(&(NV_PVEC_PTC(v))); - NV_PVEC_PTC(v) = NULL; + if (v == NULL) return; + + /* free content */ + if (v->content != NULL) { + if (NV_OWN_DATA_PTC(v) && NV_PVEC_PTC(v) != NULL) { + VecDestroy(&(NV_PVEC_PTC(v))); + NV_PVEC_PTC(v) = NULL; + } + free(v->content); + v->content = NULL; } - free(v->content); - v->content = NULL; - free(v->ops); - v->ops = NULL; - free(v); - v = NULL; + /* free ops and vector */ + if (v->ops != NULL) { free(v->ops); v->ops = NULL; } + free(v); v = NULL; return; } @@ -525,6 +467,16 @@ void N_VSetArrayPointer_Petsc(realtype *v_data, N_Vector v) return; } +void *N_VGetCommunicator_Petsc(N_Vector v) +{ + return((void *) &(NV_COMM_PTC(v))); +} + +sunindextype N_VGetLength_Petsc(N_Vector v) +{ + return(NV_GLOBLENGTH_PTC(v)); +} + void N_VLinearSum_Petsc(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) { Vec xv = NV_PVEC_PTC(x); @@ -647,6 +599,25 @@ void N_VAddConst_Petsc(N_Vector x, realtype b, N_Vector z) return; } +realtype N_VDotProdLocal_Petsc(N_Vector x, N_Vector y) +{ + sunindextype i; + sunindextype N = NV_LOCLENGTH_PTC(x); + Vec xv = NV_PVEC_PTC(x); + Vec yv = NV_PVEC_PTC(y); + PetscScalar *xd; + PetscScalar *yd; + PetscReal sum = ZERO; + + VecGetArray(xv, &xd); + VecGetArray(yv, &yd); + for (i = 0; i < N; i++) + sum += xd[i] * yd[i]; + VecRestoreArray(xv, &xd); + VecRestoreArray(yv, &yd); + return ((realtype) sum); +} + realtype N_VDotProd_Petsc(N_Vector x, N_Vector y) { Vec xv = NV_PVEC_PTC(x); @@ -654,32 +625,43 @@ realtype N_VDotProd_Petsc(N_Vector x, N_Vector y) PetscScalar dotprod; VecDot(xv, yv, &dotprod); - return dotprod; } +realtype N_VMaxNormLocal_Petsc(N_Vector x) +{ + sunindextype i; + sunindextype N = NV_LOCLENGTH_PTC(x); + Vec xv = NV_PVEC_PTC(x); + PetscScalar *xd; + PetscReal max = ZERO; + + VecGetArray(xv, &xd); + for (i = 0; i < N; i++) { + if (PetscAbsScalar(xd[i]) > max) max = PetscAbsScalar(xd[i]); + } + VecRestoreArray(xv, &xd); + return ((realtype) max); +} + realtype N_VMaxNorm_Petsc(N_Vector x) { Vec xv = NV_PVEC_PTC(x); PetscReal norm; VecNorm(xv, NORM_INFINITY, &norm); - return norm; } -realtype N_VWrmsNorm_Petsc(N_Vector x, N_Vector w) +realtype N_VWSqrSumLocal_Petsc(N_Vector x, N_Vector w) { sunindextype i; - sunindextype N = NV_LOCLENGTH_PTC(x); - sunindextype N_global = NV_GLOBLENGTH_PTC(x); - MPI_Comm comm = NV_COMM_PTC(x); + sunindextype N = NV_LOCLENGTH_PTC(x); Vec xv = NV_PVEC_PTC(x); Vec wv = NV_PVEC_PTC(w); PetscScalar *xd; PetscScalar *wd; PetscReal sum = ZERO; - realtype global_sum; VecGetArray(xv, &xd); VecGetArray(wv, &wd); @@ -688,18 +670,22 @@ realtype N_VWrmsNorm_Petsc(N_Vector x, N_Vector w) } VecRestoreArray(xv, &xd); VecRestoreArray(wv, &wd); - - global_sum = SUNMPI_Allreduce_scalar(sum, 1, comm); - return (SUNRsqrt(global_sum/N_global)); + return ((realtype) sum); } -realtype N_VWrmsNormMask_Petsc(N_Vector x, N_Vector w, N_Vector id) +realtype N_VWrmsNorm_Petsc(N_Vector x, N_Vector w) { - sunindextype i; - sunindextype N = NV_LOCLENGTH_PTC(x); + realtype global_sum; sunindextype N_global = NV_GLOBLENGTH_PTC(x); - MPI_Comm comm = NV_COMM_PTC(x); + realtype sum = N_VWSqrSumLocal_Petsc(x, w); + (void) MPI_Allreduce(&sum, &global_sum, 1, MPI_SUNREALTYPE, MPI_SUM, NV_COMM_PTC(x)); + return (SUNRsqrt(global_sum/N_global)); +} +realtype N_VWSqrSumMaskLocal_Petsc(N_Vector x, N_Vector w, N_Vector id) +{ + sunindextype i; + sunindextype N = NV_LOCLENGTH_PTC(x); Vec xv = NV_PVEC_PTC(x); Vec wv = NV_PVEC_PTC(w); Vec idv = NV_PVEC_PTC(id); @@ -707,7 +693,6 @@ realtype N_VWrmsNormMask_Petsc(N_Vector x, N_Vector w, N_Vector id) PetscScalar *wd; PetscScalar *idd; PetscReal sum = ZERO; - realtype global_sum; VecGetArray(xv, &xd); VecGetArray(wv, &wd); @@ -721,11 +706,34 @@ realtype N_VWrmsNormMask_Petsc(N_Vector x, N_Vector w, N_Vector id) VecRestoreArray(xv, &xd); VecRestoreArray(wv, &wd); VecRestoreArray(idv, &idd); + return sum; +} - global_sum = SUNMPI_Allreduce_scalar(sum, 1, comm); +realtype N_VWrmsNormMask_Petsc(N_Vector x, N_Vector w, N_Vector id) +{ + realtype global_sum; + sunindextype N_global = NV_GLOBLENGTH_PTC(x); + realtype sum = N_VWSqrSumMaskLocal_Petsc(x, w, id); + (void) MPI_Allreduce(&sum, &global_sum, 1, MPI_SUNREALTYPE, MPI_SUM, NV_COMM_PTC(x)); return (SUNRsqrt(global_sum/N_global)); } +realtype N_VMinLocal_Petsc(N_Vector x) +{ + sunindextype i; + sunindextype N = NV_LOCLENGTH_PTC(x); + Vec xv = NV_PVEC_PTC(x); + PetscScalar *xd; + PetscReal min = BIG_REAL; + + VecGetArray(xv, &xd); + for (i = 0; i < N; i++) { + if (xd[i] < min) min = xd[i]; + } + VecRestoreArray(xv, &xd); + return ((realtype) min); +} + realtype N_VMin_Petsc(N_Vector x) { Vec xv = NV_PVEC_PTC(x); @@ -733,33 +741,31 @@ realtype N_VMin_Petsc(N_Vector x) PetscInt i; VecMin(xv, &i, &minval); - return minval; } realtype N_VWL2Norm_Petsc(N_Vector x, N_Vector w) +{ + realtype global_sum; + realtype sum = N_VWSqrSumLocal_Petsc(x, w); + (void) MPI_Allreduce(&sum, &global_sum, 1, MPI_SUNREALTYPE, MPI_SUM, NV_COMM_PTC(x)); + return (SUNRsqrt(global_sum)); +} + +realtype N_VL1NormLocal_Petsc(N_Vector x) { sunindextype i; sunindextype N = NV_LOCLENGTH_PTC(x); - MPI_Comm comm = NV_COMM_PTC(x); - Vec xv = NV_PVEC_PTC(x); - Vec wv = NV_PVEC_PTC(w); PetscScalar *xd; - PetscScalar *wd; PetscReal sum = ZERO; - realtype global_sum; VecGetArray(xv, &xd); - VecGetArray(wv, &wd); for (i = 0; i < N; i++) { - sum += PetscSqr(PetscAbsScalar(xd[i] * wd[i])); + sum += PetscAbsScalar(xd[i]); } VecRestoreArray(xv, &xd); - VecRestoreArray(wv, &wd); - - global_sum = SUNMPI_Allreduce_scalar(sum, 1, comm); - return (SUNRsqrt(global_sum)); + return ((realtype) sum); } realtype N_VL1Norm_Petsc(N_Vector x) @@ -768,7 +774,6 @@ realtype N_VL1Norm_Petsc(N_Vector x) PetscReal norm; VecNorm(xv, NORM_1, &norm); - return norm; } @@ -793,11 +798,10 @@ void N_VCompare_Petsc(realtype c, N_Vector x, N_Vector z) return; } -booleantype N_VInvTest_Petsc(N_Vector x, N_Vector z) +booleantype N_VInvTestLocal_Petsc(N_Vector x, N_Vector z) { sunindextype i; sunindextype N = NV_LOCLENGTH_PTC(x); - MPI_Comm comm = NV_COMM_PTC(x); Vec xv = NV_PVEC_PTC(x); Vec zv = NV_PVEC_PTC(z); PetscScalar *xd; @@ -815,19 +819,27 @@ booleantype N_VInvTest_Petsc(N_Vector x, N_Vector z) VecRestoreArray(xv, &xd); VecRestoreArray(zv, &zd); - val = SUNMPI_Allreduce_scalar(val, 3, comm); - if (val == ZERO) return(SUNFALSE); else return(SUNTRUE); } -booleantype N_VConstrMask_Petsc(N_Vector c, N_Vector x, N_Vector m) +booleantype N_VInvTest_Petsc(N_Vector x, N_Vector z) +{ + realtype val2; + realtype val = (N_VInvTestLocal_Petsc(x, z)) ? ONE : ZERO; + (void) MPI_Allreduce(&val, &val2, 1, MPI_SUNREALTYPE, MPI_MIN, NV_COMM_PTC(x)); + if (val2 == ZERO) + return(SUNFALSE); + else + return(SUNTRUE); +} + +booleantype N_VConstrMaskLocal_Petsc(N_Vector c, N_Vector x, N_Vector m) { sunindextype i; sunindextype N = NV_LOCLENGTH_PTC(x); - MPI_Comm comm = NV_COMM_PTC(x); realtype temp; booleantype test; Vec xv = NV_PVEC_PTC(x); @@ -862,19 +874,23 @@ booleantype N_VConstrMask_Petsc(N_Vector c, N_Vector x, N_Vector m) VecRestoreArray(cv, &cd); VecRestoreArray(mv, &md); - /* Find max temp across all MPI ranks */ - temp = SUNMPI_Allreduce_scalar(temp, 2, comm); - /* Return false if any constraint was violated */ return (temp == ONE) ? SUNFALSE : SUNTRUE; } -realtype N_VMinQuotient_Petsc(N_Vector num, N_Vector denom) +booleantype N_VConstrMask_Petsc(N_Vector c, N_Vector x, N_Vector m) +{ + realtype temp2; + realtype temp = (N_VConstrMaskLocal_Petsc(c, x, m)) ? ZERO : ONE; + (void) MPI_Allreduce(&temp, &temp2, 1, MPI_SUNREALTYPE, MPI_MAX, NV_COMM_PTC(x)); + return (temp2 == ONE) ? SUNFALSE : SUNTRUE; +} + +realtype N_VMinQuotientLocal_Petsc(N_Vector num, N_Vector denom) { booleantype notEvenOnce = SUNTRUE; sunindextype i; - sunindextype N = NV_LOCLENGTH_PTC(num); - MPI_Comm comm = NV_COMM_PTC(num); + sunindextype N = NV_LOCLENGTH_PTC(num); Vec nv = NV_PVEC_PTC(num); Vec dv = NV_PVEC_PTC(denom); @@ -900,8 +916,15 @@ realtype N_VMinQuotient_Petsc(N_Vector num, N_Vector denom) } VecRestoreArray(nv, &nd); VecRestoreArray(dv, &dd); + return((realtype) minval); +} - return(SUNMPI_Allreduce_scalar(minval, 3, comm)); +realtype N_VMinQuotient_Petsc(N_Vector num, N_Vector denom) +{ + PetscReal gmin; + realtype minval = N_VMinQuotientLocal_Petsc(num, denom); + (void) MPI_Allreduce(&minval, &gmin, 1, MPI_SUNREALTYPE, MPI_MIN, NV_COMM_PTC(num)); + return(gmin); } @@ -945,6 +968,7 @@ int N_VLinearCombination_Petsc(int nvec, realtype* c, N_Vector* X, N_Vector z) */ if ((X[0] == z) && (c[0] == ONE)) { VecMAXPY(zv, nvec-1, c+1, xv+1); + free(xv); return(0); } @@ -954,6 +978,7 @@ int N_VLinearCombination_Petsc(int nvec, realtype* c, N_Vector* X, N_Vector z) if (X[0] == z) { VecScale(zv, c[0]); VecMAXPY(zv, nvec-1, c+1, xv+1); + free(xv); return(0); } @@ -962,6 +987,8 @@ int N_VLinearCombination_Petsc(int nvec, realtype* c, N_Vector* X, N_Vector z) */ VecAXPBY(zv, c[0], 0.0, xv[0]); VecMAXPY(zv, nvec-1, c+1, xv+1); + free(xv); + return(0); } @@ -1038,6 +1065,8 @@ int N_VDotProdMulti_Petsc(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods) xv = NV_PVEC_PTC(x); VecMDot(xv, nvec, yv, dotprods); + free(yv); + return(0); } @@ -1167,7 +1196,7 @@ int N_VConstVectorArray_Petsc(int nvec, realtype c, N_Vector* Z) int N_VWrmsNormVectorArray_Petsc(int nvec, N_Vector* X, N_Vector* W, realtype* nrm) { - int i; + int i, retval; sunindextype j, Nl, Ng; realtype* wd=NULL; realtype* xd=NULL; @@ -1198,19 +1227,19 @@ int N_VWrmsNormVectorArray_Petsc(int nvec, N_Vector* X, N_Vector* W, realtype* n VecRestoreArray(NV_PVEC_PTC(X[i]), &xd); VecRestoreArray(NV_PVEC_PTC(W[i]), &wd); } - SUNMPI_Allreduce(nrm, nvec, 1, comm); + retval = MPI_Allreduce(MPI_IN_PLACE, nrm, nvec, MPI_SUNREALTYPE, MPI_SUM, comm); for (i=0; i 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_nvector.h" + + +#include "nvector/nvector_pthreads.h" + +SWIGEXPORT N_Vector _wrap_FN_VNew_Pthreads(int64_t const *farg1, int const *farg2) { + N_Vector fresult ; + sunindextype arg1 ; + int arg2 ; + N_Vector result; + + arg1 = (sunindextype)(*farg1); + arg2 = (int)(*farg2); + result = (N_Vector)N_VNew_Pthreads(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VNewEmpty_Pthreads(int64_t const *farg1, int const *farg2) { + N_Vector fresult ; + sunindextype arg1 ; + int arg2 ; + N_Vector result; + + arg1 = (sunindextype)(*farg1); + arg2 = (int)(*farg2); + result = (N_Vector)N_VNewEmpty_Pthreads(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VMake_Pthreads(int64_t const *farg1, int const *farg2, double *farg3) { + N_Vector fresult ; + sunindextype arg1 ; + int arg2 ; + realtype *arg3 = (realtype *) 0 ; + N_Vector result; + + arg1 = (sunindextype)(*farg1); + arg2 = (int)(*farg2); + arg3 = (realtype *)(farg3); + result = (N_Vector)N_VMake_Pthreads(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FN_VCloneVectorArray_Pthreads(int const *farg1, N_Vector farg2) { + void * fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *result = 0 ; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + result = (N_Vector *)N_VCloneVectorArray_Pthreads(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FN_VCloneVectorArrayEmpty_Pthreads(int const *farg1, N_Vector farg2) { + void * fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *result = 0 ; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + result = (N_Vector *)N_VCloneVectorArrayEmpty_Pthreads(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VDestroyVectorArray_Pthreads(void *farg1, int const *farg2) { + N_Vector *arg1 = (N_Vector *) 0 ; + int arg2 ; + + arg1 = (N_Vector *)(farg1); + arg2 = (int)(*farg2); + N_VDestroyVectorArray_Pthreads(arg1,arg2); +} + + +SWIGEXPORT int64_t _wrap_FN_VGetLength_Pthreads(N_Vector farg1) { + int64_t fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype result; + + arg1 = (N_Vector)(farg1); + result = N_VGetLength_Pthreads(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VPrint_Pthreads(N_Vector farg1) { + N_Vector arg1 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + N_VPrint_Pthreads(arg1); +} + + +SWIGEXPORT void _wrap_FN_VPrintFile_Pthreads(N_Vector farg1, void *farg2) { + N_Vector arg1 = (N_Vector) 0 ; + FILE *arg2 = (FILE *) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (FILE *)(farg2); + N_VPrintFile_Pthreads(arg1,arg2); +} + + +SWIGEXPORT int _wrap_FN_VGetVectorID_Pthreads(N_Vector farg1) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector_ID result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector_ID)N_VGetVectorID_Pthreads(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VCloneEmpty_Pthreads(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VCloneEmpty_Pthreads(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VClone_Pthreads(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VClone_Pthreads(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VDestroy_Pthreads(N_Vector farg1) { + N_Vector arg1 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + N_VDestroy_Pthreads(arg1); +} + + +SWIGEXPORT void _wrap_FN_VSpace_Pthreads(N_Vector farg1, int64_t *farg2, int64_t *farg3) { + N_Vector arg1 = (N_Vector) 0 ; + sunindextype *arg2 = (sunindextype *) 0 ; + sunindextype *arg3 = (sunindextype *) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (sunindextype *)(farg2); + arg3 = (sunindextype *)(farg3); + N_VSpace_Pthreads(arg1,arg2,arg3); +} + + +SWIGEXPORT double * _wrap_FN_VGetArrayPointer_Pthreads(N_Vector farg1) { + double * fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype *result = 0 ; + + arg1 = (N_Vector)(farg1); + result = (realtype *)N_VGetArrayPointer_Pthreads(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VSetArrayPointer_Pthreads(double *farg1, N_Vector farg2) { + realtype *arg1 = (realtype *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype *)(farg1); + arg2 = (N_Vector)(farg2); + N_VSetArrayPointer_Pthreads(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VLinearSum_Pthreads(double const *farg1, N_Vector farg2, double const *farg3, N_Vector farg4, N_Vector farg5) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + N_VLinearSum_Pthreads(arg1,arg2,arg3,arg4,arg5); +} + + +SWIGEXPORT void _wrap_FN_VConst_Pthreads(double const *farg1, N_Vector farg2) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + N_VConst_Pthreads(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VProd_Pthreads(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VProd_Pthreads(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VDiv_Pthreads(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VDiv_Pthreads(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VScale_Pthreads(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VScale_Pthreads(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VAbs_Pthreads(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VAbs_Pthreads(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VInv_Pthreads(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VInv_Pthreads(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VAddConst_Pthreads(N_Vector farg1, double const *farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + N_VAddConst_Pthreads(arg1,arg2,arg3); +} + + +SWIGEXPORT double _wrap_FN_VDotProd_Pthreads(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VDotProd_Pthreads(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMaxNorm_Pthreads(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMaxNorm_Pthreads(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNorm_Pthreads(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWrmsNorm_Pthreads(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNormMask_Pthreads(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWrmsNormMask_Pthreads(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMin_Pthreads(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMin_Pthreads(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWL2Norm_Pthreads(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWL2Norm_Pthreads(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VL1Norm_Pthreads(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VL1Norm_Pthreads(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VCompare_Pthreads(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VCompare_Pthreads(arg1,arg2,arg3); +} + + +SWIGEXPORT int _wrap_FN_VInvTest_Pthreads(N_Vector farg1, N_Vector farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)N_VInvTest_Pthreads(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstrMask_Pthreads(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)N_VConstrMask_Pthreads(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinQuotient_Pthreads(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VMinQuotient_Pthreads(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearCombination_Pthreads(int const *farg1, double *farg2, void *farg3, N_Vector farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)N_VLinearCombination_Pthreads(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleAddMulti_Pthreads(int const *farg1, double *farg2, N_Vector farg3, void *farg4, void *farg5) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + N_Vector *arg5 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector *)(farg4); + arg5 = (N_Vector *)(farg5); + result = (int)N_VScaleAddMulti_Pthreads(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VDotProdMulti_Pthreads(int const *farg1, N_Vector farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VDotProdMulti_Pthreads(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearSumVectorArray_Pthreads(int const *farg1, double const *farg2, void *farg3, double const *farg4, void *farg5, void *farg6) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype arg4 ; + N_Vector *arg5 = (N_Vector *) 0 ; + N_Vector *arg6 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype)(*farg4); + arg5 = (N_Vector *)(farg5); + arg6 = (N_Vector *)(farg6); + result = (int)N_VLinearSumVectorArray_Pthreads(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleVectorArray_Pthreads(int const *farg1, double *farg2, void *farg3, void *farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector *)(farg4); + result = (int)N_VScaleVectorArray_Pthreads(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstVectorArray_Pthreads(int const *farg1, double const *farg2, void *farg3) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (int)N_VConstVectorArray_Pthreads(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormVectorArray_Pthreads(int const *farg1, void *farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VWrmsNormVectorArray_Pthreads(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormMaskVectorArray_Pthreads(int const *farg1, void *farg2, void *farg3, N_Vector farg4, double *farg5) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype *arg5 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype *)(farg5); + result = (int)N_VWrmsNormMaskVectorArray_Pthreads(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumLocal_Pthreads(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWSqrSumLocal_Pthreads(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumMaskLocal_Pthreads(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWSqrSumMaskLocal_Pthreads(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableFusedOps_Pthreads(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableFusedOps_Pthreads(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableLinearCombination_Pthreads(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableLinearCombination_Pthreads(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableScaleAddMulti_Pthreads(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableScaleAddMulti_Pthreads(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableDotProdMulti_Pthreads(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableDotProdMulti_Pthreads(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableLinearSumVectorArray_Pthreads(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableLinearSumVectorArray_Pthreads(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableScaleVectorArray_Pthreads(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableScaleVectorArray_Pthreads(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableConstVectorArray_Pthreads(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableConstVectorArray_Pthreads(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableWrmsNormVectorArray_Pthreads(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableWrmsNormVectorArray_Pthreads(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableWrmsNormMaskVectorArray_Pthreads(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableWrmsNormMaskVectorArray_Pthreads(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/fmod/fnvector_pthreads_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/fmod/fnvector_pthreads_mod.f90 new file mode 100644 index 000000000..4fd5c7776 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/fmod/fnvector_pthreads_mod.f90 @@ -0,0 +1,1440 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fnvector_pthreads_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FN_VNew_Pthreads + public :: FN_VNewEmpty_Pthreads + public :: FN_VMake_Pthreads + public :: FN_VCloneVectorArray_Pthreads + public :: FN_VCloneVectorArrayEmpty_Pthreads + public :: FN_VDestroyVectorArray_Pthreads + public :: FN_VGetLength_Pthreads + public :: FN_VPrint_Pthreads + public :: FN_VPrintFile_Pthreads + public :: FN_VGetVectorID_Pthreads + public :: FN_VCloneEmpty_Pthreads + public :: FN_VClone_Pthreads + public :: FN_VDestroy_Pthreads + public :: FN_VSpace_Pthreads + public :: FN_VGetArrayPointer_Pthreads + public :: FN_VSetArrayPointer_Pthreads + public :: FN_VLinearSum_Pthreads + public :: FN_VConst_Pthreads + public :: FN_VProd_Pthreads + public :: FN_VDiv_Pthreads + public :: FN_VScale_Pthreads + public :: FN_VAbs_Pthreads + public :: FN_VInv_Pthreads + public :: FN_VAddConst_Pthreads + public :: FN_VDotProd_Pthreads + public :: FN_VMaxNorm_Pthreads + public :: FN_VWrmsNorm_Pthreads + public :: FN_VWrmsNormMask_Pthreads + public :: FN_VMin_Pthreads + public :: FN_VWL2Norm_Pthreads + public :: FN_VL1Norm_Pthreads + public :: FN_VCompare_Pthreads + public :: FN_VInvTest_Pthreads + public :: FN_VConstrMask_Pthreads + public :: FN_VMinQuotient_Pthreads + public :: FN_VLinearCombination_Pthreads + public :: FN_VScaleAddMulti_Pthreads + public :: FN_VDotProdMulti_Pthreads + public :: FN_VLinearSumVectorArray_Pthreads + public :: FN_VScaleVectorArray_Pthreads + public :: FN_VConstVectorArray_Pthreads + public :: FN_VWrmsNormVectorArray_Pthreads + public :: FN_VWrmsNormMaskVectorArray_Pthreads + public :: FN_VWSqrSumLocal_Pthreads + public :: FN_VWSqrSumMaskLocal_Pthreads + public :: FN_VEnableFusedOps_Pthreads + public :: FN_VEnableLinearCombination_Pthreads + public :: FN_VEnableScaleAddMulti_Pthreads + public :: FN_VEnableDotProdMulti_Pthreads + public :: FN_VEnableLinearSumVectorArray_Pthreads + public :: FN_VEnableScaleVectorArray_Pthreads + public :: FN_VEnableConstVectorArray_Pthreads + public :: FN_VEnableWrmsNormVectorArray_Pthreads + public :: FN_VEnableWrmsNormMaskVectorArray_Pthreads + +! WRAPPER DECLARATIONS +interface +function swigc_FN_VNew_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VNew_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VNewEmpty_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VNewEmpty_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VMake_Pthreads(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VMake_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FN_VCloneVectorArray_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VCloneVectorArray_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VCloneVectorArrayEmpty_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VCloneVectorArrayEmpty_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VDestroyVectorArray_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VDestroyVectorArray_Pthreads") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +end subroutine + +function swigc_FN_VGetLength_Pthreads(farg1) & +bind(C, name="_wrap_FN_VGetLength_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +subroutine swigc_FN_VPrint_Pthreads(farg1) & +bind(C, name="_wrap_FN_VPrint_Pthreads") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FN_VPrintFile_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VPrintFile_Pthreads") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_FN_VGetVectorID_Pthreads(farg1) & +bind(C, name="_wrap_FN_VGetVectorID_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FN_VCloneEmpty_Pthreads(farg1) & +bind(C, name="_wrap_FN_VCloneEmpty_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VClone_Pthreads(farg1) & +bind(C, name="_wrap_FN_VClone_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VDestroy_Pthreads(farg1) & +bind(C, name="_wrap_FN_VDestroy_Pthreads") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FN_VSpace_Pthreads(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VSpace_Pthreads") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VGetArrayPointer_Pthreads(farg1) & +bind(C, name="_wrap_FN_VGetArrayPointer_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VSetArrayPointer_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VSetArrayPointer_Pthreads") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VLinearSum_Pthreads(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VLinearSum_Pthreads") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +end subroutine + +subroutine swigc_FN_VConst_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VConst_Pthreads") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VProd_Pthreads(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VProd_Pthreads") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VDiv_Pthreads(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VDiv_Pthreads") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VScale_Pthreads(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VScale_Pthreads") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VAbs_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VAbs_Pthreads") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VInv_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VInv_Pthreads") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VAddConst_Pthreads(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VAddConst_Pthreads") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VDotProd_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VDotProd_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMaxNorm_Pthreads(farg1) & +bind(C, name="_wrap_FN_VMaxNorm_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNorm_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VWrmsNorm_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNormMask_Pthreads(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWrmsNormMask_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMin_Pthreads(farg1) & +bind(C, name="_wrap_FN_VMin_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWL2Norm_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VWL2Norm_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VL1Norm_Pthreads(farg1) & +bind(C, name="_wrap_FN_VL1Norm_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +subroutine swigc_FN_VCompare_Pthreads(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VCompare_Pthreads") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VInvTest_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VInvTest_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstrMask_Pthreads(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstrMask_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VMinQuotient_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VMinQuotient_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VLinearCombination_Pthreads(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VLinearCombination_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleAddMulti_Pthreads(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VScaleAddMulti_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VDotProdMulti_Pthreads(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VDotProdMulti_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VLinearSumVectorArray_Pthreads(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FN_VLinearSumVectorArray_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleVectorArray_Pthreads(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VScaleVectorArray_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstVectorArray_Pthreads(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstVectorArray_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormVectorArray_Pthreads(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VWrmsNormVectorArray_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormMaskVectorArray_Pthreads(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VWrmsNormMaskVectorArray_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWSqrSumLocal_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VWSqrSumLocal_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWSqrSumMaskLocal_Pthreads(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWSqrSumMaskLocal_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VEnableFusedOps_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableFusedOps_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableLinearCombination_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableLinearCombination_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableScaleAddMulti_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableScaleAddMulti_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableDotProdMulti_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableDotProdMulti_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableLinearSumVectorArray_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableLinearSumVectorArray_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableScaleVectorArray_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableScaleVectorArray_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableConstVectorArray_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableConstVectorArray_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableWrmsNormVectorArray_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableWrmsNormVectorArray_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableWrmsNormMaskVectorArray_Pthreads(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableWrmsNormMaskVectorArray_Pthreads") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FN_VNew_Pthreads(vec_length, n_threads) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer(C_INT64_T), intent(in) :: vec_length +integer(C_INT), intent(in) :: n_threads +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +integer(C_INT) :: farg2 + +farg1 = vec_length +farg2 = n_threads +fresult = swigc_FN_VNew_Pthreads(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VNewEmpty_Pthreads(vec_length, n_threads) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer(C_INT64_T), intent(in) :: vec_length +integer(C_INT), intent(in) :: n_threads +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +integer(C_INT) :: farg2 + +farg1 = vec_length +farg2 = n_threads +fresult = swigc_FN_VNewEmpty_Pthreads(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VMake_Pthreads(vec_length, n_threads, v_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer(C_INT64_T), intent(in) :: vec_length +integer(C_INT), intent(in) :: n_threads +real(C_DOUBLE), dimension(*), target, intent(inout) :: v_data +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = vec_length +farg2 = n_threads +farg3 = c_loc(v_data(1)) +fresult = swigc_FN_VMake_Pthreads(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VCloneVectorArray_Pthreads(count, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: count +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 + +farg1 = count +farg2 = c_loc(w) +fresult = swigc_FN_VCloneVectorArray_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VCloneVectorArrayEmpty_Pthreads(count, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: count +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 + +farg1 = count +farg2 = c_loc(w) +fresult = swigc_FN_VCloneVectorArrayEmpty_Pthreads(farg1, farg2) +swig_result = fresult +end function + +subroutine FN_VDestroyVectorArray_Pthreads(vs, count) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: vs +integer(C_INT), intent(in) :: count +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = vs +farg2 = count +call swigc_FN_VDestroyVectorArray_Pthreads(farg1, farg2) +end subroutine + +function FN_VGetLength_Pthreads(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetLength_Pthreads(farg1) +swig_result = fresult +end function + +subroutine FN_VPrint_Pthreads(v) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +call swigc_FN_VPrint_Pthreads(farg1) +end subroutine + +subroutine FN_VPrintFile_Pthreads(v, outfile) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: outfile +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(v) +farg2 = outfile +call swigc_FN_VPrintFile_Pthreads(farg1, farg2) +end subroutine + +function FN_VGetVectorID_Pthreads(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(N_Vector_ID) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetVectorID_Pthreads(farg1) +swig_result = fresult +end function + +function FN_VCloneEmpty_Pthreads(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VCloneEmpty_Pthreads(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VClone_Pthreads(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VClone_Pthreads(farg1) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FN_VDestroy_Pthreads(v) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +call swigc_FN_VDestroy_Pthreads(farg1) +end subroutine + +subroutine FN_VSpace_Pthreads(v, lrw, liw) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), dimension(*), target, intent(inout) :: lrw +integer(C_INT64_T), dimension(*), target, intent(inout) :: liw +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(v) +farg2 = c_loc(lrw(1)) +farg3 = c_loc(liw(1)) +call swigc_FN_VSpace_Pthreads(farg1, farg2, farg3) +end subroutine + +function FN_VGetArrayPointer_Pthreads(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetArrayPointer_Pthreads(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +subroutine FN_VSetArrayPointer_Pthreads(v_data, v) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(*), target, intent(inout) :: v_data +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(v_data(1)) +farg2 = c_loc(v) +call swigc_FN_VSetArrayPointer_Pthreads(farg1, farg2) +end subroutine + +subroutine FN_VLinearSum_Pthreads(a, x, b, y, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: a +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = a +farg2 = c_loc(x) +farg3 = b +farg4 = c_loc(y) +farg5 = c_loc(z) +call swigc_FN_VLinearSum_Pthreads(farg1, farg2, farg3, farg4, farg5) +end subroutine + +subroutine FN_VConst_Pthreads(c, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c +farg2 = c_loc(z) +call swigc_FN_VConst_Pthreads(farg1, farg2) +end subroutine + +subroutine FN_VProd_Pthreads(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VProd_Pthreads(farg1, farg2, farg3) +end subroutine + +subroutine FN_VDiv_Pthreads(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VDiv_Pthreads(farg1, farg2, farg3) +end subroutine + +subroutine FN_VScale_Pthreads(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VScale_Pthreads(farg1, farg2, farg3) +end subroutine + +subroutine FN_VAbs_Pthreads(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VAbs_Pthreads(farg1, farg2) +end subroutine + +subroutine FN_VInv_Pthreads(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VInv_Pthreads(farg1, farg2) +end subroutine + +subroutine FN_VAddConst_Pthreads(x, b, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = b +farg3 = c_loc(z) +call swigc_FN_VAddConst_Pthreads(farg1, farg2, farg3) +end subroutine + +function FN_VDotProd_Pthreads(x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(y) +fresult = swigc_FN_VDotProd_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VMaxNorm_Pthreads(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMaxNorm_Pthreads(farg1) +swig_result = fresult +end function + +function FN_VWrmsNorm_Pthreads(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWrmsNorm_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VWrmsNormMask_Pthreads(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWrmsNormMask_Pthreads(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMin_Pthreads(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMin_Pthreads(farg1) +swig_result = fresult +end function + +function FN_VWL2Norm_Pthreads(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWL2Norm_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VL1Norm_Pthreads(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VL1Norm_Pthreads(farg1) +swig_result = fresult +end function + +subroutine FN_VCompare_Pthreads(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VCompare_Pthreads(farg1, farg2, farg3) +end subroutine + +function FN_VInvTest_Pthreads(x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +fresult = swigc_FN_VInvTest_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VConstrMask_Pthreads(c, x, m) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: m +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(c) +farg2 = c_loc(x) +farg3 = c_loc(m) +fresult = swigc_FN_VConstrMask_Pthreads(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMinQuotient_Pthreads(num, denom) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: num +type(N_Vector), target, intent(inout) :: denom +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(num) +farg2 = c_loc(denom) +fresult = swigc_FN_VMinQuotient_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VLinearCombination_Pthreads(nvec, c, x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: x +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = x +farg4 = c_loc(z) +fresult = swigc_FN_VLinearCombination_Pthreads(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VScaleAddMulti_Pthreads(nvec, a, x, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvec +farg2 = c_loc(a(1)) +farg3 = c_loc(x) +farg4 = y +farg5 = z +fresult = swigc_FN_VScaleAddMulti_Pthreads(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VDotProdMulti_Pthreads(nvec, x, y, dotprods) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +real(C_DOUBLE), dimension(*), target, intent(inout) :: dotprods +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(x) +farg3 = y +farg4 = c_loc(dotprods(1)) +fresult = swigc_FN_VDotProdMulti_Pthreads(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VLinearSumVectorArray_Pthreads(nvec, a, x, b, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), intent(in) :: a +type(C_PTR) :: x +real(C_DOUBLE), intent(in) :: b +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = nvec +farg2 = a +farg3 = x +farg4 = b +farg5 = y +farg6 = z +fresult = swigc_FN_VLinearSumVectorArray_Pthreads(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FN_VScaleVectorArray_Pthreads(nvec, c, x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: x +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = x +farg4 = z +fresult = swigc_FN_VScaleVectorArray_Pthreads(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VConstVectorArray_Pthreads(nvec, c, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), intent(in) :: c +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = nvec +farg2 = c +farg3 = z +fresult = swigc_FN_VConstVectorArray_Pthreads(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VWrmsNormVectorArray_Pthreads(nvec, x, w, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(C_PTR) :: x +type(C_PTR) :: w +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = x +farg3 = w +farg4 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormVectorArray_Pthreads(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VWrmsNormMaskVectorArray_Pthreads(nvec, x, w, id, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(C_PTR) :: x +type(C_PTR) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvec +farg2 = x +farg3 = w +farg4 = c_loc(id) +farg5 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormMaskVectorArray_Pthreads(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VWSqrSumLocal_Pthreads(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWSqrSumLocal_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VWSqrSumMaskLocal_Pthreads(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWSqrSumMaskLocal_Pthreads(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VEnableFusedOps_Pthreads(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableFusedOps_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableLinearCombination_Pthreads(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableLinearCombination_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableScaleAddMulti_Pthreads(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableScaleAddMulti_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableDotProdMulti_Pthreads(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableDotProdMulti_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableLinearSumVectorArray_Pthreads(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableLinearSumVectorArray_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableScaleVectorArray_Pthreads(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableScaleVectorArray_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableConstVectorArray_Pthreads(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableConstVectorArray_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableWrmsNormVectorArray_Pthreads(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableWrmsNormVectorArray_Pthreads(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableWrmsNormMaskVectorArray_Pthreads(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableWrmsNormMaskVectorArray_Pthreads(farg1, farg2) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.c b/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.c index 9ca099918..1880be837 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.c +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.c @@ -3,7 +3,7 @@ * Programmer(s): Steven Smith @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -50,22 +50,22 @@ void FNV_INITPTS(int *code, long int *N, int *num_threads, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vec = NULL; - F2C_CVODE_vec = N_VNewEmpty_Pthreads(*N, *num_threads); + F2C_CVODE_vec = N_VNewEmpty_Pthreads((sunindextype)(*N), *num_threads); if (F2C_CVODE_vec == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vec = NULL; - F2C_IDA_vec = N_VNewEmpty_Pthreads(*N, *num_threads); + F2C_IDA_vec = N_VNewEmpty_Pthreads((sunindextype)(*N), *num_threads); if (F2C_IDA_vec == NULL) *ier = -1; break; case FCMIX_KINSOL: F2C_KINSOL_vec = NULL; - F2C_KINSOL_vec = N_VNewEmpty_Pthreads(*N, *num_threads); + F2C_KINSOL_vec = N_VNewEmpty_Pthreads((sunindextype)(*N), *num_threads); if (F2C_KINSOL_vec == NULL) *ier = -1; break; case FCMIX_ARKODE: F2C_ARKODE_vec = NULL; - F2C_ARKODE_vec = N_VNewEmpty_Pthreads(*N, *num_threads); + F2C_ARKODE_vec = N_VNewEmpty_Pthreads((sunindextype)(*N), *num_threads); if (F2C_ARKODE_vec == NULL) *ier = -1; break; default: @@ -80,12 +80,12 @@ void FNV_INITPTS_Q(int *code, long int *Nq, int *num_threads, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vecQ = NULL; - F2C_CVODE_vecQ = N_VNewEmpty_Pthreads(*Nq, *num_threads); + F2C_CVODE_vecQ = N_VNewEmpty_Pthreads((sunindextype)(*Nq), *num_threads); if (F2C_CVODE_vecQ == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vecQ = NULL; - F2C_IDA_vecQ = N_VNewEmpty_Pthreads(*Nq, *num_threads); + F2C_IDA_vecQ = N_VNewEmpty_Pthreads((sunindextype)(*Nq), *num_threads); if (F2C_IDA_vecQ == NULL) *ier = -1; break; default: @@ -100,12 +100,12 @@ void FNV_INITPTS_B(int *code, long int *NB, int *num_threads, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vecB = NULL; - F2C_CVODE_vecB = N_VNewEmpty_Pthreads(*NB, *num_threads); + F2C_CVODE_vecB = N_VNewEmpty_Pthreads((sunindextype)(*NB), *num_threads); if (F2C_CVODE_vecB == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vecB = NULL; - F2C_IDA_vecB = N_VNewEmpty_Pthreads(*NB, *num_threads); + F2C_IDA_vecB = N_VNewEmpty_Pthreads((sunindextype)(*NB), *num_threads); if (F2C_IDA_vecB == NULL) *ier = -1; break; default: @@ -120,12 +120,12 @@ void FNV_INITPTS_QB(int *code, long int *NqB, int *num_threads, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vecQB = NULL; - F2C_CVODE_vecQB = N_VNewEmpty_Pthreads(*NqB, *num_threads); + F2C_CVODE_vecQB = N_VNewEmpty_Pthreads((sunindextype)(*NqB), *num_threads); if (F2C_CVODE_vecQB == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vecQB = NULL; - F2C_IDA_vecQB = N_VNewEmpty_Pthreads(*NqB, *num_threads); + F2C_IDA_vecQB = N_VNewEmpty_Pthreads((sunindextype)(*NqB), *num_threads); if (F2C_IDA_vecQB == NULL) *ier = -1; break; default: diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.h b/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.h index 0fd2f6085..ebdc8ef8a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.h +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.h @@ -3,7 +3,7 @@ * Programmer(s): Steven Smith @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/nvector_pthreads.c b/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/nvector_pthreads.c index 70883fd8f..7e1ec91d5 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/nvector_pthreads.c +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/pthreads/nvector_pthreads.c @@ -7,7 +7,7 @@ * @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -52,7 +52,7 @@ static int VScaleSumVectorArray_Pthreads(int nvec, realtype c, N_Vector* X, N_Ve static int VScaleDiffVectorArray_Pthreads(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=c(X-Y) */ static int VLin1VectorArray_Pthreads(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=aX+Y */ static int VLin2VectorArray_Pthreads(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=aX-Y */ -static int VaxpyVectorArray_Pthreads(int nvec, realtype a, N_Vector* X, N_Vector* Y); /* Y <- aX+Y */ +static int VaxpyVectorArray_Pthreads(int nvec, realtype a, N_Vector* X, N_Vector* Y); /* Y <- aX+Y */ /* Pthread companion functions for vector operations */ static void *N_VLinearSum_PT(void *thread_data); @@ -66,12 +66,12 @@ static void *N_VAddConst_PT(void *thread_data); static void *N_VCompare_PT(void *thread_data); static void *N_VDotProd_PT(void *thread_data); static void *N_VMaxNorm_PT(void *thread_data); -static void *N_VWrmsNorm_PT(void *thread_data); +static void *N_VWSqrSum_PT(void *thread_data); static void *N_VMin_PT(void *thread_data); static void *N_VWL2Norm_PT(void *thread_data); static void *N_VL1Norm_PT(void *thread_data); static void *N_VInvTest_PT(void *thread_data); -static void *N_VWrmsNormMask_PT(void *thread_data); +static void *N_VWSqrSumMask_PT(void *thread_data); static void *N_VConstrMask_PT(void *thread_data); static void *N_VMinQuotient_PT(void *thread_data); @@ -112,7 +112,7 @@ static void *VaxpyVectorArray_PT(void *thread_data); /* Function to determine loop values for threads */ static void N_VSplitLoop(int myid, int *nthreads, sunindextype *N, - sunindextype *start, sunindextype *end); + sunindextype *start, sunindextype *end); /* Function to initialize thread data */ static void N_VInitThreadData(Pthreads_Data *thread_data); @@ -139,76 +139,73 @@ N_Vector_ID N_VGetVectorID_Pthreads(N_Vector v) N_Vector N_VNewEmpty_Pthreads(sunindextype length, int num_threads) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_Pthreads content; - /* Create vector */ + /* Create an empty vector object */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } + /* Attach operations */ - ops->nvgetvectorid = N_VGetVectorID_Pthreads; - ops->nvclone = N_VClone_Pthreads; - ops->nvcloneempty = N_VCloneEmpty_Pthreads; - ops->nvdestroy = N_VDestroy_Pthreads; - ops->nvspace = N_VSpace_Pthreads; - ops->nvgetarraypointer = N_VGetArrayPointer_Pthreads; - ops->nvsetarraypointer = N_VSetArrayPointer_Pthreads; + /* constructors, destructors, and utility operations */ + v->ops->nvgetvectorid = N_VGetVectorID_Pthreads; + v->ops->nvclone = N_VClone_Pthreads; + v->ops->nvcloneempty = N_VCloneEmpty_Pthreads; + v->ops->nvdestroy = N_VDestroy_Pthreads; + v->ops->nvspace = N_VSpace_Pthreads; + v->ops->nvgetarraypointer = N_VGetArrayPointer_Pthreads; + v->ops->nvsetarraypointer = N_VSetArrayPointer_Pthreads; + v->ops->nvgetlength = N_VGetLength_Pthreads; /* standard vector operations */ - ops->nvlinearsum = N_VLinearSum_Pthreads; - ops->nvconst = N_VConst_Pthreads; - ops->nvprod = N_VProd_Pthreads; - ops->nvdiv = N_VDiv_Pthreads; - ops->nvscale = N_VScale_Pthreads; - ops->nvabs = N_VAbs_Pthreads; - ops->nvinv = N_VInv_Pthreads; - ops->nvaddconst = N_VAddConst_Pthreads; - ops->nvdotprod = N_VDotProd_Pthreads; - ops->nvmaxnorm = N_VMaxNorm_Pthreads; - ops->nvwrmsnormmask = N_VWrmsNormMask_Pthreads; - ops->nvwrmsnorm = N_VWrmsNorm_Pthreads; - ops->nvmin = N_VMin_Pthreads; - ops->nvwl2norm = N_VWL2Norm_Pthreads; - ops->nvl1norm = N_VL1Norm_Pthreads; - ops->nvcompare = N_VCompare_Pthreads; - ops->nvinvtest = N_VInvTest_Pthreads; - ops->nvconstrmask = N_VConstrMask_Pthreads; - ops->nvminquotient = N_VMinQuotient_Pthreads; - - /* fused vector operations (optional, NULL means disabled by default) */ - ops->nvlinearcombination = NULL; - ops->nvscaleaddmulti = NULL; - ops->nvdotprodmulti = NULL; - - /* vector array operations (optional, NULL means disabled by default) */ - ops->nvlinearsumvectorarray = NULL; - ops->nvscalevectorarray = NULL; - ops->nvconstvectorarray = NULL; - ops->nvwrmsnormvectorarray = NULL; - ops->nvwrmsnormmaskvectorarray = NULL; - ops->nvscaleaddmultivectorarray = NULL; - ops->nvlinearcombinationvectorarray = NULL; + v->ops->nvlinearsum = N_VLinearSum_Pthreads; + v->ops->nvconst = N_VConst_Pthreads; + v->ops->nvprod = N_VProd_Pthreads; + v->ops->nvdiv = N_VDiv_Pthreads; + v->ops->nvscale = N_VScale_Pthreads; + v->ops->nvabs = N_VAbs_Pthreads; + v->ops->nvinv = N_VInv_Pthreads; + v->ops->nvaddconst = N_VAddConst_Pthreads; + v->ops->nvdotprod = N_VDotProd_Pthreads; + v->ops->nvmaxnorm = N_VMaxNorm_Pthreads; + v->ops->nvwrmsnormmask = N_VWrmsNormMask_Pthreads; + v->ops->nvwrmsnorm = N_VWrmsNorm_Pthreads; + v->ops->nvmin = N_VMin_Pthreads; + v->ops->nvwl2norm = N_VWL2Norm_Pthreads; + v->ops->nvl1norm = N_VL1Norm_Pthreads; + v->ops->nvcompare = N_VCompare_Pthreads; + v->ops->nvinvtest = N_VInvTest_Pthreads; + v->ops->nvconstrmask = N_VConstrMask_Pthreads; + v->ops->nvminquotient = N_VMinQuotient_Pthreads; + + /* fused and vector array operations are disabled (NULL) by default */ + + /* local reduction operations */ + v->ops->nvdotprodlocal = N_VDotProd_Pthreads; + v->ops->nvmaxnormlocal = N_VMaxNorm_Pthreads; + v->ops->nvminlocal = N_VMin_Pthreads; + v->ops->nvl1normlocal = N_VL1Norm_Pthreads; + v->ops->nvinvtestlocal = N_VInvTest_Pthreads; + v->ops->nvconstrmasklocal = N_VConstrMask_Pthreads; + v->ops->nvminquotientlocal = N_VMinQuotient_Pthreads; + v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_Pthreads; + v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_Pthreads; /* Create content */ content = NULL; - content = (N_VectorContent_Pthreads) malloc(sizeof(struct _N_VectorContent_Pthreads)); - if (content == NULL) { free(ops); free(v); return(NULL); } + content = (N_VectorContent_Pthreads) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } + + /* Attach content */ + v->content = content; + /* Initialize content */ content->length = length; content->num_threads = num_threads; content->own_data = SUNFALSE; content->data = NULL; - /* Attach content and ops */ - v->content = content; - v->ops = ops; - return(v); } @@ -267,15 +264,15 @@ N_Vector N_VMake_Pthreads(sunindextype length, int num_threads, realtype *v_data * Function to create an array of new vectors. */ -N_Vector *N_VCloneVectorArray_Pthreads(int count, N_Vector w) +N_Vector* N_VCloneVectorArray_Pthreads(int count, N_Vector w) { - N_Vector *vs; + N_Vector* vs; int j; if (count <= 0) return(NULL); vs = NULL; - vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + vs = (N_Vector*) malloc(count * sizeof(N_Vector)); if(vs == NULL) return(NULL); for (j = 0; j < count; j++) { @@ -294,15 +291,15 @@ N_Vector *N_VCloneVectorArray_Pthreads(int count, N_Vector w) * Function to create an array of new vectors with NULL data array. */ -N_Vector *N_VCloneVectorArrayEmpty_Pthreads(int count, N_Vector w) +N_Vector* N_VCloneVectorArrayEmpty_Pthreads(int count, N_Vector w) { - N_Vector *vs; + N_Vector* vs; int j; if (count <= 0) return(NULL); vs = NULL; - vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + vs = (N_Vector*) malloc(count * sizeof(N_Vector)); if(vs == NULL) return(NULL); for (j = 0; j < count; j++) { @@ -321,7 +318,7 @@ N_Vector *N_VCloneVectorArrayEmpty_Pthreads(int count, N_Vector w) * Function to free an array created with N_VCloneVectorArray_Pthreads */ -void N_VDestroyVectorArray_Pthreads(N_Vector *vs, int count) +void N_VDestroyVectorArray_Pthreads(N_Vector* vs, int count) { int j; @@ -390,78 +387,32 @@ void N_VPrintFile_Pthreads(N_Vector x, FILE *outfile) N_Vector N_VCloneEmpty_Pthreads(N_Vector w) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_Pthreads content; if (w == NULL) return(NULL); /* Create vector */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } - - ops->nvgetvectorid = w->ops->nvgetvectorid; - ops->nvclone = w->ops->nvclone; - ops->nvcloneempty = w->ops->nvcloneempty; - ops->nvdestroy = w->ops->nvdestroy; - ops->nvspace = w->ops->nvspace; - ops->nvgetarraypointer = w->ops->nvgetarraypointer; - ops->nvsetarraypointer = w->ops->nvsetarraypointer; - - /* standard vector operations */ - ops->nvlinearsum = w->ops->nvlinearsum; - ops->nvconst = w->ops->nvconst; - ops->nvprod = w->ops->nvprod; - ops->nvdiv = w->ops->nvdiv; - ops->nvscale = w->ops->nvscale; - ops->nvabs = w->ops->nvabs; - ops->nvinv = w->ops->nvinv; - ops->nvaddconst = w->ops->nvaddconst; - ops->nvdotprod = w->ops->nvdotprod; - ops->nvmaxnorm = w->ops->nvmaxnorm; - ops->nvwrmsnormmask = w->ops->nvwrmsnormmask; - ops->nvwrmsnorm = w->ops->nvwrmsnorm; - ops->nvmin = w->ops->nvmin; - ops->nvwl2norm = w->ops->nvwl2norm; - ops->nvl1norm = w->ops->nvl1norm; - ops->nvcompare = w->ops->nvcompare; - ops->nvinvtest = w->ops->nvinvtest; - ops->nvconstrmask = w->ops->nvconstrmask; - ops->nvminquotient = w->ops->nvminquotient; - - /* fused vector operations */ - ops->nvlinearcombination = w->ops->nvlinearcombination; - ops->nvscaleaddmulti = w->ops->nvscaleaddmulti; - ops->nvdotprodmulti = w->ops->nvdotprodmulti; - - /* vector array operations */ - ops->nvlinearsumvectorarray = w->ops->nvlinearsumvectorarray; - ops->nvscalevectorarray = w->ops->nvscalevectorarray; - ops->nvconstvectorarray = w->ops->nvconstvectorarray; - ops->nvwrmsnormvectorarray = w->ops->nvwrmsnormvectorarray; - ops->nvwrmsnormmaskvectorarray = w->ops->nvwrmsnormmaskvectorarray; - ops->nvscaleaddmultivectorarray = w->ops->nvscaleaddmultivectorarray; - ops->nvlinearcombinationvectorarray = w->ops->nvlinearcombinationvectorarray; + /* Attach operations */ + if (N_VCopyOps(w, v)) { N_VDestroy(v); return(NULL); } /* Create content */ content = NULL; - content = (N_VectorContent_Pthreads) malloc(sizeof(struct _N_VectorContent_Pthreads)); - if (content == NULL) { free(ops); free(v); return(NULL); } + content = (N_VectorContent_Pthreads) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } + /* Attach content */ + v->content = content; + + /* Initialize content */ content->length = NV_LENGTH_PT(w); content->num_threads = NV_NUM_THREADS_PT(w); content->own_data = SUNFALSE; content->data = NULL; - /* Attach content and ops */ - v->content = content; - v->ops = ops; - return(v); } @@ -505,12 +456,20 @@ N_Vector N_VClone_Pthreads(N_Vector w) void N_VDestroy_Pthreads(N_Vector v) { - if (NV_OWN_DATA_PT(v) == SUNTRUE) { - free(NV_DATA_PT(v)); - NV_DATA_PT(v) = NULL; + if (v == NULL) return; + + /* free content */ + if (v->content != NULL) { + if (NV_OWN_DATA_PT(v) && NV_DATA_PT(v) != NULL) { + free(NV_DATA_PT(v)); + NV_DATA_PT(v) = NULL; + } + free(v->content); + v->content = NULL; } - free(v->content); v->content = NULL; - free(v->ops); v->ops = NULL; + + /* free ops and vector */ + if (v->ops != NULL) { free(v->ops); v->ops = NULL; } free(v); v = NULL; return; @@ -1483,6 +1442,16 @@ static void *N_VMaxNorm_PT(void *thread_data) */ realtype N_VWrmsNorm_Pthreads(N_Vector x, N_Vector w) +{ + return(SUNRsqrt(N_VWSqrSumLocal_Pthreads(x, w)/(NV_LENGTH_PT(x)))); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted square sum of a vector + */ + +realtype N_VWSqrSumLocal_Pthreads(N_Vector x, N_Vector w) { sunindextype N; int i, nthreads; @@ -1519,7 +1488,7 @@ realtype N_VWrmsNorm_Pthreads(N_Vector x, N_Vector w) thread_data[i].global_mutex = &global_mutex; /* create threads and call pthread companion function */ - pthread_create(&threads[i], &attr, N_VWrmsNorm_PT, (void *) &thread_data[i]); + pthread_create(&threads[i], &attr, N_VWSqrSum_PT, (void *) &thread_data[i]); } /* wait for all threads to finish */ @@ -1533,7 +1502,7 @@ realtype N_VWrmsNorm_Pthreads(N_Vector x, N_Vector w) free(threads); free(thread_data); - return(SUNRsqrt(sum/N)); + return(sum); } @@ -1541,7 +1510,7 @@ realtype N_VWrmsNorm_Pthreads(N_Vector x, N_Vector w) * Pthread companion function to N_VWrmsNorm */ -static void *N_VWrmsNorm_PT(void *thread_data) +static void *N_VWSqrSum_PT(void *thread_data) { sunindextype i, start, end; realtype *xd, *wd; @@ -1581,6 +1550,16 @@ static void *N_VWrmsNorm_PT(void *thread_data) */ realtype N_VWrmsNormMask_Pthreads(N_Vector x, N_Vector w, N_Vector id) +{ + return(SUNRsqrt(N_VWSqrSumMaskLocal_Pthreads(x, w, id)/(NV_LENGTH_PT(x)))); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted square sum of a masked vector + */ + +realtype N_VWSqrSumMaskLocal_Pthreads(N_Vector x, N_Vector w, N_Vector id) { sunindextype N; int i, nthreads; @@ -1618,7 +1597,7 @@ realtype N_VWrmsNormMask_Pthreads(N_Vector x, N_Vector w, N_Vector id) thread_data[i].global_mutex = &global_mutex; /* create threads and call pthread companion function */ - pthread_create(&threads[i], &attr, N_VWrmsNormMask_PT, (void *) &thread_data[i]); + pthread_create(&threads[i], &attr, N_VWSqrSumMask_PT, (void *) &thread_data[i]); } /* wait for all threads to finish */ @@ -1632,15 +1611,15 @@ realtype N_VWrmsNormMask_Pthreads(N_Vector x, N_Vector w, N_Vector id) free(threads); free(thread_data); - return(SUNRsqrt(sum/N)); + return(sum); } /* ---------------------------------------------------------------------------- - * Pthread companion function to N_VWrmsNormMask + * Pthread companion function to N_VWSqrSumMask */ -static void *N_VWrmsNormMask_PT(void *thread_data) +static void *N_VWSqrSumMask_PT(void *thread_data) { sunindextype i, start, end; realtype *xd, *wd, *idd; @@ -2476,7 +2455,7 @@ static void *N_VLinearCombination_PT(void *thread_data) /* * X[0] = c[0] * X[0] + sum{ c[i] * X[i] }, i = 1,...,nvec-1 */ - if ((my_data->Y1[0] == my_data->x1)) { + if (my_data->Y1[0] == my_data->x1) { for (j=start; j:--expt-extended-lambda>) + target_link_libraries(sundials_nveccudaraja_static PUBLIC RAJA) + set_target_properties(sundials_nveccudaraja_static PROPERTIES + OUTPUT_NAME sundials_nveccudaraja + CLEAN_DIRECT_OUTPUT 1) + install(TARGETS sundials_nveccudaraja_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: # - Add the build target for the NVECRAJA library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries # - Install the NVECRAJA library -IF(BUILD_SHARED_LIBS) - # ----------------------- CUDA only - CUDA_ADD_LIBRARY(sundials_nveccudaraja_shared SHARED - ${nvecraja_SOURCES} ${shared_SOURCES} - OPTIONS -DSUNDIALS_MPI_ENABLED=0 - ) - TARGET_COMPILE_DEFINITIONS(sundials_nveccudaraja_shared PUBLIC -DSUNDIALS_MPI_ENABLED=0) - SET_TARGET_PROPERTIES(sundials_nveccudaraja_shared - PROPERTIES OUTPUT_NAME sundials_nveccudaraja CLEAN_DIRECT_OUTPUT 1 - VERSION ${nveclib_VERSION} SOVERSION ${nveclib_SOVERSION} - ) - INSTALL(TARGETS sundials_nveccudaraja_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - - # ----------------------- MPI+CUDA - IF(MPI_ENABLE) - CUDA_ADD_LIBRARY(sundials_nvecmpicudaraja_shared SHARED ${nvecraja_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_nvecmpicudaraja_shared - PROPERTIES OUTPUT_NAME sundials_nvecmpicudaraja CLEAN_DIRECT_OUTPUT 1 - VERSION ${nveclib_VERSION} SOVERSION ${nveclib_SOVERSION} - ) - INSTALL(TARGETS sundials_nvecmpicudaraja_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF() -ENDIF(BUILD_SHARED_LIBS) +if(BUILD_SHARED_LIBS) + add_library(sundials_nveccudaraja_shared SHARED ${nvecraja_SOURCES} ${shared_SOURCES}) + target_compile_features(sundials_nveccudaraja_shared PUBLIC cxx_std_11) + target_compile_options(sundials_nveccudaraja_shared PUBLIC + $<$:--expt-extended-lambda>) + target_link_libraries(sundials_nveccudaraja_shared PUBLIC RAJA) + set_target_properties(sundials_nveccudaraja_shared PROPERTIES + OUTPUT_NAME sundials_nveccudaraja + CLEAN_DIRECT_OUTPUT 1 + VERSION ${nveclib_VERSION} + SOVERSION ${nveclib_SOVERSION}) + install(TARGETS sundials_nveccudaraja_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_SHARED_LIBS) # Install the NVECRAJA header files -INSTALL(FILES ${nvecraja_HEADERS} DESTINATION include/nvector) -INSTALL(DIRECTORY ${sundials_SOURCE_DIR}/include/nvector/raja DESTINATION include/nvector) - +install(FILES ${nvecraja_HEADERS} DESTINATION include/nvector) +install(DIRECTORY ${sundials_SOURCE_DIR}/include/nvector/raja DESTINATION include/nvector) -MESSAGE(STATUS "Added NVECTOR_RAJA module") +message(STATUS "Added NVECTOR_RAJA module") diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/raja/nvector_raja.cu b/deps/AMICI/ThirdParty/sundials/src/nvector/raja/nvector_raja.cu index 82e25aeb5..50f7d5a4c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/raja/nvector_raja.cu +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/raja/nvector_raja.cu @@ -1,8 +1,8 @@ /* ----------------------------------------------------------------- - * Programmer(s): Slaven Peles @ LLNL + * Programmer(s): Slaven Peles, Cody J. Balos @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -11,7 +11,7 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for a MPI+RAJA implementation + * This is the implementation file for a RAJA+CUDA implementation * of the NVECTOR package. * -----------------------------------------------------------------*/ @@ -19,7 +19,6 @@ #include #include -#include #include @@ -31,7 +30,7 @@ // RAJA defines #define CUDA_BLOCK_SIZE 256 #define RAJA_NODE_TYPE RAJA::cuda_exec< CUDA_BLOCK_SIZE > -#define RAJA_REDUCE_TYPE RAJA::cuda_reduce< CUDA_BLOCK_SIZE > +#define RAJA_REDUCE_TYPE RAJA::cuda_reduce #define RAJA_LAMBDA [=] __device__ extern "C" { @@ -44,24 +43,6 @@ typedef sunrajavec::Vector vector_type; // Static constants static constexpr sunindextype zeroIdx = 0; -/* - * ---------------------------------------------------------------- - * private accessor/helper functions - * ---------------------------------------------------------------- - */ - -static inline sunindextype getLocalLength(N_Vector v) -{ - vector_type* vp = static_cast(v->content); - return vp->size(); -} - -static inline SUNMPI_Comm getMPIComm(N_Vector v) -{ - vector_type* vp = static_cast(v->content); - return vp->comm(); -} - /* ---------------------------------------------------------------- * Returns vector type ID. Used to identify vector implementation * from abstract N_Vector interface. @@ -74,85 +55,59 @@ N_Vector_ID N_VGetVectorID_Raja(N_Vector v) N_Vector N_VNewEmpty_Raja() { N_Vector v; - N_Vector_Ops ops; - /* Create vector */ + /* Create an empty vector object */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } + /* Attach operations */ - ops->nvgetvectorid = N_VGetVectorID_Raja; - ops->nvclone = N_VClone_Raja; - ops->nvcloneempty = N_VCloneEmpty_Raja; - ops->nvdestroy = N_VDestroy_Raja; - ops->nvspace = N_VSpace_Raja; - ops->nvgetarraypointer = NULL; //N_VGetArrayPointer_Raja; - ops->nvsetarraypointer = NULL; //N_VSetArrayPointer_Raja; + /* constructors, destructors, and utility operations */ + v->ops->nvgetvectorid = N_VGetVectorID_Raja; + v->ops->nvclone = N_VClone_Raja; + v->ops->nvcloneempty = N_VCloneEmpty_Raja; + v->ops->nvdestroy = N_VDestroy_Raja; + v->ops->nvspace = N_VSpace_Raja; + v->ops->nvgetlength = N_VGetLength_Raja; /* standard vector operations */ - ops->nvlinearsum = N_VLinearSum_Raja; - ops->nvconst = N_VConst_Raja; - ops->nvprod = N_VProd_Raja; - ops->nvdiv = N_VDiv_Raja; - ops->nvscale = N_VScale_Raja; - ops->nvabs = N_VAbs_Raja; - ops->nvinv = N_VInv_Raja; - ops->nvaddconst = N_VAddConst_Raja; - ops->nvdotprod = N_VDotProd_Raja; - ops->nvmaxnorm = N_VMaxNorm_Raja; - ops->nvwrmsnormmask = N_VWrmsNormMask_Raja; - ops->nvwrmsnorm = N_VWrmsNorm_Raja; - ops->nvmin = N_VMin_Raja; - ops->nvwl2norm = N_VWL2Norm_Raja; - ops->nvl1norm = N_VL1Norm_Raja; - ops->nvcompare = N_VCompare_Raja; - ops->nvinvtest = N_VInvTest_Raja; - ops->nvconstrmask = N_VConstrMask_Raja; - ops->nvminquotient = N_VMinQuotient_Raja; - - /* fused vector operations (optional, NULL means disabled by default) */ - ops->nvlinearcombination = NULL; - ops->nvscaleaddmulti = NULL; - ops->nvdotprodmulti = NULL; - - /* vector array operations (optional, NULL means disabled by default) */ - ops->nvlinearsumvectorarray = NULL; - ops->nvscalevectorarray = NULL; - ops->nvconstvectorarray = NULL; - ops->nvwrmsnormvectorarray = NULL; - ops->nvwrmsnormmaskvectorarray = NULL; - ops->nvscaleaddmultivectorarray = NULL; - ops->nvlinearcombinationvectorarray = NULL; - - /* Attach ops and set content to NULL */ - v->content = NULL; - v->ops = ops; + v->ops->nvlinearsum = N_VLinearSum_Raja; + v->ops->nvconst = N_VConst_Raja; + v->ops->nvprod = N_VProd_Raja; + v->ops->nvdiv = N_VDiv_Raja; + v->ops->nvscale = N_VScale_Raja; + v->ops->nvabs = N_VAbs_Raja; + v->ops->nvinv = N_VInv_Raja; + v->ops->nvaddconst = N_VAddConst_Raja; + v->ops->nvdotprod = N_VDotProd_Raja; + v->ops->nvmaxnorm = N_VMaxNorm_Raja; + v->ops->nvmin = N_VMin_Raja; + v->ops->nvl1norm = N_VL1Norm_Raja; + v->ops->nvinvtest = N_VInvTest_Raja; + v->ops->nvconstrmask = N_VConstrMask_Raja; + v->ops->nvminquotient = N_VMinQuotient_Raja; + v->ops->nvwrmsnormmask = N_VWrmsNormMask_Raja; + v->ops->nvwrmsnorm = N_VWrmsNorm_Raja; + v->ops->nvwl2norm = N_VWL2Norm_Raja; + v->ops->nvcompare = N_VCompare_Raja; + + /* fused and vector array operations are disabled (NULL) by default */ + + /* local reduction operations */ + v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_Raja; + v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_Raja; + v->ops->nvdotprodlocal = N_VDotProd_Raja; + v->ops->nvmaxnormlocal = N_VMaxNorm_Raja; + v->ops->nvminlocal = N_VMin_Raja; + v->ops->nvl1normlocal = N_VL1Norm_Raja; + v->ops->nvinvtestlocal = N_VInvTest_Raja; + v->ops->nvconstrmasklocal = N_VConstrMask_Raja; + v->ops->nvminquotientlocal = N_VMinQuotient_Raja; return(v); } - -#if SUNDIALS_MPI_ENABLED -N_Vector N_VNew_Raja(MPI_Comm comm, - sunindextype local_length, - sunindextype global_length) -{ - N_Vector v; - - v = NULL; - v = N_VNewEmpty_Raja(); - if (v == NULL) return(NULL); - - v->content = new vector_type(comm, local_length, global_length); - - return(v); -} -#else N_Vector N_VNew_Raja(sunindextype length) { N_Vector v; @@ -165,8 +120,6 @@ N_Vector N_VNew_Raja(sunindextype length) return(v); } -#endif - N_Vector N_VMake_Raja(N_VectorContent_Raja c) { @@ -188,31 +141,11 @@ N_Vector N_VMake_Raja(N_VectorContent_Raja c) * Function to return the global length of the vector. */ sunindextype N_VGetLength_Raja(N_Vector v) -{ - vector_type* xd = static_cast(v->content); - return xd->sizeGlobal(); -} - -#if SUNDIALS_MPI_ENABLED -/* ----------------------------------------------------------------- - * Function to return the local length of the vector. - */ -sunindextype N_VGetLocalLength_Raja(N_Vector v) { vector_type* xd = static_cast(v->content); return xd->size(); } -/* ----------------------------------------------------------------- - * Function to return the MPI communicator for the vector. - */ -MPI_Comm N_VGetMPIComm_Raja(N_Vector v) -{ - vector_type* xd = static_cast(v->content); - return (xd->comm()); -} -#endif - /* ---------------------------------------------------------------------------- * Return pointer to the raw host data */ @@ -269,7 +202,7 @@ void N_VPrint_Raja(N_Vector X) void N_VPrintFile_Raja(N_Vector X, FILE *outfile) { const realtype *xd = N_VGetDeviceArrayPointer_Raja(X); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); sunindextype i; for (i = 0; i < N; ++i) { @@ -295,66 +228,16 @@ void N_VPrintFile_Raja(N_Vector X, FILE *outfile) N_Vector N_VCloneEmpty_Raja(N_Vector w) { N_Vector v; - N_Vector_Ops ops; if (w == NULL) return(NULL); /* Create vector */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } - - ops->nvgetvectorid = w->ops->nvgetvectorid; - ops->nvclone = w->ops->nvclone; - ops->nvcloneempty = w->ops->nvcloneempty; - ops->nvdestroy = w->ops->nvdestroy; - ops->nvspace = w->ops->nvspace; - ops->nvgetarraypointer = w->ops->nvgetarraypointer; - ops->nvsetarraypointer = w->ops->nvsetarraypointer; - - /* standard vector operations */ - ops->nvlinearsum = w->ops->nvlinearsum; - ops->nvconst = w->ops->nvconst; - ops->nvprod = w->ops->nvprod; - ops->nvdiv = w->ops->nvdiv; - ops->nvscale = w->ops->nvscale; - ops->nvabs = w->ops->nvabs; - ops->nvinv = w->ops->nvinv; - ops->nvaddconst = w->ops->nvaddconst; - ops->nvdotprod = w->ops->nvdotprod; - ops->nvmaxnorm = w->ops->nvmaxnorm; - ops->nvwrmsnormmask = w->ops->nvwrmsnormmask; - ops->nvwrmsnorm = w->ops->nvwrmsnorm; - ops->nvmin = w->ops->nvmin; - ops->nvwl2norm = w->ops->nvwl2norm; - ops->nvl1norm = w->ops->nvl1norm; - ops->nvcompare = w->ops->nvcompare; - ops->nvinvtest = w->ops->nvinvtest; - ops->nvconstrmask = w->ops->nvconstrmask; - ops->nvminquotient = w->ops->nvminquotient; - - /* fused vector operations */ - ops->nvlinearcombination = w->ops->nvlinearcombination; - ops->nvscaleaddmulti = w->ops->nvscaleaddmulti; - ops->nvdotprodmulti = w->ops->nvdotprodmulti; - - /* vector array operations */ - ops->nvlinearsumvectorarray = w->ops->nvlinearsumvectorarray; - ops->nvscalevectorarray = w->ops->nvscalevectorarray; - ops->nvconstvectorarray = w->ops->nvconstvectorarray; - ops->nvwrmsnormvectorarray = w->ops->nvwrmsnormvectorarray; - ops->nvwrmsnormmaskvectorarray = w->ops->nvwrmsnormmaskvectorarray; - ops->nvscaleaddmultivectorarray = w->ops->nvscaleaddmultivectorarray; - ops->nvlinearcombinationvectorarray = w->ops->nvlinearcombinationvectorarray; - - /* Create content */ - v->content = NULL; - v->ops = ops; + /* Attach operations */ + if (N_VCopyOps(w, v)) { N_VDestroy(v); return(NULL); } return(v); } @@ -362,12 +245,13 @@ N_Vector N_VCloneEmpty_Raja(N_Vector w) N_Vector N_VClone_Raja(N_Vector w) { N_Vector v; - vector_type* wdat = static_cast(w->content); - vector_type* vdat = new vector_type(*wdat); v = NULL; v = N_VCloneEmpty_Raja(w); if (v == NULL) return(NULL); + vector_type* wdat = static_cast(w->content); + vector_type* vdat = new vector_type(*wdat); + v->content = vdat; return(v); @@ -376,13 +260,16 @@ N_Vector N_VClone_Raja(N_Vector w) void N_VDestroy_Raja(N_Vector v) { + if (v == NULL) return; + vector_type* x = static_cast(v->content); if (x != NULL) { delete x; v->content = NULL; } - free(v->ops); v->ops = NULL; + /* free ops and vector */ + if (v->ops != NULL) { free(v->ops); v->ops = NULL; } free(v); v = NULL; return; @@ -390,18 +277,13 @@ void N_VDestroy_Raja(N_Vector v) void N_VSpace_Raja(N_Vector X, sunindextype *lrw, sunindextype *liw) { - SUNMPI_Comm comm = getMPIComm(X); - int npes; - - SUNMPI_Comm_size(comm, &npes); - *lrw = N_VGetLength_Raja(X); - *liw = 2*npes; + *liw = 2; } void N_VConst_Raja(realtype c, N_Vector Z) { - const sunindextype N = getLocalLength(Z); + const sunindextype N = N_VGetLength_Raja(Z); realtype *zdata = N_VGetDeviceArrayPointer_Raja(Z); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), RAJA_LAMBDA(sunindextype i) { @@ -413,7 +295,7 @@ void N_VLinearSum_Raja(realtype a, N_Vector X, realtype b, N_Vector Y, N_Vector { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); const realtype *ydata = N_VGetDeviceArrayPointer_Raja(Y); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); realtype *zdata = N_VGetDeviceArrayPointer_Raja(Z); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), @@ -427,7 +309,7 @@ void N_VProd_Raja(N_Vector X, N_Vector Y, N_Vector Z) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); const realtype *ydata = N_VGetDeviceArrayPointer_Raja(Y); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); realtype *zdata = N_VGetDeviceArrayPointer_Raja(Z); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), @@ -441,7 +323,7 @@ void N_VDiv_Raja(N_Vector X, N_Vector Y, N_Vector Z) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); const realtype *ydata = N_VGetDeviceArrayPointer_Raja(Y); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); realtype *zdata = N_VGetDeviceArrayPointer_Raja(Z); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), @@ -454,7 +336,7 @@ void N_VDiv_Raja(N_Vector X, N_Vector Y, N_Vector Z) void N_VScale_Raja(realtype c, N_Vector X, N_Vector Z) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); realtype *zdata = N_VGetDeviceArrayPointer_Raja(Z); RAJA::forall(RAJA::RangeSegment(zeroIdx, N), @@ -467,7 +349,7 @@ void N_VScale_Raja(realtype c, N_Vector X, N_Vector Z) void N_VAbs_Raja(N_Vector X, N_Vector Z) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); realtype *zdata = N_VGetDeviceArrayPointer_Raja(Z); RAJA::forall(RAJA::RangeSegment(zeroIdx, N), @@ -480,7 +362,7 @@ void N_VAbs_Raja(N_Vector X, N_Vector Z) void N_VInv_Raja(N_Vector X, N_Vector Z) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); realtype *zdata = N_VGetDeviceArrayPointer_Raja(Z); RAJA::forall(RAJA::RangeSegment(zeroIdx, N), @@ -493,7 +375,7 @@ void N_VInv_Raja(N_Vector X, N_Vector Z) void N_VAddConst_Raja(N_Vector X, realtype b, N_Vector Z) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); realtype *zdata = N_VGetDeviceArrayPointer_Raja(Z); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), @@ -507,7 +389,7 @@ realtype N_VDotProd_Raja(N_Vector X, N_Vector Y) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); const realtype *ydata = N_VGetDeviceArrayPointer_Raja(Y); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); RAJA::ReduceSum< RAJA_REDUCE_TYPE, realtype> gpu_result(0.0); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), @@ -516,17 +398,13 @@ realtype N_VDotProd_Raja(N_Vector X, N_Vector Y) } ); - /* Reduce across MPI processes */ - realtype sum = static_cast(gpu_result); - SUNMPI_Comm comm = getMPIComm(X); - realtype gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); - return gsum; + return(static_cast(gpu_result)); } realtype N_VMaxNorm_Raja(N_Vector X) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); RAJA::ReduceMax< RAJA_REDUCE_TYPE, realtype> gpu_result(0.0); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), @@ -535,18 +413,14 @@ realtype N_VMaxNorm_Raja(N_Vector X) } ); - /* Reduce across MPI processes */ - realtype maximum = static_cast(gpu_result); - SUNMPI_Comm comm = getMPIComm(X); - return SUNMPI_Allreduce_scalar(maximum, 2, comm); + return(static_cast(gpu_result)); } -realtype N_VWrmsNorm_Raja(N_Vector X, N_Vector W) +realtype N_VWSqrSumLocal_Raja(N_Vector X, N_Vector W) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); const realtype *wdata = N_VGetDeviceArrayPointer_Raja(W); - const sunindextype N = getLocalLength(X); - const sunindextype Nglobal = N_VGetLength_Raja(X); + const sunindextype N = N_VGetLength_Raja(X); RAJA::ReduceSum< RAJA_REDUCE_TYPE, realtype> gpu_result(0.0); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), @@ -555,19 +429,22 @@ realtype N_VWrmsNorm_Raja(N_Vector X, N_Vector W) } ); - /* Reduce across MPI processes */ - realtype sum = static_cast(gpu_result); - SUNMPI_Comm comm = getMPIComm(X); - return std::sqrt(SUNMPI_Allreduce_scalar(sum, 1, comm)/Nglobal); + return(static_cast(gpu_result)); } -realtype N_VWrmsNormMask_Raja(N_Vector X, N_Vector W, N_Vector ID) +realtype N_VWrmsNorm_Raja(N_Vector X, N_Vector W) +{ + const realtype sum = N_VWSqrSumLocal_Raja(X, W); + const sunindextype N = N_VGetLength_Raja(X); + return std::sqrt(sum/N); +} + +realtype N_VWSqrSumMaskLocal_Raja(N_Vector X, N_Vector W, N_Vector ID) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); const realtype *wdata = N_VGetDeviceArrayPointer_Raja(W); const realtype *iddata = N_VGetDeviceArrayPointer_Raja(ID); - const sunindextype N = getLocalLength(X); - const sunindextype Nglobal = N_VGetLength_Raja(X); + const sunindextype N = N_VGetLength_Raja(X); RAJA::ReduceSum< RAJA_REDUCE_TYPE, realtype> gpu_result(0.0); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), @@ -577,16 +454,20 @@ realtype N_VWrmsNormMask_Raja(N_Vector X, N_Vector W, N_Vector ID) } ); - /* Reduce across MPI processes */ - realtype sum = static_cast(gpu_result); - SUNMPI_Comm comm = getMPIComm(X); - return std::sqrt(SUNMPI_Allreduce_scalar(sum, 1, comm)/Nglobal); + return(static_cast(gpu_result)); +} + +realtype N_VWrmsNormMask_Raja(N_Vector X, N_Vector W, N_Vector ID) +{ + const realtype sum = N_VWSqrSumMaskLocal_Raja(X, W, ID); + const sunindextype N = N_VGetLength_Raja(X); + return std::sqrt(sum/N); } realtype N_VMin_Raja(N_Vector X) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); RAJA::ReduceMin< RAJA_REDUCE_TYPE, realtype> gpu_result(std::numeric_limits::max()); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), @@ -595,35 +476,18 @@ realtype N_VMin_Raja(N_Vector X) } ); - /* Reduce across MPI processes */ - realtype minumum = static_cast(gpu_result); - SUNMPI_Comm comm = getMPIComm(X); - return SUNMPI_Allreduce_scalar(minumum, 3, comm); + return(static_cast(gpu_result)); } realtype N_VWL2Norm_Raja(N_Vector X, N_Vector W) { - const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); - const realtype *wdata = N_VGetDeviceArrayPointer_Raja(W); - const sunindextype N = getLocalLength(X); - - RAJA::ReduceSum< RAJA_REDUCE_TYPE, realtype> gpu_result(0.0); - RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), - RAJA_LAMBDA(sunindextype i) { - gpu_result += (xdata[i] * wdata[i] * xdata[i] * wdata[i]); - } - ); - - /* Reduce across MPI processes */ - realtype sum = static_cast(gpu_result); - SUNMPI_Comm comm = getMPIComm(X); - return std::sqrt(SUNMPI_Allreduce_scalar(sum, 1, comm)); + return std::sqrt(N_VWSqrSumLocal_Raja(X, W)); } realtype N_VL1Norm_Raja(N_Vector X) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); RAJA::ReduceSum< RAJA_REDUCE_TYPE, realtype> gpu_result(0.0); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), @@ -632,16 +496,13 @@ realtype N_VL1Norm_Raja(N_Vector X) } ); - /* Reduce across MPI processes */ - realtype sum = static_cast(gpu_result); - SUNMPI_Comm comm = getMPIComm(X); - return SUNMPI_Allreduce_scalar(sum, 1, comm); + return(static_cast(gpu_result)); } void N_VCompare_Raja(realtype c, N_Vector X, N_Vector Z) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(X); - const sunindextype N = getLocalLength(X); + const sunindextype N = N_VGetLength_Raja(X); realtype *zdata = N_VGetDeviceArrayPointer_Raja(Z); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), @@ -654,7 +515,7 @@ void N_VCompare_Raja(realtype c, N_Vector X, N_Vector Z) booleantype N_VInvTest_Raja(N_Vector x, N_Vector z) { const realtype *xdata = N_VGetDeviceArrayPointer_Raja(x); - const sunindextype N = getLocalLength(x); + const sunindextype N = N_VGetLength_Raja(x); realtype *zdata = N_VGetDeviceArrayPointer_Raja(z); RAJA::ReduceSum< RAJA_REDUCE_TYPE, realtype> gpu_result(ZERO); @@ -667,20 +528,15 @@ booleantype N_VInvTest_Raja(N_Vector x, N_Vector z) } } ); - - /* Reduce across MPI processes */ realtype minimum = static_cast(gpu_result); - SUNMPI_Comm comm = getMPIComm(x); - realtype global_minimum = SUNMPI_Allreduce_scalar(minimum, 3, comm); - - return (global_minimum < HALF); + return (minimum < HALF); } booleantype N_VConstrMask_Raja(N_Vector c, N_Vector x, N_Vector m) { const realtype *cdata = N_VGetDeviceArrayPointer_Raja(c); const realtype *xdata = N_VGetDeviceArrayPointer_Raja(x); - const sunindextype N = getLocalLength(x); + const sunindextype N = N_VGetLength_Raja(x); realtype *mdata = N_VGetDeviceArrayPointer_Raja(m); RAJA::ReduceSum< RAJA_REDUCE_TYPE, realtype> gpu_result(ZERO); @@ -693,19 +549,15 @@ booleantype N_VConstrMask_Raja(N_Vector c, N_Vector x, N_Vector m) } ); - /* Reduce across MPI processes */ realtype sum = static_cast(gpu_result); - SUNMPI_Comm comm = getMPIComm(x); - realtype global_sum = SUNMPI_Allreduce_scalar(sum, 1, comm); - - return (global_sum < HALF); + return(sum < HALF); } realtype N_VMinQuotient_Raja(N_Vector num, N_Vector denom) { const realtype *ndata = N_VGetDeviceArrayPointer_Raja(num); const realtype *ddata = N_VGetDeviceArrayPointer_Raja(denom); - const sunindextype N = getLocalLength(num); + const sunindextype N = N_VGetLength_Raja(num); RAJA::ReduceMin< RAJA_REDUCE_TYPE, realtype> gpu_result(std::numeric_limits::max()); RAJA::forall< RAJA_NODE_TYPE >(RAJA::RangeSegment(zeroIdx, N), @@ -714,11 +566,7 @@ realtype N_VMinQuotient_Raja(N_Vector num, N_Vector denom) gpu_result.min(ndata[i]/ddata[i]); } ); - - /* Reduce across MPI processes */ - realtype minimum = static_cast(gpu_result); - SUNMPI_Comm comm = getMPIComm(num); - return SUNMPI_Allreduce_scalar(minimum, 3, comm); + return(static_cast(gpu_result)); } @@ -732,7 +580,7 @@ int N_VLinearCombination_Raja(int nvec, realtype* c, N_Vector* X, N_Vector z) { cudaError_t err; - sunindextype N = getLocalLength(z); + sunindextype N = N_VGetLength_Raja(z); realtype* d_zd = N_VGetDeviceArrayPointer_Raja(z); // Copy c array to device @@ -779,7 +627,7 @@ int N_VScaleAddMulti_Raja(int nvec, realtype* c, N_Vector x, N_Vector* Y, N_Vect { cudaError_t err; - sunindextype N = getLocalLength(x); + sunindextype N = N_VGetLength_Raja(x); realtype* d_xd = N_VGetDeviceArrayPointer_Raja(x); // Copy c array to device @@ -847,7 +695,7 @@ int N_VLinearSumVectorArray_Raja(int nvec, { cudaError_t err; - sunindextype N = getLocalLength(Z[0]); + sunindextype N = N_VGetLength_Raja(Z[0]); // Create array of device pointers on host realtype** h_Xd = new realtype*[nvec]; @@ -909,7 +757,7 @@ int N_VScaleVectorArray_Raja(int nvec, realtype* c, N_Vector* X, N_Vector* Z) { cudaError_t err; - sunindextype N = getLocalLength(Z[0]); + sunindextype N = N_VGetLength_Raja(Z[0]); // Copy c array to device realtype* d_c; @@ -965,7 +813,7 @@ int N_VConstVectorArray_Raja(int nvec, realtype c, N_Vector* Z) { cudaError_t err; - sunindextype N = getLocalLength(Z[0]); + sunindextype N = N_VGetLength_Raja(Z[0]); // Create array of device pointers on host realtype** h_Zd = new realtype*[nvec]; @@ -1002,7 +850,7 @@ int N_VScaleAddMultiVectorArray_Raja(int nvec, int nsum, realtype* c, { cudaError_t err; - sunindextype N = getLocalLength(X[0]); + sunindextype N = N_VGetLength_Raja(X[0]); // Copy c array to device realtype* d_c; @@ -1075,7 +923,7 @@ int N_VLinearCombinationVectorArray_Raja(int nvec, int nsum, realtype* c, { cudaError_t err; - sunindextype N = getLocalLength(Z[0]); + sunindextype N = N_VGetLength_Raja(Z[0]); // Copy c array to device realtype* d_c; diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/CMakeLists.txt index 8e99388aa..0cfd7e11c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Radu Serban @ LLNL +# Programmer(s): Radu Serban @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,92 +12,94 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the serial NVECTOR library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall NVECTOR_SERIAL\n\")") +install(CODE "MESSAGE(\"\nInstall NVECTOR_SERIAL\n\")") # Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF(F90_FOUND AND F2003_INTERFACE_ENABLE) +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) # Add variable nvecserial_SOURCES with the sources for the NVECSERIAL lib -SET(nvecserial_SOURCES nvector_serial.c) +set(nvecserial_SOURCES nvector_serial.c) # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the NVECSERIAL library -SET(shared_SOURCES +set(shared_SOURCES + ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c ) # Add variable nvecserial_HEADERS with the exported NVECSERIAL header files -SET(nvecserial_HEADERS +set(nvecserial_HEADERS ${sundials_SOURCE_DIR}/include/nvector/nvector_serial.h ) # Add source directory to include directories -INCLUDE_DIRECTORIES(.) +include_directories(.) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) # Rules for building and installing the static library: # - Add the build target for the NVECSERIAL library # - Set the library name and make sure it is not deleted # - Install the NVECSERIAL library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_nvecserial_static STATIC ${nvecserial_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_nvecserial_static +if(BUILD_STATIC_LIBS) + add_library(sundials_nvecserial_static STATIC ${nvecserial_SOURCES} ${shared_SOURCES}) + set_target_properties(sundials_nvecserial_static PROPERTIES OUTPUT_NAME sundials_nvecserial CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_nvecserial_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) + install(TARGETS sundials_nvecserial_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: # - Add the build target for the NVECSERIAL library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries # - Install the NVECSERIAL library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_nvecserial_shared SHARED ${nvecserial_SOURCES} ${shared_SOURCES}) +if(BUILD_SHARED_LIBS) + add_library(sundials_nvecserial_shared SHARED ${nvecserial_SOURCES} ${shared_SOURCES}) - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_nvecserial_shared m) - ENDIF() + if(UNIX) + target_link_libraries(sundials_nvecserial_shared m) + endif() - SET_TARGET_PROPERTIES(sundials_nvecserial_shared + set_target_properties(sundials_nvecserial_shared PROPERTIES OUTPUT_NAME sundials_nvecserial CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_nvecserial_shared + set_target_properties(sundials_nvecserial_shared PROPERTIES VERSION ${nveclib_VERSION} SOVERSION ${nveclib_SOVERSION}) - INSTALL(TARGETS sundials_nvecserial_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) + install(TARGETS sundials_nvecserial_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_SHARED_LIBS) # Install the NVECSERIAL header files -INSTALL(FILES ${nvecserial_HEADERS} DESTINATION include/nvector) +install(FILES ${nvecserial_HEADERS} DESTINATION include/nvector) # If FCMIX is enabled, build and install the FNVECSERIAL library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fnvecserial_SOURCES fnvector_serial.c) +if(F77_INTERFACE_ENABLE AND F77_FOUND) + set(fnvecserial_SOURCES fnvector_serial.c) - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fnvecserial_static STATIC ${fnvecserial_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fnvecserial_static + if(BUILD_STATIC_LIBS) + add_library(sundials_fnvecserial_static STATIC ${fnvecserial_SOURCES}) + set_target_properties(sundials_fnvecserial_static PROPERTIES OUTPUT_NAME sundials_fnvecserial CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fnvecserial_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) + install(TARGETS sundials_fnvecserial_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fnvecserial_shared ${fnvecserial_SOURCES}) + if(BUILD_SHARED_LIBS) + add_library(sundials_fnvecserial_shared ${fnvecserial_SOURCES}) # fnvecserial depends on nvecserial - TARGET_LINK_LIBRARIES(sundials_fnvecserial_shared sundials_nvecserial_shared) + target_link_libraries(sundials_fnvecserial_shared sundials_nvecserial_shared) - SET_TARGET_PROPERTIES(sundials_fnvecserial_shared + set_target_properties(sundials_fnvecserial_shared PROPERTIES OUTPUT_NAME sundials_fnvecserial CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fnvecserial_shared + set_target_properties(sundials_fnvecserial_shared PROPERTIES VERSION ${nveclib_VERSION} SOVERSION ${nveclib_SOVERSION}) - INSTALL(TARGETS sundials_fnvecserial_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + install(TARGETS sundials_fnvecserial_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(F77_INTERFACE_ENABLE AND F77_FOUND) # -MESSAGE(STATUS "Added NVECTOR_SERIAL module") +message(STATUS "Added NVECTOR_SERIAL module") diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/F90/CMakeLists.txt deleted file mode 100644 index 30d9dafe5..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/F90/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# --------------------------------------------------------------- -# Programmer: Cody J. Balos @ LLNL -# --------------------------------------------------------------- -# SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security -# and Southern Methodist University. -# All rights reserved. -# -# See the top-level LICENSE and NOTICE files for details. -# -# SPDX-License-Identifier: BSD-3-Clause -# SUNDIALS Copyright End -# --------------------------------------------------------------- -# CMakeLists.txt file for the F2003 serial NVECTOR object library - -set(nvecserial_SOURCES fnvector_serial.f90) - -if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fnvecserial_mod_static STATIC - ${nvecserial_SOURCES} - ) - set_target_properties(sundials_fnvecserial_mod_static - PROPERTIES OUTPUT_NAME sundials_fnvecserial_mod CLEAN_DIRECT_OUTPUT 1) - install(TARGETS sundials_fnvecserial_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -endif(BUILD_STATIC_LIBS) - -if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fnvecserial_mod_shared SHARED - ${nvecserial_SOURCES} - ) - set_target_properties(sundials_fnvecserial_mod_shared - PROPERTIES OUTPUT_NAME sundials_fnvecserial_mod CLEAN_DIRECT_OUTPUT 1) - set_target_properties(sundials_fnvecserial_mod_shared - PROPERTIES VERSION ${nveclib_VERSION} SOVERSION ${nveclib_SOVERSION}) - install(TARGETS sundials_fnvecserial_mod_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -endif(BUILD_SHARED_LIBS) - -message(STATUS "Added NVECTOR_SERIAL F2003 interface") diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/F90/fnvector_serial.f90 b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/F90/fnvector_serial.f90 deleted file mode 100644 index 460c499a6..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/F90/fnvector_serial.f90 +++ /dev/null @@ -1,478 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): David J. Gardner @ LLNL -! Daniel R. Reynolds @ SMU -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS serial NVector using the ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fnvector_serial_mod - - !======= Interfaces ========= - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - ! ----------------------------------------------------------------- - ! N_VNew_Serial - ! ----------------------------------------------------------------- - - type(c_ptr) function FN_VNew_Serial(vec_length) & - bind(C,name='N_VNew_Serial') - use, intrinsic :: iso_c_binding - implicit none - integer(c_long), value :: vec_length - end function FN_VNew_Serial - - ! ----------------------------------------------------------------- - ! N_VNewEmpty_Serial - ! ----------------------------------------------------------------- - - type(c_ptr) function FN_VNewEmpty_Serial(vec_length) & - bind(C,name='N_VNewEmpty_Serial') - use, intrinsic :: iso_c_binding - implicit none - integer(c_long), value :: vec_length - end function FN_VNewEmpty_Serial - - ! ----------------------------------------------------------------- - ! N_VMake_Serial - ! ----------------------------------------------------------------- - - type(c_ptr) function FN_VMake_Serial(length, v_data) & - bind(C,name='N_VMake_Serial') - use, intrinsic :: iso_c_binding - implicit none - integer(c_long), value :: length - real(c_double) :: v_data(length) - end function FN_VMake_Serial - - ! ----------------------------------------------------------------- - ! N_VCloneVectorArray_Serial: NOT INTERFACED - ! ----------------------------------------------------------------- - - ! ----------------------------------------------------------------- - ! N_VCloneVectorArrayEmpty_Serial: NOT INTERFACED - ! ----------------------------------------------------------------- - - ! ================================================================= - ! Destructors - ! ================================================================= - - ! ----------------------------------------------------------------- - ! N_VDestroy_Serial - ! ----------------------------------------------------------------- - - subroutine FN_VDestroy_Serial(v) & - bind(C,name='N_VDestroy_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: v - end subroutine FN_VDestroy_Serial - - ! ----------------------------------------------------------------- - ! N_VDestroyVectorArray_Serial: NOT INTERFACED - ! ----------------------------------------------------------------- - - ! ================================================================= - ! Other routines - ! ================================================================= - - ! ----------------------------------------------------------------- - ! N_VGetLength_Serial - ! ----------------------------------------------------------------- - - integer(c_long) function FN_VGetLength_Serial(v) & - bind(C,name='N_VGetLength_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: v - end function FN_VGetLength_Serial - - ! ----------------------------------------------------------------- - ! N_VPrint_Serial - ! ----------------------------------------------------------------- - - subroutine FN_VPrint_Serial(v) & - bind(C,name='N_VPrint_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: v - end subroutine FN_VPrint_Serial - - ! ----------------------------------------------------------------- - ! NOT INTERFACED: N_VPrintFile_Serial - ! ----------------------------------------------------------------- - - ! ================================================================= - ! Operations - ! ================================================================= - - ! ----------------------------------------------------------------- - ! N_VGetVectorID_Serial - ! ----------------------------------------------------------------- - - integer(c_int) function FN_VGetVectorID_Serial(v) & - bind(C,name='N_VGetVectorID_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: v - end function FN_VGetVectorID_Serial - - ! ----------------------------------------------------------------- - ! N_VCloneEmpty_Serial - ! ----------------------------------------------------------------- - - type(c_ptr) function FN_VCloneEmpty_Serial(w) & - bind(C,name='N_VCloneEmpty_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: w - end function FN_VCloneEmpty_Serial - - ! ----------------------------------------------------------------- - ! N_VClone_Serial - ! ----------------------------------------------------------------- - - type(c_ptr) function FN_VClone_Serial(w) & - bind(C,name='N_VClone_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: w - end function FN_VClone_Serial - - ! ----------------------------------------------------------------- - ! N_VSpace_Serial - ! ----------------------------------------------------------------- - - subroutine FN_VSpace_Serial(v, lrw, liw) & - bind(C,name='N_VSpace_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: v - integer(c_long) :: lrw - integer(c_long) :: liw - end subroutine FN_VSpace_Serial - - ! ----------------------------------------------------------------- - ! N_VGetArrayPointer_Serial - ! ----------------------------------------------------------------- - - type(c_ptr) function FN_VGetArrayPointer_Serial(vec) & - bind(C,name='N_VGetArrayPointer_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: vec - end function FN_VGetArrayPointer_Serial - - ! ----------------------------------------------------------------- - ! N_VSetArrayPointer_Serial - ! ----------------------------------------------------------------- - - subroutine FN_VSetArrayPointer_Serial(v_data, v) & - bind(C,name='N_VSetArrayPointer_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: v_data - type(c_ptr), value :: v - end subroutine FN_VSetArrayPointer_Serial - - ! ----------------------------------------------------------------- - ! N_VLinearSum_Serial - ! ----------------------------------------------------------------- - - subroutine FN_VLinearSum_Serial(a, x, b, y, z) & - bind(C,name='N_VLinearSum_Serial') - use, intrinsic :: iso_c_binding - implicit none - real(c_double), value :: a - type(c_ptr), value :: x - real(c_double), value :: b - type(c_ptr), value :: y - type(c_ptr), value :: z - end subroutine FN_VLinearSum_Serial - - ! ----------------------------------------------------------------- - ! N_VConst_Serial - ! ----------------------------------------------------------------- - - subroutine FN_VConst_Serial(c, z) & - bind(C,name='N_VConst_Serial') - use, intrinsic :: iso_c_binding - implicit none - real(c_double), value :: c - type(c_ptr), value :: z - end subroutine FN_VConst_Serial - - ! ----------------------------------------------------------------- - ! N_VProd_Serial - ! ----------------------------------------------------------------- - - subroutine FN_VProd_Serial(x, y, z) & - bind(C,name='N_VProd_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: y - type(c_ptr), value :: z - end subroutine FN_VProd_Serial - - ! ----------------------------------------------------------------- - ! N_VDiv_Serial - ! ----------------------------------------------------------------- - - subroutine FN_VDiv_Serial(x, y, z) & - bind(C,name='N_VDiv_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: y - type(c_ptr), value :: z - end subroutine FN_VDiv_Serial - - ! ----------------------------------------------------------------- - ! N_VScale_Serial - ! ----------------------------------------------------------------- - - subroutine FN_VScale_Serial(c, x, z) & - bind(C,name='N_VScale_Serial') - use, intrinsic :: iso_c_binding - implicit none - real(c_double), value :: c - type(c_ptr), value :: x - type(c_ptr), value :: z - end subroutine FN_VScale_Serial - - ! ----------------------------------------------------------------- - ! N_VAbs_Serial - ! ----------------------------------------------------------------- - - subroutine FN_VAbs_Serial(x, z) & - bind(C,name='N_VAbs_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: z - end subroutine FN_VAbs_Serial - - ! ----------------------------------------------------------------- - ! N_VInv_Serial - ! ----------------------------------------------------------------- - - subroutine FN_VInv_Serial(x, z) & - bind(C,name='N_VInv_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: z - end subroutine FN_VInv_Serial - - ! ----------------------------------------------------------------- - ! N_VAddConst - ! ----------------------------------------------------------------- - - subroutine FN_VAddConst_Serial(x, b, z) & - bind(C,name='N_VAddConst_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - real(c_double), value :: b - type(c_ptr), value :: z - end subroutine FN_VAddConst_Serial - - ! ----------------------------------------------------------------- - ! N_VDotProd_Serial - ! ----------------------------------------------------------------- - - real(c_double) function FN_VDotProd_Serial(x, y) & - bind(C,name='N_VDotProd_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: y - end function FN_VDotProd_Serial - - ! ----------------------------------------------------------------- - ! N_VMaxNorm_Serial - ! ----------------------------------------------------------------- - - real(c_double) function FN_VMaxNorm_Serial(x) & - bind(C,name='N_VMaxNorm_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - end function FN_VMaxNorm_Serial - - ! ----------------------------------------------------------------- - ! N_VWrmsNorm_Serial - ! ----------------------------------------------------------------- - - real(c_double) function FN_VWrmsNorm_Serial(x, w) & - bind(C,name='N_VWrmsNorm_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: w - end function FN_VWrmsNorm_Serial - - ! ----------------------------------------------------------------- - ! N_VWrmsNormMask_Serial - ! ----------------------------------------------------------------- - - real(c_double) function FN_VWrmsNormMask_Serial(x, w, id) & - bind(C,name='N_VWrmsNormMask_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: w - type(c_ptr), value :: id - end function FN_VWrmsNormMask_Serial - - ! ----------------------------------------------------------------- - ! N_VMin_Serial - ! ----------------------------------------------------------------- - - real(c_double) function FN_VMin_Serial(x) & - bind(C,name='N_VMin_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - end function FN_VMin_Serial - - ! ----------------------------------------------------------------- - ! N_VWL2Norm_Serial - ! ----------------------------------------------------------------- - - real(c_double) function FN_VWL2Norm_Serial(x, w) & - bind(C,name='N_VWL2Norm_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: w - end function FN_VWL2Norm_Serial - - ! ----------------------------------------------------------------- - ! N_VL1Norm_Serial - ! ----------------------------------------------------------------- - - real(c_double) function FN_VL1Norm_Serial(x) & - bind(C,name='N_VL1Norm_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - end function FN_VL1Norm_Serial - - ! ----------------------------------------------------------------- - ! N_VCompare_Serial - ! ----------------------------------------------------------------- - - subroutine FN_VCompare_Serial(c, x, z) & - bind(C,name='N_VCompare_Serial') - use, intrinsic :: iso_c_binding - implicit none - real(c_double), value :: c - type(c_ptr), value :: x - type(c_ptr), value :: z - end subroutine FN_VCompare_Serial - - ! ----------------------------------------------------------------- - ! N_VInvTest_Serial - ! ----------------------------------------------------------------- - - integer(c_int) function FN_VInvTest_Serial(x, z) & - bind(C,name='N_VInvTest_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: x - type(c_ptr), value :: z - end function FN_VInvTest_Serial - - ! ----------------------------------------------------------------- - ! N_VConstrMask_Serial - ! ----------------------------------------------------------------- - - integer(c_int) function FN_VConstrMask_Serial(c, x, m) & - bind(C,name='N_VConstrMask_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: c - type(c_ptr), value :: x - type(c_ptr), value :: m - end function FN_VConstrMask_Serial - - ! ----------------------------------------------------------------- - ! N_VMinQuotient_Serial - ! ----------------------------------------------------------------- - - real(c_double) function FN_VMinQuotient_Serial(num, denom) & - bind(C,name='N_VMinQuotient_Serial') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: num - type(c_ptr), value :: denom - end function FN_VMinQuotient_Serial - - ! ================================================================ - ! Fused vector operations: NOT INTERFACED - ! ================================================================ - - ! ================================================================ - ! Vector array operations: NOT INTERFACED - ! ================================================================ - - end interface - -contains - - ! ================================================================ - ! Helpful routines - ! ================================================================ - - ! ---------------------------------------------------------------- - ! FN_VGetData_Serial - ! - ! Extracts data array from a serial SUNDIALS N_Vector - ! ---------------------------------------------------------------- - - subroutine FN_VGetData_Serial(vec, f_array) - - !======= Inclusions =========== - use, intrinsic :: iso_c_binding - - !======= Declarations ========= - implicit none - - ! calling variables - type(c_ptr) :: vec - integer(c_long) :: length - real(c_double), pointer :: f_array(:) - - ! C pointer for N_Vector interal data array - type(c_ptr) :: c_array - - !======= Internals ============ - - ! get data pointer from N_Vector - c_array = FN_VGetArrayPointer_Serial(vec) - - ! get vector length - length = FN_VGetLength_Serial(vec) - - ! convert c pointer to f pointer - call c_f_pointer(c_array, f_array, (/length/)) - - end subroutine FN_VGetData_Serial - -end module fnvector_serial_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fmod/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fmod/CMakeLists.txt new file mode 100644 index 000000000..ffed884ad --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fmod/CMakeLists.txt @@ -0,0 +1,41 @@ +# --------------------------------------------------------------- +# Programmer(s): Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the F2003 serial NVECTOR object library +# --------------------------------------------------------------- + +set(nvecserial_SOURCES fnvector_serial_mod.f90 fnvector_serial_mod.c) + +if(BUILD_STATIC_LIBS) + sundials_add_f2003_interface_library(sundials_fnvecserial_mod_static STATIC_OBJECT + ${nvecserial_SOURCES}) + add_dependencies(sundials_fnvecserial_mod_static_obj sundials_fgeneric_static_obj) + set_target_properties(sundials_fnvecserial_mod_static PROPERTIES + OUTPUT_NAME sundials_fnvecserial_mod + CLEAN_DIRECT_OUTPUT 1) + install(TARGETS sundials_fnvecserial_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_STATIC_LIBS) + +if(BUILD_SHARED_LIBS) + sundials_add_f2003_interface_library(sundials_fnvecserial_mod_shared SHARED_OBJECT + ${nvecserial_SOURCES}) + add_dependencies(sundials_fnvecserial_mod_shared_obj sundials_fgeneric_shared_obj) + set_target_properties(sundials_fnvecserial_mod_shared PROPERTIES + OUTPUT_NAME sundials_fnvecserial_mod + CLEAN_DIRECT_OUTPUT 1 + VERSION ${nveclib_VERSION} + SOVERSION ${nveclib_SOVERSION}) + install(TARGETS sundials_fnvecserial_mod_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_SHARED_LIBS) + +message(STATUS "Added NVECTOR_SERIAL F2003 interface") diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fmod/fnvector_serial_mod.c b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fmod/fnvector_serial_mod.c new file mode 100644 index 000000000..e8f3cae5d --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fmod/fnvector_serial_mod.c @@ -0,0 +1,945 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_nvector.h" + + +#include "nvector/nvector_serial.h" + +SWIGEXPORT N_Vector _wrap_FN_VNew_Serial(int64_t const *farg1) { + N_Vector fresult ; + sunindextype arg1 ; + N_Vector result; + + arg1 = (sunindextype)(*farg1); + result = (N_Vector)N_VNew_Serial(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VNewEmpty_Serial(int64_t const *farg1) { + N_Vector fresult ; + sunindextype arg1 ; + N_Vector result; + + arg1 = (sunindextype)(*farg1); + result = (N_Vector)N_VNewEmpty_Serial(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VMake_Serial(int64_t const *farg1, double *farg2) { + N_Vector fresult ; + sunindextype arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector result; + + arg1 = (sunindextype)(*farg1); + arg2 = (realtype *)(farg2); + result = (N_Vector)N_VMake_Serial(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FN_VCloneVectorArray_Serial(int const *farg1, N_Vector farg2) { + void * fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *result = 0 ; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + result = (N_Vector *)N_VCloneVectorArray_Serial(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FN_VCloneVectorArrayEmpty_Serial(int const *farg1, N_Vector farg2) { + void * fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *result = 0 ; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + result = (N_Vector *)N_VCloneVectorArrayEmpty_Serial(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VDestroyVectorArray_Serial(void *farg1, int const *farg2) { + N_Vector *arg1 = (N_Vector *) 0 ; + int arg2 ; + + arg1 = (N_Vector *)(farg1); + arg2 = (int)(*farg2); + N_VDestroyVectorArray_Serial(arg1,arg2); +} + + +SWIGEXPORT int64_t _wrap_FN_VGetLength_Serial(N_Vector farg1) { + int64_t fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype result; + + arg1 = (N_Vector)(farg1); + result = N_VGetLength_Serial(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VPrint_Serial(N_Vector farg1) { + N_Vector arg1 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + N_VPrint_Serial(arg1); +} + + +SWIGEXPORT void _wrap_FN_VPrintFile_Serial(N_Vector farg1, void *farg2) { + N_Vector arg1 = (N_Vector) 0 ; + FILE *arg2 = (FILE *) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (FILE *)(farg2); + N_VPrintFile_Serial(arg1,arg2); +} + + +SWIGEXPORT int _wrap_FN_VGetVectorID_Serial(N_Vector farg1) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector_ID result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector_ID)N_VGetVectorID_Serial(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VCloneEmpty_Serial(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VCloneEmpty_Serial(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VClone_Serial(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VClone_Serial(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VDestroy_Serial(N_Vector farg1) { + N_Vector arg1 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + N_VDestroy_Serial(arg1); +} + + +SWIGEXPORT void _wrap_FN_VSpace_Serial(N_Vector farg1, int64_t *farg2, int64_t *farg3) { + N_Vector arg1 = (N_Vector) 0 ; + sunindextype *arg2 = (sunindextype *) 0 ; + sunindextype *arg3 = (sunindextype *) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (sunindextype *)(farg2); + arg3 = (sunindextype *)(farg3); + N_VSpace_Serial(arg1,arg2,arg3); +} + + +SWIGEXPORT double * _wrap_FN_VGetArrayPointer_Serial(N_Vector farg1) { + double * fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype *result = 0 ; + + arg1 = (N_Vector)(farg1); + result = (realtype *)N_VGetArrayPointer_Serial(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VSetArrayPointer_Serial(double *farg1, N_Vector farg2) { + realtype *arg1 = (realtype *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype *)(farg1); + arg2 = (N_Vector)(farg2); + N_VSetArrayPointer_Serial(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VLinearSum_Serial(double const *farg1, N_Vector farg2, double const *farg3, N_Vector farg4, N_Vector farg5) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + N_VLinearSum_Serial(arg1,arg2,arg3,arg4,arg5); +} + + +SWIGEXPORT void _wrap_FN_VConst_Serial(double const *farg1, N_Vector farg2) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + N_VConst_Serial(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VProd_Serial(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VProd_Serial(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VDiv_Serial(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VDiv_Serial(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VScale_Serial(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VScale_Serial(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VAbs_Serial(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VAbs_Serial(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VInv_Serial(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VInv_Serial(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VAddConst_Serial(N_Vector farg1, double const *farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + N_VAddConst_Serial(arg1,arg2,arg3); +} + + +SWIGEXPORT double _wrap_FN_VDotProd_Serial(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VDotProd_Serial(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMaxNorm_Serial(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMaxNorm_Serial(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNorm_Serial(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWrmsNorm_Serial(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNormMask_Serial(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWrmsNormMask_Serial(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMin_Serial(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMin_Serial(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWL2Norm_Serial(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWL2Norm_Serial(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VL1Norm_Serial(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VL1Norm_Serial(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VCompare_Serial(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VCompare_Serial(arg1,arg2,arg3); +} + + +SWIGEXPORT int _wrap_FN_VInvTest_Serial(N_Vector farg1, N_Vector farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)N_VInvTest_Serial(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstrMask_Serial(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)N_VConstrMask_Serial(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinQuotient_Serial(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VMinQuotient_Serial(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearCombination_Serial(int const *farg1, double *farg2, void *farg3, N_Vector farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)N_VLinearCombination_Serial(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleAddMulti_Serial(int const *farg1, double *farg2, N_Vector farg3, void *farg4, void *farg5) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + N_Vector *arg5 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector *)(farg4); + arg5 = (N_Vector *)(farg5); + result = (int)N_VScaleAddMulti_Serial(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VDotProdMulti_Serial(int const *farg1, N_Vector farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VDotProdMulti_Serial(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearSumVectorArray_Serial(int const *farg1, double const *farg2, void *farg3, double const *farg4, void *farg5, void *farg6) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype arg4 ; + N_Vector *arg5 = (N_Vector *) 0 ; + N_Vector *arg6 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype)(*farg4); + arg5 = (N_Vector *)(farg5); + arg6 = (N_Vector *)(farg6); + result = (int)N_VLinearSumVectorArray_Serial(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleVectorArray_Serial(int const *farg1, double *farg2, void *farg3, void *farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector *)(farg4); + result = (int)N_VScaleVectorArray_Serial(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstVectorArray_Serial(int const *farg1, double const *farg2, void *farg3) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (int)N_VConstVectorArray_Serial(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormVectorArray_Serial(int const *farg1, void *farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VWrmsNormVectorArray_Serial(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormMaskVectorArray_Serial(int const *farg1, void *farg2, void *farg3, N_Vector farg4, double *farg5) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype *arg5 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype *)(farg5); + result = (int)N_VWrmsNormMaskVectorArray_Serial(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumLocal_Serial(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWSqrSumLocal_Serial(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumMaskLocal_Serial(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWSqrSumMaskLocal_Serial(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableFusedOps_Serial(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableFusedOps_Serial(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableLinearCombination_Serial(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableLinearCombination_Serial(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableScaleAddMulti_Serial(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableScaleAddMulti_Serial(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableDotProdMulti_Serial(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableDotProdMulti_Serial(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableLinearSumVectorArray_Serial(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableLinearSumVectorArray_Serial(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableScaleVectorArray_Serial(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableScaleVectorArray_Serial(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableConstVectorArray_Serial(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableConstVectorArray_Serial(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableWrmsNormVectorArray_Serial(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableWrmsNormVectorArray_Serial(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VEnableWrmsNormMaskVectorArray_Serial(N_Vector farg1, int const *farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (int)N_VEnableWrmsNormMaskVectorArray_Serial(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fmod/fnvector_serial_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fmod/fnvector_serial_mod.f90 new file mode 100644 index 000000000..a41d6d29b --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fmod/fnvector_serial_mod.f90 @@ -0,0 +1,1428 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fnvector_serial_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FN_VNew_Serial + public :: FN_VNewEmpty_Serial + public :: FN_VMake_Serial + public :: FN_VCloneVectorArray_Serial + public :: FN_VCloneVectorArrayEmpty_Serial + public :: FN_VDestroyVectorArray_Serial + public :: FN_VGetLength_Serial + public :: FN_VPrint_Serial + public :: FN_VPrintFile_Serial + public :: FN_VGetVectorID_Serial + public :: FN_VCloneEmpty_Serial + public :: FN_VClone_Serial + public :: FN_VDestroy_Serial + public :: FN_VSpace_Serial + public :: FN_VGetArrayPointer_Serial + public :: FN_VSetArrayPointer_Serial + public :: FN_VLinearSum_Serial + public :: FN_VConst_Serial + public :: FN_VProd_Serial + public :: FN_VDiv_Serial + public :: FN_VScale_Serial + public :: FN_VAbs_Serial + public :: FN_VInv_Serial + public :: FN_VAddConst_Serial + public :: FN_VDotProd_Serial + public :: FN_VMaxNorm_Serial + public :: FN_VWrmsNorm_Serial + public :: FN_VWrmsNormMask_Serial + public :: FN_VMin_Serial + public :: FN_VWL2Norm_Serial + public :: FN_VL1Norm_Serial + public :: FN_VCompare_Serial + public :: FN_VInvTest_Serial + public :: FN_VConstrMask_Serial + public :: FN_VMinQuotient_Serial + public :: FN_VLinearCombination_Serial + public :: FN_VScaleAddMulti_Serial + public :: FN_VDotProdMulti_Serial + public :: FN_VLinearSumVectorArray_Serial + public :: FN_VScaleVectorArray_Serial + public :: FN_VConstVectorArray_Serial + public :: FN_VWrmsNormVectorArray_Serial + public :: FN_VWrmsNormMaskVectorArray_Serial + public :: FN_VWSqrSumLocal_Serial + public :: FN_VWSqrSumMaskLocal_Serial + public :: FN_VEnableFusedOps_Serial + public :: FN_VEnableLinearCombination_Serial + public :: FN_VEnableScaleAddMulti_Serial + public :: FN_VEnableDotProdMulti_Serial + public :: FN_VEnableLinearSumVectorArray_Serial + public :: FN_VEnableScaleVectorArray_Serial + public :: FN_VEnableConstVectorArray_Serial + public :: FN_VEnableWrmsNormVectorArray_Serial + public :: FN_VEnableWrmsNormMaskVectorArray_Serial + +! WRAPPER DECLARATIONS +interface +function swigc_FN_VNew_Serial(farg1) & +bind(C, name="_wrap_FN_VNew_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VNewEmpty_Serial(farg1) & +bind(C, name="_wrap_FN_VNewEmpty_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VMake_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VMake_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VCloneVectorArray_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VCloneVectorArray_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VCloneVectorArrayEmpty_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VCloneVectorArrayEmpty_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VDestroyVectorArray_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VDestroyVectorArray_Serial") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +end subroutine + +function swigc_FN_VGetLength_Serial(farg1) & +bind(C, name="_wrap_FN_VGetLength_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +subroutine swigc_FN_VPrint_Serial(farg1) & +bind(C, name="_wrap_FN_VPrint_Serial") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FN_VPrintFile_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VPrintFile_Serial") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_FN_VGetVectorID_Serial(farg1) & +bind(C, name="_wrap_FN_VGetVectorID_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FN_VCloneEmpty_Serial(farg1) & +bind(C, name="_wrap_FN_VCloneEmpty_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VClone_Serial(farg1) & +bind(C, name="_wrap_FN_VClone_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VDestroy_Serial(farg1) & +bind(C, name="_wrap_FN_VDestroy_Serial") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FN_VSpace_Serial(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VSpace_Serial") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VGetArrayPointer_Serial(farg1) & +bind(C, name="_wrap_FN_VGetArrayPointer_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VSetArrayPointer_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VSetArrayPointer_Serial") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VLinearSum_Serial(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VLinearSum_Serial") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +end subroutine + +subroutine swigc_FN_VConst_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VConst_Serial") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VProd_Serial(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VProd_Serial") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VDiv_Serial(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VDiv_Serial") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VScale_Serial(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VScale_Serial") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VAbs_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VAbs_Serial") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VInv_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VInv_Serial") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VAddConst_Serial(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VAddConst_Serial") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VDotProd_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VDotProd_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMaxNorm_Serial(farg1) & +bind(C, name="_wrap_FN_VMaxNorm_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNorm_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VWrmsNorm_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNormMask_Serial(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWrmsNormMask_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMin_Serial(farg1) & +bind(C, name="_wrap_FN_VMin_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWL2Norm_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VWL2Norm_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VL1Norm_Serial(farg1) & +bind(C, name="_wrap_FN_VL1Norm_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +subroutine swigc_FN_VCompare_Serial(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VCompare_Serial") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VInvTest_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VInvTest_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstrMask_Serial(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstrMask_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VMinQuotient_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VMinQuotient_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VLinearCombination_Serial(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VLinearCombination_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleAddMulti_Serial(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VScaleAddMulti_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VDotProdMulti_Serial(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VDotProdMulti_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VLinearSumVectorArray_Serial(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FN_VLinearSumVectorArray_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleVectorArray_Serial(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VScaleVectorArray_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstVectorArray_Serial(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstVectorArray_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormVectorArray_Serial(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VWrmsNormVectorArray_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormMaskVectorArray_Serial(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VWrmsNormMaskVectorArray_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWSqrSumLocal_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VWSqrSumLocal_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWSqrSumMaskLocal_Serial(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWSqrSumMaskLocal_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VEnableFusedOps_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableFusedOps_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableLinearCombination_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableLinearCombination_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableScaleAddMulti_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableScaleAddMulti_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableDotProdMulti_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableDotProdMulti_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableLinearSumVectorArray_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableLinearSumVectorArray_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableScaleVectorArray_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableScaleVectorArray_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableConstVectorArray_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableConstVectorArray_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableWrmsNormVectorArray_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableWrmsNormVectorArray_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VEnableWrmsNormMaskVectorArray_Serial(farg1, farg2) & +bind(C, name="_wrap_FN_VEnableWrmsNormMaskVectorArray_Serial") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FN_VNew_Serial(vec_length) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer(C_INT64_T), intent(in) :: vec_length +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 + +farg1 = vec_length +fresult = swigc_FN_VNew_Serial(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VNewEmpty_Serial(vec_length) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer(C_INT64_T), intent(in) :: vec_length +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 + +farg1 = vec_length +fresult = swigc_FN_VNewEmpty_Serial(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VMake_Serial(vec_length, v_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +integer(C_INT64_T), intent(in) :: vec_length +real(C_DOUBLE), dimension(*), target, intent(inout) :: v_data +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +type(C_PTR) :: farg2 + +farg1 = vec_length +farg2 = c_loc(v_data(1)) +fresult = swigc_FN_VMake_Serial(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VCloneVectorArray_Serial(count, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: count +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 + +farg1 = count +farg2 = c_loc(w) +fresult = swigc_FN_VCloneVectorArray_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VCloneVectorArrayEmpty_Serial(count, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: count +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 + +farg1 = count +farg2 = c_loc(w) +fresult = swigc_FN_VCloneVectorArrayEmpty_Serial(farg1, farg2) +swig_result = fresult +end function + +subroutine FN_VDestroyVectorArray_Serial(vs, count) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: vs +integer(C_INT), intent(in) :: count +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = vs +farg2 = count +call swigc_FN_VDestroyVectorArray_Serial(farg1, farg2) +end subroutine + +function FN_VGetLength_Serial(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetLength_Serial(farg1) +swig_result = fresult +end function + +subroutine FN_VPrint_Serial(v) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +call swigc_FN_VPrint_Serial(farg1) +end subroutine + +subroutine FN_VPrintFile_Serial(v, outfile) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: outfile +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(v) +farg2 = outfile +call swigc_FN_VPrintFile_Serial(farg1, farg2) +end subroutine + +function FN_VGetVectorID_Serial(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(N_Vector_ID) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetVectorID_Serial(farg1) +swig_result = fresult +end function + +function FN_VCloneEmpty_Serial(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VCloneEmpty_Serial(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VClone_Serial(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VClone_Serial(farg1) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FN_VDestroy_Serial(v) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +call swigc_FN_VDestroy_Serial(farg1) +end subroutine + +subroutine FN_VSpace_Serial(v, lrw, liw) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), dimension(*), target, intent(inout) :: lrw +integer(C_INT64_T), dimension(*), target, intent(inout) :: liw +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(v) +farg2 = c_loc(lrw(1)) +farg3 = c_loc(liw(1)) +call swigc_FN_VSpace_Serial(farg1, farg2, farg3) +end subroutine + +function FN_VGetArrayPointer_Serial(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetArrayPointer_Serial(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +subroutine FN_VSetArrayPointer_Serial(v_data, v) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(*), target, intent(inout) :: v_data +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(v_data(1)) +farg2 = c_loc(v) +call swigc_FN_VSetArrayPointer_Serial(farg1, farg2) +end subroutine + +subroutine FN_VLinearSum_Serial(a, x, b, y, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: a +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = a +farg2 = c_loc(x) +farg3 = b +farg4 = c_loc(y) +farg5 = c_loc(z) +call swigc_FN_VLinearSum_Serial(farg1, farg2, farg3, farg4, farg5) +end subroutine + +subroutine FN_VConst_Serial(c, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c +farg2 = c_loc(z) +call swigc_FN_VConst_Serial(farg1, farg2) +end subroutine + +subroutine FN_VProd_Serial(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VProd_Serial(farg1, farg2, farg3) +end subroutine + +subroutine FN_VDiv_Serial(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VDiv_Serial(farg1, farg2, farg3) +end subroutine + +subroutine FN_VScale_Serial(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VScale_Serial(farg1, farg2, farg3) +end subroutine + +subroutine FN_VAbs_Serial(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VAbs_Serial(farg1, farg2) +end subroutine + +subroutine FN_VInv_Serial(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VInv_Serial(farg1, farg2) +end subroutine + +subroutine FN_VAddConst_Serial(x, b, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = b +farg3 = c_loc(z) +call swigc_FN_VAddConst_Serial(farg1, farg2, farg3) +end subroutine + +function FN_VDotProd_Serial(x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(y) +fresult = swigc_FN_VDotProd_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VMaxNorm_Serial(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMaxNorm_Serial(farg1) +swig_result = fresult +end function + +function FN_VWrmsNorm_Serial(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWrmsNorm_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VWrmsNormMask_Serial(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWrmsNormMask_Serial(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMin_Serial(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMin_Serial(farg1) +swig_result = fresult +end function + +function FN_VWL2Norm_Serial(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWL2Norm_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VL1Norm_Serial(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VL1Norm_Serial(farg1) +swig_result = fresult +end function + +subroutine FN_VCompare_Serial(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VCompare_Serial(farg1, farg2, farg3) +end subroutine + +function FN_VInvTest_Serial(x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +fresult = swigc_FN_VInvTest_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VConstrMask_Serial(c, x, m) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: m +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(c) +farg2 = c_loc(x) +farg3 = c_loc(m) +fresult = swigc_FN_VConstrMask_Serial(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMinQuotient_Serial(num, denom) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: num +type(N_Vector), target, intent(inout) :: denom +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(num) +farg2 = c_loc(denom) +fresult = swigc_FN_VMinQuotient_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VLinearCombination_Serial(nvec, c, v, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: v +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = v +farg4 = c_loc(z) +fresult = swigc_FN_VLinearCombination_Serial(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VScaleAddMulti_Serial(nvec, a, x, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvec +farg2 = c_loc(a(1)) +farg3 = c_loc(x) +farg4 = y +farg5 = z +fresult = swigc_FN_VScaleAddMulti_Serial(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VDotProdMulti_Serial(nvec, x, y, dotprods) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +real(C_DOUBLE), dimension(*), target, intent(inout) :: dotprods +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(x) +farg3 = y +farg4 = c_loc(dotprods(1)) +fresult = swigc_FN_VDotProdMulti_Serial(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VLinearSumVectorArray_Serial(nvec, a, x, b, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), intent(in) :: a +type(C_PTR) :: x +real(C_DOUBLE), intent(in) :: b +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = nvec +farg2 = a +farg3 = x +farg4 = b +farg5 = y +farg6 = z +fresult = swigc_FN_VLinearSumVectorArray_Serial(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FN_VScaleVectorArray_Serial(nvec, c, x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: x +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = x +farg4 = z +fresult = swigc_FN_VScaleVectorArray_Serial(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VConstVectorArray_Serial(nvecs, c, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvecs +real(C_DOUBLE), intent(in) :: c +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = nvecs +farg2 = c +farg3 = z +fresult = swigc_FN_VConstVectorArray_Serial(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VWrmsNormVectorArray_Serial(nvecs, x, w, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvecs +type(C_PTR) :: x +type(C_PTR) :: w +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvecs +farg2 = x +farg3 = w +farg4 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormVectorArray_Serial(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VWrmsNormMaskVectorArray_Serial(nvecs, x, w, id, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvecs +type(C_PTR) :: x +type(C_PTR) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvecs +farg2 = x +farg3 = w +farg4 = c_loc(id) +farg5 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormMaskVectorArray_Serial(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VWSqrSumLocal_Serial(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWSqrSumLocal_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VWSqrSumMaskLocal_Serial(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWSqrSumMaskLocal_Serial(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VEnableFusedOps_Serial(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableFusedOps_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableLinearCombination_Serial(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableLinearCombination_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableScaleAddMulti_Serial(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableScaleAddMulti_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableDotProdMulti_Serial(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableDotProdMulti_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableLinearSumVectorArray_Serial(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableLinearSumVectorArray_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableScaleVectorArray_Serial(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableScaleVectorArray_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableConstVectorArray_Serial(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableConstVectorArray_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableWrmsNormVectorArray_Serial(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableWrmsNormVectorArray_Serial(farg1, farg2) +swig_result = fresult +end function + +function FN_VEnableWrmsNormMaskVectorArray_Serial(v, tf) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT), intent(in) :: tf +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(v) +farg2 = tf +fresult = swigc_FN_VEnableWrmsNormMaskVectorArray_Serial(farg1, farg2) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fnvector_serial.c b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fnvector_serial.c index 12516fc55..c5b5bdea4 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fnvector_serial.c +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fnvector_serial.c @@ -3,7 +3,7 @@ * Programmer(s): Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -50,22 +50,22 @@ void FNV_INITS(int *code, long int *N, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vec = NULL; - F2C_CVODE_vec = N_VNewEmpty_Serial(*N); + F2C_CVODE_vec = N_VNewEmpty_Serial((sunindextype)(*N)); if (F2C_CVODE_vec == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vec = NULL; - F2C_IDA_vec = N_VNewEmpty_Serial(*N); + F2C_IDA_vec = N_VNewEmpty_Serial((sunindextype)(*N)); if (F2C_IDA_vec == NULL) *ier = -1; break; case FCMIX_KINSOL: F2C_KINSOL_vec = NULL; - F2C_KINSOL_vec = N_VNewEmpty_Serial(*N); + F2C_KINSOL_vec = N_VNewEmpty_Serial((sunindextype)(*N)); if (F2C_KINSOL_vec == NULL) *ier = -1; break; case FCMIX_ARKODE: F2C_ARKODE_vec = NULL; - F2C_ARKODE_vec = N_VNewEmpty_Serial(*N); + F2C_ARKODE_vec = N_VNewEmpty_Serial((sunindextype)(*N)); if (F2C_ARKODE_vec == NULL) *ier = -1; break; default: @@ -80,12 +80,12 @@ void FNV_INITS_Q(int *code, long int *Nq, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vecQ = NULL; - F2C_CVODE_vecQ = N_VNewEmpty_Serial(*Nq); + F2C_CVODE_vecQ = N_VNewEmpty_Serial((sunindextype)(*Nq)); if (F2C_CVODE_vecQ == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vecQ = NULL; - F2C_IDA_vecQ = N_VNewEmpty_Serial(*Nq); + F2C_IDA_vecQ = N_VNewEmpty_Serial((sunindextype)(*Nq)); if (F2C_IDA_vecQ == NULL) *ier = -1; break; default: @@ -100,12 +100,12 @@ void FNV_INITS_B(int *code, long int *NB, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vecB = NULL; - F2C_CVODE_vecB = N_VNewEmpty_Serial(*NB); + F2C_CVODE_vecB = N_VNewEmpty_Serial((sunindextype)(*NB)); if (F2C_CVODE_vecB == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vecB = NULL; - F2C_IDA_vecB = N_VNewEmpty_Serial(*NB); + F2C_IDA_vecB = N_VNewEmpty_Serial((sunindextype)(*NB)); if (F2C_IDA_vecB == NULL) *ier = -1; break; default: @@ -120,12 +120,12 @@ void FNV_INITS_QB(int *code, long int *NqB, int *ier) switch(*code) { case FCMIX_CVODE: F2C_CVODE_vecQB = NULL; - F2C_CVODE_vecQB = N_VNewEmpty_Serial(*NqB); + F2C_CVODE_vecQB = N_VNewEmpty_Serial((sunindextype)(*NqB)); if (F2C_CVODE_vecQB == NULL) *ier = -1; break; case FCMIX_IDA: F2C_IDA_vecQB = NULL; - F2C_IDA_vecQB = N_VNewEmpty_Serial(*NqB); + F2C_IDA_vecQB = N_VNewEmpty_Serial((sunindextype)(*NqB)); if (F2C_IDA_vecQB == NULL) *ier = -1; break; default: diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fnvector_serial.h b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fnvector_serial.h index 8ee03b572..5ab7452da 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fnvector_serial.h +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/fnvector_serial.h @@ -3,7 +3,7 @@ * Programmer(s): Radu Serban and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/nvector_serial.c b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/nvector_serial.c index 25f72c9e6..5b5dbd6bd 100644 --- a/deps/AMICI/ThirdParty/sundials/src/nvector/serial/nvector_serial.c +++ b/deps/AMICI/ThirdParty/sundials/src/nvector/serial/nvector_serial.c @@ -3,7 +3,7 @@ * and Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -46,7 +46,7 @@ static int VScaleSumVectorArray_Serial(int nvec, realtype c, N_Vector* X, N_Vect static int VScaleDiffVectorArray_Serial(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=c(X-Y) */ static int VLin1VectorArray_Serial(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=aX+Y */ static int VLin2VectorArray_Serial(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=aX-Y */ -static int VaxpyVectorArray_Serial(int nvec, realtype a, N_Vector* X, N_Vector* Y); /* Y <- aX+Y */ +static int VaxpyVectorArray_Serial(int nvec, realtype a, N_Vector* X, N_Vector* Y); /* Y <- aX+Y */ /* * ----------------------------------------------------------------- @@ -70,75 +70,72 @@ N_Vector_ID N_VGetVectorID_Serial(N_Vector v) N_Vector N_VNewEmpty_Serial(sunindextype length) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_Serial content; - /* Create vector */ + /* Create an empty vector object */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } + /* Attach operations */ - ops->nvgetvectorid = N_VGetVectorID_Serial; - ops->nvclone = N_VClone_Serial; - ops->nvcloneempty = N_VCloneEmpty_Serial; - ops->nvdestroy = N_VDestroy_Serial; - ops->nvspace = N_VSpace_Serial; - ops->nvgetarraypointer = N_VGetArrayPointer_Serial; - ops->nvsetarraypointer = N_VSetArrayPointer_Serial; + /* constructors, destructors, and utility operations */ + v->ops->nvgetvectorid = N_VGetVectorID_Serial; + v->ops->nvclone = N_VClone_Serial; + v->ops->nvcloneempty = N_VCloneEmpty_Serial; + v->ops->nvdestroy = N_VDestroy_Serial; + v->ops->nvspace = N_VSpace_Serial; + v->ops->nvgetarraypointer = N_VGetArrayPointer_Serial; + v->ops->nvsetarraypointer = N_VSetArrayPointer_Serial; + v->ops->nvgetlength = N_VGetLength_Serial; /* standard vector operations */ - ops->nvlinearsum = N_VLinearSum_Serial; - ops->nvconst = N_VConst_Serial; - ops->nvprod = N_VProd_Serial; - ops->nvdiv = N_VDiv_Serial; - ops->nvscale = N_VScale_Serial; - ops->nvabs = N_VAbs_Serial; - ops->nvinv = N_VInv_Serial; - ops->nvaddconst = N_VAddConst_Serial; - ops->nvdotprod = N_VDotProd_Serial; - ops->nvmaxnorm = N_VMaxNorm_Serial; - ops->nvwrmsnormmask = N_VWrmsNormMask_Serial; - ops->nvwrmsnorm = N_VWrmsNorm_Serial; - ops->nvmin = N_VMin_Serial; - ops->nvwl2norm = N_VWL2Norm_Serial; - ops->nvl1norm = N_VL1Norm_Serial; - ops->nvcompare = N_VCompare_Serial; - ops->nvinvtest = N_VInvTest_Serial; - ops->nvconstrmask = N_VConstrMask_Serial; - ops->nvminquotient = N_VMinQuotient_Serial; - - /* fused vector operations (optional, NULL means disabled by default) */ - ops->nvlinearcombination = NULL; - ops->nvscaleaddmulti = NULL; - ops->nvdotprodmulti = NULL; - - /* vector array operations (optional, NULL means disabled by default) */ - ops->nvlinearsumvectorarray = NULL; - ops->nvscalevectorarray = NULL; - ops->nvconstvectorarray = NULL; - ops->nvwrmsnormvectorarray = NULL; - ops->nvwrmsnormmaskvectorarray = NULL; - ops->nvscaleaddmultivectorarray = NULL; - ops->nvlinearcombinationvectorarray = NULL; + v->ops->nvlinearsum = N_VLinearSum_Serial; + v->ops->nvconst = N_VConst_Serial; + v->ops->nvprod = N_VProd_Serial; + v->ops->nvdiv = N_VDiv_Serial; + v->ops->nvscale = N_VScale_Serial; + v->ops->nvabs = N_VAbs_Serial; + v->ops->nvinv = N_VInv_Serial; + v->ops->nvaddconst = N_VAddConst_Serial; + v->ops->nvdotprod = N_VDotProd_Serial; + v->ops->nvmaxnorm = N_VMaxNorm_Serial; + v->ops->nvwrmsnormmask = N_VWrmsNormMask_Serial; + v->ops->nvwrmsnorm = N_VWrmsNorm_Serial; + v->ops->nvmin = N_VMin_Serial; + v->ops->nvwl2norm = N_VWL2Norm_Serial; + v->ops->nvl1norm = N_VL1Norm_Serial; + v->ops->nvcompare = N_VCompare_Serial; + v->ops->nvinvtest = N_VInvTest_Serial; + v->ops->nvconstrmask = N_VConstrMask_Serial; + v->ops->nvminquotient = N_VMinQuotient_Serial; + + /* fused and vector array operations are disabled (NULL) by default */ + + /* local reduction operations */ + v->ops->nvdotprodlocal = N_VDotProd_Serial; + v->ops->nvmaxnormlocal = N_VMaxNorm_Serial; + v->ops->nvminlocal = N_VMin_Serial; + v->ops->nvl1normlocal = N_VL1Norm_Serial; + v->ops->nvinvtestlocal = N_VInvTest_Serial; + v->ops->nvconstrmasklocal = N_VConstrMask_Serial; + v->ops->nvminquotientlocal = N_VMinQuotient_Serial; + v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_Serial; + v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_Serial; /* Create content */ content = NULL; - content = (N_VectorContent_Serial) malloc(sizeof(struct _N_VectorContent_Serial)); - if (content == NULL) { free(ops); free(v); return(NULL); } + content = (N_VectorContent_Serial) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } + + /* Attach content */ + v->content = content; + /* Initialize content */ content->length = length; content->own_data = SUNFALSE; content->data = NULL; - /* Attach content and ops */ - v->content = content; - v->ops = ops; - return(v); } @@ -197,15 +194,15 @@ N_Vector N_VMake_Serial(sunindextype length, realtype *v_data) * Function to create an array of new serial vectors. */ -N_Vector *N_VCloneVectorArray_Serial(int count, N_Vector w) +N_Vector* N_VCloneVectorArray_Serial(int count, N_Vector w) { - N_Vector *vs; + N_Vector* vs; int j; if (count <= 0) return(NULL); vs = NULL; - vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + vs = (N_Vector*) malloc(count * sizeof(N_Vector)); if(vs == NULL) return(NULL); for (j = 0; j < count; j++) { @@ -224,15 +221,15 @@ N_Vector *N_VCloneVectorArray_Serial(int count, N_Vector w) * Function to create an array of new serial vectors with NULL data array. */ -N_Vector *N_VCloneVectorArrayEmpty_Serial(int count, N_Vector w) +N_Vector* N_VCloneVectorArrayEmpty_Serial(int count, N_Vector w) { - N_Vector *vs; + N_Vector* vs; int j; if (count <= 0) return(NULL); vs = NULL; - vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + vs = (N_Vector*) malloc(count * sizeof(N_Vector)); if(vs == NULL) return(NULL); for (j = 0; j < count; j++) { @@ -251,7 +248,7 @@ N_Vector *N_VCloneVectorArrayEmpty_Serial(int count, N_Vector w) * Function to free an array created with N_VCloneVectorArray_Serial */ -void N_VDestroyVectorArray_Serial(N_Vector *vs, int count) +void N_VDestroyVectorArray_Serial(N_Vector* vs, int count) { int j; @@ -316,77 +313,31 @@ void N_VPrintFile_Serial(N_Vector x, FILE* outfile) N_Vector N_VCloneEmpty_Serial(N_Vector w) { N_Vector v; - N_Vector_Ops ops; N_VectorContent_Serial content; if (w == NULL) return(NULL); /* Create vector */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { free(v); return(NULL); } - - ops->nvgetvectorid = w->ops->nvgetvectorid; - ops->nvclone = w->ops->nvclone; - ops->nvcloneempty = w->ops->nvcloneempty; - ops->nvdestroy = w->ops->nvdestroy; - ops->nvspace = w->ops->nvspace; - ops->nvgetarraypointer = w->ops->nvgetarraypointer; - ops->nvsetarraypointer = w->ops->nvsetarraypointer; - - /* standard vector operations */ - ops->nvlinearsum = w->ops->nvlinearsum; - ops->nvconst = w->ops->nvconst; - ops->nvprod = w->ops->nvprod; - ops->nvdiv = w->ops->nvdiv; - ops->nvscale = w->ops->nvscale; - ops->nvabs = w->ops->nvabs; - ops->nvinv = w->ops->nvinv; - ops->nvaddconst = w->ops->nvaddconst; - ops->nvdotprod = w->ops->nvdotprod; - ops->nvmaxnorm = w->ops->nvmaxnorm; - ops->nvwrmsnormmask = w->ops->nvwrmsnormmask; - ops->nvwrmsnorm = w->ops->nvwrmsnorm; - ops->nvmin = w->ops->nvmin; - ops->nvwl2norm = w->ops->nvwl2norm; - ops->nvl1norm = w->ops->nvl1norm; - ops->nvcompare = w->ops->nvcompare; - ops->nvinvtest = w->ops->nvinvtest; - ops->nvconstrmask = w->ops->nvconstrmask; - ops->nvminquotient = w->ops->nvminquotient; - - /* fused vector operations */ - ops->nvlinearcombination = w->ops->nvlinearcombination; - ops->nvscaleaddmulti = w->ops->nvscaleaddmulti; - ops->nvdotprodmulti = w->ops->nvdotprodmulti; - - /* vector array operations */ - ops->nvlinearsumvectorarray = w->ops->nvlinearsumvectorarray; - ops->nvscalevectorarray = w->ops->nvscalevectorarray; - ops->nvconstvectorarray = w->ops->nvconstvectorarray; - ops->nvwrmsnormvectorarray = w->ops->nvwrmsnormvectorarray; - ops->nvwrmsnormmaskvectorarray = w->ops->nvwrmsnormmaskvectorarray; - ops->nvscaleaddmultivectorarray = w->ops->nvscaleaddmultivectorarray; - ops->nvlinearcombinationvectorarray = w->ops->nvlinearcombinationvectorarray; + /* Attach operations */ + if (N_VCopyOps(w, v)) { N_VDestroy(v); return(NULL); } /* Create content */ content = NULL; - content = (N_VectorContent_Serial) malloc(sizeof(struct _N_VectorContent_Serial)); - if (content == NULL) { free(ops); free(v); return(NULL); } + content = (N_VectorContent_Serial) malloc(sizeof *content); + if (content == NULL) { N_VDestroy(v); return(NULL); } + + /* Attach content */ + v->content = content; + /* Initialize content */ content->length = NV_LENGTH_S(w); content->own_data = SUNFALSE; content->data = NULL; - /* Attach content and ops */ - v->content = content; - v->ops = ops; - return(v); } @@ -421,12 +372,21 @@ N_Vector N_VClone_Serial(N_Vector w) void N_VDestroy_Serial(N_Vector v) { - if (NV_OWN_DATA_S(v) == SUNTRUE) { - free(NV_DATA_S(v)); - NV_DATA_S(v) = NULL; + if (v == NULL) return; + + /* free content */ + if (v->content != NULL) { + /* free data array if it's owned by the vector */ + if (NV_OWN_DATA_S(v) && NV_DATA_S(v) != NULL) { + free(NV_DATA_S(v)); + NV_DATA_S(v) = NULL; + } + free(v->content); + v->content = NULL; } - free(v->content); v->content = NULL; - free(v->ops); v->ops = NULL; + + /* free ops and vector */ + if (v->ops != NULL) { free(v->ops); v->ops = NULL; } free(v); v = NULL; return; @@ -705,6 +665,11 @@ realtype N_VMaxNorm_Serial(N_Vector x) } realtype N_VWrmsNorm_Serial(N_Vector x, N_Vector w) +{ + return(SUNRsqrt(N_VWSqrSumLocal_Serial(x, w)/(NV_LENGTH_S(x)))); +} + +realtype N_VWSqrSumLocal_Serial(N_Vector x, N_Vector w) { sunindextype i, N; realtype sum, prodi, *xd, *wd; @@ -721,10 +686,15 @@ realtype N_VWrmsNorm_Serial(N_Vector x, N_Vector w) sum += SUNSQR(prodi); } - return(SUNRsqrt(sum/N)); + return(sum); } realtype N_VWrmsNormMask_Serial(N_Vector x, N_Vector w, N_Vector id) +{ + return(SUNRsqrt(N_VWSqrSumMaskLocal_Serial(x, w, id) / (NV_LENGTH_S(x)))); +} + +realtype N_VWSqrSumMaskLocal_Serial(N_Vector x, N_Vector w, N_Vector id) { sunindextype i, N; realtype sum, prodi, *xd, *wd, *idd; @@ -744,7 +714,7 @@ realtype N_VWrmsNormMask_Serial(N_Vector x, N_Vector w, N_Vector id) } } - return(SUNRsqrt(sum / N)); + return(sum); } realtype N_VMin_Serial(N_Vector x) @@ -1085,8 +1055,8 @@ int N_VLinearSumVectorArray_Serial(int nvec, realtype* yd=NULL; realtype* zd=NULL; realtype c; - N_Vector* V1; - N_Vector* V2; + N_Vector* V1; + N_Vector* V2; booleantype test; /* invalid number of vectors */ @@ -1330,8 +1300,8 @@ int N_VScaleAddMultiVectorArray_Serial(int nvec, int nsum, realtype* a, realtype* zd=NULL; int retval; - N_Vector* YY; - N_Vector* ZZ; + N_Vector* YY; + N_Vector* ZZ; /* invalid number of vectors */ if (nvec < 1) return(-1); @@ -1350,8 +1320,8 @@ int N_VScaleAddMultiVectorArray_Serial(int nvec, int nsum, realtype* a, } /* should have called N_VScaleAddMulti */ - YY = (N_Vector *) malloc(nsum * sizeof(N_Vector)); - ZZ = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + YY = (N_Vector*) malloc(nsum * sizeof(N_Vector)); + ZZ = (N_Vector*) malloc(nsum * sizeof(N_Vector)); for (j=0; jnvgetvectorid = N_VGetVectorID_Trilinos; - ops->nvclone = N_VClone_Trilinos; - ops->nvcloneempty = N_VCloneEmpty_Trilinos; - ops->nvdestroy = N_VDestroy_Trilinos; - ops->nvspace = N_VSpace_Trilinos; - ops->nvgetarraypointer = NULL; - ops->nvsetarraypointer = NULL; - ops->nvlinearsum = N_VLinearSum_Trilinos; - ops->nvconst = N_VConst_Trilinos; - ops->nvprod = N_VProd_Trilinos; - ops->nvdiv = N_VDiv_Trilinos; - ops->nvscale = N_VScale_Trilinos; - ops->nvabs = N_VAbs_Trilinos; - ops->nvinv = N_VInv_Trilinos; - ops->nvaddconst = N_VAddConst_Trilinos; - ops->nvdotprod = N_VDotProd_Trilinos; - ops->nvmaxnorm = N_VMaxNorm_Trilinos; - ops->nvwrmsnorm = N_VWrmsNorm_Trilinos; - ops->nvwrmsnormmask = N_VWrmsNormMask_Trilinos; - ops->nvmin = N_VMin_Trilinos; - ops->nvwl2norm = N_VWL2Norm_Trilinos; - ops->nvl1norm = N_VL1Norm_Trilinos; - ops->nvcompare = N_VCompare_Trilinos; - ops->nvinvtest = N_VInvTest_Trilinos; - ops->nvconstrmask = N_VConstrMask_Trilinos; - ops->nvminquotient = N_VMinQuotient_Trilinos; - - /* fused vector operations */ - ops->nvlinearcombination = NULL; - ops->nvscaleaddmulti = NULL; - ops->nvdotprodmulti = NULL; - - /* vector array operations */ - ops->nvlinearsumvectorarray = NULL; - ops->nvscalevectorarray = NULL; - ops->nvconstvectorarray = NULL; - ops->nvwrmsnormvectorarray = NULL; - ops->nvwrmsnormmaskvectorarray = NULL; - ops->nvscaleaddmultivectorarray = NULL; - ops->nvlinearcombinationvectorarray = NULL; - - /* Attach ops and set content to NULL */ - v->content = NULL; - v->ops = ops; + /* Attach operations */ + + /* constructors, destructors, and utility operations */ + v->ops->nvgetvectorid = N_VGetVectorID_Trilinos; + v->ops->nvclone = N_VClone_Trilinos; + v->ops->nvcloneempty = N_VCloneEmpty_Trilinos; + v->ops->nvdestroy = N_VDestroy_Trilinos; + v->ops->nvspace = N_VSpace_Trilinos; + v->ops->nvgetcommunicator = N_VGetCommunicator_Trilinos; + v->ops->nvgetlength = N_VGetLength_Trilinos; + + /* standard vector operations */ + v->ops->nvlinearsum = N_VLinearSum_Trilinos; + v->ops->nvconst = N_VConst_Trilinos; + v->ops->nvprod = N_VProd_Trilinos; + v->ops->nvdiv = N_VDiv_Trilinos; + v->ops->nvscale = N_VScale_Trilinos; + v->ops->nvabs = N_VAbs_Trilinos; + v->ops->nvinv = N_VInv_Trilinos; + v->ops->nvaddconst = N_VAddConst_Trilinos; + v->ops->nvdotprod = N_VDotProd_Trilinos; + v->ops->nvmaxnorm = N_VMaxNorm_Trilinos; + v->ops->nvwrmsnorm = N_VWrmsNorm_Trilinos; + v->ops->nvwrmsnormmask = N_VWrmsNormMask_Trilinos; + v->ops->nvmin = N_VMin_Trilinos; + v->ops->nvwl2norm = N_VWL2Norm_Trilinos; + v->ops->nvl1norm = N_VL1Norm_Trilinos; + v->ops->nvcompare = N_VCompare_Trilinos; + v->ops->nvinvtest = N_VInvTest_Trilinos; + v->ops->nvconstrmask = N_VConstrMask_Trilinos; + v->ops->nvminquotient = N_VMinQuotient_Trilinos; + + /* fused and vector array operations are disabled (NULL) by default */ + + /* local reduction operations */ + v->ops->nvdotprodlocal = N_VDotProdLocal_Trilinos; + v->ops->nvmaxnormlocal = N_VMaxNormLocal_Trilinos; + v->ops->nvminlocal = N_VMinLocal_Trilinos; + v->ops->nvl1normlocal = N_VL1NormLocal_Trilinos; + v->ops->nvinvtestlocal = N_VInvTestLocal_Trilinos; + v->ops->nvconstrmasklocal = N_VConstrMaskLocal_Trilinos; + v->ops->nvminquotientlocal = N_VMinQuotientLocal_Trilinos; + v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_Trilinos; + v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_Trilinos; return(v); } @@ -144,16 +138,11 @@ N_Vector N_VMake_Trilinos(Teuchos::RCP vec) // Create an N_Vector with operators attached and empty content v = N_VNewEmpty_Trilinos(); - if (v == NULL) - return(NULL); + if (v == NULL) return(NULL); // Create vector content using a pointer to Tpetra vector v->content = new Sundials::TpetraVectorInterface(vec); - if (v->content == NULL) { - free(v->ops); - free(v); - return NULL; - } + if (v->content == NULL) { N_VDestroy(v); return NULL; } return(v); } @@ -168,67 +157,16 @@ N_Vector N_VMake_Trilinos(Teuchos::RCP vec) N_Vector N_VCloneEmpty_Trilinos(N_Vector w) { N_Vector v; - N_Vector_Ops ops; if (w == NULL) return(NULL); /* Create vector */ v = NULL; - v = (N_Vector) malloc(sizeof *v); + v = N_VNewEmpty(); if (v == NULL) return(NULL); - /* Create vector operation structure */ - ops = NULL; - ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops)); - if (ops == NULL) { - free(v); - return(NULL); - } - - ops->nvgetvectorid = w->ops->nvgetvectorid; - ops->nvclone = w->ops->nvclone; - ops->nvcloneempty = w->ops->nvcloneempty; - ops->nvdestroy = w->ops->nvdestroy; - ops->nvspace = w->ops->nvspace; - ops->nvgetarraypointer = w->ops->nvgetarraypointer; - ops->nvsetarraypointer = w->ops->nvsetarraypointer; - ops->nvlinearsum = w->ops->nvlinearsum; - ops->nvconst = w->ops->nvconst; - ops->nvprod = w->ops->nvprod; - ops->nvdiv = w->ops->nvdiv; - ops->nvscale = w->ops->nvscale; - ops->nvabs = w->ops->nvabs; - ops->nvinv = w->ops->nvinv; - ops->nvaddconst = w->ops->nvaddconst; - ops->nvdotprod = w->ops->nvdotprod; - ops->nvmaxnorm = w->ops->nvmaxnorm; - ops->nvwrmsnorm = w->ops->nvwrmsnorm; - ops->nvwrmsnormmask = w->ops->nvwrmsnormmask; - ops->nvmin = w->ops->nvmin; - ops->nvwl2norm = w->ops->nvwl2norm; - ops->nvl1norm = w->ops->nvl1norm; - ops->nvcompare = w->ops->nvcompare; - ops->nvinvtest = w->ops->nvinvtest; - ops->nvconstrmask = w->ops->nvconstrmask; - ops->nvminquotient = w->ops->nvminquotient; - - /* fused vector operations */ - ops->nvlinearcombination = w->ops->nvlinearcombination; - ops->nvscaleaddmulti = w->ops->nvscaleaddmulti; - ops->nvdotprodmulti = w->ops->nvdotprodmulti; - - /* vector array operations */ - ops->nvlinearsumvectorarray = w->ops->nvlinearsumvectorarray; - ops->nvscalevectorarray = w->ops->nvscalevectorarray; - ops->nvconstvectorarray = w->ops->nvconstvectorarray; - ops->nvwrmsnormvectorarray = w->ops->nvwrmsnormvectorarray; - ops->nvwrmsnormmaskvectorarray = w->ops->nvwrmsnormmaskvectorarray; - ops->nvscaleaddmultivectorarray = w->ops->nvscaleaddmultivectorarray; - ops->nvlinearcombinationvectorarray = w->ops->nvlinearcombinationvectorarray; - - /* Attach ops and set content to NULL */ - v->content = NULL; - v->ops = ops; + /* Attach operations */ + if (N_VCopyOps(w, v)) { N_VDestroy(v); return(NULL); } return(v); } @@ -236,8 +174,7 @@ N_Vector N_VCloneEmpty_Trilinos(N_Vector w) N_Vector N_VClone_Trilinos(N_Vector w) { N_Vector v = N_VCloneEmpty_Trilinos(w); - if (v == NULL) - return(NULL); + if (v == NULL) return(NULL); // Get raw pointer to Tpetra vector Teuchos::RCP wvec = N_VGetVector_Trilinos(w); @@ -248,17 +185,15 @@ N_Vector N_VClone_Trilinos(N_Vector w) // Create vector content using the raw pointer to the cloned Tpetra vector v->content = new Sundials::TpetraVectorInterface(tvec); - if (v->content == NULL) { - free(v->ops); - free(v); - return NULL; - } + if (v->content == NULL) { N_VDestroy(v); return NULL; } return(v); } void N_VDestroy_Trilinos(N_Vector v) { + if (v == NULL) return; + if(v->content != NULL) { Sundials::TpetraVectorInterface* iface = reinterpret_cast(v->content); @@ -268,11 +203,11 @@ void N_VDestroy_Trilinos(N_Vector v) v->content = NULL; } - free(v->ops); - v->ops = NULL; + /* free ops and vector */ + if (v->ops != NULL) { free(v->ops); v->ops = NULL; } + free(v); v = NULL; - free(v); - v = NULL; + return; } void N_VSpace_Trilinos(N_Vector x, sunindextype *lrw, sunindextype *liw) @@ -283,10 +218,40 @@ void N_VSpace_Trilinos(N_Vector x, sunindextype *lrw, sunindextype *liw) const Teuchos::RCP >& comm = xv->getMap()->getComm(); int npes = comm->getSize(); - *lrw = xv->getGlobalLength(); + *lrw = (sunindextype)(xv->getGlobalLength()); *liw = 2*npes; } +/* + * MPI communicator accessor + */ +void *N_VGetCommunicator_Trilinos(N_Vector x) +{ + using namespace Sundials; + +#ifdef SUNDIALS_TRILINOS_HAVE_MPI + Teuchos::RCP xv = N_VGetVector_Trilinos(x); + /* Access Teuchos::Comm* (which is actually a Teuchos::MpiComm*) */ + auto comm = Teuchos::rcp_dynamic_cast>(xv->getMap()->getComm()); + + return((void*) comm->getRawMpiComm().get()); /* extract raw pointer to MPI_Comm */ +#else + return(NULL); +#endif +} + +/* + * Global vector length accessor + */ +sunindextype N_VGetLength_Trilinos(N_Vector x) +{ + using namespace Sundials; + + Teuchos::RCP xv = N_VGetVector_Trilinos(x); + + return ((sunindextype) xv->getGlobalLength()); +} + /* * Linear combination of two vectors: z = a*x + b*y */ @@ -517,7 +482,7 @@ booleantype N_VInvTest_Trilinos(N_Vector x, N_Vector z) /* * Checks constraint violations for vector x. Constraints are defined in - * vector c, and constrain violation flags are stored in vector m. + * vector c, and constraint violation flags are stored in vector m. */ booleantype N_VConstrMask_Trilinos(N_Vector c, N_Vector x, N_Vector m) { @@ -542,3 +507,120 @@ realtype N_VMinQuotient_Trilinos(N_Vector num, N_Vector denom) return TpetraVector::minQuotient(*numv, *denv); } + +/* + * MPI task-local dot product + */ +realtype N_VDotProdLocal_Trilinos(N_Vector x, N_Vector y) +{ + using namespace Sundials; + + Teuchos::RCP xv = N_VGetVector_Trilinos(x); + Teuchos::RCP yv = N_VGetVector_Trilinos(y); + + return TpetraVector::dotProdLocal(*xv, *yv); +} + +/* + * MPI task-local maximum norm + */ +realtype N_VMaxNormLocal_Trilinos(N_Vector x) +{ + using namespace Sundials; + + Teuchos::RCP xv = N_VGetVector_Trilinos(x); + + return TpetraVector::maxNormLocal(*xv); +} + +/* + * MPI task-local minimum element + */ +realtype N_VMinLocal_Trilinos(N_Vector x) +{ + using namespace Sundials; + + Teuchos::RCP xv = N_VGetVector_Trilinos(x); + + return TpetraVector::minLocal(*xv); +} + +/* + * MPI task-local L1 norm + */ +realtype N_VL1NormLocal_Trilinos(N_Vector x) +{ + using namespace Sundials; + + Teuchos::RCP xv = N_VGetVector_Trilinos(x); + + return TpetraVector::L1NormLocal(*xv); +} + +/* + * MPI task-local weighted squared sum + */ +realtype N_VWSqrSumLocal_Trilinos(N_Vector x, N_Vector w) +{ + using namespace Sundials; + + Teuchos::RCP xv = N_VGetVector_Trilinos(x); + Teuchos::RCP wv = N_VGetVector_Trilinos(w); + + return TpetraVector::WSqrSumLocal(*xv, *wv); +} + +/* + * MPI task-local weighted masked squared sum + */ +realtype N_VWSqrSumMaskLocal_Trilinos(N_Vector x, N_Vector w, N_Vector id) +{ + using namespace Sundials; + + Teuchos::RCP xv = N_VGetVector_Trilinos(x); + Teuchos::RCP wv = N_VGetVector_Trilinos(w); + Teuchos::RCP idv = N_VGetVector_Trilinos(id); + + return TpetraVector::WSqrSumMaskLocal(*xv, *wv, *idv); +} + +/* + * MPI task-local elementwise inverse with zero checking: z[i] = 1/x[i], x[i] != 0 + */ +booleantype N_VInvTestLocal_Trilinos(N_Vector x, N_Vector z) +{ + using namespace Sundials; + + Teuchos::RCP xv = N_VGetVector_Trilinos(x); + Teuchos::RCP zv = N_VGetVector_Trilinos(z); + + return TpetraVector::invTestLocal(*xv, *zv) ? SUNTRUE : SUNFALSE; +} + +/* + * MPI task-local constraint checking for vector x. Constraints are defined in + * vector c, and constraint violation flags are stored in vector m. + */ +booleantype N_VConstrMaskLocal_Trilinos(N_Vector c, N_Vector x, N_Vector m) +{ + using namespace Sundials; + + Teuchos::RCP cv = N_VGetVector_Trilinos(c); + Teuchos::RCP xv = N_VGetVector_Trilinos(x); + Teuchos::RCP mv = N_VGetVector_Trilinos(m); + + return TpetraVector::constraintMaskLocal(*cv, *xv, *mv) ? SUNTRUE : SUNFALSE; +} + +/* + * MPI task-local minimum quotient: minq = min ( num[i]/denom[i]), denom[i] != 0. + */ +realtype N_VMinQuotientLocal_Trilinos(N_Vector num, N_Vector denom) +{ + using namespace Sundials; + + Teuchos::RCP numv = N_VGetVector_Trilinos(num); + Teuchos::RCP denv = N_VGetVector_Trilinos(denom); + + return TpetraVector::minQuotientLocal(*numv, *denv); +} diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sundials/CMakeLists.txt index e5680d0ba..72a0dd496 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Radu Serban @ LLNL +# Programmer(s): Radu Serban and Cody J. Balos @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,47 +12,83 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the generic SUNDIALS modules +# --------------------------------------------------------------- # From here we only install the generic SUNDIALS headers. # The implementations themselves are incorporated in the individual SUNDIALS solver libraries. -INSTALL(CODE "MESSAGE(\"\nInstall shared components\n\")") +install(CODE "MESSAGE(\"\nInstall shared components\n\")") + +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) # Add variable sundials_HEADERS with the exported SUNDIALS header files -SET(sundials_HEADERS +set(sundials_HEADERS sundials_band.h sundials_dense.h sundials_direct.h sundials_fnvector.h + sundials_futils.h sundials_iterative.h sundials_linearsolver.h sundials_math.h sundials_matrix.h - sundials_mpi.h - sundials_mpi_types.h sundials_nonlinearsolver.h - sundials_mpi.h sundials_mpi_types.h sundials_nvector.h - sundials_pcg.h - sundials_sparse.h - sundials_spbcgs.h - sundials_spfgmr.h - sundials_spgmr.h - sundials_sptfqmr.h sundials_types.h sundials_version.h ) # Add prefix with complete path to the SUNDIALS header files -ADD_PREFIX(${sundials_SOURCE_DIR}/include/sundials/ sundials_HEADERS) +add_prefix(${sundials_SOURCE_DIR}/include/sundials/ sundials_HEADERS) + +# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY +add_definitions(-DBUILD_SUNDIALS_LIBRARY) + +# Create an object library out of the generic sundials modules +if(BUILD_STATIC_LIBS) + add_library(sundials_generic_static_obj OBJECT + sundials_band.c + sundials_dense.c + sundials_direct.c + sundials_futils.c + sundials_iterative.c + sundials_linearsolver.c + sundials_math.c + sundials_matrix.c + sundials_nonlinearsolver.c + sundials_nvector.c + sundials_nvector_senswrapper.c + sundials_version.c) +endif() + +if(BUILD_SHARED_LIBS) + add_library(sundials_generic_shared_obj OBJECT + sundials_band.c + sundials_dense.c + sundials_direct.c + sundials_futils.c + sundials_iterative.c + sundials_linearsolver.c + sundials_math.c + sundials_matrix.c + sundials_nonlinearsolver.c + sundials_nvector.c + sundials_nvector_senswrapper.c + sundials_version.c) + set_target_properties(sundials_generic_shared_obj PROPERTIES + POSITION_INDEPENDENT_CODE TRUE) +endif() # Install the SUNDIALS header files -INSTALL(FILES ${sundials_HEADERS} DESTINATION include/sundials) +install(FILES ${sundials_HEADERS} DESTINATION include/sundials) # If Blas/Lapack support was enabled, install the Lapack interface headers -IF(LAPACK_FOUND) - SET(sundials_BL_HEADERS sundials_lapack.h) - ADD_PREFIX(${sundials_SOURCE_DIR}/include/sundials/ sundials_BL_HEADERS) - INSTALL(FILES ${sundials_BL_HEADERS} DESTINATION include/sundials) -ENDIF(LAPACK_FOUND) +if(LAPACK_FOUND) + set(sundials_BL_HEADERS sundials_lapack.h) + add_prefix(${sundials_SOURCE_DIR}/include/sundials/ sundials_BL_HEADERS) + install(FILES ${sundials_BL_HEADERS} DESTINATION include/sundials) +endif(LAPACK_FOUND) diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/CMakeLists.txt new file mode 100644 index 000000000..c20451f98 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/CMakeLists.txt @@ -0,0 +1,46 @@ +# --------------------------------------------------------------- +# Programmer(s): Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the F2003 SUNDIALS object library +# --------------------------------------------------------------- + +set(sundials_SOURCES + fsundials_futils_mod.f90 + fsundials_futils_mod.c + fsundials_linearsolver_mod.f90 + fsundials_linearsolver_mod.c + fsundials_matrix_mod.f90 + fsundials_matrix_mod.c + fsundials_nonlinearsolver_mod.f90 + fsundials_nonlinearsolver_mod.c + fsundials_nvector_mod.f90 + fsundials_nvector_mod.c + fsundials_types_mod.f90 + fsundials_types_mod.c) + +if(BUILD_STATIC_LIBS) + add_library(sundials_fgeneric_static_obj OBJECT ${sundials_SOURCES}) + set_target_properties(sundials_fgeneric_static_obj PROPERTIES + Fortran_MODULE_DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY}_STATIC) + target_include_directories(sundials_fgeneric_static_obj PRIVATE + ${CMAKE_Fortran_MODULE_DIRECTORY}_STATIC) +endif() + +if(BUILD_SHARED_LIBS) + add_library(sundials_fgeneric_shared_obj OBJECT ${sundials_SOURCES}) + set_target_properties(sundials_fgeneric_shared_obj PROPERTIES + POSITION_INDEPENDENT_CODE TRUE + Fortran_MODULE_DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY}_SHARED) + target_include_directories(sundials_fgeneric_shared_obj PRIVATE + ${CMAKE_Fortran_MODULE_DIRECTORY}_SHARED) +endif() diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_futils_mod.c b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_futils_mod.c new file mode 100644 index 000000000..ef44c7d75 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_futils_mod.c @@ -0,0 +1,255 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_futils.h" + + +#include +#ifdef _MSC_VER +# ifndef strtoull +# define strtoull _strtoui64 +# endif +# ifndef strtoll +# define strtoll _strtoi64 +# endif +#endif + + +typedef struct { + void* data; + size_t size; +} SwigArrayWrapper; + + +SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() { + SwigArrayWrapper result; + result.data = NULL; + result.size = 0; + return result; +} + +SWIGEXPORT void * _wrap_FSUNDIALSFileOpen(SwigArrayWrapper *farg1, SwigArrayWrapper *farg2) { + void * fresult ; + char *arg1 = (char *) 0 ; + char *arg2 = (char *) 0 ; + FILE *result = 0 ; + + arg1 = (char *)(farg1->data); + arg2 = (char *)(farg2->data); + result = (FILE *)SUNDIALSFileOpen((char const *)arg1,(char const *)arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FSUNDIALSFileClose(void *farg1) { + FILE *arg1 = (FILE *) 0 ; + + arg1 = (FILE *)(farg1); + SUNDIALSFileClose(arg1); +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_futils_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_futils_mod.f90 new file mode 100644 index 000000000..dda8b3573 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_futils_mod.f90 @@ -0,0 +1,103 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsundials_futils_mod + use, intrinsic :: ISO_C_BINDING + implicit none + private + + ! DECLARATION CONSTRUCTS + type, bind(C) :: SwigArrayWrapper + type(C_PTR), public :: data = C_NULL_PTR + integer(C_SIZE_T), public :: size = 0 + end type + public :: FSUNDIALSFileOpen + public :: FSUNDIALSFileClose + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNDIALSFileOpen(farg1, farg2) & +bind(C, name="_wrap_FSUNDIALSFileOpen") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigarraywrapper +type(SwigArrayWrapper) :: farg1 +type(SwigArrayWrapper) :: farg2 +type(C_PTR) :: fresult +end function + +subroutine swigc_FSUNDIALSFileClose(farg1) & +bind(C, name="_wrap_FSUNDIALSFileClose") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +end interface + + +contains + ! MODULE SUBPROGRAMS + +subroutine SWIG_string_to_chararray(string, chars, wrap) + use, intrinsic :: ISO_C_BINDING + character(kind=C_CHAR, len=*), intent(IN) :: string + character(kind=C_CHAR), dimension(:), target, allocatable, intent(OUT) :: chars + type(SwigArrayWrapper), intent(OUT) :: wrap + integer :: i + + allocate(character(kind=C_CHAR) :: chars(len(string) + 1)) + do i=1,len(string) + chars(i) = string(i:i) + end do + i = len(string) + 1 + chars(i) = C_NULL_CHAR ! C string compatibility + wrap%data = c_loc(chars) + wrap%size = len(string) +end subroutine + +function FSUNDIALSFileOpen(filename, modes) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +character(kind=C_CHAR, len=*), target :: filename +character(kind=C_CHAR), dimension(:), allocatable, target :: farg1_chars +character(kind=C_CHAR, len=*), target :: modes +character(kind=C_CHAR), dimension(:), allocatable, target :: farg2_chars +type(C_PTR) :: fresult +type(SwigArrayWrapper) :: farg1 +type(SwigArrayWrapper) :: farg2 + +call SWIG_string_to_chararray(filename, farg1_chars, farg1) +call SWIG_string_to_chararray(modes, farg2_chars, farg2) +fresult = swigc_FSUNDIALSFileOpen(farg1, farg2) +swig_result = fresult +end function + +subroutine FSUNDIALSFileClose(fp) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: fp +type(C_PTR) :: farg1 + +farg1 = fp +call swigc_FSUNDIALSFileClose(farg1) +end subroutine + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_linearsolver_mod.c b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_linearsolver_mod.c new file mode 100644 index 000000000..c53fe1bb6 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_linearsolver_mod.c @@ -0,0 +1,488 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_iterative.h" +#include "sundials/sundials_linearsolver.h" + +SWIGEXPORT int _wrap_FModifiedGS(void *farg1, void *farg2, int const *farg3, int const *farg4, double *farg5) { + int fresult ; + N_Vector *arg1 = (N_Vector *) 0 ; + realtype **arg2 = (realtype **) 0 ; + int arg3 ; + int arg4 ; + realtype *arg5 = (realtype *) 0 ; + int result; + + arg1 = (N_Vector *)(farg1); + arg2 = (realtype **)(farg2); + arg3 = (int)(*farg3); + arg4 = (int)(*farg4); + arg5 = (realtype *)(farg5); + result = (int)ModifiedGS(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FClassicalGS(void *farg1, void *farg2, int const *farg3, int const *farg4, double *farg5, double *farg6, void *farg7) { + int fresult ; + N_Vector *arg1 = (N_Vector *) 0 ; + realtype **arg2 = (realtype **) 0 ; + int arg3 ; + int arg4 ; + realtype *arg5 = (realtype *) 0 ; + realtype *arg6 = (realtype *) 0 ; + N_Vector *arg7 = (N_Vector *) 0 ; + int result; + + arg1 = (N_Vector *)(farg1); + arg2 = (realtype **)(farg2); + arg3 = (int)(*farg3); + arg4 = (int)(*farg4); + arg5 = (realtype *)(farg5); + arg6 = (realtype *)(farg6); + arg7 = (N_Vector *)(farg7); + result = (int)ClassicalGS(arg1,arg2,arg3,arg4,arg5,arg6,arg7); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FQRfact(int const *farg1, void *farg2, double *farg3, int const *farg4) { + int fresult ; + int arg1 ; + realtype **arg2 = (realtype **) 0 ; + realtype *arg3 = (realtype *) 0 ; + int arg4 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype **)(farg2); + arg3 = (realtype *)(farg3); + arg4 = (int)(*farg4); + result = (int)QRfact(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FQRsol(int const *farg1, void *farg2, double *farg3, double *farg4) { + int fresult ; + int arg1 ; + realtype **arg2 = (realtype **) 0 ; + realtype *arg3 = (realtype *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype **)(farg2); + arg3 = (realtype *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)QRsol(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SUNLinearSolver _wrap_FSUNLinSolNewEmpty() { + SUNLinearSolver fresult ; + SUNLinearSolver result; + + result = (SUNLinearSolver)SUNLinSolNewEmpty(); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FSUNLinSolFreeEmpty(SUNLinearSolver farg1) { + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + + arg1 = (SUNLinearSolver)(farg1); + SUNLinSolFreeEmpty(arg1); +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetType(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_Type result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_Type)SUNLinSolGetType(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetID(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_ID result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_ID)SUNLinSolGetID(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetATimes(SUNLinearSolver farg1, void *farg2, ATimesFn farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + void *arg2 = (void *) 0 ; + ATimesFn arg3 = (ATimesFn) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (void *)(farg2); + arg3 = (ATimesFn)(farg3); + result = (int)SUNLinSolSetATimes(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetPreconditioner(SUNLinearSolver farg1, void *farg2, PSetupFn farg3, PSolveFn farg4) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + void *arg2 = (void *) 0 ; + PSetupFn arg3 = (PSetupFn) 0 ; + PSolveFn arg4 = (PSolveFn) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (void *)(farg2); + arg3 = (PSetupFn)(farg3); + arg4 = (PSolveFn)(farg4); + result = (int)SUNLinSolSetPreconditioner(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetScalingVectors(SUNLinearSolver farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)SUNLinSolSetScalingVectors(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolInitialize(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolInitialize(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetup(SUNLinearSolver farg1, SUNMatrix farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNLinSolSetup(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSolve(SUNLinearSolver farg1, SUNMatrix farg2, N_Vector farg3, N_Vector farg4, double const *farg5) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype arg5 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype)(*farg5); + result = (int)SUNLinSolSolve(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolNumIters(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolNumIters(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FSUNLinSolResNorm(SUNLinearSolver farg1) { + double fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + realtype result; + + arg1 = (SUNLinearSolver)(farg1); + result = (realtype)SUNLinSolResNorm(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FSUNLinSolResid(SUNLinearSolver farg1) { + N_Vector fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + N_Vector result; + + arg1 = (SUNLinearSolver)(farg1); + result = (N_Vector)SUNLinSolResid(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNLinSolLastFlag(SUNLinearSolver farg1) { + int64_t fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + sunindextype result; + + arg1 = (SUNLinearSolver)(farg1); + result = SUNLinSolLastFlag(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSpace(SUNLinearSolver farg1, long *farg2, long *farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNLinSolSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolFree(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolFree(arg1); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_linearsolver_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_linearsolver_mod.f90 new file mode 100644 index 000000000..dc9802730 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_linearsolver_mod.f90 @@ -0,0 +1,660 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. +module fsundials_linearsolver_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + enum, bind(c) + enumerator :: PREC_NONE + enumerator :: PREC_LEFT + enumerator :: PREC_RIGHT + enumerator :: PREC_BOTH + end enum + public :: PREC_NONE, PREC_LEFT, PREC_RIGHT, PREC_BOTH + enum, bind(c) + enumerator :: MODIFIED_GS = 1 + enumerator :: CLASSICAL_GS = 2 + end enum + public :: MODIFIED_GS, CLASSICAL_GS + public :: FModifiedGS + public :: FClassicalGS + public :: FQRfact + public :: FQRsol + ! typedef enum SUNLinearSolver_Type + enum, bind(c) + enumerator :: SUNLINEARSOLVER_DIRECT + enumerator :: SUNLINEARSOLVER_ITERATIVE + enumerator :: SUNLINEARSOLVER_MATRIX_ITERATIVE + end enum + integer, parameter, public :: SUNLinearSolver_Type = kind(SUNLINEARSOLVER_DIRECT) + public :: SUNLINEARSOLVER_DIRECT, SUNLINEARSOLVER_ITERATIVE, SUNLINEARSOLVER_MATRIX_ITERATIVE + ! typedef enum SUNLinearSolver_ID + enum, bind(c) + enumerator :: SUNLINEARSOLVER_BAND + enumerator :: SUNLINEARSOLVER_DENSE + enumerator :: SUNLINEARSOLVER_KLU + enumerator :: SUNLINEARSOLVER_LAPACKBAND + enumerator :: SUNLINEARSOLVER_LAPACKDENSE + enumerator :: SUNLINEARSOLVER_PCG + enumerator :: SUNLINEARSOLVER_SPBCGS + enumerator :: SUNLINEARSOLVER_SPFGMR + enumerator :: SUNLINEARSOLVER_SPGMR + enumerator :: SUNLINEARSOLVER_SPTFQMR + enumerator :: SUNLINEARSOLVER_SUPERLUDIST + enumerator :: SUNLINEARSOLVER_SUPERLUMT + enumerator :: SUNLINEARSOLVER_CUSOLVERSP_BATCHQR + enumerator :: SUNLINEARSOLVER_CUSTOM + end enum + integer, parameter, public :: SUNLinearSolver_ID = kind(SUNLINEARSOLVER_BAND) + public :: SUNLINEARSOLVER_BAND, SUNLINEARSOLVER_DENSE, SUNLINEARSOLVER_KLU, SUNLINEARSOLVER_LAPACKBAND, & + SUNLINEARSOLVER_LAPACKDENSE, SUNLINEARSOLVER_PCG, SUNLINEARSOLVER_SPBCGS, SUNLINEARSOLVER_SPFGMR, SUNLINEARSOLVER_SPGMR, & + SUNLINEARSOLVER_SPTFQMR, SUNLINEARSOLVER_SUPERLUDIST, SUNLINEARSOLVER_SUPERLUMT, SUNLINEARSOLVER_CUSOLVERSP_BATCHQR, & + SUNLINEARSOLVER_CUSTOM + ! struct struct _generic_SUNLinearSolver_Ops + type, bind(C), public :: SUNLinearSolver_Ops + type(C_FUNPTR), public :: gettype + type(C_FUNPTR), public :: getid + type(C_FUNPTR), public :: setatimes + type(C_FUNPTR), public :: setpreconditioner + type(C_FUNPTR), public :: setscalingvectors + type(C_FUNPTR), public :: initialize + type(C_FUNPTR), public :: setup + type(C_FUNPTR), public :: solve + type(C_FUNPTR), public :: numiters + type(C_FUNPTR), public :: resnorm + type(C_FUNPTR), public :: lastflag + type(C_FUNPTR), public :: space + type(C_FUNPTR), public :: resid + type(C_FUNPTR), public :: free + end type SUNLinearSolver_Ops + ! struct struct _generic_SUNLinearSolver + type, bind(C), public :: SUNLinearSolver + type(C_PTR), public :: content + type(C_PTR), public :: ops + end type SUNLinearSolver + public :: FSUNLinSolNewEmpty + public :: FSUNLinSolFreeEmpty + public :: FSUNLinSolGetType + public :: FSUNLinSolGetID + public :: FSUNLinSolSetATimes + public :: FSUNLinSolSetPreconditioner + public :: FSUNLinSolSetScalingVectors + public :: FSUNLinSolInitialize + public :: FSUNLinSolSetup + public :: FSUNLinSolSolve + public :: FSUNLinSolNumIters + public :: FSUNLinSolResNorm + public :: FSUNLinSolResid + public :: FSUNLinSolLastFlag + public :: FSUNLinSolSpace + public :: FSUNLinSolFree + integer(C_INT), parameter, public :: SUNLS_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: SUNLS_MEM_NULL = -801_C_INT + integer(C_INT), parameter, public :: SUNLS_ILL_INPUT = -802_C_INT + integer(C_INT), parameter, public :: SUNLS_MEM_FAIL = -803_C_INT + integer(C_INT), parameter, public :: SUNLS_ATIMES_FAIL_UNREC = -804_C_INT + integer(C_INT), parameter, public :: SUNLS_PSET_FAIL_UNREC = -805_C_INT + integer(C_INT), parameter, public :: SUNLS_PSOLVE_FAIL_UNREC = -806_C_INT + integer(C_INT), parameter, public :: SUNLS_PACKAGE_FAIL_UNREC = -807_C_INT + integer(C_INT), parameter, public :: SUNLS_GS_FAIL = -808_C_INT + integer(C_INT), parameter, public :: SUNLS_QRSOL_FAIL = -809_C_INT + integer(C_INT), parameter, public :: SUNLS_VECTOROP_ERR = -810_C_INT + integer(C_INT), parameter, public :: SUNLS_RES_REDUCED = 801_C_INT + integer(C_INT), parameter, public :: SUNLS_CONV_FAIL = 802_C_INT + integer(C_INT), parameter, public :: SUNLS_ATIMES_FAIL_REC = 803_C_INT + integer(C_INT), parameter, public :: SUNLS_PSET_FAIL_REC = 804_C_INT + integer(C_INT), parameter, public :: SUNLS_PSOLVE_FAIL_REC = 805_C_INT + integer(C_INT), parameter, public :: SUNLS_PACKAGE_FAIL_REC = 806_C_INT + integer(C_INT), parameter, public :: SUNLS_QRFACT_FAIL = 807_C_INT + integer(C_INT), parameter, public :: SUNLS_LUFACT_FAIL = 808_C_INT + +! WRAPPER DECLARATIONS +interface +function swigc_FModifiedGS(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FModifiedGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT), intent(in) :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FClassicalGS(farg1, farg2, farg3, farg4, farg5, farg6, farg7) & +bind(C, name="_wrap_FClassicalGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT), intent(in) :: farg3 +integer(C_INT), intent(in) :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +type(C_PTR), value :: farg7 +integer(C_INT) :: fresult +end function + +function swigc_FQRfact(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FQRfact") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FQRsol(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FQRsol") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolNewEmpty() & +bind(C, name="_wrap_FSUNLinSolNewEmpty") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: fresult +end function + +subroutine swigc_FSUNLinSolFreeEmpty(farg1) & +bind(C, name="_wrap_FSUNLinSolFreeEmpty") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FSUNLinSolGetType(farg1) & +bind(C, name="_wrap_FSUNLinSolGetType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetID(farg1) & +bind(C, name="_wrap_FSUNLinSolGetID") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetATimes(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSetATimes") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetPreconditioner(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FSUNLinSolSetPreconditioner") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetScalingVectors(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSetScalingVectors") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolInitialize(farg1) & +bind(C, name="_wrap_FSUNLinSolInitialize") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetup(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSolSetup") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSolve(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FSUNLinSolSolve") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolNumIters(farg1) & +bind(C, name="_wrap_FSUNLinSolNumIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolResNorm(farg1) & +bind(C, name="_wrap_FSUNLinSolResNorm") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FSUNLinSolResid(farg1) & +bind(C, name="_wrap_FSUNLinSolResid") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSolLastFlag(farg1) & +bind(C, name="_wrap_FSUNLinSolLastFlag") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNLinSolSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolFree(farg1) & +bind(C, name="_wrap_FSUNLinSolFree") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FModifiedGS(v, h, k, p, new_vk_norm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: v +type(C_PTR), target, intent(inout) :: h +integer(C_INT), intent(in) :: k +integer(C_INT), intent(in) :: p +real(C_DOUBLE), dimension(*), target, intent(inout) :: new_vk_norm +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT) :: farg3 +integer(C_INT) :: farg4 +type(C_PTR) :: farg5 + +farg1 = v +farg2 = c_loc(h) +farg3 = k +farg4 = p +farg5 = c_loc(new_vk_norm(1)) +fresult = swigc_FModifiedGS(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FClassicalGS(v, h, k, p, new_vk_norm, stemp, vtemp) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(C_PTR) :: v +type(C_PTR), target, intent(inout) :: h +integer(C_INT), intent(in) :: k +integer(C_INT), intent(in) :: p +real(C_DOUBLE), dimension(*), target, intent(inout) :: new_vk_norm +real(C_DOUBLE), dimension(*), target, intent(inout) :: stemp +type(C_PTR) :: vtemp +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT) :: farg3 +integer(C_INT) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 +type(C_PTR) :: farg7 + +farg1 = v +farg2 = c_loc(h) +farg3 = k +farg4 = p +farg5 = c_loc(new_vk_norm(1)) +farg6 = c_loc(stemp(1)) +farg7 = vtemp +fresult = swigc_FClassicalGS(farg1, farg2, farg3, farg4, farg5, farg6, farg7) +swig_result = fresult +end function + +function FQRfact(n, h, q, job) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: n +type(C_PTR), target, intent(inout) :: h +real(C_DOUBLE), dimension(*), target, intent(inout) :: q +integer(C_INT), intent(in) :: job +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +integer(C_INT) :: farg4 + +farg1 = n +farg2 = c_loc(h) +farg3 = c_loc(q(1)) +farg4 = job +fresult = swigc_FQRfact(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FQRsol(n, h, q, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: n +type(C_PTR), target, intent(inout) :: h +real(C_DOUBLE), dimension(*), target, intent(inout) :: q +real(C_DOUBLE), dimension(*), target, intent(inout) :: b +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = n +farg2 = c_loc(h) +farg3 = c_loc(q(1)) +farg4 = c_loc(b(1)) +fresult = swigc_FQRsol(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FSUNLinSolNewEmpty() & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(C_PTR) :: fresult + +fresult = swigc_FSUNLinSolNewEmpty() +call c_f_pointer(fresult, swig_result) +end function + +subroutine FSUNLinSolFreeEmpty(s) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +call swigc_FSUNLinSolFreeEmpty(farg1) +end subroutine + +function FSUNLinSolGetType(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_Type) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetType(farg1) +swig_result = fresult +end function + +function FSUNLinSolGetID(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_ID) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetID(farg1) +swig_result = fresult +end function + +function FSUNLinSolSetATimes(s, a_data, atimes) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: a_data +type(C_FUNPTR), intent(in), value :: atimes +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = c_loc(s) +farg2 = a_data +farg3 = atimes +fresult = swigc_FSUNLinSolSetATimes(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolSetPreconditioner(s, p_data, pset, psol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: p_data +type(C_FUNPTR), intent(in), value :: pset +type(C_FUNPTR), intent(in), value :: psol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = c_loc(s) +farg2 = p_data +farg3 = pset +farg4 = psol +fresult = swigc_FSUNLinSolSetPreconditioner(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FSUNLinSolSetScalingVectors(s, s1, s2) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(N_Vector), target, intent(inout) :: s1 +type(N_Vector), target, intent(inout) :: s2 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(s1) +farg3 = c_loc(s2) +fresult = swigc_FSUNLinSolSetScalingVectors(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolInitialize(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolInitialize(farg1) +swig_result = fresult +end function + +function FSUNLinSolSetup(s, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(s) +farg2 = c_loc(a) +fresult = swigc_FSUNLinSolSetup(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolSolve(s, a, x, b, tol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: b +real(C_DOUBLE), intent(in) :: tol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +real(C_DOUBLE) :: farg5 + +farg1 = c_loc(s) +farg2 = c_loc(a) +farg3 = c_loc(x) +farg4 = c_loc(b) +farg5 = tol +fresult = swigc_FSUNLinSolSolve(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FSUNLinSolNumIters(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolNumIters(farg1) +swig_result = fresult +end function + +function FSUNLinSolResNorm(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolResNorm(farg1) +swig_result = fresult +end function + +function FSUNLinSolResid(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolResid(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSolLastFlag(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolLastFlag(farg1) +swig_result = fresult +end function + +function FSUNLinSolSpace(s, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FSUNLinSolSpace(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolFree(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolFree(farg1) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_matrix_mod.c b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_matrix_mod.c new file mode 100644 index 000000000..a30b3b5d6 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_matrix_mod.c @@ -0,0 +1,357 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_matrix.h" + +SWIGEXPORT SUNMatrix _wrap_FSUNMatNewEmpty() { + SUNMatrix fresult ; + SUNMatrix result; + + result = (SUNMatrix)SUNMatNewEmpty(); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FSUNMatFreeEmpty(SUNMatrix farg1) { + SUNMatrix arg1 = (SUNMatrix) 0 ; + + arg1 = (SUNMatrix)(farg1); + SUNMatFreeEmpty(arg1); +} + + +SWIGEXPORT int _wrap_FSUNMatCopyOps(SUNMatrix farg1, SUNMatrix farg2) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNMatCopyOps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatGetID(SUNMatrix farg1) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix_ID result; + + arg1 = (SUNMatrix)(farg1); + result = (SUNMatrix_ID)SUNMatGetID(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SUNMatrix _wrap_FSUNMatClone(SUNMatrix farg1) { + SUNMatrix fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix result; + + arg1 = (SUNMatrix)(farg1); + result = (SUNMatrix)SUNMatClone(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FSUNMatDestroy(SUNMatrix farg1) { + SUNMatrix arg1 = (SUNMatrix) 0 ; + + arg1 = (SUNMatrix)(farg1); + SUNMatDestroy(arg1); +} + + +SWIGEXPORT int _wrap_FSUNMatZero(SUNMatrix farg1) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + result = (int)SUNMatZero(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatCopy(SUNMatrix farg1, SUNMatrix farg2) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNMatCopy(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatScaleAdd(double const *farg1, SUNMatrix farg2, SUNMatrix farg3) { + int fresult ; + realtype arg1 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + SUNMatrix arg3 = (SUNMatrix) 0 ; + int result; + + arg1 = (realtype)(*farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (SUNMatrix)(farg3); + result = (int)SUNMatScaleAdd(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatScaleAddI(double const *farg1, SUNMatrix farg2) { + int fresult ; + realtype arg1 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (realtype)(*farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNMatScaleAddI(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatMatvecSetup(SUNMatrix farg1) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + result = (int)SUNMatMatvecSetup(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatMatvec(SUNMatrix farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)SUNMatMatvec(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatSpace(SUNMatrix farg1, long *farg2, long *farg3) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNMatSpace(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_matrix_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_matrix_mod.f90 new file mode 100644 index 000000000..7d1e5593a --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_matrix_mod.f90 @@ -0,0 +1,364 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. +module fsundials_matrix_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + ! typedef enum SUNMatrix_ID + enum, bind(c) + enumerator :: SUNMATRIX_DENSE + enumerator :: SUNMATRIX_BAND + enumerator :: SUNMATRIX_SPARSE + enumerator :: SUNMATRIX_SLUNRLOC + enumerator :: SUNMATRIX_CUSPARSE + enumerator :: SUNMATRIX_CUSTOM + end enum + integer, parameter, public :: SUNMatrix_ID = kind(SUNMATRIX_DENSE) + public :: SUNMATRIX_DENSE, SUNMATRIX_BAND, SUNMATRIX_SPARSE, SUNMATRIX_SLUNRLOC, SUNMATRIX_CUSPARSE, SUNMATRIX_CUSTOM + ! struct struct _generic_SUNMatrix_Ops + type, bind(C), public :: SUNMatrix_Ops + type(C_FUNPTR), public :: getid + type(C_FUNPTR), public :: clone + type(C_FUNPTR), public :: destroy + type(C_FUNPTR), public :: zero + type(C_FUNPTR), public :: copy + type(C_FUNPTR), public :: scaleadd + type(C_FUNPTR), public :: scaleaddi + type(C_FUNPTR), public :: matvecsetup + type(C_FUNPTR), public :: matvec + type(C_FUNPTR), public :: space + end type SUNMatrix_Ops + ! struct struct _generic_SUNMatrix + type, bind(C), public :: SUNMatrix + type(C_PTR), public :: content + type(C_PTR), public :: ops + end type SUNMatrix + public :: FSUNMatNewEmpty + public :: FSUNMatFreeEmpty + public :: FSUNMatCopyOps + public :: FSUNMatGetID + public :: FSUNMatClone + public :: FSUNMatDestroy + public :: FSUNMatZero + public :: FSUNMatCopy + public :: FSUNMatScaleAdd + public :: FSUNMatScaleAddI + public :: FSUNMatMatvecSetup + public :: FSUNMatMatvec + public :: FSUNMatSpace + integer(C_INT), parameter, public :: SUNMAT_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: SUNMAT_ILL_INPUT = -701_C_INT + integer(C_INT), parameter, public :: SUNMAT_MEM_FAIL = -702_C_INT + integer(C_INT), parameter, public :: SUNMAT_OPERATION_FAIL = -703_C_INT + integer(C_INT), parameter, public :: SUNMAT_MATVEC_SETUP_REQUIRED = -704_C_INT + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNMatNewEmpty() & +bind(C, name="_wrap_FSUNMatNewEmpty") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: fresult +end function + +subroutine swigc_FSUNMatFreeEmpty(farg1) & +bind(C, name="_wrap_FSUNMatFreeEmpty") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FSUNMatCopyOps(farg1, farg2) & +bind(C, name="_wrap_FSUNMatCopyOps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatGetID(farg1) & +bind(C, name="_wrap_FSUNMatGetID") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatClone(farg1) & +bind(C, name="_wrap_FSUNMatClone") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FSUNMatDestroy(farg1) & +bind(C, name="_wrap_FSUNMatDestroy") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FSUNMatZero(farg1) & +bind(C, name="_wrap_FSUNMatZero") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatCopy(farg1, farg2) & +bind(C, name="_wrap_FSUNMatCopy") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatScaleAdd(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNMatScaleAdd") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatScaleAddI(farg1, farg2) & +bind(C, name="_wrap_FSUNMatScaleAddI") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatMatvecSetup(farg1) & +bind(C, name="_wrap_FSUNMatMatvecSetup") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatMatvec(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNMatMatvec") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNMatSpace") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNMatNewEmpty() & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), pointer :: swig_result +type(C_PTR) :: fresult + +fresult = swigc_FSUNMatNewEmpty() +call c_f_pointer(fresult, swig_result) +end function + +subroutine FSUNMatFreeEmpty(a) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +call swigc_FSUNMatFreeEmpty(farg1) +end subroutine + +function FSUNMatCopyOps(a, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(SUNMatrix), target, intent(inout) :: b +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(a) +farg2 = c_loc(b) +fresult = swigc_FSUNMatCopyOps(farg1, farg2) +swig_result = fresult +end function + +function FSUNMatGetID(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNMatrix_ID) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatGetID(farg1) +swig_result = fresult +end function + +function FSUNMatClone(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatClone(farg1) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FSUNMatDestroy(a) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +call swigc_FSUNMatDestroy(farg1) +end subroutine + +function FSUNMatZero(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatZero(farg1) +swig_result = fresult +end function + +function FSUNMatCopy(a, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(SUNMatrix), target, intent(inout) :: b +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(a) +farg2 = c_loc(b) +fresult = swigc_FSUNMatCopy(farg1, farg2) +swig_result = fresult +end function + +function FSUNMatScaleAdd(c, a, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +real(C_DOUBLE), intent(in) :: c +type(SUNMatrix), target, intent(inout) :: a +type(SUNMatrix), target, intent(inout) :: b +integer(C_INT) :: fresult +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(a) +farg3 = c_loc(b) +fresult = swigc_FSUNMatScaleAdd(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNMatScaleAddI(c, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +real(C_DOUBLE), intent(in) :: c +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c +farg2 = c_loc(a) +fresult = swigc_FSUNMatScaleAddI(farg1, farg2) +swig_result = fresult +end function + +function FSUNMatMatvecSetup(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatMatvecSetup(farg1) +swig_result = fresult +end function + +function FSUNMatMatvec(a, x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(a) +farg2 = c_loc(x) +farg3 = c_loc(y) +fresult = swigc_FSUNMatMatvec(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNMatSpace(a, lenrw, leniw) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_LONG), dimension(*), target, intent(inout) :: lenrw +integer(C_LONG), dimension(*), target, intent(inout) :: leniw +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(a) +farg2 = c_loc(lenrw(1)) +farg3 = c_loc(leniw(1)) +fresult = swigc_FSUNMatSpace(farg1, farg2, farg3) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_nonlinearsolver_mod.c b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_nonlinearsolver_mod.c new file mode 100644 index 000000000..de8c83860 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_nonlinearsolver_mod.c @@ -0,0 +1,401 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_nonlinearsolver.h" + +SWIGEXPORT SUNNonlinearSolver _wrap_FSUNNonlinSolNewEmpty() { + SUNNonlinearSolver fresult ; + SUNNonlinearSolver result; + + result = (SUNNonlinearSolver)SUNNonlinSolNewEmpty(); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FSUNNonlinSolFreeEmpty(SUNNonlinearSolver farg1) { + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + + arg1 = (SUNNonlinearSolver)(farg1); + SUNNonlinSolFreeEmpty(arg1); +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetType(SUNNonlinearSolver farg1) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinearSolver_Type result; + + arg1 = (SUNNonlinearSolver)(farg1); + result = (SUNNonlinearSolver_Type)SUNNonlinSolGetType(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolInitialize(SUNNonlinearSolver farg1) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + result = (int)SUNNonlinSolInitialize(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetup(SUNNonlinearSolver farg1, N_Vector farg2, void *farg3) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (void *)(farg3); + result = (int)SUNNonlinSolSetup(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSolve(SUNNonlinearSolver farg1, N_Vector farg2, N_Vector farg3, N_Vector farg4, double const *farg5, int const *farg6, void *farg7) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype arg5 ; + int arg6 ; + void *arg7 = (void *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype)(*farg5); + arg6 = (int)(*farg6); + arg7 = (void *)(farg7); + result = (int)SUNNonlinSolSolve(arg1,arg2,arg3,arg4,arg5,arg6,arg7); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolFree(SUNNonlinearSolver farg1) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + result = (int)SUNNonlinSolFree(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetSysFn(SUNNonlinearSolver farg1, SUNNonlinSolSysFn farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinSolSysFn arg2 = (SUNNonlinSolSysFn) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (SUNNonlinSolSysFn)(farg2); + result = (int)SUNNonlinSolSetSysFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetLSetupFn(SUNNonlinearSolver farg1, SUNNonlinSolLSetupFn farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinSolLSetupFn arg2 = (SUNNonlinSolLSetupFn) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (SUNNonlinSolLSetupFn)(farg2); + result = (int)SUNNonlinSolSetLSetupFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetLSolveFn(SUNNonlinearSolver farg1, SUNNonlinSolLSolveFn farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinSolLSolveFn arg2 = (SUNNonlinSolLSolveFn) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (SUNNonlinSolLSolveFn)(farg2); + result = (int)SUNNonlinSolSetLSolveFn(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetConvTestFn(SUNNonlinearSolver farg1, SUNNonlinSolConvTestFn farg2, void *farg3) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinSolConvTestFn arg2 = (SUNNonlinSolConvTestFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (SUNNonlinSolConvTestFn)(farg2); + arg3 = (void *)(farg3); + result = (int)SUNNonlinSolSetConvTestFn(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetMaxIters(SUNNonlinearSolver farg1, int const *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNNonlinSolSetMaxIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetNumIters(SUNNonlinearSolver farg1, long *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (long *)(farg2); + result = (int)SUNNonlinSolGetNumIters(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetCurIter(SUNNonlinearSolver farg1, int *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (int *)(farg2); + result = (int)SUNNonlinSolGetCurIter(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetNumConvFails(SUNNonlinearSolver farg1, long *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (long *)(farg2); + result = (int)SUNNonlinSolGetNumConvFails(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_nonlinearsolver_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_nonlinearsolver_mod.f90 new file mode 100644 index 000000000..91096943f --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_nonlinearsolver_mod.f90 @@ -0,0 +1,448 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. +module fsundials_nonlinearsolver_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + ! typedef enum SUNNonlinearSolver_Type + enum, bind(c) + enumerator :: SUNNONLINEARSOLVER_ROOTFIND + enumerator :: SUNNONLINEARSOLVER_FIXEDPOINT + end enum + integer, parameter, public :: SUNNonlinearSolver_Type = kind(SUNNONLINEARSOLVER_ROOTFIND) + public :: SUNNONLINEARSOLVER_ROOTFIND, SUNNONLINEARSOLVER_FIXEDPOINT + ! struct struct _generic_SUNNonlinearSolver_Ops + type, bind(C), public :: SUNNonlinearSolver_Ops + type(C_FUNPTR), public :: gettype + type(C_FUNPTR), public :: initialize + type(C_FUNPTR), public :: setup + type(C_FUNPTR), public :: solve + type(C_FUNPTR), public :: free + type(C_FUNPTR), public :: setsysfn + type(C_FUNPTR), public :: setlsetupfn + type(C_FUNPTR), public :: setlsolvefn + type(C_FUNPTR), public :: setctestfn + type(C_FUNPTR), public :: setmaxiters + type(C_FUNPTR), public :: getnumiters + type(C_FUNPTR), public :: getcuriter + type(C_FUNPTR), public :: getnumconvfails + end type SUNNonlinearSolver_Ops + ! struct struct _generic_SUNNonlinearSolver + type, bind(C), public :: SUNNonlinearSolver + type(C_PTR), public :: content + type(C_PTR), public :: ops + end type SUNNonlinearSolver + public :: FSUNNonlinSolNewEmpty + public :: FSUNNonlinSolFreeEmpty + public :: FSUNNonlinSolGetType + public :: FSUNNonlinSolInitialize + public :: FSUNNonlinSolSetup + public :: FSUNNonlinSolSolve + public :: FSUNNonlinSolFree + public :: FSUNNonlinSolSetSysFn + public :: FSUNNonlinSolSetLSetupFn + public :: FSUNNonlinSolSetLSolveFn + public :: FSUNNonlinSolSetConvTestFn + public :: FSUNNonlinSolSetMaxIters + public :: FSUNNonlinSolGetNumIters + public :: FSUNNonlinSolGetCurIter + public :: FSUNNonlinSolGetNumConvFails + integer(C_INT), parameter, public :: SUN_NLS_SUCCESS = 0_C_INT + integer(C_INT), parameter, public :: SUN_NLS_CONTINUE = +901_C_INT + integer(C_INT), parameter, public :: SUN_NLS_CONV_RECVR = +902_C_INT + integer(C_INT), parameter, public :: SUN_NLS_MEM_NULL = -901_C_INT + integer(C_INT), parameter, public :: SUN_NLS_MEM_FAIL = -902_C_INT + integer(C_INT), parameter, public :: SUN_NLS_ILL_INPUT = -903_C_INT + integer(C_INT), parameter, public :: SUN_NLS_VECTOROP_ERR = -904_C_INT + integer(C_INT), parameter, public :: SUN_NLS_EXT_FAIL = -905_C_INT + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNNonlinSolNewEmpty() & +bind(C, name="_wrap_FSUNNonlinSolNewEmpty") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: fresult +end function + +subroutine swigc_FSUNNonlinSolFreeEmpty(farg1) & +bind(C, name="_wrap_FSUNNonlinSolFreeEmpty") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FSUNNonlinSolGetType(farg1) & +bind(C, name="_wrap_FSUNNonlinSolGetType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolInitialize(farg1) & +bind(C, name="_wrap_FSUNNonlinSolInitialize") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetup(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNNonlinSolSetup") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSolve(farg1, farg2, farg3, farg4, farg5, farg6, farg7) & +bind(C, name="_wrap_FSUNNonlinSolSolve") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT), intent(in) :: farg6 +type(C_PTR), value :: farg7 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolFree(farg1) & +bind(C, name="_wrap_FSUNNonlinSolFree") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetSysFn(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolSetSysFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetLSetupFn(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolSetLSetupFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetLSolveFn(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolSetLSolveFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetConvTestFn(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNNonlinSolSetConvTestFn") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetMaxIters(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolSetMaxIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolGetNumIters(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolGetNumIters") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolGetCurIter(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolGetCurIter") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolGetNumConvFails(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolGetNumConvFails") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNNonlinSolNewEmpty() & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNNonlinearSolver), pointer :: swig_result +type(C_PTR) :: fresult + +fresult = swigc_FSUNNonlinSolNewEmpty() +call c_f_pointer(fresult, swig_result) +end function + +subroutine FSUNNonlinSolFreeEmpty(nls) +use, intrinsic :: ISO_C_BINDING +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_PTR) :: farg1 + +farg1 = c_loc(nls) +call swigc_FSUNNonlinSolFreeEmpty(farg1) +end subroutine + +function FSUNNonlinSolGetType(nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNNonlinearSolver_Type) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(nls) +fresult = swigc_FSUNNonlinSolGetType(farg1) +swig_result = fresult +end function + +function FSUNNonlinSolInitialize(nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(nls) +fresult = swigc_FSUNNonlinSolInitialize(farg1) +swig_result = fresult +end function + +function FSUNNonlinSolSetup(nls, y, mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(N_Vector), target, intent(inout) :: y +type(C_PTR) :: mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(nls) +farg2 = c_loc(y) +farg3 = mem +fresult = swigc_FSUNNonlinSolSetup(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNNonlinSolSolve(nls, y0, y, w, tol, calllsetup, mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(N_Vector), target, intent(inout) :: y0 +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE), intent(in) :: tol +integer(C_INT), intent(in) :: calllsetup +type(C_PTR) :: mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +real(C_DOUBLE) :: farg5 +integer(C_INT) :: farg6 +type(C_PTR) :: farg7 + +farg1 = c_loc(nls) +farg2 = c_loc(y0) +farg3 = c_loc(y) +farg4 = c_loc(w) +farg5 = tol +farg6 = calllsetup +farg7 = mem +fresult = swigc_FSUNNonlinSolSolve(farg1, farg2, farg3, farg4, farg5, farg6, farg7) +swig_result = fresult +end function + +function FSUNNonlinSolFree(nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(nls) +fresult = swigc_FSUNNonlinSolFree(farg1) +swig_result = fresult +end function + +function FSUNNonlinSolSetSysFn(nls, sysfn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_FUNPTR), intent(in), value :: sysfn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = sysfn +fresult = swigc_FSUNNonlinSolSetSysFn(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolSetLSetupFn(nls, setupfn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_FUNPTR), intent(in), value :: setupfn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = setupfn +fresult = swigc_FSUNNonlinSolSetLSetupFn(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolSetLSolveFn(nls, solvefn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_FUNPTR), intent(in), value :: solvefn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = solvefn +fresult = swigc_FSUNNonlinSolSetLSolveFn(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolSetConvTestFn(nls, ctestfn, ctest_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_FUNPTR), intent(in), value :: ctestfn +type(C_PTR) :: ctest_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(nls) +farg2 = ctestfn +farg3 = ctest_data +fresult = swigc_FSUNNonlinSolSetConvTestFn(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNNonlinSolSetMaxIters(nls, maxiters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT), intent(in) :: maxiters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(nls) +farg2 = maxiters +fresult = swigc_FSUNNonlinSolSetMaxIters(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolGetNumIters(nls, niters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_LONG), dimension(*), target, intent(inout) :: niters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = c_loc(niters(1)) +fresult = swigc_FSUNNonlinSolGetNumIters(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolGetCurIter(nls, iter) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT), dimension(*), target, intent(inout) :: iter +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = c_loc(iter(1)) +fresult = swigc_FSUNNonlinSolGetCurIter(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolGetNumConvFails(nls, nconvfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_LONG), dimension(*), target, intent(inout) :: nconvfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = c_loc(nconvfails(1)) +fresult = swigc_FSUNNonlinSolGetNumConvFails(farg1, farg2) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_nvector_mod.c b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_nvector_mod.c new file mode 100644 index 000000000..45c0bdac7 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_nvector_mod.c @@ -0,0 +1,921 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_nvector.h" + +SWIGEXPORT N_Vector _wrap_FN_VNewEmpty() { + N_Vector fresult ; + N_Vector result; + + result = (N_Vector)N_VNewEmpty(); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VFreeEmpty(N_Vector farg1) { + N_Vector arg1 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + N_VFreeEmpty(arg1); +} + + +SWIGEXPORT int _wrap_FN_VCopyOps(N_Vector farg1, N_Vector farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)N_VCopyOps(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VGetVectorID(N_Vector farg1) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector_ID result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector_ID)N_VGetVectorID(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VClone(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VClone(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FN_VCloneEmpty(N_Vector farg1) { + N_Vector fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector result; + + arg1 = (N_Vector)(farg1); + result = (N_Vector)N_VCloneEmpty(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VDestroy(N_Vector farg1) { + N_Vector arg1 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + N_VDestroy(arg1); +} + + +SWIGEXPORT void _wrap_FN_VSpace(N_Vector farg1, int64_t *farg2, int64_t *farg3) { + N_Vector arg1 = (N_Vector) 0 ; + sunindextype *arg2 = (sunindextype *) 0 ; + sunindextype *arg3 = (sunindextype *) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (sunindextype *)(farg2); + arg3 = (sunindextype *)(farg3); + N_VSpace(arg1,arg2,arg3); +} + + +SWIGEXPORT double * _wrap_FN_VGetArrayPointer(N_Vector farg1) { + double * fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype *result = 0 ; + + arg1 = (N_Vector)(farg1); + result = (realtype *)N_VGetArrayPointer(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VSetArrayPointer(double *farg1, N_Vector farg2) { + realtype *arg1 = (realtype *) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype *)(farg1); + arg2 = (N_Vector)(farg2); + N_VSetArrayPointer(arg1,arg2); +} + + +SWIGEXPORT void * _wrap_FN_VGetCommunicator(N_Vector farg1) { + void * fresult ; + N_Vector arg1 = (N_Vector) 0 ; + void *result = 0 ; + + arg1 = (N_Vector)(farg1); + result = (void *)N_VGetCommunicator(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FN_VGetLength(N_Vector farg1) { + int64_t fresult ; + N_Vector arg1 = (N_Vector) 0 ; + sunindextype result; + + arg1 = (N_Vector)(farg1); + result = N_VGetLength(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VLinearSum(double const *farg1, N_Vector farg2, double const *farg3, N_Vector farg4, N_Vector farg5) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype arg3 ; + N_Vector arg4 = (N_Vector) 0 ; + N_Vector arg5 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (realtype)(*farg3); + arg4 = (N_Vector)(farg4); + arg5 = (N_Vector)(farg5); + N_VLinearSum(arg1,arg2,arg3,arg4,arg5); +} + + +SWIGEXPORT void _wrap_FN_VConst(double const *farg1, N_Vector farg2) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + N_VConst(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VProd(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VProd(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VDiv(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VDiv(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VScale(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VScale(arg1,arg2,arg3); +} + + +SWIGEXPORT void _wrap_FN_VAbs(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VAbs(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VInv(N_Vector farg1, N_Vector farg2) { + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + N_VInv(arg1,arg2); +} + + +SWIGEXPORT void _wrap_FN_VAddConst(N_Vector farg1, double const *farg2, N_Vector farg3) { + N_Vector arg1 = (N_Vector) 0 ; + realtype arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector)(farg3); + N_VAddConst(arg1,arg2,arg3); +} + + +SWIGEXPORT double _wrap_FN_VDotProd(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VDotProd(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMaxNorm(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMaxNorm(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNorm(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWrmsNorm(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWrmsNormMask(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWrmsNormMask(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMin(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMin(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWL2Norm(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWL2Norm(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VL1Norm(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VL1Norm(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VCompare(double const *farg1, N_Vector farg2, N_Vector farg3) { + realtype arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (realtype)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + N_VCompare(arg1,arg2,arg3); +} + + +SWIGEXPORT int _wrap_FN_VInvTest(N_Vector farg1, N_Vector farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)N_VInvTest(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstrMask(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)N_VConstrMask(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinQuotient(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VMinQuotient(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearCombination(int const *farg1, double *farg2, void *farg3, N_Vector farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + result = (int)N_VLinearCombination(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleAddMulti(int const *farg1, double *farg2, N_Vector farg3, void *farg4, void *farg5) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + N_Vector *arg5 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector *)(farg4); + arg5 = (N_Vector *)(farg5); + result = (int)N_VScaleAddMulti(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VDotProdMulti(int const *farg1, N_Vector farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VDotProdMulti(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VLinearSumVectorArray(int const *farg1, double const *farg2, void *farg3, double const *farg4, void *farg5, void *farg6) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype arg4 ; + N_Vector *arg5 = (N_Vector *) 0 ; + N_Vector *arg6 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype)(*farg4); + arg5 = (N_Vector *)(farg5); + arg6 = (N_Vector *)(farg6); + result = (int)N_VLinearSumVectorArray(arg1,arg2,arg3,arg4,arg5,arg6); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VScaleVectorArray(int const *farg1, double *farg2, void *farg3, void *farg4) { + int fresult ; + int arg1 ; + realtype *arg2 = (realtype *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector *arg4 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector *)(farg4); + result = (int)N_VScaleVectorArray(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstVectorArray(int const *farg1, double const *farg2, void *farg3) { + int fresult ; + int arg1 ; + realtype arg2 ; + N_Vector *arg3 = (N_Vector *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (realtype)(*farg2); + arg3 = (N_Vector *)(farg3); + result = (int)N_VConstVectorArray(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormVectorArray(int const *farg1, void *farg2, void *farg3, double *farg4) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + realtype *arg4 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (realtype *)(farg4); + result = (int)N_VWrmsNormVectorArray(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VWrmsNormMaskVectorArray(int const *farg1, void *farg2, void *farg3, N_Vector farg4, double *farg5) { + int fresult ; + int arg1 ; + N_Vector *arg2 = (N_Vector *) 0 ; + N_Vector *arg3 = (N_Vector *) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype *arg5 = (realtype *) 0 ; + int result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector *)(farg2); + arg3 = (N_Vector *)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype *)(farg5); + result = (int)N_VWrmsNormMaskVectorArray(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VDotProdLocal(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VDotProdLocal(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMaxNormLocal(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMaxNormLocal(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinLocal(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VMinLocal(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VL1NormLocal(N_Vector farg1) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + result = (realtype)N_VL1NormLocal(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumLocal(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VWSqrSumLocal(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VWSqrSumMaskLocal(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (realtype)N_VWSqrSumMaskLocal(arg1,arg2,arg3); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VInvTestLocal(N_Vector farg1, N_Vector farg2) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (int)N_VInvTestLocal(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FN_VConstrMaskLocal(N_Vector farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)N_VConstrMaskLocal(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FN_VMinQuotientLocal(N_Vector farg1, N_Vector farg2) { + double fresult ; + N_Vector arg1 = (N_Vector) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + realtype result; + + arg1 = (N_Vector)(farg1); + arg2 = (N_Vector)(farg2); + result = (realtype)N_VMinQuotientLocal(arg1,arg2); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT void * _wrap_FN_VNewVectorArray(int const *farg1) { + void * fresult ; + int arg1 ; + N_Vector *result = 0 ; + + arg1 = (int)(*farg1); + result = (N_Vector *)N_VNewVectorArray(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FN_VCloneEmptyVectorArray(int const *farg1, N_Vector farg2) { + void * fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *result = 0 ; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + result = (N_Vector *)N_VCloneEmptyVectorArray(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FN_VCloneVectorArray(int const *farg1, N_Vector farg2) { + void * fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector *result = 0 ; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + result = (N_Vector *)N_VCloneVectorArray(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VDestroyVectorArray(void *farg1, int const *farg2) { + N_Vector *arg1 = (N_Vector *) 0 ; + int arg2 ; + + arg1 = (N_Vector *)(farg1); + arg2 = (int)(*farg2); + N_VDestroyVectorArray(arg1,arg2); +} + + +SWIGEXPORT N_Vector _wrap_FN_VGetVecAtIndexVectorArray(void *farg1, int const *farg2) { + N_Vector fresult ; + N_Vector *arg1 = (N_Vector *) 0 ; + int arg2 ; + N_Vector result; + + arg1 = (N_Vector *)(farg1); + arg2 = (int)(*farg2); + result = (N_Vector)N_VGetVecAtIndexVectorArray(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FN_VSetVecAtIndexVectorArray(void *farg1, int const *farg2, N_Vector farg3) { + N_Vector *arg1 = (N_Vector *) 0 ; + int arg2 ; + N_Vector arg3 = (N_Vector) 0 ; + + arg1 = (N_Vector *)(farg1); + arg2 = (int)(*farg2); + arg3 = (N_Vector)(farg3); + N_VSetVecAtIndexVectorArray(arg1,arg2,arg3); +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_nvector_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_nvector_mod.f90 new file mode 100644 index 000000000..988163fe2 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_nvector_mod.f90 @@ -0,0 +1,1476 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. +module fsundials_nvector_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + ! typedef enum N_Vector_ID + enum, bind(c) + enumerator :: SUNDIALS_NVEC_SERIAL + enumerator :: SUNDIALS_NVEC_PARALLEL + enumerator :: SUNDIALS_NVEC_OPENMP + enumerator :: SUNDIALS_NVEC_PTHREADS + enumerator :: SUNDIALS_NVEC_PARHYP + enumerator :: SUNDIALS_NVEC_PETSC + enumerator :: SUNDIALS_NVEC_CUDA + enumerator :: SUNDIALS_NVEC_RAJA + enumerator :: SUNDIALS_NVEC_OPENMPDEV + enumerator :: SUNDIALS_NVEC_TRILINOS + enumerator :: SUNDIALS_NVEC_MANYVECTOR + enumerator :: SUNDIALS_NVEC_MPIMANYVECTOR + enumerator :: SUNDIALS_NVEC_MPIPLUSX + enumerator :: SUNDIALS_NVEC_CUSTOM + end enum + integer, parameter, public :: N_Vector_ID = kind(SUNDIALS_NVEC_SERIAL) + public :: SUNDIALS_NVEC_SERIAL, SUNDIALS_NVEC_PARALLEL, SUNDIALS_NVEC_OPENMP, SUNDIALS_NVEC_PTHREADS, SUNDIALS_NVEC_PARHYP, & + SUNDIALS_NVEC_PETSC, SUNDIALS_NVEC_CUDA, SUNDIALS_NVEC_RAJA, SUNDIALS_NVEC_OPENMPDEV, SUNDIALS_NVEC_TRILINOS, & + SUNDIALS_NVEC_MANYVECTOR, SUNDIALS_NVEC_MPIMANYVECTOR, SUNDIALS_NVEC_MPIPLUSX, SUNDIALS_NVEC_CUSTOM + ! struct struct _generic_N_Vector_Ops + type, bind(C), public :: N_Vector_Ops + type(C_FUNPTR), public :: nvgetvectorid + type(C_FUNPTR), public :: nvclone + type(C_FUNPTR), public :: nvcloneempty + type(C_FUNPTR), public :: nvdestroy + type(C_FUNPTR), public :: nvspace + type(C_FUNPTR), public :: nvgetarraypointer + type(C_FUNPTR), public :: nvsetarraypointer + type(C_FUNPTR), public :: nvgetcommunicator + type(C_FUNPTR), public :: nvgetlength + type(C_FUNPTR), public :: nvlinearsum + type(C_FUNPTR), public :: nvconst + type(C_FUNPTR), public :: nvprod + type(C_FUNPTR), public :: nvdiv + type(C_FUNPTR), public :: nvscale + type(C_FUNPTR), public :: nvabs + type(C_FUNPTR), public :: nvinv + type(C_FUNPTR), public :: nvaddconst + type(C_FUNPTR), public :: nvdotprod + type(C_FUNPTR), public :: nvmaxnorm + type(C_FUNPTR), public :: nvwrmsnorm + type(C_FUNPTR), public :: nvwrmsnormmask + type(C_FUNPTR), public :: nvmin + type(C_FUNPTR), public :: nvwl2norm + type(C_FUNPTR), public :: nvl1norm + type(C_FUNPTR), public :: nvcompare + type(C_FUNPTR), public :: nvinvtest + type(C_FUNPTR), public :: nvconstrmask + type(C_FUNPTR), public :: nvminquotient + type(C_FUNPTR), public :: nvlinearcombination + type(C_FUNPTR), public :: nvscaleaddmulti + type(C_FUNPTR), public :: nvdotprodmulti + type(C_FUNPTR), public :: nvlinearsumvectorarray + type(C_FUNPTR), public :: nvscalevectorarray + type(C_FUNPTR), public :: nvconstvectorarray + type(C_FUNPTR), public :: nvwrmsnormvectorarray + type(C_FUNPTR), public :: nvwrmsnormmaskvectorarray + type(C_FUNPTR), public :: nvscaleaddmultivectorarray + type(C_FUNPTR), public :: nvlinearcombinationvectorarray + type(C_FUNPTR), public :: nvdotprodlocal + type(C_FUNPTR), public :: nvmaxnormlocal + type(C_FUNPTR), public :: nvminlocal + type(C_FUNPTR), public :: nvl1normlocal + type(C_FUNPTR), public :: nvinvtestlocal + type(C_FUNPTR), public :: nvconstrmasklocal + type(C_FUNPTR), public :: nvminquotientlocal + type(C_FUNPTR), public :: nvwsqrsumlocal + type(C_FUNPTR), public :: nvwsqrsummasklocal + end type N_Vector_Ops + ! struct struct _generic_N_Vector + type, bind(C), public :: N_Vector + type(C_PTR), public :: content + type(C_PTR), public :: ops + end type N_Vector + public :: FN_VNewEmpty + public :: FN_VFreeEmpty + public :: FN_VCopyOps + public :: FN_VGetVectorID + public :: FN_VClone + public :: FN_VCloneEmpty + public :: FN_VDestroy + public :: FN_VSpace + public :: FN_VGetArrayPointer + public :: FN_VSetArrayPointer + public :: FN_VGetCommunicator + public :: FN_VGetLength + public :: FN_VLinearSum + public :: FN_VConst + public :: FN_VProd + public :: FN_VDiv + public :: FN_VScale + public :: FN_VAbs + public :: FN_VInv + public :: FN_VAddConst + public :: FN_VDotProd + public :: FN_VMaxNorm + public :: FN_VWrmsNorm + public :: FN_VWrmsNormMask + public :: FN_VMin + public :: FN_VWL2Norm + public :: FN_VL1Norm + public :: FN_VCompare + public :: FN_VInvTest + public :: FN_VConstrMask + public :: FN_VMinQuotient + public :: FN_VLinearCombination + public :: FN_VScaleAddMulti + public :: FN_VDotProdMulti + public :: FN_VLinearSumVectorArray + public :: FN_VScaleVectorArray + public :: FN_VConstVectorArray + public :: FN_VWrmsNormVectorArray + public :: FN_VWrmsNormMaskVectorArray + public :: FN_VDotProdLocal + public :: FN_VMaxNormLocal + public :: FN_VMinLocal + public :: FN_VL1NormLocal + public :: FN_VWSqrSumLocal + public :: FN_VWSqrSumMaskLocal + public :: FN_VInvTestLocal + public :: FN_VConstrMaskLocal + public :: FN_VMinQuotientLocal + public :: FN_VNewVectorArray + public :: FN_VCloneEmptyVectorArray + public :: FN_VCloneVectorArray + public :: FN_VDestroyVectorArray + public :: FN_VGetVecAtIndexVectorArray + public :: FN_VSetVecAtIndexVectorArray + +! WRAPPER DECLARATIONS +interface +function swigc_FN_VNewEmpty() & +bind(C, name="_wrap_FN_VNewEmpty") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VFreeEmpty(farg1) & +bind(C, name="_wrap_FN_VFreeEmpty") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FN_VCopyOps(farg1, farg2) & +bind(C, name="_wrap_FN_VCopyOps") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VGetVectorID(farg1) & +bind(C, name="_wrap_FN_VGetVectorID") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FN_VClone(farg1) & +bind(C, name="_wrap_FN_VClone") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VCloneEmpty(farg1) & +bind(C, name="_wrap_FN_VCloneEmpty") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VDestroy(farg1) & +bind(C, name="_wrap_FN_VDestroy") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +subroutine swigc_FN_VSpace(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VSpace") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VGetArrayPointer(farg1) & +bind(C, name="_wrap_FN_VGetArrayPointer") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VSetArrayPointer(farg1, farg2) & +bind(C, name="_wrap_FN_VSetArrayPointer") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_FN_VGetCommunicator(farg1) & +bind(C, name="_wrap_FN_VGetCommunicator") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VGetLength(farg1) & +bind(C, name="_wrap_FN_VGetLength") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +subroutine swigc_FN_VLinearSum(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VLinearSum") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE), intent(in) :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +end subroutine + +subroutine swigc_FN_VConst(farg1, farg2) & +bind(C, name="_wrap_FN_VConst") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VProd(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VProd") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VDiv(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VDiv") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VScale(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VScale") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +subroutine swigc_FN_VAbs(farg1, farg2) & +bind(C, name="_wrap_FN_VAbs") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VInv(farg1, farg2) & +bind(C, name="_wrap_FN_VInv") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +subroutine swigc_FN_VAddConst(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VAddConst") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VDotProd(farg1, farg2) & +bind(C, name="_wrap_FN_VDotProd") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMaxNorm(farg1) & +bind(C, name="_wrap_FN_VMaxNorm") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNorm(farg1, farg2) & +bind(C, name="_wrap_FN_VWrmsNorm") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWrmsNormMask(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWrmsNormMask") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMin(farg1) & +bind(C, name="_wrap_FN_VMin") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWL2Norm(farg1, farg2) & +bind(C, name="_wrap_FN_VWL2Norm") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VL1Norm(farg1) & +bind(C, name="_wrap_FN_VL1Norm") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +subroutine swigc_FN_VCompare(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VCompare") +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +function swigc_FN_VInvTest(farg1, farg2) & +bind(C, name="_wrap_FN_VInvTest") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstrMask(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstrMask") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VMinQuotient(farg1, farg2) & +bind(C, name="_wrap_FN_VMinQuotient") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VLinearCombination(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VLinearCombination") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleAddMulti(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VScaleAddMulti") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VDotProdMulti(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VDotProdMulti") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VLinearSumVectorArray(farg1, farg2, farg3, farg4, farg5, farg6) & +bind(C, name="_wrap_FN_VLinearSumVectorArray") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE), intent(in) :: farg4 +type(C_PTR), value :: farg5 +type(C_PTR), value :: farg6 +integer(C_INT) :: fresult +end function + +function swigc_FN_VScaleVectorArray(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VScaleVectorArray") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstVectorArray(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstVectorArray") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormVectorArray(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FN_VWrmsNormVectorArray") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FN_VWrmsNormMaskVectorArray(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FN_VWrmsNormMaskVectorArray") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +type(C_PTR), value :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FN_VDotProdLocal(farg1, farg2) & +bind(C, name="_wrap_FN_VDotProdLocal") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMaxNormLocal(farg1) & +bind(C, name="_wrap_FN_VMaxNormLocal") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VMinLocal(farg1) & +bind(C, name="_wrap_FN_VMinLocal") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VL1NormLocal(farg1) & +bind(C, name="_wrap_FN_VL1NormLocal") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWSqrSumLocal(farg1, farg2) & +bind(C, name="_wrap_FN_VWSqrSumLocal") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VWSqrSumMaskLocal(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VWSqrSumMaskLocal") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VInvTestLocal(farg1, farg2) & +bind(C, name="_wrap_FN_VInvTestLocal") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FN_VConstrMaskLocal(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VConstrMaskLocal") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FN_VMinQuotientLocal(farg1, farg2) & +bind(C, name="_wrap_FN_VMinQuotientLocal") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +real(C_DOUBLE) :: fresult +end function + +function swigc_FN_VNewVectorArray(farg1) & +bind(C, name="_wrap_FN_VNewVectorArray") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FN_VCloneEmptyVectorArray(farg1, farg2) & +bind(C, name="_wrap_FN_VCloneEmptyVectorArray") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FN_VCloneVectorArray(farg1, farg2) & +bind(C, name="_wrap_FN_VCloneVectorArray") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VDestroyVectorArray(farg1, farg2) & +bind(C, name="_wrap_FN_VDestroyVectorArray") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +end subroutine + +function swigc_FN_VGetVecAtIndexVectorArray(farg1, farg2) & +bind(C, name="_wrap_FN_VGetVecAtIndexVectorArray") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +subroutine swigc_FN_VSetVecAtIndexVectorArray(farg1, farg2, farg3) & +bind(C, name="_wrap_FN_VSetVecAtIndexVectorArray") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR), value :: farg3 +end subroutine + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FN_VNewEmpty() & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(C_PTR) :: fresult + +fresult = swigc_FN_VNewEmpty() +call c_f_pointer(fresult, swig_result) +end function + +subroutine FN_VFreeEmpty(v) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +call swigc_FN_VFreeEmpty(farg1) +end subroutine + +function FN_VCopyOps(w, v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: v +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(w) +farg2 = c_loc(v) +fresult = swigc_FN_VCopyOps(farg1, farg2) +swig_result = fresult +end function + +function FN_VGetVectorID(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(N_Vector_ID) :: swig_result +type(N_Vector), target, intent(inout) :: w +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VGetVectorID(farg1) +swig_result = fresult +end function + +function FN_VClone(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VClone(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FN_VCloneEmpty(w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(w) +fresult = swigc_FN_VCloneEmpty(farg1) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FN_VDestroy(v) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +call swigc_FN_VDestroy(farg1) +end subroutine + +subroutine FN_VSpace(v, lrw, liw) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T), dimension(*), target, intent(inout) :: lrw +integer(C_INT64_T), dimension(*), target, intent(inout) :: liw +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(v) +farg2 = c_loc(lrw(1)) +farg3 = c_loc(liw(1)) +call swigc_FN_VSpace(farg1, farg2, farg3) +end subroutine + +function FN_VGetArrayPointer(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetArrayPointer(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +subroutine FN_VSetArrayPointer(v_data, v) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(*), target, intent(inout) :: v_data +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(v_data(1)) +farg2 = c_loc(v) +call swigc_FN_VSetArrayPointer(farg1, farg2) +end subroutine + +function FN_VGetCommunicator(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +type(N_Vector), target, intent(inout) :: v +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetCommunicator(farg1) +swig_result = fresult +end function + +function FN_VGetLength(v) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(N_Vector), target, intent(inout) :: v +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(v) +fresult = swigc_FN_VGetLength(farg1) +swig_result = fresult +end function + +subroutine FN_VLinearSum(a, x, b, y, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: a +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +real(C_DOUBLE) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = a +farg2 = c_loc(x) +farg3 = b +farg4 = c_loc(y) +farg5 = c_loc(z) +call swigc_FN_VLinearSum(farg1, farg2, farg3, farg4, farg5) +end subroutine + +subroutine FN_VConst(c, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c +farg2 = c_loc(z) +call swigc_FN_VConst(farg1, farg2) +end subroutine + +subroutine FN_VProd(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VProd(farg1, farg2, farg3) +end subroutine + +subroutine FN_VDiv(x, y, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(y) +farg3 = c_loc(z) +call swigc_FN_VDiv(farg1, farg2, farg3) +end subroutine + +subroutine FN_VScale(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VScale(farg1, farg2, farg3) +end subroutine + +subroutine FN_VAbs(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VAbs(farg1, farg2) +end subroutine + +subroutine FN_VInv(x, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +call swigc_FN_VInv(farg1, farg2) +end subroutine + +subroutine FN_VAddConst(x, b, z) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE), intent(in) :: b +type(N_Vector), target, intent(inout) :: z +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = b +farg3 = c_loc(z) +call swigc_FN_VAddConst(farg1, farg2, farg3) +end subroutine + +function FN_VDotProd(x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(y) +fresult = swigc_FN_VDotProd(farg1, farg2) +swig_result = fresult +end function + +function FN_VMaxNorm(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMaxNorm(farg1) +swig_result = fresult +end function + +function FN_VWrmsNorm(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWrmsNorm(farg1, farg2) +swig_result = fresult +end function + +function FN_VWrmsNormMask(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWrmsNormMask(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMin(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMin(farg1) +swig_result = fresult +end function + +function FN_VWL2Norm(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWL2Norm(farg1, farg2) +swig_result = fresult +end function + +function FN_VL1Norm(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VL1Norm(farg1) +swig_result = fresult +end function + +subroutine FN_VCompare(c, x, z) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(x) +farg3 = c_loc(z) +call swigc_FN_VCompare(farg1, farg2, farg3) +end subroutine + +function FN_VInvTest(x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +fresult = swigc_FN_VInvTest(farg1, farg2) +swig_result = fresult +end function + +function FN_VConstrMask(c, x, m) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: m +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(c) +farg2 = c_loc(x) +farg3 = c_loc(m) +fresult = swigc_FN_VConstrMask(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMinQuotient(num, denom) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: num +type(N_Vector), target, intent(inout) :: denom +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(num) +farg2 = c_loc(denom) +fresult = swigc_FN_VMinQuotient(farg1, farg2) +swig_result = fresult +end function + +function FN_VLinearCombination(nvec, c, x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: x +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = x +farg4 = c_loc(z) +fresult = swigc_FN_VLinearCombination(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VScaleAddMulti(nvec, a, x, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvec +farg2 = c_loc(a(1)) +farg3 = c_loc(x) +farg4 = y +farg5 = z +fresult = swigc_FN_VScaleAddMulti(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VDotProdMulti(nvec, x, y, dotprods) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(N_Vector), target, intent(inout) :: x +type(C_PTR) :: y +real(C_DOUBLE), dimension(*), target, intent(inout) :: dotprods +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(x) +farg3 = y +farg4 = c_loc(dotprods(1)) +fresult = swigc_FN_VDotProdMulti(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VLinearSumVectorArray(nvec, a, x, b, y, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), intent(in) :: a +type(C_PTR) :: x +real(C_DOUBLE), intent(in) :: b +type(C_PTR) :: y +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 +real(C_DOUBLE) :: farg4 +type(C_PTR) :: farg5 +type(C_PTR) :: farg6 + +farg1 = nvec +farg2 = a +farg3 = x +farg4 = b +farg5 = y +farg6 = z +fresult = swigc_FN_VLinearSumVectorArray(farg1, farg2, farg3, farg4, farg5, farg6) +swig_result = fresult +end function + +function FN_VScaleVectorArray(nvec, c, x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), dimension(*), target, intent(inout) :: c +type(C_PTR) :: x +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = c_loc(c(1)) +farg3 = x +farg4 = z +fresult = swigc_FN_VScaleVectorArray(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VConstVectorArray(nvec, c, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +real(C_DOUBLE), intent(in) :: c +type(C_PTR) :: z +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +real(C_DOUBLE) :: farg2 +type(C_PTR) :: farg3 + +farg1 = nvec +farg2 = c +farg3 = z +fresult = swigc_FN_VConstVectorArray(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VWrmsNormVectorArray(nvec, x, w, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(C_PTR) :: x +type(C_PTR) :: w +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 + +farg1 = nvec +farg2 = x +farg3 = w +farg4 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormVectorArray(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FN_VWrmsNormMaskVectorArray(nvec, x, w, id, nrm) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +integer(C_INT), intent(in) :: nvec +type(C_PTR) :: x +type(C_PTR) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE), dimension(*), target, intent(inout) :: nrm +integer(C_INT) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +type(C_PTR) :: farg5 + +farg1 = nvec +farg2 = x +farg3 = w +farg4 = c_loc(id) +farg5 = c_loc(nrm(1)) +fresult = swigc_FN_VWrmsNormMaskVectorArray(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FN_VDotProdLocal(x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(y) +fresult = swigc_FN_VDotProdLocal(farg1, farg2) +swig_result = fresult +end function + +function FN_VMaxNormLocal(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMaxNormLocal(farg1) +swig_result = fresult +end function + +function FN_VMinLocal(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VMinLocal(farg1) +swig_result = fresult +end function + +function FN_VL1NormLocal(x) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(x) +fresult = swigc_FN_VL1NormLocal(farg1) +swig_result = fresult +end function + +function FN_VWSqrSumLocal(x, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(w) +fresult = swigc_FN_VWSqrSumLocal(farg1, farg2) +swig_result = fresult +end function + +function FN_VWSqrSumMaskLocal(x, w, id) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: w +type(N_Vector), target, intent(inout) :: id +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(x) +farg2 = c_loc(w) +farg3 = c_loc(id) +fresult = swigc_FN_VWSqrSumMaskLocal(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VInvTestLocal(x, z) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: z +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(x) +farg2 = c_loc(z) +fresult = swigc_FN_VInvTestLocal(farg1, farg2) +swig_result = fresult +end function + +function FN_VConstrMaskLocal(c, x, m) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(N_Vector), target, intent(inout) :: c +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: m +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(c) +farg2 = c_loc(x) +farg3 = c_loc(m) +fresult = swigc_FN_VConstrMaskLocal(farg1, farg2, farg3) +swig_result = fresult +end function + +function FN_VMinQuotientLocal(num, denom) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(N_Vector), target, intent(inout) :: num +type(N_Vector), target, intent(inout) :: denom +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(num) +farg2 = c_loc(denom) +fresult = swigc_FN_VMinQuotientLocal(farg1, farg2) +swig_result = fresult +end function + +function FN_VNewVectorArray(count) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: count +type(C_PTR) :: fresult +integer(C_INT) :: farg1 + +farg1 = count +fresult = swigc_FN_VNewVectorArray(farg1) +swig_result = fresult +end function + +function FN_VCloneEmptyVectorArray(count, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: count +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 + +farg1 = count +farg2 = c_loc(w) +fresult = swigc_FN_VCloneEmptyVectorArray(farg1, farg2) +swig_result = fresult +end function + +function FN_VCloneVectorArray(count, w) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: swig_result +integer(C_INT), intent(in) :: count +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 + +farg1 = count +farg2 = c_loc(w) +fresult = swigc_FN_VCloneVectorArray(farg1, farg2) +swig_result = fresult +end function + +subroutine FN_VDestroyVectorArray(vs, count) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: vs +integer(C_INT), intent(in) :: count +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = vs +farg2 = count +call swigc_FN_VDestroyVectorArray(farg1, farg2) +end subroutine + +function FN_VGetVecAtIndexVectorArray(vs, index) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(C_PTR) :: vs +integer(C_INT), intent(in) :: index +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = vs +farg2 = index +fresult = swigc_FN_VGetVecAtIndexVectorArray(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FN_VSetVecAtIndexVectorArray(vs, index, w) +use, intrinsic :: ISO_C_BINDING +type(C_PTR) :: vs +integer(C_INT), intent(in) :: index +type(N_Vector), target, intent(inout) :: w +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +type(C_PTR) :: farg3 + +farg1 = vs +farg2 = index +farg3 = c_loc(w) +call swigc_FN_VSetVecAtIndexVectorArray(farg1, farg2, farg3) +end subroutine + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_types_mod.c b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_types_mod.c new file mode 100644 index 000000000..57838fd9e --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_types_mod.c @@ -0,0 +1,219 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include + + +#include "sundials/sundials_types.h" + +#ifndef SUNDIALS_DOUBLE_PRECISION +#error "The Fortran bindings are only targeted at double-precision" +#endif + +#ifndef SUNDIALS_INT64_T +#error "The Fortran bindings are only targeted at 64-bit indices" +#endif + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_types_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_types_mod.f90 new file mode 100644 index 000000000..f0de1b736 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/fmod/fsundials_types_mod.f90 @@ -0,0 +1,30 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsundials_types_mod + use, intrinsic :: ISO_C_BINDING + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: SUNFALSE = 0_C_INT + integer(C_INT), parameter, public :: SUNTRUE = 1_C_INT + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_band.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_band.c index 1495a5747..124ace82b 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_band.c +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_band.c @@ -6,7 +6,7 @@ * Programmer(s): Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_cuda.h b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_cuda.h new file mode 100644 index 000000000..e629ae423 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_cuda.h @@ -0,0 +1,101 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Cody J. Balos @ LLNL + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------- + * This header files defines internal utility functions and macros + * for working with CUDA. + * ----------------------------------------------------------------- + */ + +#include + +#include +#include +#include + +#include + +#ifndef _SUNDIALS_CUDA_H +#define _SUNDIALS_CUDA_H + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* --------------------------------------------------------------------------- + * Constants + * ---------------------------------------------------------------------------*/ + +#define CUDA_WARP_SIZE 32 + + +/* --------------------------------------------------------------------------- + * Utility macros + * ---------------------------------------------------------------------------*/ + +#define SUNDIALS_CUDA_VERIFY(cuerr) SUNDIALS_CUDA_Assert(cuerr, __FILE__, __LINE__) +#define SUNDIALS_CUSPARSE_VERIFY(cuerr) SUNDIALS_CUSPARSE_Assert(cuerr, __FILE__, __LINE__) +#define SUNDIALS_CUSOLVER_VERIFY(cuerr) SUNDIALS_CUSOLVER_Assert(cuerr, __FILE__, __LINE__) + + +/* --------------------------------------------------------------------------- + * Utility functions + * ---------------------------------------------------------------------------*/ +inline booleantype SUNDIALS_CUDA_Assert(cudaError_t cuerr, const char *file, int line) +{ + if (cuerr != cudaSuccess) + { +#ifdef SUNDIALS_DEBUG + fprintf(stderr, + "ERROR in CUDA runtime operation: %s %s:%d\n", + cudaGetErrorString(cuerr), file, line); +#endif + return SUNFALSE; /* Assert failed */ + } + return SUNTRUE; /* Assert OK */ +} + +inline booleantype SUNDIALS_CUSPARSE_Assert(cusparseStatus_t status, const char *file, int line) +{ + if (status != CUSPARSE_STATUS_SUCCESS) + { +#ifdef SUNDIALS_DEBUG + fprintf(stderr, + "ERROR in cuSPARSE runtime operation: cusparseStatus_t = %d %s:%d\n", + status, file, line); +#endif + return SUNFALSE; /* Assert failed */ + } + return SUNTRUE; /* Assert OK */ +} + +inline booleantype SUNDIALS_CUSOLVER_Assert(cusolverStatus_t status, const char *file, int line) +{ + if (status != CUSOLVER_STATUS_SUCCESS) + { +#ifdef SUNDIALS_DEBUG + fprintf(stderr, + "ERROR in cuSOLVER runtime operation: cusolverStatus_t = %d %s:%d\n", + status, file, line); +#endif + return SUNFALSE; /* Assert failed */ + } + return SUNTRUE; /* Assert OK */ +} + + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +} +#endif + +#endif /* _SUNDIALS_CUDA_H */ \ No newline at end of file diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_debug.h b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_debug.h new file mode 100644 index 000000000..17178d8b6 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_debug.h @@ -0,0 +1,40 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Cody J. Balos @ LLNL + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------- + * This header files defines internal utility functions and macros + * for SUNDIALS debugging. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNDIALS_DEBUG_H +#define _SUNDIALS_DEBUG_H + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * Macro which prints to stderr when in debug mode + */ +#ifdef SUNDIALS_DEBUG +#define SUNDIALS_DEBUG_PRINT(str) fprintf(stderr, str) +#else +#define SUNDIALS_DEBUG_PRINT(str) +#endif + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +} +#endif + +#endif /* _SUNDIALS_DEBUG_H */ \ No newline at end of file diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_dense.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_dense.c index debaf7f5a..3ef5bfda2 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_dense.c +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_dense.c @@ -7,7 +7,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_direct.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_direct.c index 6d2dab64a..7b51603f4 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_direct.c +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_direct.c @@ -2,7 +2,7 @@ * Programmer: Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_futils.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_futils.c new file mode 100644 index 000000000..33cad23b2 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_futils.c @@ -0,0 +1,29 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Cody J. Balos + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------- + * SUNDIALS Fortran 2003 interface utility implementations. + * -----------------------------------------------------------------*/ + +#include + +/* Create a file pointer with the given file name and mode. */ +FILE* SUNDIALSFileOpen(const char* filename, const char* mode) +{ + return fopen(filename, mode); +} + +/* Close a file pointer with the given file name. */ +void SUNDIALSFileClose(FILE* fp) +{ + fclose(fp); +} diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_iterative.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_iterative.c index da71f3b16..b6f640e87 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_iterative.c +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_iterative.c @@ -7,7 +7,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_linearsolver.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_linearsolver.c index b2895bbff..b6cb21fd0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_linearsolver.c +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_linearsolver.c @@ -1,10 +1,10 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU - * David Gardner, Carol Woodward, Slaven Peles @ LLNL + * David J. Gardner, Carol S. Woodward, and + * Slaven Peles @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -13,26 +13,88 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for a generic SUNLINEARSOLVER + * This is the implementation file for a generic SUNLINEARSOLVER * package. It contains the implementation of the SUNLinearSolver * operations listed in sundials_linearsolver.h - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- + * Create a new empty SUNLinearSolver object + * ----------------------------------------------------------------- */ + +SUNLinearSolver SUNLinSolNewEmpty() +{ + SUNLinearSolver LS; + SUNLinearSolver_Ops ops; + + /* create linear solver object */ + LS = NULL; + LS = (SUNLinearSolver) malloc(sizeof *LS); + if (LS == NULL) return(NULL); + + /* create linear solver ops structure */ + ops = NULL; + ops = (SUNLinearSolver_Ops) malloc(sizeof *ops); + if (ops == NULL) { free(LS); return(NULL); } + + /* initialize operations to NULL */ + ops->gettype = NULL; + ops->getid = NULL; + ops->setatimes = NULL; + ops->setpreconditioner = NULL; + ops->setscalingvectors = NULL; + ops->initialize = NULL; + ops->setup = NULL; + ops->solve = NULL; + ops->numiters = NULL; + ops->resnorm = NULL; + ops->resid = NULL; + ops->lastflag = NULL; + ops->space = NULL; + ops->free = NULL; + + /* attach ops and initialize content to NULL */ + LS->ops = ops; + LS->content = NULL; + + return(LS); +} + +/* ----------------------------------------------------------------- + * Free a generic SUNLinearSolver (assumes content is already empty) + * ----------------------------------------------------------------- */ + +void SUNLinSolFreeEmpty(SUNLinearSolver S) +{ + if (S == NULL) return; + + /* free non-NULL ops structure */ + if (S->ops) free(S->ops); + S->ops = NULL; + + /* free overall N_Vector object and return */ + free(S); + return; +} + +/* ----------------------------------------------------------------- * Functions in the 'ops' structure - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ SUNLinearSolver_Type SUNLinSolGetType(SUNLinearSolver S) { - SUNLinearSolver_Type type; - type = S->ops->gettype(S); - return(type); + return(S->ops->gettype(S)); +} + +SUNLinearSolver_ID SUNLinSolGetID(SUNLinearSolver S) +{ + if (S->ops->getid) + return(S->ops->getid(S)); + else + return(SUNLINEARSOLVER_CUSTOM); } int SUNLinSolSetATimes(SUNLinearSolver S, void* A_data, @@ -44,7 +106,7 @@ int SUNLinSolSetATimes(SUNLinearSolver S, void* A_data, return SUNLS_SUCCESS; } - + int SUNLinSolSetPreconditioner(SUNLinearSolver S, void* P_data, PSetupFn Pset, PSolveFn Psol) { @@ -53,7 +115,7 @@ int SUNLinSolSetPreconditioner(SUNLinearSolver S, void* P_data, else return SUNLS_SUCCESS; } - + int SUNLinSolSetScalingVectors(SUNLinearSolver S, N_Vector s1, N_Vector s2) { @@ -62,15 +124,21 @@ int SUNLinSolSetScalingVectors(SUNLinearSolver S, else return SUNLS_SUCCESS; } - + int SUNLinSolInitialize(SUNLinearSolver S) { - return ((int) S->ops->initialize(S)); + if (S->ops->initialize) + return ((int) S->ops->initialize(S)); + else + return SUNLS_SUCCESS; } - + int SUNLinSolSetup(SUNLinearSolver S, SUNMatrix A) { - return ((int) S->ops->setup(S, A)); + if (S->ops->setup) + return ((int) S->ops->setup(S, A)); + else + return SUNLS_SUCCESS; } int SUNLinSolSolve(SUNLinearSolver S, SUNMatrix A, N_Vector x, @@ -78,7 +146,7 @@ int SUNLinSolSolve(SUNLinearSolver S, SUNMatrix A, N_Vector x, { return ((int) S->ops->solve(S, A, x, b, tol)); } - + int SUNLinSolNumIters(SUNLinearSolver S) { if (S->ops->numiters) @@ -103,10 +171,10 @@ N_Vector SUNLinSolResid(SUNLinearSolver S) return NULL; } -long int SUNLinSolLastFlag(SUNLinearSolver S) +sunindextype SUNLinSolLastFlag(SUNLinearSolver S) { if (S->ops->lastflag) - return ((long int) S->ops->lastflag(S)); + return ((sunindextype) S->ops->lastflag(S)); else return SUNLS_SUCCESS; } @@ -125,8 +193,17 @@ int SUNLinSolSpace(SUNLinearSolver S, long int *lenrwLS, int SUNLinSolFree(SUNLinearSolver S) { - if (S==NULL) return 0; - S->ops->free(S); - return 0; -} + if (S == NULL) return SUNLS_SUCCESS; + + /* if the free operation exists use it */ + if (S->ops) + if (S->ops->free) return(S->ops->free(S)); + /* if we reach this point, either ops == NULL or free == NULL, + try to cleanup by freeing the content, ops, and solver */ + if (S->content) { free(S->content); S->content = NULL; } + if (S->ops) { free(S->ops); S->ops = NULL; } + free(S); S = NULL; + + return(SUNLS_SUCCESS); +} diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_math.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_math.c index bca60cdac..246386ae0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_math.c +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_math.c @@ -3,7 +3,7 @@ * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_matrix.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_matrix.c index e4702c389..1cc6b9b85 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_matrix.c +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_matrix.c @@ -1,10 +1,10 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU - * David Gardner, Carol Woodward, Slaven Peles @ LLNL + * David J. Gardner, Carol S. Woodward, and + * Slaven Peles @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -16,18 +16,97 @@ * This is the implementation file for a generic SUNMATRIX package. * It contains the implementation of the SUNMatrix operations listed * in sundials_matrix.h - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include #include -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- + * Create a new empty SUNMatrix object + * ----------------------------------------------------------------- */ + +SUNMatrix SUNMatNewEmpty() +{ + SUNMatrix A; + SUNMatrix_Ops ops; + + /* create matrix object */ + A = NULL; + A = (SUNMatrix) malloc(sizeof *A); + if (A == NULL) return(NULL); + + /* create matrix ops structure */ + ops = NULL; + ops = (SUNMatrix_Ops) malloc(sizeof *ops); + if (ops == NULL) { free(A); return(NULL); } + + /* initialize operations to NULL */ + ops->getid = NULL; + ops->clone = NULL; + ops->destroy = NULL; + ops->zero = NULL; + ops->copy = NULL; + ops->scaleadd = NULL; + ops->scaleaddi = NULL; + ops->matvecsetup = NULL; + ops->matvec = NULL; + ops->space = NULL; + + /* attach ops and initialize content to NULL */ + A->ops = ops; + A->content = NULL; + + return(A); +} + + +/* ----------------------------------------------------------------- + * Free a generic SUNMatrix (assumes content is already empty) + * ----------------------------------------------------------------- */ + +void SUNMatFreeEmpty(SUNMatrix A) +{ + if (A == NULL) return; + + /* free non-NULL ops structure */ + if (A->ops) free(A->ops); + A->ops = NULL; + + /* free overall SUNMatrix object and return */ + free(A); + return; +} + + +/* ----------------------------------------------------------------- + * Copy a matrix 'ops' structure + * -----------------------------------------------------------------*/ + +int SUNMatCopyOps(SUNMatrix A, SUNMatrix B) +{ + /* Check that ops structures exist */ + if (A == NULL || B == NULL) return(-1); + if (A->ops == NULL || B->ops == NULL) return(-1); + + /* Copy ops from A to B */ + B->ops->getid = A->ops->getid; + B->ops->clone = A->ops->clone; + B->ops->destroy = A->ops->destroy; + B->ops->zero = A->ops->zero; + B->ops->copy = A->ops->copy; + B->ops->scaleadd = A->ops->scaleadd; + B->ops->scaleaddi = A->ops->scaleaddi; + B->ops->matvec = A->ops->matvec; + B->ops->space = A->ops->space; + + return(0); +} + + +/* ----------------------------------------------------------------- * Functions in the 'ops' structure - * ----------------------------------------------------------------- - */ + * ----------------------------------------------------------------- */ SUNMatrix_ID SUNMatGetID(SUNMatrix A) { @@ -45,8 +124,18 @@ SUNMatrix SUNMatClone(SUNMatrix A) void SUNMatDestroy(SUNMatrix A) { - if (A==NULL) return; - A->ops->destroy(A); + if (A == NULL) return; + + /* if the destroy operation exists use it */ + if (A->ops) + if (A->ops->destroy) { A->ops->destroy(A); return; } + + /* if we reach this point, either ops == NULL or destroy == NULL, + try to cleanup by freeing the content, ops, and matrix */ + if (A->content) { free(A->content); A->content = NULL; } + if (A->ops) { free(A->ops); A->ops = NULL; } + free(A); A = NULL; + return; } @@ -70,6 +159,11 @@ int SUNMatScaleAddI(realtype c, SUNMatrix A) return((int) A->ops->scaleaddi(c, A)); } +int SUNMatMatvecSetup(SUNMatrix A) +{ + return((int) A->ops->matvecsetup(A)); +} + int SUNMatMatvec(SUNMatrix A, N_Vector x, N_Vector y) { return((int) A->ops->matvec(A, x, y)); @@ -79,4 +173,3 @@ int SUNMatSpace(SUNMatrix A, long int *lenrw, long int *leniw) { return((int) A->ops->space(A, lenrw, leniw)); } - diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_mpi.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_mpi.c deleted file mode 100644 index 05823af67..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_mpi.c +++ /dev/null @@ -1,99 +0,0 @@ -/* ----------------------------------------------------------------- - * Programmer(s): Slaven Peles @ LLNL - * ----------------------------------------------------------------- - * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security - * and Southern Methodist University. - * All rights reserved. - * - * See the top-level LICENSE and NOTICE files for details. - * - * SPDX-License-Identifier: BSD-3-Clause - * SUNDIALS Copyright End - * ----------------------------------------------------------------- - * This is implementation of SUNDIALS MPI wrapper functions. - * -----------------------------------------------------------------*/ - -#include - -int SUNMPI_Comm_size(SUNMPI_Comm comm, int *size) -{ -#if SUNDIALS_MPI_ENABLED - return MPI_Comm_size(comm, size); -#else - *size = 1; - return 0; -#endif -} - -realtype SUNMPI_Allreduce_scalar(realtype d, int op, SUNMPI_Comm comm) -{ - /* - * This function does a global reduction. The operation is - * sum if op = 1, - * max if op = 2, - * min if op = 3. - * The operation is over all processors in the communicator - */ - -#if SUNDIALS_MPI_ENABLED - - realtype out; - - switch (op) { - case 1: MPI_Allreduce(&d, &out, 1, PVEC_REAL_MPI_TYPE, MPI_SUM, comm); - break; - - case 2: MPI_Allreduce(&d, &out, 1, PVEC_REAL_MPI_TYPE, MPI_MAX, comm); - break; - - case 3: MPI_Allreduce(&d, &out, 1, PVEC_REAL_MPI_TYPE, MPI_MIN, comm); - break; - - default: break; - } - - return(out); - -#else - - /* If MPI is not enabled don't do reduction */ - return d; - -#endif /* ifdef SUNDIALS_MPI_ENABLED */ -} - - -void SUNMPI_Allreduce(realtype *d, int nvec, int op, SUNMPI_Comm comm) -{ - /* - * This function does a global reduction. The operation is - * sum if op = 1, - * max if op = 2, - * min if op = 3. - * The operation is over all processors in the communicator - */ - -#if SUNDIALS_MPI_ENABLED - - switch (op) { - case 1: MPI_Allreduce(MPI_IN_PLACE, d, nvec, PVEC_REAL_MPI_TYPE, MPI_SUM, comm); - break; - - case 2: MPI_Allreduce(MPI_IN_PLACE, d, nvec, PVEC_REAL_MPI_TYPE, MPI_MAX, comm); - break; - - case 3: MPI_Allreduce(MPI_IN_PLACE, d, nvec, PVEC_REAL_MPI_TYPE, MPI_MIN, comm); - break; - - default: break; - } - -#else - - /* If MPI is not enabled don't do reduction */ - -#endif /* ifdef SUNDIALS_MPI_ENABLED */ -} - - diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_nonlinearsolver.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_nonlinearsolver.c index 1a6dc8e70..af73cd05c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_nonlinearsolver.c +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_nonlinearsolver.c @@ -1,8 +1,8 @@ /* ----------------------------------------------------------------------------- - * Programmer(s): David Gardner @ LLNL + * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -19,6 +19,64 @@ #include #include +/* ----------------------------------------------------------------------------- + * Create a new empty SUNLinearSolver object + * ---------------------------------------------------------------------------*/ + +SUNNonlinearSolver SUNNonlinSolNewEmpty() +{ + SUNNonlinearSolver NLS; + SUNNonlinearSolver_Ops ops; + + /* create nonlinear solver object */ + NLS = NULL; + NLS = (SUNNonlinearSolver) malloc(sizeof *NLS); + if (NLS == NULL) return(NULL); + + /* create nonlinear solver ops structure */ + ops = NULL; + ops = (SUNNonlinearSolver_Ops) malloc(sizeof *ops); + if (ops == NULL) { free(NLS); return(NULL); } + + /* initialize operations to NULL */ + ops->gettype = NULL; + ops->initialize = NULL; + ops->setup = NULL; + ops->solve = NULL; + ops->free = NULL; + ops->setsysfn = NULL; + ops->setlsetupfn = NULL; + ops->setlsolvefn = NULL; + ops->setctestfn = NULL; + ops->setmaxiters = NULL; + ops->getnumiters = NULL; + ops->getcuriter = NULL; + ops->getnumconvfails = NULL; + + /* attach ops and initialize content to NULL */ + NLS->ops = ops; + NLS->content = NULL; + + return(NLS); +} + +/* ----------------------------------------------------------------------------- + * Free a generic SUNNonlinearSolver (assumes content is already empty) + * ---------------------------------------------------------------------------*/ + +void SUNNonlinSolFreeEmpty(SUNNonlinearSolver NLS) +{ + if (NLS == NULL) return; + + /* free non-NULL ops structure */ + if (NLS->ops) free(NLS->ops); + NLS->ops = NULL; + + /* free overall N_Vector object and return */ + free(NLS); + return; +} + /* ----------------------------------------------------------------------------- * core functions * ---------------------------------------------------------------------------*/ @@ -55,25 +113,18 @@ int SUNNonlinSolSolve(SUNNonlinearSolver NLS, int SUNNonlinSolFree(SUNNonlinearSolver NLS) { if (NLS == NULL) return(SUN_NLS_SUCCESS); - if (NLS->ops == NULL) return(SUN_NLS_SUCCESS); - if (NLS->ops->free) { - return(NLS->ops->free(NLS)); - } else { - /* free the content structure */ - if (NLS->content) { - free(NLS->content); - NLS->content = NULL; - } - /* free the ops structure */ - if (NLS->ops) { - free(NLS->ops); - NLS->ops = NULL; - } - /* free the nonlinear solver */ - free(NLS); - return(SUN_NLS_SUCCESS); - } + /* if the free operation exists use it */ + if (NLS->ops) + if (NLS->ops->free) return(NLS->ops->free(NLS)); + + /* if we reach this point, either ops == NULL or free == NULL, + try to cleanup by freeing the content, ops, and solver */ + if (NLS->content) { free(NLS->content); NLS->content = NULL; } + if (NLS->ops) { free(NLS->ops); NLS->ops = NULL; } + free(NLS); NLS = NULL; + + return(SUN_NLS_SUCCESS); } /* ----------------------------------------------------------------------------- @@ -105,10 +156,12 @@ int SUNNonlinSolSetLSolveFn(SUNNonlinearSolver NLS, SUNNonlinSolLSolveFn LSolveF } /* set the convergence test function (optional) */ -int SUNNonlinSolSetConvTestFn(SUNNonlinearSolver NLS, SUNNonlinSolConvTestFn CTestFn) +int SUNNonlinSolSetConvTestFn(SUNNonlinearSolver NLS, + SUNNonlinSolConvTestFn CTestFn, + void* ctest_data) { if (NLS->ops->setctestfn) - return((int) NLS->ops->setctestfn(NLS, CTestFn)); + return((int) NLS->ops->setctestfn(NLS, CTestFn, ctest_data)); else return(SUN_NLS_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_nvector.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_nvector.c index 9227bae56..d905748a2 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_nvector.c +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_nvector.c @@ -1,8 +1,10 @@ -/* ----------------------------------------------------------------- - * Programmer(s): Radu Serban and Aaron Collier @ LLNL +/* ----------------------------------------------------------------- + * Programmer(s): Radu Serban, Aaron Collier, and + * David J. Gardner @ LLNL + * Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -17,40 +19,217 @@ * -----------------------------------------------------------------*/ #include - #include -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- + * Create an empty NVector object + * -----------------------------------------------------------------*/ + +N_Vector N_VNewEmpty() +{ + N_Vector v; + N_Vector_Ops ops; + + /* create vector object */ + v = NULL; + v = (N_Vector) malloc(sizeof *v); + if (v == NULL) return(NULL); + + /* create vector ops structure */ + ops = NULL; + ops = (N_Vector_Ops) malloc(sizeof *ops); + if (ops == NULL) { free(v); return(NULL); } + + /* initialize operations to NULL */ + + /* constructors, destructors, and utility operations */ + ops->nvgetvectorid = NULL; + ops->nvclone = NULL; + ops->nvcloneempty = NULL; + ops->nvdestroy = NULL; + ops->nvspace = NULL; + ops->nvgetarraypointer = NULL; + ops->nvsetarraypointer = NULL; + ops->nvgetcommunicator = NULL; + ops->nvgetlength = NULL; + + /* standard vector operations */ + ops->nvlinearsum = NULL; + ops->nvconst = NULL; + ops->nvprod = NULL; + ops->nvdiv = NULL; + ops->nvscale = NULL; + ops->nvabs = NULL; + ops->nvinv = NULL; + ops->nvaddconst = NULL; + ops->nvdotprod = NULL; + ops->nvmaxnorm = NULL; + ops->nvwrmsnormmask = NULL; + ops->nvwrmsnorm = NULL; + ops->nvmin = NULL; + ops->nvwl2norm = NULL; + ops->nvl1norm = NULL; + ops->nvcompare = NULL; + ops->nvinvtest = NULL; + ops->nvconstrmask = NULL; + ops->nvminquotient = NULL; + + /* fused vector operations (optional) */ + ops->nvlinearcombination = NULL; + ops->nvscaleaddmulti = NULL; + ops->nvdotprodmulti = NULL; + + /* vector array operations (optional) */ + ops->nvlinearsumvectorarray = NULL; + ops->nvscalevectorarray = NULL; + ops->nvconstvectorarray = NULL; + ops->nvwrmsnormvectorarray = NULL; + ops->nvwrmsnormmaskvectorarray = NULL; + ops->nvscaleaddmultivectorarray = NULL; + ops->nvlinearcombinationvectorarray = NULL; + + /* local reduction operations (optional) */ + ops->nvdotprodlocal = NULL; + ops->nvmaxnormlocal = NULL; + ops->nvminlocal = NULL; + ops->nvl1normlocal = NULL; + ops->nvinvtestlocal = NULL; + ops->nvconstrmasklocal = NULL; + ops->nvminquotientlocal = NULL; + ops->nvwsqrsumlocal = NULL; + ops->nvwsqrsummasklocal = NULL; + + /* attach ops and initialize content to NULL */ + v->ops = ops; + v->content = NULL; + + return(v); +} + + +/* ----------------------------------------------------------------- + * Free a generic N_Vector (assumes content is already empty) + * -----------------------------------------------------------------*/ + +void N_VFreeEmpty(N_Vector v) +{ + if (v == NULL) return; + + /* free non-NULL ops structure */ + if (v->ops) free(v->ops); + v->ops = NULL; + + /* free overall N_Vector object and return */ + free(v); + return; +} + + +/* ----------------------------------------------------------------- + * Copy a vector 'ops' structure + * -----------------------------------------------------------------*/ + +int N_VCopyOps(N_Vector w, N_Vector v) +{ + /* Check that ops structures exist */ + if (w == NULL || v == NULL) return(-1); + if (w->ops == NULL || v->ops == NULL) return(-1); + + /* Copy ops from w to v */ + + /* constructors, destructors, and utility operations */ + v->ops->nvgetvectorid = w->ops->nvgetvectorid; + v->ops->nvclone = w->ops->nvclone; + v->ops->nvcloneempty = w->ops->nvcloneempty; + v->ops->nvdestroy = w->ops->nvdestroy; + v->ops->nvspace = w->ops->nvspace; + v->ops->nvgetarraypointer = w->ops->nvgetarraypointer; + v->ops->nvsetarraypointer = w->ops->nvsetarraypointer; + v->ops->nvgetcommunicator = w->ops->nvgetcommunicator; + v->ops->nvgetlength = w->ops->nvgetlength; + + /* standard vector operations */ + v->ops->nvlinearsum = w->ops->nvlinearsum; + v->ops->nvconst = w->ops->nvconst; + v->ops->nvprod = w->ops->nvprod; + v->ops->nvdiv = w->ops->nvdiv; + v->ops->nvscale = w->ops->nvscale; + v->ops->nvabs = w->ops->nvabs; + v->ops->nvinv = w->ops->nvinv; + v->ops->nvaddconst = w->ops->nvaddconst; + v->ops->nvdotprod = w->ops->nvdotprod; + v->ops->nvmaxnorm = w->ops->nvmaxnorm; + v->ops->nvwrmsnormmask = w->ops->nvwrmsnormmask; + v->ops->nvwrmsnorm = w->ops->nvwrmsnorm; + v->ops->nvmin = w->ops->nvmin; + v->ops->nvwl2norm = w->ops->nvwl2norm; + v->ops->nvl1norm = w->ops->nvl1norm; + v->ops->nvcompare = w->ops->nvcompare; + v->ops->nvinvtest = w->ops->nvinvtest; + v->ops->nvconstrmask = w->ops->nvconstrmask; + v->ops->nvminquotient = w->ops->nvminquotient; + + /* fused vector operations */ + v->ops->nvlinearcombination = w->ops->nvlinearcombination; + v->ops->nvscaleaddmulti = w->ops->nvscaleaddmulti; + v->ops->nvdotprodmulti = w->ops->nvdotprodmulti; + + /* vector array operations */ + v->ops->nvlinearsumvectorarray = w->ops->nvlinearsumvectorarray; + v->ops->nvscalevectorarray = w->ops->nvscalevectorarray; + v->ops->nvconstvectorarray = w->ops->nvconstvectorarray; + v->ops->nvwrmsnormvectorarray = w->ops->nvwrmsnormvectorarray; + v->ops->nvwrmsnormmaskvectorarray = w->ops->nvwrmsnormmaskvectorarray; + v->ops->nvscaleaddmultivectorarray = w->ops->nvscaleaddmultivectorarray; + v->ops->nvlinearcombinationvectorarray = w->ops->nvlinearcombinationvectorarray; + + /* local reduction operations */ + v->ops->nvdotprodlocal = w->ops->nvdotprodlocal; + v->ops->nvmaxnormlocal = w->ops->nvmaxnormlocal; + v->ops->nvminlocal = w->ops->nvminlocal; + v->ops->nvl1normlocal = w->ops->nvl1normlocal; + v->ops->nvinvtestlocal = w->ops->nvinvtestlocal; + v->ops->nvconstrmasklocal = w->ops->nvconstrmasklocal; + v->ops->nvminquotientlocal = w->ops->nvminquotientlocal; + v->ops->nvwsqrsumlocal = w->ops->nvwsqrsumlocal; + v->ops->nvwsqrsummasklocal = w->ops->nvwsqrsummasklocal; + + return(0); +} + +/* ----------------------------------------------------------------- * Functions in the 'ops' structure - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ N_Vector_ID N_VGetVectorID(N_Vector w) { - N_Vector_ID id; - id = w->ops->nvgetvectorid(w); - return(id); + return(w->ops->nvgetvectorid(w)); } N_Vector N_VClone(N_Vector w) { - N_Vector v = NULL; - v = w->ops->nvclone(w); - return(v); + return(w->ops->nvclone(w)); } N_Vector N_VCloneEmpty(N_Vector w) { - N_Vector v = NULL; - v = w->ops->nvcloneempty(w); - return(v); + return(w->ops->nvcloneempty(w)); } void N_VDestroy(N_Vector v) { - if (v==NULL) return; - v->ops->nvdestroy(v); + if (v == NULL) return; + + /* if the destroy operation exists use it */ + if (v->ops) + if (v->ops->nvdestroy) { v->ops->nvdestroy(v); return; } + + /* if we reach this point, either ops == NULL or nvdestroy == NULL, + try to cleanup by freeing the content, ops, and vector */ + if (v->content) { free(v->content); v->content = NULL; } + if (v->ops) { free(v->ops); v->ops = NULL; } + free(v); v = NULL; + return; } @@ -71,9 +250,22 @@ void N_VSetArrayPointer(realtype *v_data, N_Vector v) return; } +void *N_VGetCommunicator(N_Vector v) +{ + if (v->ops->nvgetcommunicator) + return(v->ops->nvgetcommunicator(v)); + else + return(NULL); +} + +sunindextype N_VGetLength(N_Vector v) +{ + return((sunindextype) v->ops->nvgetlength(v)); +} + /* ----------------------------------------------------------------- * standard vector operations - * ----------------------------------------------------------------- */ + * -----------------------------------------------------------------*/ void N_VLinearSum(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) { @@ -99,7 +291,7 @@ void N_VDiv(N_Vector x, N_Vector y, N_Vector z) return; } -void N_VScale(realtype c, N_Vector x, N_Vector z) +void N_VScale(realtype c, N_Vector x, N_Vector z) { z->ops->nvscale(c, x, z); return; @@ -180,8 +372,8 @@ realtype N_VMinQuotient(N_Vector num, N_Vector denom) } /* ----------------------------------------------------------------- - * fused vector operations - * ----------------------------------------------------------------- */ + * OPTIONAL fused vector operations + * -----------------------------------------------------------------*/ int N_VLinearCombination(int nvec, realtype* c, N_Vector* X, N_Vector z) { @@ -209,7 +401,7 @@ int N_VScaleAddMulti(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Vector* Z realtype ONE=RCONST(1.0); if (x->ops->nvscaleaddmulti != NULL) { - + return(x->ops->nvscaleaddmulti(nvec, a, x, Y, Z)); } else { @@ -227,7 +419,7 @@ int N_VDotProdMulti(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods) int i; if (x->ops->nvdotprodmulti != NULL) { - + return(x->ops->nvdotprodmulti(nvec, x, Y, dotprods)); } else { @@ -241,8 +433,8 @@ int N_VDotProdMulti(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods) } /* ----------------------------------------------------------------- - * vector array operations - * ----------------------------------------------------------------- */ + * OPTIONAL vector array operations + * -----------------------------------------------------------------*/ int N_VLinearSumVectorArray(int nvec, realtype a, N_Vector* X, realtype b, N_Vector* Y, N_Vector* Z) @@ -250,7 +442,7 @@ int N_VLinearSumVectorArray(int nvec, realtype a, N_Vector* X, int i; if (Z[0]->ops->nvlinearsumvectorarray != NULL) { - + return(Z[0]->ops->nvlinearsumvectorarray(nvec, a, X, b, Y, Z)); } else { @@ -268,7 +460,7 @@ int N_VScaleVectorArray(int nvec, realtype* c, N_Vector* X, N_Vector* Z) int i; if (Z[0]->ops->nvscalevectorarray != NULL) { - + return(Z[0]->ops->nvscalevectorarray(nvec, c, X, Z)); } else { @@ -286,7 +478,7 @@ int N_VConstVectorArray(int nvec, realtype c, N_Vector* Z) int i, ier; if (Z[0]->ops->nvconstvectorarray != NULL) { - + ier = Z[0]->ops->nvconstvectorarray(nvec, c, Z); return(ier); @@ -305,7 +497,7 @@ int N_VWrmsNormVectorArray(int nvec, N_Vector* X, N_Vector* W, realtype* nrm) int i, ier; if (X[0]->ops->nvwrmsnormvectorarray != NULL) { - + ier = X[0]->ops->nvwrmsnormvectorarray(nvec, X, W, nrm); return(ier); @@ -342,8 +534,9 @@ int N_VWrmsNormMaskVectorArray(int nvec, N_Vector* X, N_Vector* W, N_Vector id, int N_VScaleAddMultiVectorArray(int nvec, int nsum, realtype* a, N_Vector* X, N_Vector** Y, N_Vector** Z) { - int i, j, ier; - realtype ONE=RCONST(1.0); + int i, j; + int ier=0; + realtype ONE=RCONST(1.0); N_Vector* YY=NULL; N_Vector* ZZ=NULL; @@ -355,8 +548,8 @@ int N_VScaleAddMultiVectorArray(int nvec, int nsum, realtype* a, N_Vector* X, } else if (X[0]->ops->nvscaleaddmulti != NULL ) { /* allocate arrays of vectors */ - YY = (N_Vector *) malloc(nsum * sizeof(N_Vector)); - ZZ = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + YY = (N_Vector*) malloc(nsum * sizeof(N_Vector)); + ZZ = (N_Vector*) malloc(nsum * sizeof(N_Vector)); for (i=0; iops->nvlinearcombinationvectorarray != NULL) { - + ier = Z[0]->ops->nvlinearcombinationvectorarray(nvec, nsum, c, X, Z); return(ier); } else if (Z[0]->ops->nvlinearcombination != NULL ) { - + /* allocate array of vectors */ - Y = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + Y = (N_Vector* ) malloc(nsum * sizeof(N_Vector)); for (i=0; iops->nvlinearcombination(nsum, c, Y, Z[i]); if (ier != 0) break; } - + /* free array of vectors */ free(Y); @@ -430,23 +624,82 @@ int N_VLinearCombinationVectorArray(int nvec, int nsum, realtype* c, N_Vector** } } -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- + * OPTIONAL local reduction kernels (no parallel communication) + * -----------------------------------------------------------------*/ + +realtype N_VDotProdLocal(N_Vector x, N_Vector y) +{ + return((realtype) y->ops->nvdotprodlocal(x, y)); +} + +realtype N_VMaxNormLocal(N_Vector x) +{ + return((realtype) x->ops->nvmaxnormlocal(x)); +} + +realtype N_VMinLocal(N_Vector x) +{ + return((realtype) x->ops->nvminlocal(x)); +} + +realtype N_VL1NormLocal(N_Vector x) +{ + return((realtype) x->ops->nvl1normlocal(x)); +} + +realtype N_VWSqrSumLocal(N_Vector x, N_Vector w) +{ + return((realtype) x->ops->nvwsqrsumlocal(x,w)); +} + +realtype N_VWSqrSumMaskLocal(N_Vector x, N_Vector w, N_Vector id) +{ + return((realtype) x->ops->nvwsqrsummasklocal(x,w,id)); +} + +booleantype N_VInvTestLocal(N_Vector x, N_Vector z) +{ + return((booleantype) z->ops->nvinvtestlocal(x,z)); +} + +booleantype N_VConstrMaskLocal(N_Vector c, N_Vector x, N_Vector m) +{ + return((booleantype) x->ops->nvconstrmasklocal(c,x,m)); +} + +realtype N_VMinQuotientLocal(N_Vector num, N_Vector denom) +{ + return((realtype) num->ops->nvminquotientlocal(num,denom)); +} + +/* ----------------------------------------------------------------- * Additional functions exported by the generic NVECTOR: + * N_VNewVectorArray * N_VCloneEmptyVectorArray * N_VCloneVectorArray * N_VDestroyVectorArray - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ +N_Vector* N_VNewVectorArray(int count) +{ + N_Vector* vs = NULL; -N_Vector *N_VCloneEmptyVectorArray(int count, N_Vector w) + if (count <= 0) return(NULL); + + vs = (N_Vector* ) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + return(vs); +} + +N_Vector* N_VCloneEmptyVectorArray(int count, N_Vector w) { - N_Vector *vs = NULL; + N_Vector* vs = NULL; int j; if (count <= 0) return(NULL); - vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + vs = (N_Vector* ) malloc(count * sizeof(N_Vector)); if(vs == NULL) return(NULL); for (j = 0; j < count; j++) { @@ -460,14 +713,14 @@ N_Vector *N_VCloneEmptyVectorArray(int count, N_Vector w) return(vs); } -N_Vector *N_VCloneVectorArray(int count, N_Vector w) +N_Vector* N_VCloneVectorArray(int count, N_Vector w) { - N_Vector *vs = NULL; + N_Vector* vs = NULL; int j; if (count <= 0) return(NULL); - vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + vs = (N_Vector* ) malloc(count * sizeof(N_Vector)); if(vs == NULL) return(NULL); for (j = 0; j < count; j++) { @@ -481,7 +734,7 @@ N_Vector *N_VCloneVectorArray(int count, N_Vector w) return(vs); } -void N_VDestroyVectorArray(N_Vector *vs, int count) +void N_VDestroyVectorArray(N_Vector* vs, int count) { int j; @@ -493,3 +746,18 @@ void N_VDestroyVectorArray(N_Vector *vs, int count) return; } + +/* These function are really only for users of the Fortran interface */ +N_Vector N_VGetVecAtIndexVectorArray(N_Vector* vs, int index) +{ + if (vs==NULL) return NULL; + else if (index < 0) return NULL; + else return vs[index]; +} + +void N_VSetVecAtIndexVectorArray(N_Vector* vs, int index, N_Vector w) +{ + if (vs==NULL) return; + else if (index < 0) return; + else vs[index] = w; +} diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_nvector_senswrapper.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_nvector_senswrapper.c index b16f40172..099582327 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_nvector_senswrapper.c +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_nvector_senswrapper.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_pcg.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_pcg.c deleted file mode 100644 index affadd266..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_pcg.c +++ /dev/null @@ -1,223 +0,0 @@ -/*--------------------------------------------------------------- - Programmer(s): Daniel R. Reynolds @ SMU - ---------------------------------------------------------------- - LLNS/SMU Copyright Start - Copyright (c) 2002-2018, Southern Methodist University and - Lawrence Livermore National Security - - This work was performed under the auspices of the U.S. Department - of Energy by Southern Methodist University and Lawrence Livermore - National Laboratory under Contract DE-AC52-07NA27344. - Produced at Southern Methodist University and the Lawrence - Livermore National Laboratory. - - All rights reserved. - For details, see the LICENSE file. - LLNS/SMU Copyright End - ---------------------------------------------------------------- - This is the implementation file for the preconditioned conjugate - gradient solver in SUNDIALS. - --------------------------------------------------------------*/ -#include -#include -#include -#include - - -/*--------------------------------------------------------------- - private constants - --------------------------------------------------------------*/ -#define ZERO RCONST(0.0) -#define ONE RCONST(1.0) - - -/*--------------------------------------------------------------- - Function : PcgMalloc - --------------------------------------------------------------*/ -PcgMem PcgMalloc(int l_max, N_Vector vec_tmpl) -{ - PcgMem mem; - N_Vector r, p, z, Ap; - - /* Check the input parameters */ - if (l_max <= 0) return(NULL); - - /* Create temporary arrays */ - r = N_VClone(vec_tmpl); - if (r == NULL) { - return(NULL); - } - - p = N_VClone(vec_tmpl); - if (p == NULL) { - N_VDestroy(r); - return(NULL); - } - - z = N_VClone(vec_tmpl); - if (z == NULL) { - N_VDestroy(r); - N_VDestroy(p); - return(NULL); - } - - Ap = N_VClone(vec_tmpl); - if (Ap == NULL) { - N_VDestroy(r); - N_VDestroy(p); - N_VDestroy(z); - return(NULL); - } - - /* Get memory for an PcgMemRec containing PCG vectors */ - mem = NULL; - mem = (PcgMem) malloc(sizeof(PcgMemRec)); - if (mem == NULL) { - N_VDestroy(r); - N_VDestroy(p); - N_VDestroy(z); - N_VDestroy(Ap); - return(NULL); - } - - /* Set the structure fields */ - mem->l_max = l_max; - mem->r = r; - mem->p = p; - mem->z = z; - mem->Ap = Ap; - - /* Return the pointer to PCG memory */ - return(mem); -} - - -/*--------------------------------------------------------------- - Function : PcgSolve - --------------------------------------------------------------*/ -int PcgSolve(PcgMem mem, void *A_data, N_Vector x, N_Vector b, - int pretype, realtype delta, void *P_data, - N_Vector w, ATimesFn atimes, PSolveFn psolve, - realtype *res_norm, int *nli, int *nps) -{ - realtype alpha, beta, r0_norm, rho, rz, rz_old; - N_Vector r, p, z, Ap; - booleantype UsePrec, converged; - int l, l_max, ier; - - if (mem == NULL) return(PCG_MEM_NULL); - - /* Make local copies of mem variables */ - l_max = mem->l_max; - r = mem->r; - p = mem->p; - z = mem->z; - Ap = mem->Ap; - - /* Initialize counters and converged flag */ - *nli = *nps = 0; - converged = SUNFALSE; - - /* Set preconditioning flag */ - UsePrec = ((pretype == PREC_BOTH) || (pretype == PREC_LEFT) || (pretype == PREC_RIGHT)); - - /* Set r to initial residual r_0 = b - A*x_0 */ - if (N_VDotProd(x, x) == ZERO) N_VScale(ONE, b, r); - else { - ier = atimes(A_data, x, r); - if (ier != 0) - return((ier < 0) ? PCG_ATIMES_FAIL_UNREC : PCG_ATIMES_FAIL_REC); - N_VLinearSum(ONE, b, -ONE, r, r); - } - - /* Set rho to L2 norm of r, and return if small */ - *res_norm = r0_norm = rho = N_VWrmsNorm(r,w); - if (rho <= delta) return(PCG_SUCCESS); - - /* Apply preconditioner and b-scaling to r = r_0 */ - if (UsePrec) { - ier = psolve(P_data, r, z, delta, PREC_LEFT); /* z = P^{-1}r */ - (*nps)++; - if (ier != 0) return((ier < 0) ? PCG_PSOLVE_FAIL_UNREC : PCG_PSOLVE_FAIL_REC); - } - else N_VScale(ONE, r, z); - - /* Initialize rz to */ - rz = N_VDotProd(r, z); - - /* Copy z to p */ - N_VScale(ONE, z, p); - - /* Begin main iteration loop */ - for(l=0; l / */ - alpha = rz / N_VDotProd(Ap, p); - - /* Update x = x + alpha*p */ - N_VLinearSum(ONE, x, alpha, p, x); - - /* Update r = r - alpha*Ap */ - N_VLinearSum(ONE, r, -alpha, Ap, r); - - /* Set rho and check convergence */ - *res_norm = rho = N_VWrmsNorm(r, w); - if (rho <= delta) { - converged = SUNTRUE; - break; - } - - /* Apply preconditioner: z = P^{-1}*r */ - if (UsePrec) { - ier = psolve(P_data, r, z, delta, PREC_LEFT); - (*nps)++; - if (ier != 0) return((ier < 0) ? PCG_PSOLVE_FAIL_UNREC : PCG_PSOLVE_FAIL_REC); - } - else N_VScale(ONE, r, z); - - /* update rz */ - rz_old = rz; - rz = N_VDotProd(r, z); - - /* Calculate beta = / */ - beta = rz / rz_old; - - /* Update p = z + beta*p */ - N_VLinearSum(ONE, z, beta, p, p); - - } - - /* Main loop finished, return with result */ - if (converged == SUNTRUE) return(PCG_SUCCESS); - if (rho < r0_norm) return(PCG_RES_REDUCED); - return(PCG_CONV_FAIL); -} - - -/*--------------------------------------------------------------- - Function : PcgFree - --------------------------------------------------------------*/ -void PcgFree(PcgMem mem) -{ - if (mem == NULL) return; - - N_VDestroy(mem->r); - N_VDestroy(mem->p); - N_VDestroy(mem->z); - N_VDestroy(mem->Ap); - - free(mem); mem = NULL; -} - - -/*=============================================================== - EOF -===============================================================*/ diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_sparse.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_sparse.c deleted file mode 100644 index eeeeb1ddd..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_sparse.c +++ /dev/null @@ -1,870 +0,0 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- - * Programmers: Carol Woodward, Slaven Peles @ LLNL - * Daniel R. Reynolds @ SMU - * ----------------------------------------------------------------- - * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security - * and Southern Methodist University. - * All rights reserved. - * - * See the top-level LICENSE and NOTICE files for details. - * - * SPDX-License-Identifier: BSD-3-Clause - * SUNDIALS Copyright End - * ----------------------------------------------------------------- - * This is the implementation file for operations on the SUNDIALS - * sparse matrix structure. - * ----------------------------------------------------------------- - */ - -#include -#include - -#include -#include - -#define ZERO RCONST(0.0) -#define ONE RCONST(1.0) - -/* - * ================================================================== - * Private function prototypes (functions working on SlsMat) - * ================================================================== - */ - -/* - * ----------------------------------------------------------------- - * Functions: SparseMatvecCSC - * ----------------------------------------------------------------- - * This function computes the matrix-vector product, y=A*x, where A - * is a CSC sparse matrix of dimension MxN, x is a realtype array of - * length N, and y is a realtype array of length M. Upon successful - * completion, the return value is zero; otherwise 1 is returned. - * ----------------------------------------------------------------- - */ - -static int SparseMatvecCSC(const SlsMat A, const realtype *x, realtype *y); - -/* - * ----------------------------------------------------------------- - * Functions: SparseMatvecCSR - * ----------------------------------------------------------------- - * This function computes the matrix-vector product, y=A*x, where A - * is a CSR sparse matrix of dimension MxN, x is a realtype array of - * length N, and y is a realtype array of length M. Upon successful - * completion, the return value is zero; otherwise 1 is returned. - * ----------------------------------------------------------------- - */ - -static int SparseMatvecCSR(const SlsMat A, const realtype *x, realtype *y); - - - -/* - * ================================================================== - * Implementation of sparse matrix methods (functions on SlsMat) - * ================================================================== - */ - -/* - * Default Constructor - * - * Creates a new (empty) sparse matrix of a desired size and nonzero density. - * Returns NULL if a memory allocation error occurred. - * - */ -SlsMat SparseNewMat(int M, int N, int NNZ, int sparsetype) -{ - SlsMat A; - - if ( (M <= 0) || (N <= 0) ) return(NULL); - - A = NULL; - A = (SlsMat) malloc(sizeof(struct _SlsMat)); - if (A==NULL) return (NULL); - - A->sparsetype = sparsetype; - - switch(A->sparsetype){ - case CSC_MAT: - A->NP = N; - A->rowvals = &(A->indexvals); - A->colptrs = &(A->indexptrs); - /* CSR indices */ - A->colvals = NULL; - A->rowptrs = NULL; - break; - case CSR_MAT: - A->NP = M; - A->colvals = &(A->indexvals); - A->rowptrs = &(A->indexptrs); - /* CSC indices */ - A->rowvals = NULL; - A->colptrs = NULL; - break; - default: - free(A); - A = NULL; - return(NULL); - } - - A->data = (realtype *) malloc(NNZ * sizeof(realtype)); - if (A->data == NULL) { - free(A); A = NULL; - return(NULL); - } - - A->indexvals = (int *) malloc(NNZ * sizeof(int)); - if (A->indexvals == NULL) { - free(A->data); A->data = NULL; - free(A); A = NULL; - return(NULL); - } - A->indexptrs = (int *) malloc((A->NP + 1) * sizeof(int)); - if (A->indexptrs == NULL) { - free(A->indexvals); - free(A->data); A->data = NULL; - free(A); A = NULL; - return(NULL); - } - - A->M = M; - A->N = N; - A->NNZ = NNZ; - /* A->colptrs[N] = NNZ; */ - A->indexptrs[A->NP] = 0; - - return(A); -} - -/** - * Constructor - * - * Creates a new sparse matrix out of an existing dense or band matrix. - * Returns NULL if a memory allocation error occurred. - * - */ -SlsMat SparseFromDenseMat(const DlsMat Ad, int sparsetype) -{ - int i, j, nnz; - int M, N; - realtype dtmp; - SlsMat As = NULL; - - switch(sparsetype) { - case CSC_MAT: - /* CSC is transpose of CSR */ - M = Ad->N; - N = Ad->M; - break; - case CSR_MAT: - M = Ad->M; - N = Ad->N; - break; - default: - /* Sparse matrix type not recognized */ - return NULL; - } - - /* proceed according to A's type (dense/band) */ - if (Ad->type == SUNDIALS_DENSE) { - - /* determine total number of nonzeros */ - nnz = 0; - for (j=0; jN; j++) - for (i=0; iM; i++) - nnz += (DENSE_ELEM(Ad,i,j) != 0.0); - - /* allocate sparse matrix */ - As = SparseNewMat(Ad->M, Ad->N, nnz, sparsetype); - if (As == NULL) return NULL; - - /* copy nonzeros from A into As */ - nnz = 0; - for (i=0; iindexptrs)[i] = nnz; - for (j=0; jindexvals)[nnz] = j; - As->data[nnz++] = dtmp; - } - } - } - (As->indexptrs)[M] = nnz; - - } else { /* SUNDIALS_BAND */ - - /* determine total number of nonzeros */ - nnz = 0; - for (j=0; jN; j++) - for (i=j-(Ad->mu); iml); i++) - nnz += (BAND_ELEM(Ad,i,j) != 0.0); - - /* allocate sparse matrix */ - As = SparseNewMat(Ad->M, Ad->N, nnz, sparsetype); - if (As == NULL) return NULL; - - /* copy nonzeros from A into As */ - nnz = 0; - for (i=0; iindexptrs)[i] = nnz; - for (j=i-(Ad->mu); jml); j++) { - /* CSR = row major looping; CSC = column major looping */ - dtmp = (sparsetype == CSR_MAT) ? BAND_ELEM(Ad,i,j) : BAND_ELEM(Ad,j,i); - if ( dtmp != 0.0 ) { - (As->indexvals)[nnz] = j; - As->data[nnz++] = dtmp; - } - } - } - (As->indexptrs)[M] = nnz; - - } - - return(As); -} - - -/** - * - * Destructor - * - * Frees memory and deletes the structure for an existing sparse matrix. - * - */ -int SparseDestroyMat(SlsMat A) -{ - if (A->data) { - free(A->data); - A->data = NULL; - } - if (A->indexvals) { - free(A->indexvals); - A->indexvals = NULL; - A->rowvals = NULL; - A->colvals = NULL; - } - if (A->indexptrs) { - free(A->indexptrs); - A->indexptrs = NULL; - A->colptrs = NULL; - A->rowptrs = NULL; - } - free(A); - A = NULL; - - return 0; -} - - -/** - * Sets all sparse matrix entries to zero. - */ -int SparseSetMatToZero(SlsMat A) -{ - int i; - - for (i=0; iNNZ; i++) { - A->data[i] = ZERO; - A->indexvals[i] = 0; - } - - for (i=0; iNP; i++) { - A->indexptrs[i] = 0; - } - /* A->colptrs[A->N] = A->NNZ; */ - A->indexptrs[A->NP] = 0; - - return 0; -} - - -/** - * Copies the sparse matrix A into sparse matrix B. - * - * It is assumed that A and B have the same dimensions, but we account - * for the situation in which B has fewer nonzeros than A. - * - */ -int SparseCopyMat(const SlsMat A, SlsMat B) -{ - int i; - int A_nz = A->indexptrs[A->NP]; - - if(A->M != B->M || A->N != B->N) { - /* fprintf(stderr, "Error: Copying sparse matrices of different size!\n"); */ - return (-1); - } - - - /* ensure B is of the same type as A */ - B->sparsetype = A->sparsetype; - - /* ensure that B is allocated with at least as - much memory as we have nonzeros in A */ - if (B->NNZ < A_nz) { - B->indexvals = (int *) realloc(B->indexvals, A_nz*sizeof(int)); - B->data = (realtype *) realloc(B->data, A_nz*sizeof(realtype)); - B->NNZ = A_nz; - } - - /* zero out B so that copy works correctly */ - SparseSetMatToZero(B); - - /* copy the data and row indices over */ - for (i=0; idata[i] = A->data[i]; - B->indexvals[i] = A->indexvals[i]; - } - - /* copy the column pointers over */ - for (i=0; iNP; i++) { - B->indexptrs[i] = A->indexptrs[i]; - } - B->indexptrs[A->NP] = A_nz; - - return 0; -} - - -/** - * Scales a sparse matrix A by the coefficient b. - */ -int SparseScaleMat(realtype b, SlsMat A) -{ - int i; - - for (i=0; iindexptrs[A->NP]; i++){ - A->data[i] = b * (A->data[i]); - } - return 0; -} - - - - -/** - * Adds 1 to every diagonal entry of A. - * - * Works for general [rectangular] matrices and handles potentially increased - * size if A does not currently contain a value on the diagonal. - * - * The function was developed originally for CSC matrices. To make it work for - * CSR, one simply need to transpose it, i.e. transpose M and N in the - * implementation. - * - */ -int SparseAddIdentityMat(SlsMat A) -{ - int j, i, p, nz, newmat, found; - int *w, *Ap, *Ai, *Cp, *Ci; - realtype *x, *Ax, *Cx; - SlsMat C; - int M; - int N; - - /* determine if A already contains values on the diagonal (hence - memory allocation necessary)*/ - newmat=0; - for (j=0; j < SUNMIN(A->N,A->M); j++) { - /* scan column (row if CSR) of A, searching for diagonal value */ - found = 0; - for (i=A->indexptrs[j]; iindexptrs[j+1]; i++) { - if (A->indexvals[i] == j) { - found = 1; - break; - } - } - /* if no diagonal found, signal new matrix */ - if (!found) { - newmat=1; - break; - } - } - - /* perform operation */ - - /* case 1: A already contains a diagonal */ - if (!newmat) { - - /* iterate through columns, adding 1.0 to diagonal */ - for (j=0; j < SUNMIN(A->N,A->M); j++) - for (i=A->indexptrs[j]; iindexptrs[j+1]; i++) - if (A->indexvals[i] == j) - A->data[i] += ONE; - - /* case 2: A does not already contain a diagonal */ - } else { - - if (A->sparsetype == CSC_MAT) { - M = A->M; - N = A->N; - } - else if (A->sparsetype == CSR_MAT) { - M = A->N; - N = A->M; - } - else - return (-1); - - /* create work arrays for row indices and nonzero column values */ - w = (int *) malloc(A->M * sizeof(int)); - x = (realtype *) malloc(A->M * sizeof(realtype)); - - /* create new matrix for sum (overestimate nnz as sum of each) */ - C = SparseNewMat(A->M, A->N, (A->indexptrs)[A->NP] + SUNMIN(A->M, A->N), A->sparsetype); - - /* access data from CSR structures (return if failure) */ - Cp = Ci = Ap = Ai = NULL; - Cx = Ax = NULL; - if (C->indexptrs) Cp = C->indexptrs; - else return (-1); - if (C->indexvals) Ci = C->indexvals; - else return (-1); - if (C->data) Cx = C->data; - else return (-1); - if (A->indexptrs) Ap = A->indexptrs; - else return (-1); - if (A->indexvals) Ai = A->indexvals; - else return (-1); - if (A->data) Ax = A->data; - else return (-1); - - /* initialize total nonzero count */ - nz = 0; - - /* iterate through columns (rows for CSR) */ - for (j=0; j 0 ) { - Ci[nz] = i; - Cx[nz++] = x[i]; - } - } - } - - /* indicate end of data */ - Cp[N] = nz; - - /* update A's structure with C's values; nullify C's pointers */ - A->NNZ = C->NNZ; - - if (A->data) - free(A->data); - A->data = C->data; - C->data = NULL; - - if (A->indexvals) - free(A->indexvals); - A->indexvals = C->indexvals; - C->indexvals = NULL; - - if (A->indexptrs) - free(A->indexptrs); - A->indexptrs = C->indexptrs; - C->indexptrs = NULL; - - /* clean up */ - SparseDestroyMat(C); - free(w); - free(x); - - /* reallocate the new matrix to remove extra space */ - SparseReallocMat(A); - } - return 0; -} - - -/** - * Add two sparse matrices: A = A+B. - * - * Handles potentially increased size if matrices have different sparsity patterns. - * Returns 0 if successful, and 1 if unsuccessful (in which case A is left unchanged). - * - * The function was developed originally for CSC matrices. To make it work for - * CSR, one simply need to transpose it, i.e. transpose M and N in the - * implementation. - * - */ -int SparseAddMat(SlsMat A, const SlsMat B) -{ - int j, i, p, nz, newmat; - int *w, *Ap, *Ai, *Bp, *Bi, *Cp, *Ci; - realtype *x, *Ax, *Bx, *Cx; - SlsMat C; - int M; - int N; - - /* ensure that matrix dimensions agree */ - if ((A->M != B->M) || (A->N != B->N)) { - /* fprintf(stderr, "Error: Adding sparse matrices of different size!\n"); */ - return(-1); - } - - /* if A is CSR matrix, transpose M and N */ - if (A->sparsetype == CSC_MAT) { - M = A->M; - N = A->N; - } - else if (A->sparsetype == CSR_MAT) { - M = A->N; - N = A->M; - } - else - return(-1); - - /* create work arrays for row indices and nonzero column values */ - w = (int *) malloc(M * sizeof(int)); - x = (realtype *) malloc(M * sizeof(realtype)); - - /* determine if A already contains the sparsity pattern of B */ - newmat=0; - for (j=0; jindexptrs[j]; iindexptrs[j+1]; i++) - w[A->indexvals[i]] += 1; - - /* scan column of B, decrementing w by one */ - for (i=B->indexptrs[j]; iindexptrs[j+1]; i++) - w[B->indexvals[i]] -= 1; - - /* if any entry of w is negative, A doesn't contain B's sparsity */ - for (i=0; iindexptrs[j]; i < B->indexptrs[j+1]; i++) - x[B->indexvals[i]] = B->data[i]; - - /* scan column of A, updating entries appropriately array */ - for (i = A->indexptrs[j]; i < A->indexptrs[j+1]; i++) - A->data[i] += x[A->indexvals[i]]; - - } - - /* case 2: A does not already contain B's sparsity */ - } else { - - /* create new matrix for sum (overestimate nnz as sum of each) */ - C = SparseNewMat(M, N, (A->indexptrs[N])+(B->indexptrs[N]), A->sparsetype); - - /* access data from CSR structures (return if failure) */ - Cp = Ci = Ap = Ai = Bp = Bi = NULL; - Cx = Ax = Bx = NULL; - if (C->indexptrs) Cp = C->indexptrs; - else return(-1); - if (C->indexvals) Ci = C->indexvals; - else return(-1); - if (C->data) Cx = C->data; - else return(-1); - if (A->indexptrs) Ap = (A->indexptrs); - else return(-1); - if (A->indexvals) Ai = (A->indexvals); - else return(-1); - if (A->data) Ax = A->data; - else return(-1); - if (B->indexptrs) Bp = B->indexptrs; - else return(-1); - if (B->indexvals) Bi = B->indexvals; - else return(-1); - if (B->data) Bx = B->data; - else return(-1); - - /* initialize total nonzero count */ - nz = 0; - - /* iterate through columns */ - for (j=0; j 0 ) { - Ci[nz] = i; - Cx[nz++] = x[i]; - } - } - } - - /* indicate end of data */ - Cp[N] = nz; - - /* update A's structure with C's values; nullify C's pointers */ - A->NNZ = C->NNZ; - - free(A->data); - A->data = C->data; - C->data = NULL; - - free(A->indexvals); - A->indexvals = C->indexvals; - C->indexvals = NULL; - - free(A->indexptrs); - A->indexptrs = C->indexptrs; - C->indexptrs = NULL; - - /* clean up */ - SparseDestroyMat(C); - - /* reallocate the new matrix to remove extra space */ - SparseReallocMat(A); - - } - - /* clean up */ - free(w); - free(x); - - /* return success */ - return(0); -} - - -/** - * Resizes the memory allocated for a given sparse matrix, shortening - * it down to the number of actual nonzero entries. - */ -int SparseReallocMat(SlsMat A) -{ - int nzmax; - - nzmax = A->indexptrs[A->NP]; - A->indexvals = (int *) realloc(A->indexvals, nzmax*sizeof(int)); - A->data = (realtype *) realloc(A->data, nzmax*sizeof(realtype)); - A->NNZ = nzmax; - - return 0; -} - - -/** - * Computes y=A*x, where A is a sparse matrix of dimension MxN, x is a - * realtype array of length N, and y is a realtype array of length M. - * - * Returns 0 if successful, -1 if unsuccessful (failed memory access). - */ -int SparseMatvec(const SlsMat A, const realtype *x, realtype *y) -{ - if(A->sparsetype == CSC_MAT) - return SparseMatvecCSC(A, x, y); - else if (A->sparsetype == CSR_MAT) - return SparseMatvecCSR(A, x, y); - else - return(-1); -} - - -/** - * Prints the nonzero entries of a sparse matrix to screen. - */ -void SparsePrintMat(const SlsMat A, FILE* outfile) -{ - int i,j, NNZ; - char *matrixtype; - char *indexname; - - NNZ = A->NNZ; - - switch(A->sparsetype) { - case CSC_MAT: - indexname = (char*) "col"; - matrixtype = (char*) "CSC"; - break; - case CSR_MAT: - indexname = (char*) "row"; - matrixtype = (char*) "CSR"; - break; - default: - /* Sparse matrix type not recognized */ - return; - } - - - fprintf(outfile, "\n"); - - fprintf(outfile, "%d by %d %s matrix, NNZ: %d \n", A->M, A->N, matrixtype, NNZ); - for (j=0; j < A->NP; j++) { - fprintf(outfile, "%s %d : locations %d to %d\n", indexname, j, (A->indexptrs)[j], (A->indexptrs)[j+1]-1); - fprintf(outfile, " "); - for (i = (A->indexptrs)[j]; i < (A->indexptrs)[j+1]; i++) { -#if defined(SUNDIALS_EXTENDED_PRECISION) - fprintf(outfile, "%d: %Lg ", A->indexvals[i], A->data[i]); -#elif defined(SUNDIALS_DOUBLE_PRECISION) - fprintf(outfile, "%d: %g ", A->indexvals[i], A->data[i]); -#else - fprintf(outfile, "%d: %g ", A->indexvals[i], A->data[i]); -#endif - } - fprintf(outfile, "\n"); - } - fprintf(outfile, "\n"); - -} - - - -/* - * ================================================================== - * Private function definitions - * ================================================================== - */ - - - -/** - * Computes y=A*x, where A is a CSC matrix of dimension MxN, x is a - * realtype array of length N, and y is a realtype array of length M. - * - * Returns 0 if successful, -1 if unsuccessful (failed memory access). - */ -int SparseMatvecCSC(const SlsMat A, const realtype *x, realtype *y) -{ - int j, i; - int *Ap, *Ai; - realtype *Ax; - - /* access data from CSR structure (return if failure) */ - if (*A->colptrs) Ap = A->indexptrs; - else return(-1); - if (*A->rowvals) Ai = A->indexvals; - else return(-1); - if (A->data) Ax = A->data; - else return(-1); - - /* ensure that vectors are non-NULL */ - if ((x == NULL) || (y == NULL)) - return(-1); - - /* initialize result */ - for (i=0; iM; i++) - y[i] = 0.0; - - /* iterate through matrix columns */ - for (j=0; jN; j++) { - - /* iterate down column of A, performing product */ - for (i=Ap[j]; irowptrs) Ap = A->indexptrs; - else return(-1); - if (*A->colvals) Aj = A->indexvals; - else return(-1); - if (A->data) Ax = A->data; - else return(-1); - - /* ensure that vectors are non-NULL */ - if ((x == NULL) || (y == NULL)) - return(-1); - - /* initialize result */ - for (i=0; iM; i++) - y[i] = 0.0; - - /* iterate through matrix rows */ - for (i=0; iM; ++i) { - - /* iterate along row of A, performing product */ - for (j=Ap[i]; j -#include - -#include -#include - -/* - * ----------------------------------------------------------------- - * private constants - * ----------------------------------------------------------------- - */ - -#define ZERO RCONST(0.0) -#define ONE RCONST(1.0) - -/* - * ----------------------------------------------------------------- - * Function : SpbcgMalloc - * ----------------------------------------------------------------- - */ - -SpbcgMem SpbcgMalloc(int l_max, N_Vector vec_tmpl) -{ - SpbcgMem mem; - N_Vector r_star, r, p, q, u, Ap, vtemp; - - /* Check the input parameters */ - - if (l_max <= 0) return(NULL); - - /* Get arrays to hold temporary vectors */ - - r_star = N_VClone(vec_tmpl); - if (r_star == NULL) { - return(NULL); - } - - r = N_VClone(vec_tmpl); - if (r == NULL) { - N_VDestroy(r_star); - return(NULL); - } - - p = N_VClone(vec_tmpl); - if (p == NULL) { - N_VDestroy(r_star); - N_VDestroy(r); - return(NULL); - } - - q = N_VClone(vec_tmpl); - if (q == NULL) { - N_VDestroy(r_star); - N_VDestroy(r); - N_VDestroy(p); - return(NULL); - } - - u = N_VClone(vec_tmpl); - if (u == NULL) { - N_VDestroy(r_star); - N_VDestroy(r); - N_VDestroy(p); - N_VDestroy(q); - return(NULL); - } - - Ap = N_VClone(vec_tmpl); - if (Ap == NULL) { - N_VDestroy(r_star); - N_VDestroy(r); - N_VDestroy(p); - N_VDestroy(q); - N_VDestroy(u); - return(NULL); - } - - vtemp = N_VClone(vec_tmpl); - if (vtemp == NULL) { - N_VDestroy(r_star); - N_VDestroy(r); - N_VDestroy(p); - N_VDestroy(q); - N_VDestroy(u); - N_VDestroy(Ap); - return(NULL); - } - - /* Get memory for an SpbcgMemRec containing SPBCG matrices and vectors */ - - mem = NULL; - mem = (SpbcgMem) malloc(sizeof(SpbcgMemRec)); - if (mem == NULL) { - N_VDestroy(r_star); - N_VDestroy(r); - N_VDestroy(p); - N_VDestroy(q); - N_VDestroy(u); - N_VDestroy(Ap); - N_VDestroy(vtemp); - return(NULL); - } - - /* Set the fields of mem */ - - mem->l_max = l_max; - mem->r_star = r_star; - mem->r = r; - mem->p = p; - mem->q = q; - mem->u = u; - mem->Ap = Ap; - mem->vtemp = vtemp; - - /* Return the pointer to SPBCG memory */ - - return(mem); -} - -/* - * ----------------------------------------------------------------- - * Function : SpbcgSolve - * ----------------------------------------------------------------- - */ - -int SpbcgSolve(SpbcgMem mem, void *A_data, N_Vector x, N_Vector b, - int pretype, realtype delta, void *P_data, N_Vector sx, - N_Vector sb, ATimesFn atimes, PSolveFn psolve, - realtype *res_norm, int *nli, int *nps) -{ - realtype alpha, beta, omega, omega_denom, beta_num, beta_denom, r_norm, rho; - N_Vector r_star, r, p, q, u, Ap, vtemp; - booleantype preOnLeft, preOnRight, scale_x, scale_b, converged; - int l, l_max, ier; - - if (mem == NULL) return(SPBCG_MEM_NULL); - - /* Make local copies of mem variables */ - - l_max = mem->l_max; - r_star = mem->r_star; - r = mem->r; - p = mem->p; - q = mem->q; - u = mem->u; - Ap = mem->Ap; - vtemp = mem->vtemp; - - *nli = *nps = 0; /* Initialize counters */ - converged = SUNFALSE; /* Initialize converged flag */ - - if ((pretype != PREC_LEFT) && (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) pretype = PREC_NONE; - - preOnLeft = ((pretype == PREC_BOTH) || (pretype == PREC_LEFT)); - preOnRight = ((pretype == PREC_BOTH) || (pretype == PREC_RIGHT)); - - scale_x = (sx != NULL); - scale_b = (sb != NULL); - - /* Set r_star to initial (unscaled) residual r_0 = b - A*x_0 */ - - if (N_VDotProd(x, x) == ZERO) N_VScale(ONE, b, r_star); - else { - ier = atimes(A_data, x, r_star); - if (ier != 0) - return((ier < 0) ? SPBCG_ATIMES_FAIL_UNREC : SPBCG_ATIMES_FAIL_REC); - N_VLinearSum(ONE, b, -ONE, r_star, r_star); - } - - /* Apply left preconditioner and b-scaling to r_star = r_0 */ - - if (preOnLeft) { - ier = psolve(P_data, r_star, r, delta, PREC_LEFT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPBCG_PSOLVE_FAIL_UNREC : SPBCG_PSOLVE_FAIL_REC); - } - else N_VScale(ONE, r_star, r); - - if (scale_b) N_VProd(sb, r, r_star); - else N_VScale(ONE, r, r_star); - - /* Initialize beta_denom to the dot product of r0 with r0 */ - - beta_denom = N_VDotProd(r_star, r_star); - - /* Set r_norm to L2 norm of r_star = sb P1_inv r_0, and - return if small */ - - *res_norm = r_norm = rho = SUNRsqrt(beta_denom); - if (r_norm <= delta) return(SPBCG_SUCCESS); - - /* Copy r_star to r and p */ - - N_VScale(ONE, r_star, r); - N_VScale(ONE, r_star, p); - - /* Begin main iteration loop */ - - for(l = 0; l < l_max; l++) { - - (*nli)++; - - /* Generate Ap = A-tilde p, where A-tilde = sb P1_inv A P2_inv sx_inv */ - - /* Apply x-scaling: vtemp = sx_inv p */ - - if (scale_x) N_VDiv(p, sx, vtemp); - else N_VScale(ONE, p, vtemp); - - /* Apply right preconditioner: vtemp = P2_inv sx_inv p */ - - if (preOnRight) { - N_VScale(ONE, vtemp, Ap); - ier = psolve(P_data, Ap, vtemp, delta, PREC_RIGHT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPBCG_PSOLVE_FAIL_UNREC : SPBCG_PSOLVE_FAIL_REC); - } - - /* Apply A: Ap = A P2_inv sx_inv p */ - - ier = atimes(A_data, vtemp, Ap ); - if (ier != 0) - return((ier < 0) ? SPBCG_ATIMES_FAIL_UNREC : SPBCG_ATIMES_FAIL_REC); - - /* Apply left preconditioner: vtemp = P1_inv A P2_inv sx_inv p */ - - if (preOnLeft) { - ier = psolve(P_data, Ap, vtemp, delta, PREC_LEFT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPBCG_PSOLVE_FAIL_UNREC : SPBCG_PSOLVE_FAIL_REC); - } - else N_VScale(ONE, Ap, vtemp); - - /* Apply b-scaling: Ap = sb P1_inv A P2_inv sx_inv p */ - - if (scale_b) N_VProd(sb, vtemp, Ap); - else N_VScale(ONE, vtemp, Ap); - - - /* Calculate alpha = / */ - - alpha = ((beta_denom / N_VDotProd(Ap, r_star))); - - /* Update q = r - alpha*Ap = r - alpha*(sb P1_inv A P2_inv sx_inv p) */ - - N_VLinearSum(ONE, r, -alpha, Ap, q); - - /* Generate u = A-tilde q */ - - /* Apply x-scaling: vtemp = sx_inv q */ - - if (scale_x) N_VDiv(q, sx, vtemp); - else N_VScale(ONE, q, vtemp); - - /* Apply right preconditioner: vtemp = P2_inv sx_inv q */ - - if (preOnRight) { - N_VScale(ONE, vtemp, u); - ier = psolve(P_data, u, vtemp, delta, PREC_RIGHT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPBCG_PSOLVE_FAIL_UNREC : SPBCG_PSOLVE_FAIL_REC); - } - - /* Apply A: u = A P2_inv sx_inv u */ - - ier = atimes(A_data, vtemp, u ); - if (ier != 0) - return((ier < 0) ? SPBCG_ATIMES_FAIL_UNREC : SPBCG_ATIMES_FAIL_REC); - - /* Apply left preconditioner: vtemp = P1_inv A P2_inv sx_inv p */ - - if (preOnLeft) { - ier = psolve(P_data, u, vtemp, delta, PREC_LEFT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPBCG_PSOLVE_FAIL_UNREC : SPBCG_PSOLVE_FAIL_REC); - } - else N_VScale(ONE, u, vtemp); - - /* Apply b-scaling: u = sb P1_inv A P2_inv sx_inv u */ - - if (scale_b) N_VProd(sb, vtemp, u); - else N_VScale(ONE, vtemp, u); - - - /* Calculate omega = / */ - - omega_denom = N_VDotProd(u, u); - if (omega_denom == ZERO) omega_denom = ONE; - omega = (N_VDotProd(u, q) / omega_denom); - - /* Update x = x + alpha*p + omega*q */ - - N_VLinearSum(alpha, p, omega, q, vtemp); - N_VLinearSum(ONE, x, ONE, vtemp, x); - - /* Update the residual r = q - omega*u */ - - N_VLinearSum(ONE, q, -omega, u, r); - - /* Set rho = norm(r) and check convergence */ - - *res_norm = rho = SUNRsqrt(N_VDotProd(r, r)); - if (rho <= delta) { - converged = SUNTRUE; - break; - } - - /* Not yet converged, continue iteration */ - /* Update beta = / * alpha / omega */ - - beta_num = N_VDotProd(r, r_star); - beta = ((beta_num / beta_denom) * (alpha / omega)); - beta_denom = beta_num; - - /* Update p = r + beta*(p - omega*Ap) */ - - N_VLinearSum(ONE, p, -omega, Ap, vtemp); - N_VLinearSum(ONE, r, beta, vtemp, p); - - } - - /* Main loop finished */ - - if ((converged == SUNTRUE) || (rho < r_norm)) { - - /* Apply the x-scaling and right preconditioner: x = P2_inv sx_inv x */ - - if (scale_x) N_VDiv(x, sx, x); - if (preOnRight) { - ier = psolve(P_data, x, vtemp, delta, PREC_RIGHT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPBCG_PSOLVE_FAIL_UNREC : SPBCG_PSOLVE_FAIL_REC); - N_VScale(ONE, vtemp, x); - } - - if (converged == SUNTRUE) return(SPBCG_SUCCESS); - else return(SPBCG_RES_REDUCED); - } - else return(SPBCG_CONV_FAIL); -} - -/* - * ----------------------------------------------------------------- - * Function : SpbcgFree - * ----------------------------------------------------------------- - */ - -void SpbcgFree(SpbcgMem mem) -{ - - if (mem == NULL) return; - - N_VDestroy(mem->r_star); - N_VDestroy(mem->r); - N_VDestroy(mem->p); - N_VDestroy(mem->q); - N_VDestroy(mem->u); - N_VDestroy(mem->Ap); - N_VDestroy(mem->vtemp); - - free(mem); mem = NULL; -} diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_spfgmr.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_spfgmr.c deleted file mode 100644 index c8419ea68..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_spfgmr.c +++ /dev/null @@ -1,374 +0,0 @@ -/*---------------------------------------------------------------- - Programmer(s): Daniel R. Reynolds and Hilari C. Tiedeman @ SMU - ----------------------------------------------------------------- - LLNS/SMU Copyright Start - Copyright (c) 2002-2018, Southern Methodist University and - Lawrence Livermore National Security - - This work was performed under the auspices of the U.S. Department - of Energy by Southern Methodist University and Lawrence Livermore - National Laboratory under Contract DE-AC52-07NA27344. - Produced at Southern Methodist University and the Lawrence - Livermore National Laboratory. - - All rights reserved. - For details, see the LICENSE file. - LLNS/SMU Copyright End - ------------------------------------------------------------------- - This is the implementation file for the scaled preconditioned - FGMRES (SPFGMR) iterative linear solver. - ---------------------------------------------------------------*/ -#include -#include -#include -#include - -/*---------------------------------------------------------------- - private constants - ---------------------------------------------------------------*/ -#define ZERO RCONST(0.0) -#define ONE RCONST(1.0) - -/*---------------------------------------------------------------- - Function : SpfgmrMalloc - ---------------------------------------------------------------*/ -SpfgmrMem SpfgmrMalloc(int l_max, N_Vector vec_tmpl) -{ - SpfgmrMem mem; - N_Vector *V, *Z, xcor, vtemp; - realtype **Hes, *givens, *yg; - int k, i; - - /* Check the input parameters. */ - if (l_max <= 0) return(NULL); - - /* Get memory for the Krylov basis vectors V[0], ..., V[l_max]. */ - V = N_VCloneVectorArray(l_max+1, vec_tmpl); - if (V == NULL) return(NULL); - - /* Get memory for the preconditioned basis vectors Z[0], ..., Z[l_max]. */ - Z = N_VCloneVectorArray(l_max+1, vec_tmpl); - if (Z == NULL) { - N_VDestroyVectorArray(V, l_max+1); - return(NULL); - } - - /* Get memory for the Hessenberg matrix Hes. */ - Hes = NULL; - Hes = (realtype **) malloc((l_max+1)*sizeof(realtype *)); - if (Hes == NULL) { - N_VDestroyVectorArray(V, l_max+1); - N_VDestroyVectorArray(Z, l_max+1); - return(NULL); - } - for (k=0; k<=l_max; k++) { - Hes[k] = NULL; - Hes[k] = (realtype *) malloc(l_max*sizeof(realtype)); - if (Hes[k] == NULL) { - for (i=0; il_max = l_max; - mem->V = V; - mem->Z = Z; - mem->Hes = Hes; - mem->givens = givens; - mem->xcor = xcor; - mem->yg = yg; - mem->vtemp = vtemp; - - /* Return the pointer to SPFGMR memory. */ - return(mem); -} - -/*---------------------------------------------------------------- - Function : SpfgmrSolve - ---------------------------------------------------------------*/ -int SpfgmrSolve(SpfgmrMem mem, void *A_data, N_Vector x, - N_Vector b, int pretype, int gstype, realtype delta, - int max_restarts, int maxit, void *P_data, - N_Vector s1, N_Vector s2, ATimesFn atimes, - PSolveFn psolve, realtype *res_norm, int *nli, int *nps) -{ - N_Vector *V, *Z, xcor, vtemp; - realtype **Hes, *givens, *yg; - realtype beta, rotation_product, r_norm, s_product, rho; - booleantype preOnRight, scale1, scale2, converged; - int i, j, k, l, l_max, krydim, ier, ntries; - - if (mem == NULL) return(SPFGMR_MEM_NULL); - - /* Initialize some variables */ - krydim = 0; - - /* Make local copies of mem variables. */ - l_max = mem->l_max; - V = mem->V; - Z = mem->Z; - Hes = mem->Hes; - givens = mem->givens; - xcor = mem->xcor; - yg = mem->yg; - vtemp = mem->vtemp; - - *nli = *nps = 0; /* Initialize counters */ - converged = SUNFALSE; /* Initialize converged flag */ - - /* If maxit is greater than l_max, then set maxit=l_max */ - if (maxit > l_max) maxit = l_max; - - /* Check for legal value of max_restarts */ - if (max_restarts < 0) max_restarts = 0; - - /* Set preconditioning flag (enabling any preconditioner implies right - preconditioning, since FGMRES does not support left preconditioning) */ - preOnRight = ((pretype == PREC_RIGHT) || (pretype == PREC_BOTH) || (pretype == PREC_LEFT)); - - /* Set scaling flags */ - scale1 = (s1 != NULL); - scale2 = (s2 != NULL); - - /* Set vtemp to initial (unscaled) residual r_0 = b - A*x_0. */ - if (N_VDotProd(x, x) == ZERO) { - N_VScale(ONE, b, vtemp); - } else { - ier = atimes(A_data, x, vtemp); - if (ier != 0) - return((ier < 0) ? SPFGMR_ATIMES_FAIL_UNREC : SPFGMR_ATIMES_FAIL_REC); - N_VLinearSum(ONE, b, -ONE, vtemp, vtemp); - } - - /* Apply left scaling to vtemp = r_0 to fill V[0]. */ - if (scale1) { - N_VProd(s1, vtemp, V[0]); - } else { - N_VScale(ONE, vtemp, V[0]); - } - - /* Set r_norm = beta to L2 norm of V[0] = s1 r_0, and return if small */ - *res_norm = r_norm = beta = SUNRsqrt(N_VDotProd(V[0], V[0])); - if (r_norm <= delta) - return(SPFGMR_SUCCESS); - - /* Initialize rho to avoid compiler warning message */ - rho = beta; - - /* Set xcor = 0. */ - N_VConst(ZERO, xcor); - - /* Begin outer iterations: up to (max_restarts + 1) attempts. */ - for (ntries=0; ntries<=max_restarts; ntries++) { - - /* Initialize the Hessenberg matrix Hes and Givens rotation - product. Normalize the initial vector V[0]. */ - for (i=0; i<=l_max; i++) - for (j=0; j0; i--) { - yg[i] = s_product*givens[2*i-2]; - s_product *= givens[2*i-1]; - } - yg[0] = s_product; - - /* Scale r_norm and yg. */ - r_norm *= s_product; - for (i=0; i<=krydim; i++) - yg[i] *= r_norm; - r_norm = SUNRabs(r_norm); - - /* Multiply yg by V_(krydim+1) to get last residual vector; restart. */ - N_VScale(yg[0], V[0], V[0]); - for (k=1; k<=krydim; k++) - N_VLinearSum(yg[k], V[k], ONE, V[0], V[0]); - - } - - /* Failed to converge, even after allowed restarts. - If the residual norm was reduced below its initial value, compute - and return x anyway. Otherwise return failure flag. */ - if (rho < beta) { - N_VLinearSum(ONE, x, ONE, xcor, x); - return(SPFGMR_RES_REDUCED); - } - - return(SPFGMR_CONV_FAIL); -} - -/*---------------------------------------------------------------- - Function : SpfgmrFree - ---------------------------------------------------------------*/ -void SpfgmrFree(SpfgmrMem mem) -{ - int i; - - if (mem == NULL) return; - - for (i=0; i<=mem->l_max; i++) { - free(mem->Hes[i]); - mem->Hes[i] = NULL; - } - free(mem->Hes); mem->Hes = NULL; - free(mem->givens); mem->givens = NULL; - free(mem->yg); mem->yg = NULL; - - N_VDestroyVectorArray(mem->V, mem->l_max+1); - N_VDestroyVectorArray(mem->Z, mem->l_max+1); - N_VDestroy(mem->xcor); - N_VDestroy(mem->vtemp); - - free(mem); mem = NULL; -} - - -/*=============================================================== - EOF -===============================================================*/ diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_spgmr.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_spgmr.c deleted file mode 100644 index fd7785119..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_spgmr.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- - * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh and - * Radu Serban @ LLNL - * ----------------------------------------------------------------- - * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security - * and Southern Methodist University. - * All rights reserved. - * - * See the top-level LICENSE and NOTICE files for details. - * - * SPDX-License-Identifier: BSD-3-Clause - * SUNDIALS Copyright End - * ----------------------------------------------------------------- - * This is the implementation file for the scaled preconditioned - * GMRES (SPGMR) iterative linear solver. - * ----------------------------------------------------------------- - */ - -#include -#include - -#include -#include - -/* - * ----------------------------------------------------------------- - * private constants - * ----------------------------------------------------------------- - */ - -#define ZERO RCONST(0.0) -#define ONE RCONST(1.0) - -/* - * ----------------------------------------------------------------- - * Function : SpgmrMalloc - * ----------------------------------------------------------------- - */ - -SpgmrMem SpgmrMalloc(int l_max, N_Vector vec_tmpl) -{ - SpgmrMem mem; - N_Vector *V, xcor, vtemp; - realtype **Hes, *givens, *yg; - int k, i; - - /* Check the input parameters. */ - - if (l_max <= 0) return(NULL); - - /* Get memory for the Krylov basis vectors V[0], ..., V[l_max]. */ - - V = N_VCloneVectorArray(l_max+1, vec_tmpl); - if (V == NULL) return(NULL); - - /* Get memory for the Hessenberg matrix Hes. */ - - Hes = NULL; - Hes = (realtype **) malloc((l_max+1)*sizeof(realtype *)); - if (Hes == NULL) { - N_VDestroyVectorArray(V, l_max+1); - return(NULL); - } - - for (k = 0; k <= l_max; k++) { - Hes[k] = NULL; - Hes[k] = (realtype *) malloc(l_max*sizeof(realtype)); - if (Hes[k] == NULL) { - for (i = 0; i < k; i++) {free(Hes[i]); Hes[i] = NULL;} - free(Hes); Hes = NULL; - N_VDestroyVectorArray(V, l_max+1); - return(NULL); - } - } - - /* Get memory for Givens rotation components. */ - - givens = NULL; - givens = (realtype *) malloc(2*l_max*sizeof(realtype)); - if (givens == NULL) { - for (i = 0; i <= l_max; i++) {free(Hes[i]); Hes[i] = NULL;} - free(Hes); Hes = NULL; - N_VDestroyVectorArray(V, l_max+1); - return(NULL); - } - - /* Get memory to hold the correction to z_tilde. */ - - xcor = N_VClone(vec_tmpl); - if (xcor == NULL) { - free(givens); givens = NULL; - for (i = 0; i <= l_max; i++) {free(Hes[i]); Hes[i] = NULL;} - free(Hes); Hes = NULL; - N_VDestroyVectorArray(V, l_max+1); - return(NULL); - } - - /* Get memory to hold SPGMR y and g vectors. */ - - yg = NULL; - yg = (realtype *) malloc((l_max+1)*sizeof(realtype)); - if (yg == NULL) { - N_VDestroy(xcor); - free(givens); givens = NULL; - for (i = 0; i <= l_max; i++) {free(Hes[i]); Hes[i] = NULL;} - free(Hes); Hes = NULL; - N_VDestroyVectorArray(V, l_max+1); - return(NULL); - } - - /* Get an array to hold a temporary vector. */ - - vtemp = N_VClone(vec_tmpl); - if (vtemp == NULL) { - free(yg); yg = NULL; - N_VDestroy(xcor); - free(givens); givens = NULL; - for (i = 0; i <= l_max; i++) {free(Hes[i]); Hes[i] = NULL;} - free(Hes); Hes = NULL; - N_VDestroyVectorArray(V, l_max+1); - return(NULL); - } - - /* Get memory for an SpgmrMemRec containing SPGMR matrices and vectors. */ - - mem = NULL; - mem = (SpgmrMem) malloc(sizeof(SpgmrMemRec)); - if (mem == NULL) { - N_VDestroy(vtemp); - free(yg); yg = NULL; - N_VDestroy(xcor); - free(givens); givens = NULL; - for (i = 0; i <= l_max; i++) {free(Hes[i]); Hes[i] = NULL;} - free(Hes); Hes = NULL; - N_VDestroyVectorArray(V, l_max+1); - return(NULL); - } - - /* Set the fields of mem. */ - - mem->l_max = l_max; - mem->V = V; - mem->Hes = Hes; - mem->givens = givens; - mem->xcor = xcor; - mem->yg = yg; - mem->vtemp = vtemp; - - /* Return the pointer to SPGMR memory. */ - - return(mem); -} - -/* - * ----------------------------------------------------------------- - * Function : SpgmrSolve - * ----------------------------------------------------------------- - */ - -int SpgmrSolve(SpgmrMem mem, void *A_data, N_Vector x, N_Vector b, - int pretype, int gstype, realtype delta, int max_restarts, - void *P_data, N_Vector s1, N_Vector s2, ATimesFn atimes, - PSolveFn psolve, realtype *res_norm, int *nli, int *nps) -{ - N_Vector *V, xcor, vtemp; - realtype **Hes, *givens, *yg; - realtype beta, rotation_product, r_norm, s_product, rho; - booleantype preOnLeft, preOnRight, scale2, scale1, converged; - int i, j, k, l, l_plus_1, l_max, krydim, ier, ntries; - - if (mem == NULL) return(SPGMR_MEM_NULL); - - /* Initialize some variables */ - - l_plus_1 = 0; - krydim = 0; - - /* Make local copies of mem variables. */ - - l_max = mem->l_max; - V = mem->V; - Hes = mem->Hes; - givens = mem->givens; - xcor = mem->xcor; - yg = mem->yg; - vtemp = mem->vtemp; - - *nli = *nps = 0; /* Initialize counters */ - converged = SUNFALSE; /* Initialize converged flag */ - - if (max_restarts < 0) max_restarts = 0; - - if ((pretype != PREC_LEFT) && (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) - pretype = PREC_NONE; - - preOnLeft = ((pretype == PREC_LEFT) || (pretype == PREC_BOTH)); - preOnRight = ((pretype == PREC_RIGHT) || (pretype == PREC_BOTH)); - scale1 = (s1 != NULL); - scale2 = (s2 != NULL); - - /* Set vtemp and V[0] to initial (unscaled) residual r_0 = b - A*x_0. */ - - if (N_VDotProd(x, x) == ZERO) { - N_VScale(ONE, b, vtemp); - } else { - ier = atimes(A_data, x, vtemp); - if (ier != 0) - return((ier < 0) ? SPGMR_ATIMES_FAIL_UNREC : SPGMR_ATIMES_FAIL_REC); - N_VLinearSum(ONE, b, -ONE, vtemp, vtemp); - } - N_VScale(ONE, vtemp, V[0]); - - /* Apply left preconditioner and left scaling to V[0] = r_0. */ - - if (preOnLeft) { - ier = psolve(P_data, V[0], vtemp, delta, PREC_LEFT); - (*nps)++; - if (ier != 0) - return((ier < 0) ? SPGMR_PSOLVE_FAIL_UNREC : SPGMR_PSOLVE_FAIL_REC); - } else { - N_VScale(ONE, V[0], vtemp); - } - - if (scale1) { - N_VProd(s1, vtemp, V[0]); - } else { - N_VScale(ONE, vtemp, V[0]); - } - - /* Set r_norm = beta to L2 norm of V[0] = s1 P1_inv r_0, and - return if small. */ - - *res_norm = r_norm = beta = SUNRsqrt(N_VDotProd(V[0], V[0])); - if (r_norm <= delta) - return(SPGMR_SUCCESS); - - /* Initialize rho to avoid compiler warning message */ - - rho = beta; - - /* Set xcor = 0. */ - - N_VConst(ZERO, xcor); - - - /* Begin outer iterations: up to (max_restarts + 1) attempts. */ - - for (ntries = 0; ntries <= max_restarts; ntries++) { - - /* Initialize the Hessenberg matrix Hes and Givens rotation - product. Normalize the initial vector V[0]. */ - - for (i = 0; i <= l_max; i++) - for (j = 0; j < l_max; j++) - Hes[i][j] = ZERO; - - rotation_product = ONE; - - N_VScale(ONE/r_norm, V[0], V[0]); - - /* Inner loop: generate Krylov sequence and Arnoldi basis. */ - - for (l = 0; l < l_max; l++) { - - (*nli)++; - - krydim = l_plus_1 = l + 1; - - /* Generate A-tilde V[l], where A-tilde = s1 P1_inv A P2_inv s2_inv. */ - - /* Apply right scaling: vtemp = s2_inv V[l]. */ - - if (scale2) N_VDiv(V[l], s2, vtemp); - else N_VScale(ONE, V[l], vtemp); - - /* Apply right preconditioner: vtemp = P2_inv s2_inv V[l]. */ - - if (preOnRight) { - N_VScale(ONE, vtemp, V[l_plus_1]); - ier = psolve(P_data, V[l_plus_1], vtemp, delta, PREC_RIGHT); - (*nps)++; - if (ier != 0) - return((ier < 0) ? SPGMR_PSOLVE_FAIL_UNREC : SPGMR_PSOLVE_FAIL_REC); - } - - /* Apply A: V[l+1] = A P2_inv s2_inv V[l]. */ - - ier = atimes(A_data, vtemp, V[l_plus_1] ); - if (ier != 0) - return((ier < 0) ? SPGMR_ATIMES_FAIL_UNREC : SPGMR_ATIMES_FAIL_REC); - - /* Apply left preconditioning: vtemp = P1_inv A P2_inv s2_inv V[l]. */ - - if (preOnLeft) { - ier = psolve(P_data, V[l_plus_1], vtemp, delta, PREC_LEFT); - (*nps)++; - if (ier != 0) - return((ier < 0) ? SPGMR_PSOLVE_FAIL_UNREC : SPGMR_PSOLVE_FAIL_REC); - } else { - N_VScale(ONE, V[l_plus_1], vtemp); - } - - /* Apply left scaling: V[l+1] = s1 P1_inv A P2_inv s2_inv V[l]. */ - - if (scale1) { - N_VProd(s1, vtemp, V[l_plus_1]); - } else { - N_VScale(ONE, vtemp, V[l_plus_1]); - } - - /* Orthogonalize V[l+1] against previous V[i]: V[l+1] = w_tilde. */ - - if (gstype == CLASSICAL_GS) { - if (ClassicalGS(V, Hes, l_plus_1, l_max, &(Hes[l_plus_1][l]), - vtemp, yg) != 0) - return(SPGMR_GS_FAIL); - } else { - if (ModifiedGS(V, Hes, l_plus_1, l_max, &(Hes[l_plus_1][l])) != 0) - return(SPGMR_GS_FAIL); - } - - /* Update the QR factorization of Hes. */ - - if(QRfact(krydim, Hes, givens, l) != 0 ) - return(SPGMR_QRFACT_FAIL); - - /* Update residual norm estimate; break if convergence test passes. */ - - rotation_product *= givens[2*l+1]; - *res_norm = rho = SUNRabs(rotation_product*r_norm); - - if (rho <= delta) { converged = SUNTRUE; break; } - - /* Normalize V[l+1] with norm value from the Gram-Schmidt routine. */ - - N_VScale(ONE/Hes[l_plus_1][l], V[l_plus_1], V[l_plus_1]); - } - - /* Inner loop is done. Compute the new correction vector xcor. */ - - /* Construct g, then solve for y. */ - - yg[0] = r_norm; - for (i = 1; i <= krydim; i++) yg[i]=ZERO; - if (QRsol(krydim, Hes, givens, yg) != 0) - return(SPGMR_QRSOL_FAIL); - - /* Add correction vector V_l y to xcor. */ - - for (k = 0; k < krydim; k++) - N_VLinearSum(yg[k], V[k], ONE, xcor, xcor); - - /* If converged, construct the final solution vector x and return. */ - - if (converged) { - - /* Apply right scaling and right precond.: vtemp = P2_inv s2_inv xcor. */ - - if (scale2) N_VDiv(xcor, s2, xcor); - if (preOnRight) { - ier = psolve(P_data, xcor, vtemp, delta, PREC_RIGHT); - (*nps)++; - if (ier != 0) - return((ier < 0) ? SPGMR_PSOLVE_FAIL_UNREC : SPGMR_PSOLVE_FAIL_REC); - } else { - N_VScale(ONE, xcor, vtemp); - } - - /* Add vtemp to initial x to get final solution x, and return */ - - N_VLinearSum(ONE, x, ONE, vtemp, x); - - return(SPGMR_SUCCESS); - } - - /* Not yet converged; if allowed, prepare for restart. */ - - if (ntries == max_restarts) break; - - /* Construct last column of Q in yg. */ - - s_product = ONE; - for (i = krydim; i > 0; i--) { - yg[i] = s_product*givens[2*i-2]; - s_product *= givens[2*i-1]; - } - yg[0] = s_product; - - /* Scale r_norm and yg. */ - r_norm *= s_product; - for (i = 0; i <= krydim; i++) - yg[i] *= r_norm; - r_norm = SUNRabs(r_norm); - - /* Multiply yg by V_(krydim+1) to get last residual vector; restart. */ - N_VScale(yg[0], V[0], V[0]); - for (k = 1; k <= krydim; k++) - N_VLinearSum(yg[k], V[k], ONE, V[0], V[0]); - - } - - /* Failed to converge, even after allowed restarts. - If the residual norm was reduced below its initial value, compute - and return x anyway. Otherwise return failure flag. */ - - if (rho < beta) { - - /* Apply right scaling and right precond.: vtemp = P2_inv s2_inv xcor. */ - - if (scale2) N_VDiv(xcor, s2, xcor); - if (preOnRight) { - ier = psolve(P_data, xcor, vtemp, delta, PREC_RIGHT); - (*nps)++; - if (ier != 0) - return((ier < 0) ? SPGMR_PSOLVE_FAIL_UNREC : SPGMR_PSOLVE_FAIL_REC); - } else { - N_VScale(ONE, xcor, vtemp); - } - - /* Add vtemp to initial x to get final solution x, and return. */ - - N_VLinearSum(ONE, x, ONE, vtemp, x); - - return(SPGMR_RES_REDUCED); - } - - return(SPGMR_CONV_FAIL); -} - -/* - * ----------------------------------------------------------------- - * Function : SpgmrFree - * ----------------------------------------------------------------- - */ - -void SpgmrFree(SpgmrMem mem) -{ - int i, l_max; - - if (mem == NULL) return; - - l_max = mem->l_max; - - for (i = 0; i <= l_max; i++) {free(mem->Hes[i]);} - free(mem->Hes); - free(mem->givens); - free(mem->yg); - - N_VDestroyVectorArray(mem->V, l_max+1); - N_VDestroy(mem->xcor); - N_VDestroy(mem->vtemp); - - free(mem); mem = NULL; -} diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_sptfqmr.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_sptfqmr.c deleted file mode 100644 index 7d330ce63..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_sptfqmr.c +++ /dev/null @@ -1,521 +0,0 @@ -/* - * ----------------------------------------------------------------- - * $Revision$ - * $Date$ - * ----------------------------------------------------------------- - * Programmer(s): Aaron Collier @ LLNL - * ----------------------------------------------------------------- - * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security - * and Southern Methodist University. - * All rights reserved. - * - * See the top-level LICENSE and NOTICE files for details. - * - * SPDX-License-Identifier: BSD-3-Clause - * SUNDIALS Copyright End - * ----------------------------------------------------------------- - * This is the implementation file for the scaled preconditioned - * Transpose-Free Quasi-Minimal Residual (SPTFQMR) linear solver. - * ----------------------------------------------------------------- - */ - -#include -#include - -#include -#include - -/* - * ----------------------------------------------------------------- - * private constants - * ----------------------------------------------------------------- - */ - -#define ZERO RCONST(0.0) -#define ONE RCONST(1.0) - -/* - * ----------------------------------------------------------------- - * Function : SptfqmrMalloc - * ----------------------------------------------------------------- - */ - -SptfqmrMem SptfqmrMalloc(int l_max, N_Vector vec_tmpl) -{ - SptfqmrMem mem; - N_Vector *r; - N_Vector q, d, v, p, u; - N_Vector r_star, vtemp1, vtemp2, vtemp3; - - /* Check the input parameters */ - if ((l_max <= 0) || (vec_tmpl == NULL)) return(NULL); - - /* Allocate space for vectors */ - - r_star = N_VClone(vec_tmpl); - if (r_star == NULL) return(NULL); - - q = N_VClone(vec_tmpl); - if (q == NULL) { - N_VDestroy(r_star); - return(NULL); - } - - d = N_VClone(vec_tmpl); - if (d == NULL) { - N_VDestroy(r_star); - N_VDestroy(q); - return(NULL); - } - - v = N_VClone(vec_tmpl); - if (v == NULL) { - N_VDestroy(r_star); - N_VDestroy(q); - N_VDestroy(d); - return(NULL); - } - - p = N_VClone(vec_tmpl); - if (p == NULL) { - N_VDestroy(r_star); - N_VDestroy(q); - N_VDestroy(d); - N_VDestroy(v); - return(NULL); - } - - r = N_VCloneVectorArray(2, vec_tmpl); - if (r == NULL) { - N_VDestroy(r_star); - N_VDestroy(q); - N_VDestroy(d); - N_VDestroy(v); - N_VDestroy(p); - return(NULL); - } - - u = N_VClone(vec_tmpl); - if (u == NULL) { - N_VDestroy(r_star); - N_VDestroy(q); - N_VDestroy(d); - N_VDestroy(v); - N_VDestroy(p); - N_VDestroyVectorArray(r, 2); - return(NULL); - } - - vtemp1 = N_VClone(vec_tmpl); - if (vtemp1 == NULL) { - N_VDestroy(r_star); - N_VDestroy(q); - N_VDestroy(d); - N_VDestroy(v); - N_VDestroy(p); - N_VDestroyVectorArray(r, 2); - N_VDestroy(u); - return(NULL); - } - - vtemp2 = N_VClone(vec_tmpl); - if (vtemp2 == NULL) { - N_VDestroy(r_star); - N_VDestroy(q); - N_VDestroy(d); - N_VDestroy(v); - N_VDestroy(p); - N_VDestroyVectorArray(r, 2); - N_VDestroy(u); - N_VDestroy(vtemp1); - return(NULL); - } - - vtemp3 = N_VClone(vec_tmpl); - if (vtemp3 == NULL) { - N_VDestroy(r_star); - N_VDestroy(q); - N_VDestroy(d); - N_VDestroy(v); - N_VDestroy(p); - N_VDestroyVectorArray(r, 2); - N_VDestroy(u); - N_VDestroy(vtemp1); - N_VDestroy(vtemp2); - return(NULL); - } - - /* Allocate memory for SptfqmrMemRec */ - mem = NULL; - mem = (SptfqmrMem) malloc(sizeof(SptfqmrMemRec)); - if (mem == NULL) { - N_VDestroy(r_star); - N_VDestroy(q); - N_VDestroy(d); - N_VDestroy(v); - N_VDestroy(p); - N_VDestroyVectorArray(r, 2); - N_VDestroy(u); - N_VDestroy(vtemp1); - N_VDestroy(vtemp2); - N_VDestroy(vtemp3); - return(NULL); - } - - /* Intialize SptfqmrMemRec data structure */ - mem->l_max = l_max; - mem->r_star = r_star; - mem->q = q; - mem->d = d; - mem->v = v; - mem->p = p; - mem->r = r; - mem->u = u; - mem->vtemp1 = vtemp1; - mem->vtemp2 = vtemp2; - mem->vtemp3 = vtemp3; - - /* Return pointer to SPTFQMR memory block */ - return(mem); -} - -#define l_max (mem->l_max) -#define r_star (mem->r_star) -#define q_ (mem->q) -#define d_ (mem->d) -#define v_ (mem->v) -#define p_ (mem->p) -#define r_ (mem->r) -#define u_ (mem->u) -#define vtemp1 (mem->vtemp1) -#define vtemp2 (mem->vtemp2) -#define vtemp3 (mem->vtemp3) - -/* - * ----------------------------------------------------------------- - * Function : SptfqmrSolve - * ----------------------------------------------------------------- - */ - -int SptfqmrSolve(SptfqmrMem mem, void *A_data, N_Vector x, N_Vector b, - int pretype, realtype delta, void *P_data, N_Vector sx, - N_Vector sb, ATimesFn atimes, PSolveFn psolve, - realtype *res_norm, int *nli, int *nps) -{ - realtype alpha, tau, eta, beta, c, sigma, v_bar, omega; - realtype rho[2]; - realtype r_init_norm, r_curr_norm; - realtype temp_val; - booleantype preOnLeft, preOnRight, scale_x, scale_b, converged; - booleantype b_ok; - int n, m, ier; - - /* Exit immediately if memory pointer is NULL */ - if (mem == NULL) return(SPTFQMR_MEM_NULL); - - temp_val = r_curr_norm = -ONE; /* Initialize to avoid compiler warnings */ - - *nli = *nps = 0; /* Initialize counters */ - converged = SUNFALSE; /* Initialize convergence flag */ - b_ok = SUNFALSE; - - if ((pretype != PREC_LEFT) && - (pretype != PREC_RIGHT) && - (pretype != PREC_BOTH)) pretype = PREC_NONE; - - preOnLeft = ((pretype == PREC_BOTH) || (pretype == PREC_LEFT)); - preOnRight = ((pretype == PREC_BOTH) || (pretype == PREC_RIGHT)); - - scale_x = (sx != NULL); - scale_b = (sb != NULL); - - /* Set r_star to initial (unscaled) residual r_star = r_0 = b - A*x_0 */ - /* NOTE: if x == 0 then just set residual to b and continue */ - if (N_VDotProd(x, x) == ZERO) N_VScale(ONE, b, r_star); - else { - ier = atimes(A_data, x, r_star); - if (ier != 0) - return((ier < 0) ? SPTFQMR_ATIMES_FAIL_UNREC : SPTFQMR_ATIMES_FAIL_REC); - N_VLinearSum(ONE, b, -ONE, r_star, r_star); - } - - /* Apply left preconditioner and b-scaling to r_star (or really just r_0) */ - if (preOnLeft) { - ier = psolve(P_data, r_star, vtemp1, delta, PREC_LEFT); - (*nps)++; - if (ier != 0) - return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC); - } - else N_VScale(ONE, r_star, vtemp1); - if (scale_b) N_VProd(sb, vtemp1, r_star); - else N_VScale(ONE, vtemp1, r_star); - - /* Initialize rho[0] */ - /* NOTE: initialized here to reduce number of computations - avoid need - to compute r_star^T*r_star twice, and avoid needlessly squaring - values */ - rho[0] = N_VDotProd(r_star, r_star); - - /* Compute norm of initial residual (r_0) to see if we really need - to do anything */ - *res_norm = r_init_norm = SUNRsqrt(rho[0]); - if (r_init_norm <= delta) return(SPTFQMR_SUCCESS); - - /* Set v_ = A*r_0 (preconditioned and scaled) */ - if (scale_x) N_VDiv(r_star, sx, vtemp1); - else N_VScale(ONE, r_star, vtemp1); - if (preOnRight) { - N_VScale(ONE, vtemp1, v_); - ier = psolve(P_data, v_, vtemp1, delta, PREC_RIGHT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC); - } - ier = atimes(A_data, vtemp1, v_); - if (ier != 0) - return((ier < 0) ? SPTFQMR_ATIMES_FAIL_UNREC : SPTFQMR_ATIMES_FAIL_REC); - if (preOnLeft) { - ier = psolve(P_data, v_, vtemp1, delta, PREC_LEFT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC); - } - else N_VScale(ONE, v_, vtemp1); - if (scale_b) N_VProd(sb, vtemp1, v_); - else N_VScale(ONE, vtemp1, v_); - - /* Initialize remaining variables */ - N_VScale(ONE, r_star, r_[0]); - N_VScale(ONE, r_star, u_); - N_VScale(ONE, r_star, p_); - N_VConst(ZERO, d_); - - tau = r_init_norm; - v_bar = eta = ZERO; - - /* START outer loop */ - for (n = 0; n < l_max; ++n) { - - /* Increment linear iteration counter */ - (*nli)++; - - /* sigma = r_star^T*v_ */ - sigma = N_VDotProd(r_star, v_); - - /* alpha = rho[0]/sigma */ - alpha = rho[0]/sigma; - - /* q_ = u_-alpha*v_ */ - N_VLinearSum(ONE, u_, -alpha, v_, q_); - - /* r_[1] = r_[0]-alpha*A*(u_+q_) */ - N_VLinearSum(ONE, u_, ONE, q_, r_[1]); - if (scale_x) N_VDiv(r_[1], sx, r_[1]); - if (preOnRight) { - N_VScale(ONE, r_[1], vtemp1); - ier = psolve(P_data, vtemp1, r_[1], delta, PREC_RIGHT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC); - } - ier = atimes(A_data, r_[1], vtemp1); - if (ier != 0) - return((ier < 0) ? SPTFQMR_ATIMES_FAIL_UNREC : SPTFQMR_ATIMES_FAIL_REC); - if (preOnLeft) { - ier = psolve(P_data, vtemp1, r_[1], delta, PREC_LEFT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC); - } - else N_VScale(ONE, vtemp1, r_[1]); - if (scale_b) N_VProd(sb, r_[1], vtemp1); - else N_VScale(ONE, r_[1], vtemp1); - N_VLinearSum(ONE, r_[0], -alpha, vtemp1, r_[1]); - - /* START inner loop */ - for (m = 0; m < 2; ++m) { - - /* d_ = [*]+(v_bar^2*eta/alpha)*d_ */ - /* NOTES: - * (1) [*] = u_ if m == 0, and q_ if m == 1 - * (2) using temp_val reduces the number of required computations - * if the inner loop is executed twice - */ - if (m == 0) { - temp_val = SUNRsqrt(N_VDotProd(r_[1], r_[1])); - omega = SUNRsqrt(SUNRsqrt(N_VDotProd(r_[0], r_[0]))*temp_val); - N_VLinearSum(ONE, u_, SUNSQR(v_bar)*eta/alpha, d_, d_); - } - else { - omega = temp_val; - N_VLinearSum(ONE, q_, SUNSQR(v_bar)*eta/alpha, d_, d_); - } - - /* v_bar = omega/tau */ - v_bar = omega/tau; - - /* c = (1+v_bar^2)^(-1/2) */ - c = ONE / SUNRsqrt(ONE+SUNSQR(v_bar)); - - /* tau = tau*v_bar*c */ - tau = tau*v_bar*c; - - /* eta = c^2*alpha */ - eta = SUNSQR(c)*alpha; - - /* x = x+eta*d_ */ - N_VLinearSum(ONE, x, eta, d_, x); - - /* Check for convergence... */ - /* NOTE: just use approximation to norm of residual, if possible */ - *res_norm = r_curr_norm = tau*SUNRsqrt(m+1); - - /* Exit inner loop if iteration has converged based upon approximation - to norm of current residual */ - if (r_curr_norm <= delta) { - converged = SUNTRUE; - break; - } - - /* Decide if actual norm of residual vector should be computed */ - /* NOTES: - * (1) if r_curr_norm > delta, then check if actual residual norm - * is OK (recall we first compute an approximation) - * (2) if r_curr_norm >= r_init_norm and m == 1 and n == l_max, then - * compute actual residual norm to see if the iteration can be - * saved - * (3) the scaled and preconditioned right-hand side of the given - * linear system (denoted by b) is only computed once, and the - * result is stored in vtemp3 so it can be reused - reduces the - * number of psovles if using left preconditioning - */ - if ((r_curr_norm > delta) || - (r_curr_norm >= r_init_norm && m == 1 && n == l_max)) { - - /* Compute norm of residual ||b-A*x||_2 (preconditioned and scaled) */ - if (scale_x) N_VDiv(x, sx, vtemp1); - else N_VScale(ONE, x, vtemp1); - if (preOnRight) { - ier = psolve(P_data, vtemp1, vtemp2, delta, PREC_RIGHT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_UNREC); - N_VScale(ONE, vtemp2, vtemp1); - } - ier = atimes(A_data, vtemp1, vtemp2); - if (ier != 0) - return((ier < 0) ? SPTFQMR_ATIMES_FAIL_UNREC : SPTFQMR_ATIMES_FAIL_REC); - if (preOnLeft) { - ier = psolve(P_data, vtemp2, vtemp1, delta, PREC_LEFT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC); - } - else N_VScale(ONE, vtemp2, vtemp1); - if (scale_b) N_VProd(sb, vtemp1, vtemp2); - else N_VScale(ONE, vtemp1, vtemp2); - /* Only precondition and scale b once (result saved for reuse) */ - if (!b_ok) { - b_ok = SUNTRUE; - if (preOnLeft) { - ier = psolve(P_data, b, vtemp3, delta, PREC_LEFT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC); - } - else N_VScale(ONE, b, vtemp3); - if (scale_b) N_VProd(sb, vtemp3, vtemp3); - } - N_VLinearSum(ONE, vtemp3, -ONE, vtemp2, vtemp1); - *res_norm = r_curr_norm = SUNRsqrt(N_VDotProd(vtemp1, vtemp1)); - - /* Exit inner loop if inequality condition is satisfied - (meaning exit if we have converged) */ - if (r_curr_norm <= delta) { - converged = SUNTRUE; - break; - } - - } - - } /* END inner loop */ - - /* If converged, then exit outer loop as well */ - if (converged == SUNTRUE) break; - - /* rho[1] = r_star^T*r_[1] */ - rho[1] = N_VDotProd(r_star, r_[1]); - - /* beta = rho[1]/rho[0] */ - beta = rho[1]/rho[0]; - - /* u_ = r_[1]+beta*q_ */ - N_VLinearSum(ONE, r_[1], beta, q_, u_); - - /* p_ = u_+beta*(q_+beta*p_) */ - N_VLinearSum(beta, q_, SUNSQR(beta), p_, p_); - N_VLinearSum(ONE, u_, ONE, p_, p_); - - /* v_ = A*p_ */ - if (scale_x) N_VDiv(p_, sx, vtemp1); - else N_VScale(ONE, p_, vtemp1); - if (preOnRight) { - N_VScale(ONE, vtemp1, v_); - ier = psolve(P_data, v_, vtemp1, delta, PREC_RIGHT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC); - } - ier = atimes(A_data, vtemp1, v_); - if (ier != 0) - return((ier < 0) ? SPTFQMR_ATIMES_FAIL_UNREC : SPTFQMR_ATIMES_FAIL_REC); - if (preOnLeft) { - ier = psolve(P_data, v_, vtemp1, delta, PREC_LEFT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC); - } - else N_VScale(ONE, v_, vtemp1); - if (scale_b) N_VProd(sb, vtemp1, v_); - else N_VScale(ONE, vtemp1, v_); - - /* Shift variable values */ - /* NOTE: reduces storage requirements */ - N_VScale(ONE, r_[1], r_[0]); - rho[0] = rho[1]; - - } /* END outer loop */ - - /* Determine return value */ - /* If iteration converged or residual was reduced, then return current iterate (x) */ - if ((converged == SUNTRUE) || (r_curr_norm < r_init_norm)) { - if (scale_x) N_VDiv(x, sx, x); - if (preOnRight) { - ier = psolve(P_data, x, vtemp1, delta, PREC_RIGHT); - (*nps)++; - if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_UNREC); - N_VScale(ONE, vtemp1, x); - } - if (converged == SUNTRUE) return(SPTFQMR_SUCCESS); - else return(SPTFQMR_RES_REDUCED); - } - /* Otherwise, return error code */ - else return(SPTFQMR_CONV_FAIL); -} - -/* - * ----------------------------------------------------------------- - * Function : SptfqmrFree - * ----------------------------------------------------------------- - */ - -void SptfqmrFree(SptfqmrMem mem) -{ - - if (mem == NULL) return; - - N_VDestroy(r_star); - N_VDestroy(q_); - N_VDestroy(d_); - N_VDestroy(v_); - N_VDestroy(p_); - N_VDestroyVectorArray(r_, 2); - N_VDestroy(u_); - N_VDestroy(vtemp1); - N_VDestroy(vtemp2); - N_VDestroy(vtemp3); - - free(mem); mem = NULL; -} diff --git a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_version.c b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_version.c index 5192f4308..3012d67be 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_version.c +++ b/deps/AMICI/ThirdParty/sundials/src/sundials/sundials_version.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/CMakeLists.txt index 965189e32..c443c55c9 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/CMakeLists.txt @@ -2,7 +2,7 @@ # Programmer(s): Cody J. Balos @ LLNL # ------------------------------------------------------------------------------ # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -29,6 +29,10 @@ if(KLU_ENABLE AND KLU_FOUND) add_subdirectory(klu) endif(KLU_ENABLE AND KLU_FOUND) +if(SUNDIALS_SUPERLUDIST) + add_subdirectory(superludist) +endif() + if(SUPERLUMT_ENABLE AND SUPERLUMT_FOUND) add_subdirectory(superlumt) endif(SUPERLUMT_ENABLE AND SUPERLUMT_FOUND) @@ -37,3 +41,9 @@ if(LAPACK_ENABLE AND LAPACK_FOUND) add_subdirectory(lapackband) add_subdirectory(lapackdense) endif(LAPACK_ENABLE AND LAPACK_FOUND) + +if(CUDA_ENABLE AND CMAKE_CUDA_COMPILER) + if(SUNDIALS_INDEX_SIZE MATCHES "32") + add_subdirectory(cusolversp) + endif() +endif(CUDA_ENABLE AND CMAKE_CUDA_COMPILER) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/CMakeLists.txt index 75a8f1415..3fdc8007d 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,95 +12,130 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the band SUNLinearSolver library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNLINSOL_BAND\n\")") - -# Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF(F90_FOUND AND F2003_INTERFACE_ENABLE) +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_BAND\n\")") -# Add variable sunlinsolband_SOURCES with the sources for the SUNLINSOLBAND lib -SET(sunlinsolband_SOURCES sunlinsol_band.c) +# Source files for the library +set(sunlinsolband_SOURCES sunlinsol_band.c) -# Add variable shared_SOURCES with the common SUNDIALS sources which will -# also be included in the SUNLINSOLBAND library -SET(shared_SOURCES +# Common SUNDIALS sources included in the library +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c - ${sundials_SOURCE_DIR}/src/sundials/sundials_band.c - ) + ${sundials_SOURCE_DIR}/src/sundials/sundials_band.c) -# Add variable sunlinsolband_HEADERS with the exported SUNLINSOLBAND header files -SET(sunlinsolband_HEADERS - ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_band.h - ) - -# Add source directory to include directories -INCLUDE_DIRECTORIES(.) - -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Exported header files +set(sunlinsolband_HEADERS + ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_band.h) # Rules for building and installing the static library: -# - Add the build target for the SUNLINSOLBAND library +# - Add the build target for the library # - Set the library name and make sure it is not deleted -# - Install the SUNLINSOLBAND library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunlinsolband_static STATIC ${sunlinsolband_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunlinsolband_static - PROPERTIES OUTPUT_NAME sundials_sunlinsolband CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunlinsolband_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +# - Install the library +if(BUILD_STATIC_LIBS) + + add_library(sundials_sunlinsolband_static + STATIC ${sunlinsolband_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolband_static + PROPERTIES + OUTPUT_NAME sundials_sunlinsolband + CLEAN_DIRECT_OUTPUT 1) + + # depends on sunmatrixband + target_link_libraries(sundials_sunlinsolband_static + PUBLIC sundials_sunmatrixband_static) + + target_compile_definitions(sundials_sunlinsolband_static + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolband_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: -# - Add the build target for the SUNLINSOLBAND library +# - Add the build target for the library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries -# - Install the SUNLINSOLBAND library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunlinsolband_shared SHARED ${sunlinsolband_SOURCES} ${shared_SOURCES}) - - # sunlinsolband depends on sunmatrixband - TARGET_LINK_LIBRARIES(sundials_sunlinsolband_shared sundials_sunmatrixband_shared) - - SET_TARGET_PROPERTIES(sundials_sunlinsolband_shared - PROPERTIES OUTPUT_NAME sundials_sunlinsolband CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunlinsolband_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_sunlinsolband_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) - -# Install the SUNLINSOLBAND header files -INSTALL(FILES ${sunlinsolband_HEADERS} DESTINATION include/sunlinsol) - -# If FCMIX is enabled, build and install the FSUNLINSOLBAND library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunlinsolband_SOURCES fsunlinsol_band.c) - - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunlinsolband_static STATIC ${fsunlinsolband_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunlinsolband_static - PROPERTIES OUTPUT_NAME sundials_fsunlinsolband CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunlinsolband_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) - - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunlinsolband_shared ${fsunlinsolband_SOURCES}) - - # fsunlinsolband depends on fnvecserial, fsunmatrixband, sunlinsolband - TARGET_LINK_LIBRARIES(sundials_fsunlinsolband_shared +# - Install the library +if(BUILD_SHARED_LIBS) + + add_library(sundials_sunlinsolband_shared + SHARED ${sunlinsolband_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolband_shared + PROPERTIES + OUTPUT_NAME sundials_sunlinsolband + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + + # depends on sunmatrixband + target_link_libraries(sundials_sunlinsolband_shared + PUBLIC sundials_sunmatrixband_shared) + + target_compile_definitions(sundials_sunlinsolband_shared + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolband_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_SHARED_LIBS) + +# Install the header files +install(FILES ${sunlinsolband_HEADERS} DESTINATION include/sunlinsol) + +# +message(STATUS "Added SUNLINSOL_BAND module") + +# If FCMIX is enabled, build and install the Fortran77 library +if(F77_INTERFACE_ENABLE AND F77_FOUND) + + set(fsunlinsolband_SOURCES fsunlinsol_band.c) + + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunlinsolband_static + STATIC ${fsunlinsolband_SOURCES}) + set_target_properties(sundials_fsunlinsolband_static + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolband + CLEAN_DIRECT_OUTPUT 1) + # depends on fnvecserial, fsunmatrixband, sunlinsolband + target_link_libraries(sundials_fsunlinsolband_static + PUBLIC + sundials_fnvecserial_static + sundials_fsunmatrixband_static + sundials_sunlinsolband_static) + install(TARGETS sundials_fsunlinsolband_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) + + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunlinsolband_shared + SHARED ${fsunlinsolband_SOURCES}) + set_target_properties(sundials_fsunlinsolband_shared + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolband + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + # depends on fnvecserial, fsunmatrixband, sunlinsolband + target_link_libraries(sundials_fsunlinsolband_shared + PUBLIC sundials_fnvecserial_shared sundials_fsunmatrixband_shared sundials_sunlinsolband_shared) + install(TARGETS sundials_fsunlinsolband_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) - SET_TARGET_PROPERTIES(sundials_fsunlinsolband_shared - PROPERTIES OUTPUT_NAME sundials_fsunlinsolband CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunlinsolband_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_fsunlinsolband_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + # + message(STATUS "Added SUNLINSOL_BAND F77 interface") -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(F77_INTERFACE_ENABLE AND F77_FOUND) -# -MESSAGE(STATUS "Added SUNLINSOL_BAND module") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/F90/fsunlinsol_band.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/F90/fsunlinsol_band.f90 deleted file mode 100644 index e5f5c8ca2..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/F90/fsunlinsol_band.f90 +++ /dev/null @@ -1,101 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): Cody J. Balos @ LLNL -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS banded matrix using the ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fsunlinsol_band_mod - - !======= Interfaces ========= - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - type(c_ptr) function FSUNLinSol_Band(y, A) & - bind(C,name='SUNLinSol_Band') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: y - type(c_ptr), value :: A - end function FSUNLinSol_Band - - ! ================================================================= - ! Destructors - ! ================================================================= - - subroutine FSUNLinSolFree_Band(LS) & - bind(C,name='SUNLinSolFree_Band') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end subroutine FSUNLinSolFree_Band - - ! ================================================================= - ! Operations - ! ================================================================= - - integer(c_int) function FSUNLinSolGetType_Band(LS) & - bind(C,name='SUNLinSolGetType_Band') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolGetType_Band - - integer(c_int) function FSUNLinSolInitialize_Band(LS) & - bind(C,name='SUNLinSolInitialize_Band') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolInitialize_Band - - integer(c_int) function FSUNLinSolSetup_Band(LS, A) & - bind(C,name='SUNLinSolSetup_Band') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - end function FSUNLinSolSetup_Band - - integer(c_int) function FSUNLinSolSolve_Band(LS, A, x, b, tol) & - bind(C,name='SUNLinSolSolve_Band') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - type(c_ptr), value :: x - type(c_ptr), value :: b - real(c_double), value :: tol - end function FSUNLinSolSolve_Band - - integer(c_long) function FSUNLinSolLastFlag_Band(LS) & - bind(C,name='SUNLinSolLastFlag_Band') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolLastFlag_Band - - integer(c_int) function FSUNLinSolSpace_Band(LS, lenrwLS, leniwLS) & - bind(C,name='SUNLinSolSpace_Band') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_long) :: lenrwLS - integer(c_long) :: leniwLS - end function FSUNLinSolSpace_Band - - end interface - -end module fsunlinsol_band_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fmod/CMakeLists.txt similarity index 68% rename from deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/F90/CMakeLists.txt rename to deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fmod/CMakeLists.txt index 35ba5bbd9..11516d8b4 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/F90/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fmod/CMakeLists.txt @@ -1,8 +1,8 @@ # ---------------------------------------------------------------------- -# Programmer: Cody J. Balos @ LLNL +# Programmer(s): Cody J. Balos @ LLNL # ---------------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,22 +12,27 @@ # SUNDIALS Copyright End # ---------------------------------------------------------------------- # CMakeLists.txt file for the F2003 band SUNLinearSolver object library +# ---------------------------------------------------------------------- -set(sunlinsolband_SOURCES fsunlinsol_band.f90) +set(sunlinsolband_SOURCES fsunlinsol_band_mod.f90 fsunlinsol_band_mod.c) if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolband_mod_static STATIC + sundials_add_f2003_interface_library(sundials_fsunlinsolband_mod_static STATIC_OBJECT ${sunlinsolband_SOURCES} ) + add_dependencies(sundials_fsunlinsolband_mod_static_obj sundials_fgeneric_static_obj) + target_link_libraries(sundials_fsunlinsolband_mod_static PUBLIC sundials_fsunmatrixband_mod_static) set_target_properties(sundials_fsunlinsolband_mod_static PROPERTIES OUTPUT_NAME sundials_fsunlinsolband_mod CLEAN_DIRECT_OUTPUT 1) install(TARGETS sundials_fsunlinsolband_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif(BUILD_STATIC_LIBS) if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolband_mod_shared SHARED + sundials_add_f2003_interface_library(sundials_fsunlinsolband_mod_shared SHARED_OBJECT ${sunlinsolband_SOURCES} ) + add_dependencies(sundials_fsunlinsolband_mod_shared_obj sundials_fgeneric_shared_obj) + target_link_libraries(sundials_fsunlinsolband_mod_shared PUBLIC sundials_fsunmatrixband_mod_shared) set_target_properties(sundials_fsunlinsolband_mod_shared PROPERTIES OUTPUT_NAME sundials_fsunlinsolband_mod CLEAN_DIRECT_OUTPUT 1) set_target_properties(sundials_fsunlinsolband_mod_shared diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fmod/fsunlinsol_band_mod.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fmod/fsunlinsol_band_mod.c new file mode 100644 index 000000000..7216a68d0 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fmod/fsunlinsol_band_mod.c @@ -0,0 +1,349 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_linearsolver.h" + + +#include "sunlinsol/sunlinsol_band.h" + +SWIGEXPORT SUNLinearSolver _wrap_FSUNLinSol_Band(N_Vector farg1, SUNMatrix farg2) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (SUNLinearSolver)SUNLinSol_Band(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT SUNLinearSolver _wrap_FSUNBandLinearSolver(N_Vector farg1, SUNMatrix farg2) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (SUNLinearSolver)SUNBandLinearSolver(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetType_Band(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_Type result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_Type)SUNLinSolGetType_Band(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetID_Band(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_ID result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_ID)SUNLinSolGetID_Band(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolInitialize_Band(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolInitialize_Band(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetup_Band(SUNLinearSolver farg1, SUNMatrix farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNLinSolSetup_Band(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSolve_Band(SUNLinearSolver farg1, SUNMatrix farg2, N_Vector farg3, N_Vector farg4, double const *farg5) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype arg5 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype)(*farg5); + result = (int)SUNLinSolSolve_Band(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNLinSolLastFlag_Band(SUNLinearSolver farg1) { + int64_t fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + sunindextype result; + + arg1 = (SUNLinearSolver)(farg1); + result = SUNLinSolLastFlag_Band(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSpace_Band(SUNLinearSolver farg1, long *farg2, long *farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNLinSolSpace_Band(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolFree_Band(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolFree_Band(arg1); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fmod/fsunlinsol_band_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fmod/fsunlinsol_band_mod.f90 new file mode 100644 index 000000000..f63145295 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fmod/fsunlinsol_band_mod.f90 @@ -0,0 +1,299 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunlinsol_band_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_linearsolver_mod + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FSUNLinSol_Band + public :: FSUNBandLinearSolver + public :: FSUNLinSolGetType_Band + public :: FSUNLinSolGetID_Band + public :: FSUNLinSolInitialize_Band + public :: FSUNLinSolSetup_Band + public :: FSUNLinSolSolve_Band + public :: FSUNLinSolLastFlag_Band + public :: FSUNLinSolSpace_Band + public :: FSUNLinSolFree_Band + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNLinSol_Band(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FSUNBandLinearSolver(farg1, farg2) & +bind(C, name="_wrap_FSUNBandLinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSolGetType_Band(farg1) & +bind(C, name="_wrap_FSUNLinSolGetType_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetID_Band(farg1) & +bind(C, name="_wrap_FSUNLinSolGetID_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolInitialize_Band(farg1) & +bind(C, name="_wrap_FSUNLinSolInitialize_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetup_Band(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSolSetup_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSolve_Band(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FSUNLinSolSolve_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolLastFlag_Band(farg1) & +bind(C, name="_wrap_FSUNLinSolLastFlag_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNLinSolSpace_Band(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSpace_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolFree_Band(farg1) & +bind(C, name="_wrap_FSUNLinSolFree_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNLinSol_Band(y, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(y) +farg2 = c_loc(a) +fresult = swigc_FSUNLinSol_Band(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNBandLinearSolver(y, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(y) +farg2 = c_loc(a) +fresult = swigc_FSUNBandLinearSolver(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSolGetType_Band(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_Type) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetType_Band(farg1) +swig_result = fresult +end function + +function FSUNLinSolGetID_Band(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_ID) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetID_Band(farg1) +swig_result = fresult +end function + +function FSUNLinSolInitialize_Band(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolInitialize_Band(farg1) +swig_result = fresult +end function + +function FSUNLinSolSetup_Band(s, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(s) +farg2 = c_loc(a) +fresult = swigc_FSUNLinSolSetup_Band(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolSolve_Band(s, a, x, b, tol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: b +real(C_DOUBLE), intent(in) :: tol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +real(C_DOUBLE) :: farg5 + +farg1 = c_loc(s) +farg2 = c_loc(a) +farg3 = c_loc(x) +farg4 = c_loc(b) +farg5 = tol +fresult = swigc_FSUNLinSolSolve_Band(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FSUNLinSolLastFlag_Band(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolLastFlag_Band(farg1) +swig_result = fresult +end function + +function FSUNLinSolSpace_Band(s, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FSUNLinSolSpace_Band(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolFree_Band(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolFree_Band(farg1) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.c index 13170c45d..8e5dba864 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.h b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.h index c32cee61c..f07a2451e 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/sunlinsol_band.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/sunlinsol_band.c index 53853288a..86c64cac1 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/sunlinsol_band.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/band/sunlinsol_band.c @@ -1,9 +1,8 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -12,10 +11,9 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the band implementation of + * This is the implementation file for the band implementation of * the SUNLINSOL package. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include @@ -27,13 +25,9 @@ #define ONE RCONST(1.0) #define ROW(i,j,smu) (i-j+smu) - -/* Private function prototypes */ -sunindextype GlobalVectorLength_BandLS(N_Vector y); - /* * ----------------------------------------------------------------- - * Band solver structure accessibility macros: + * Band solver structure accessibility macros: * ----------------------------------------------------------------- */ @@ -63,73 +57,60 @@ SUNLinearSolver SUNBandLinearSolver(N_Vector y, SUNMatrix A) SUNLinearSolver SUNLinSol_Band(N_Vector y, SUNMatrix A) { SUNLinearSolver S; - SUNLinearSolver_Ops ops; SUNLinearSolverContent_Band content; - sunindextype MatrixRows, VecLength; - + sunindextype MatrixRows; + /* Check compatibility with supplied SUNMatrix and N_Vector */ - if (SUNMatGetID(A) != SUNMATRIX_BAND) - return(NULL); - if (SUNBandMatrix_Rows(A) != SUNBandMatrix_Columns(A)) - return(NULL); - MatrixRows = SUNBandMatrix_Rows(A); + if (SUNMatGetID(A) != SUNMATRIX_BAND) return(NULL); + + if (SUNBandMatrix_Rows(A) != SUNBandMatrix_Columns(A)) return(NULL); + if ( (N_VGetVectorID(y) != SUNDIALS_NVEC_SERIAL) && (N_VGetVectorID(y) != SUNDIALS_NVEC_OPENMP) && (N_VGetVectorID(y) != SUNDIALS_NVEC_PTHREADS) ) return(NULL); /* Check that A has appropriate storage upper bandwidth for factorization */ + MatrixRows = SUNBandMatrix_Rows(A); + if (SUNBandMatrix_StoredUpperBandwidth(A) < - SUNMIN(MatrixRows-1, SUNBandMatrix_LowerBandwidth(A)+SUNBandMatrix_UpperBandwidth(A))) + SUNMIN(MatrixRows-1, + SUNBandMatrix_LowerBandwidth(A)+SUNBandMatrix_UpperBandwidth(A))) return(NULL); - /* optimally this function would be replaced with a generic N_Vector routine */ - VecLength = GlobalVectorLength_BandLS(y); - if (MatrixRows != VecLength) - return(NULL); - - /* Create linear solver */ + if (MatrixRows != N_VGetLength(y)) return(NULL); + + /* Create an empty linear solver */ S = NULL; - S = (SUNLinearSolver) malloc(sizeof *S); + S = SUNLinSolNewEmpty(); if (S == NULL) return(NULL); - - /* Create linear solver operation structure */ - ops = NULL; - ops = (SUNLinearSolver_Ops) malloc(sizeof(struct _generic_SUNLinearSolver_Ops)); - if (ops == NULL) { free(S); return(NULL); } /* Attach operations */ - ops->gettype = SUNLinSolGetType_Band; - ops->initialize = SUNLinSolInitialize_Band; - ops->setup = SUNLinSolSetup_Band; - ops->solve = SUNLinSolSolve_Band; - ops->lastflag = SUNLinSolLastFlag_Band; - ops->space = SUNLinSolSpace_Band; - ops->free = SUNLinSolFree_Band; - ops->setatimes = NULL; - ops->setpreconditioner = NULL; - ops->setscalingvectors = NULL; - ops->numiters = NULL; - ops->resnorm = NULL; - ops->resid = NULL; + S->ops->gettype = SUNLinSolGetType_Band; + S->ops->getid = SUNLinSolGetID_Band; + S->ops->initialize = SUNLinSolInitialize_Band; + S->ops->setup = SUNLinSolSetup_Band; + S->ops->solve = SUNLinSolSolve_Band; + S->ops->lastflag = SUNLinSolLastFlag_Band; + S->ops->space = SUNLinSolSpace_Band; + S->ops->free = SUNLinSolFree_Band; /* Create content */ content = NULL; - content = (SUNLinearSolverContent_Band) malloc(sizeof(struct _SUNLinearSolverContent_Band)); - if (content == NULL) { free(ops); free(S); return(NULL); } + content = (SUNLinearSolverContent_Band) malloc(sizeof *content); + if (content == NULL) { SUNLinSolFree(S); return(NULL); } + + /* Attach content */ + S->content = content; /* Fill content */ - content->N = MatrixRows; + content->N = MatrixRows; content->last_flag = 0; - content->pivots = NULL; + content->pivots = NULL; + + /* Allocate content */ content->pivots = (sunindextype *) malloc(MatrixRows * sizeof(sunindextype)); - if (content->pivots == NULL) { - free(content); free(ops); free(S); return(NULL); - } - - /* Attach content and ops */ - S->content = content; - S->ops = ops; + if (content->pivots == NULL) { SUNLinSolFree(S); return(NULL); } return(S); } @@ -145,11 +126,16 @@ SUNLinearSolver_Type SUNLinSolGetType_Band(SUNLinearSolver S) return(SUNLINEARSOLVER_DIRECT); } +SUNLinearSolver_ID SUNLinSolGetID_Band(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_BAND); +} + int SUNLinSolInitialize_Band(SUNLinearSolver S) { /* all solver-specific memory has already been allocated */ LASTFLAG(S) = SUNLS_SUCCESS; - return(LASTFLAG(S)); + return(SUNLS_SUCCESS); } int SUNLinSolSetup_Band(SUNLinearSolver S, SUNMatrix A) @@ -158,15 +144,15 @@ int SUNLinSolSetup_Band(SUNLinearSolver S, SUNMatrix A) sunindextype *pivots; /* check for valid inputs */ - if ( (A == NULL) || (S == NULL) ) + if ( (A == NULL) || (S == NULL) ) return(SUNLS_MEM_NULL); - + /* Ensure that A is a band matrix */ if (SUNMatGetID(A) != SUNMATRIX_BAND) { LASTFLAG(S) = SUNLS_ILL_INPUT; - return(LASTFLAG(S)); + return(SUNLS_ILL_INPUT); } - + /* access data pointers (return with failure on NULL) */ A_cols = NULL; pivots = NULL; @@ -174,35 +160,35 @@ int SUNLinSolSetup_Band(SUNLinearSolver S, SUNMatrix A) pivots = PIVOTS(S); if ( (A_cols == NULL) || (pivots == NULL) ) { LASTFLAG(S) = SUNLS_MEM_FAIL; - return(LASTFLAG(S)); + return(SUNLS_MEM_FAIL); } /* ensure that storage upper bandwidth is sufficient for fill-in */ if (SM_SUBAND_B(A) < SUNMIN(SM_COLUMNS_B(A)-1, SM_UBAND_B(A) + SM_LBAND_B(A))) { LASTFLAG(S) = SUNLS_MEM_FAIL; - return(LASTFLAG(S)); + return(SUNLS_MEM_FAIL); } - + /* perform LU factorization of input matrix */ LASTFLAG(S) = bandGBTRF(A_cols, SM_COLUMNS_B(A), SM_UBAND_B(A), - SM_LBAND_B(A), SM_SUBAND_B(A), pivots); - + SM_LBAND_B(A), SM_SUBAND_B(A), pivots); + /* store error flag (if nonzero, that row encountered zero-valued pivod) */ if (LASTFLAG(S) > 0) return(SUNLS_LUFACT_FAIL); return(SUNLS_SUCCESS); } -int SUNLinSolSolve_Band(SUNLinearSolver S, SUNMatrix A, N_Vector x, +int SUNLinSolSolve_Band(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype tol) { realtype **A_cols, *xdata; sunindextype *pivots; - + /* check for valid inputs */ - if ( (A == NULL) || (S == NULL) || (x == NULL) || (b == NULL) ) + if ( (A == NULL) || (S == NULL) || (x == NULL) || (b == NULL) ) return(SUNLS_MEM_NULL); - + /* copy b into x */ N_VScale(ONE, b, x); @@ -215,24 +201,25 @@ int SUNLinSolSolve_Band(SUNLinearSolver S, SUNMatrix A, N_Vector x, pivots = PIVOTS(S); if ( (A_cols == NULL) || (xdata == NULL) || (pivots == NULL) ) { LASTFLAG(S) = SUNLS_MEM_FAIL; - return(LASTFLAG(S)); + return(SUNLS_MEM_FAIL); } /* solve using LU factors */ - bandGBTRS(A_cols, SM_COLUMNS_B(A), SM_SUBAND_B(A), + bandGBTRS(A_cols, SM_COLUMNS_B(A), SM_SUBAND_B(A), SM_LBAND_B(A), pivots, xdata); LASTFLAG(S) = SUNLS_SUCCESS; - return(LASTFLAG(S)); + return(SUNLS_SUCCESS); } -long int SUNLinSolLastFlag_Band(SUNLinearSolver S) +sunindextype SUNLinSolLastFlag_Band(SUNLinearSolver S) { /* return the stored 'last_flag' value */ + if (S == NULL) return(-1); return(LASTFLAG(S)); } -int SUNLinSolSpace_Band(SUNLinearSolver S, - long int *lenrwLS, +int SUNLinSolSpace_Band(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS) { *leniwLS = 2 + BAND_CONTENT(S)->N; @@ -243,8 +230,7 @@ int SUNLinSolSpace_Band(SUNLinearSolver S, int SUNLinSolFree_Band(SUNLinearSolver S) { /* return if S is already free */ - if (S == NULL) - return(SUNLS_SUCCESS); + if (S == NULL) return(SUNLS_SUCCESS); /* delete items from contents, then delete generic structure */ if (S->content) { @@ -252,35 +238,13 @@ int SUNLinSolFree_Band(SUNLinearSolver S) free(PIVOTS(S)); PIVOTS(S) = NULL; } - free(S->content); + free(S->content); S->content = NULL; } if (S->ops) { - free(S->ops); + free(S->ops); S->ops = NULL; } free(S); S = NULL; return(SUNLS_SUCCESS); } - -/* - * ----------------------------------------------------------------- - * private functions - * ----------------------------------------------------------------- - */ - -/* Inefficient kludge for determining the number of entries in a N_Vector - object (replace if such a routine is ever added to the N_Vector API). - - Returns "-1" on an error. */ -sunindextype GlobalVectorLength_BandLS(N_Vector y) -{ - realtype len; - N_Vector tmp = NULL; - tmp = N_VClone(y); - if (tmp == NULL) return(-1); - N_VConst(ONE, tmp); - len = N_VDotProd(tmp, tmp); - N_VDestroy(tmp); - return( (sunindextype) len ); -} diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/cusolversp/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/cusolversp/CMakeLists.txt new file mode 100644 index 000000000..c6f2857ff --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/cusolversp/CMakeLists.txt @@ -0,0 +1,75 @@ +# --------------------------------------------------------------- +# Programmer(s): Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the cuda cuSolverSp SUNLinearSolver +# --------------------------------------------------------------- + +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_CUSOLVERSP\n\")") + +# Add variable cusolversp_SOURCES with the sources for the cusolversp lib +set(cusolversp_SOURCES sunlinsol_cusolversp_batchqr.cu) + +# Add variable shared_SOURCES with the common SUNDIALS sources which will +# also be included in the NVECCUDA library +set(shared_SOURCES + ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c + ) + +# Add variable cusolversp_HEADERS with the exported cusolversp header files +set(cusolversp_HEADERS sunlinsol_cusolversp_batchqr.h) +add_prefix(${sundials_SOURCE_DIR}/include/sunlinsol/ cusolversp_HEADERS) + +# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY +add_definitions(-DBUILD_SUNDIALS_LIBRARY) + +if(BUILD_STATIC_LIBS) + add_library(sundials_sunlinsolcusolversp_static STATIC ${cusolversp_SOURCES} ${shared_SOURCES}) + target_link_libraries(sundials_sunlinsolcusolversp_static + PUBLIC + sundials_nveccuda_static + sundials_sunmatrixcusparse_static + ${CUDA_cusolver_LIBRARY} + PRIVATE + ${CUDA_cusparse_LIBRARY}) + target_include_directories(sundials_sunlinsolcusolversp_static + PRIVATE . ${sundials_SOURCE_DIR}/src/sundials) + set_target_properties(sundials_sunlinsolcusolversp_static PROPERTIES + OUTPUT_NAME sundials_sunlinsolcusolversp + CLEAN_DIRECT_OUTPUT 1) + install(TARGETS sundials_sunlinsolcusolversp_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_STATIC_LIBS) + +if(BUILD_SHARED_LIBS) + add_library(sundials_sunlinsolcusolversp_shared SHARED ${cusolversp_SOURCES} ${shared_SOURCES}) + target_link_libraries(sundials_sunlinsolcusolversp_shared + PUBLIC + sundials_nveccuda_shared + sundials_sunmatrixcusparse_shared + ${CUDA_cusolver_LIBRARY} + PRIVATE + ${CUDA_cusparse_LIBRARY}) + target_include_directories(sundials_sunlinsolcusolversp_shared + PRIVATE . ${sundials_SOURCE_DIR}/src/sundials) + set_target_properties(sundials_sunlinsolcusolversp_shared PROPERTIES + OUTPUT_NAME sundials_sunlinsolcusolversp + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + install(TARGETS sundials_sunlinsolcusolversp_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_SHARED_LIBS) + +# Install the CUDA NVector header files +install(FILES ${cusolversp_HEADERS} DESTINATION include/sunlinsol) + +# +message(STATUS "Added SUNLINSOL_CUSOLVERSP module") diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/cusolversp/sunlinsol_cusolversp_batchqr.cu b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/cusolversp/sunlinsol_cusolversp_batchqr.cu new file mode 100644 index 000000000..905907fa4 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/cusolversp/sunlinsol_cusolversp_batchqr.cu @@ -0,0 +1,353 @@ +/* ---------------------------------------------------------------------------- + * Programmer(s): Cody J. Balos @ LLNL + * ---------------------------------------------------------------------------- + * Based on work by Donald Wilcox @ LBNL + * ---------------------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ---------------------------------------------------------------------------- + * Implementation file for cuSolverSp batched QR SUNLinearSolver interface. + * ----------------------------------------------------------------------------*/ + +#include +#include + +#include +#include +#include + +#include "sundials_cuda.h" +#include "sundials_debug.h" + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#define TWO RCONST(2.0) + +/* macros for handling the different function names based on precision */ +#if defined(SUNDIALS_DOUBLE_PRECISION) +#define _cusolverSpXcsrqrBufferInfoBatched cusolverSpDcsrqrBufferInfoBatched +#define _cusolverSpXcsrqrsvBatched cusolverSpDcsrqrsvBatched +#elif defined(SUNDIALS_SINGLE_PRECISION) +#define _cusolverSpXcsrqrBufferInfoBatched cusolverSpScsrqrBufferInfoBatched +#define _cusolverSpXcsrqrsvBatched cusolverSpScsrqrsvBatched +#endif + +/* + * ----------------------------------------------------------------- + * cuSolverSp solver structure accessibility macros: + * ----------------------------------------------------------------- + */ + +#define SUN_CUSP_CONTENT(S) ( (SUNLinearSolverContent_cuSolverSp_batchQR)(S->content) ) +#define SUN_CUSP_QRWORKSPACE(S) ( SUN_CUSP_CONTENT(S)->workspace ) +#define SUN_CUSP_FIRSTFACTORIZE(S) ( SUN_CUSP_CONTENT(S)->first_factorize ) +#define SUN_CUSP_LASTFLAG(S) ( SUN_CUSP_CONTENT(S)->last_flag ) +#define SUN_CUSOL_HANDLE(S) ( SUN_CUSP_CONTENT(S)->cusolver_handle ) +#define SUN_CUSP_DESC(S) ( SUN_CUSP_CONTENT(S)->desc ) +#define SUN_CUSP_QRINFO(S) ( SUN_CUSP_CONTENT(S)->info ) +#define SUN_CUSP_INTERNAL_SIZE(S) ( SUN_CUSP_CONTENT(S)->internal_size ) +#define SUN_CUSP_WORK_SIZE(S) ( SUN_CUSP_CONTENT(S)->workspace_size ) + +/* + * ---------------------------------------------------------------------------- + * Implementations of exported functions. + * ---------------------------------------------------------------------------- + */ + +SUNLinearSolver SUNLinSol_cuSolverSp_batchQR(N_Vector y, SUNMatrix A, cusolverSpHandle_t cusol_handle) +{ + /* Check that required arguments are not NULL */ + if (y == NULL || A == NULL) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNLinSol_cuSolverSp_batchQR: y or A is null\n"); + return NULL; + } + + /* Check compatibility with supplied SUNMatrix and N_Vector */ + if (SUNMatGetID(A) != SUNMATRIX_CUSPARSE || N_VGetVectorID(y) != SUNDIALS_NVEC_CUDA) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNLinSol_cuSolverSp_batchQR: illegal type for y or A\n"); + return NULL; + } + + /* Matrix and vector dimensions must agree */ + if (N_VGetLength(y) != SUNMatrix_cuSparse_Columns(A)) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNLinSol_cuSolverSp_batchQR: matrix and vector dimensions don't agree\n"); + return NULL; + } + + /* Create an empty linear solver */ + SUNLinearSolver S; + + S = NULL; + S = SUNLinSolNewEmpty(); + if (S == NULL) + { + return NULL; + } + + /* Attach operations */ + S->ops->gettype = SUNLinSolGetType_cuSolverSp_batchQR; + S->ops->getid = SUNLinSolGetID_cuSolverSp_batchQR; + S->ops->initialize = SUNLinSolInitialize_cuSolverSp_batchQR; + S->ops->setup = SUNLinSolSetup_cuSolverSp_batchQR; + S->ops->solve = SUNLinSolSolve_cuSolverSp_batchQR; + S->ops->lastflag = SUNLinSolLastFlag_cuSolverSp_batchQR; + S->ops->free = SUNLinSolFree_cuSolverSp_batchQR; + + /* Create content */ + SUNLinearSolverContent_cuSolverSp_batchQR content; + + content = NULL; + content = (SUNLinearSolverContent_cuSolverSp_batchQR) malloc(sizeof *content); + if (content == NULL) + { + SUNLinSolFree(S); + return NULL; + } + + /* Attach content */ + S->content = content; + + /* Fill content */ + content->cusolver_handle = cusol_handle; + content->info = NULL; + content->workspace = NULL; + content->desc = NULL; + + return S; +} + +/* + * ----------------------------------------------------------------- + * Implementation of accessor and setter functions. + * ----------------------------------------------------------------- + */ + +void SUNLinSol_cuSolverSp_batchQR_GetDescription(SUNLinearSolver S, const char** desc) +{ + *desc = SUN_CUSP_DESC(S); +} + +void SUNLinSol_cuSolverSp_batchQR_SetDescription(SUNLinearSolver S, const char* desc) +{ + SUN_CUSP_DESC(S) = desc; +} + +void SUNLinSol_cuSolverSp_batchQR_GetDeviceSpace(SUNLinearSolver S, + size_t* cuSolverInternal, + size_t* cuSolverWorkspace) +{ + /* size is in bytes */ + *cuSolverInternal = SUN_CUSP_INTERNAL_SIZE(S); /* buffer for Q and R factors */ + *cuSolverWorkspace = SUN_CUSP_WORK_SIZE(S); /* numerical factorization buffer */ +} + +/* + * ----------------------------------------------------------------- + * Implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_cuSolverSp_batchQR(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_DIRECT); +} + +SUNLinearSolver_ID SUNLinSolGetID_cuSolverSp_batchQR(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_CUSOLVERSP_BATCHQR); +} + +int SUNLinSolInitialize_cuSolverSp_batchQR(SUNLinearSolver S) +{ + SUN_CUSP_FIRSTFACTORIZE(S) = SUNTRUE; + SUN_CUSP_LASTFLAG(S) = SUNLS_SUCCESS; + return(SUN_CUSP_LASTFLAG(S)); +} + +int SUNLinSolSetup_cuSolverSp_batchQR(SUNLinearSolver S, SUNMatrix A) +{ + int blockrows, blockcols, blocknnz, nblock; + int *d_rowptr, *d_colind; + realtype *d_data; + cusparseMatDescr_t mat_descr; + cudaError_t cuerr; + cusolverStatus_t status; + + if (SUN_CUSP_LASTFLAG(S) != SUNLS_SUCCESS) + return SUN_CUSP_LASTFLAG(S); + + if (SUN_CUSP_FIRSTFACTORIZE(S)) + { + + /* Free old workspace and symbloic analysis */ + if (SUN_CUSP_QRWORKSPACE(S)) + { + cudaFree(SUN_CUSP_QRWORKSPACE(S)); + cusolverSpDestroyCsrqrInfo(SUN_CUSP_QRINFO(S)); + } + + /* We must create a new csrqrinfo_t context every time we want to + do a symbolic analysis. Trying to reuse it results in a + CUSOLVER_STATUS_INVALID_VALUE error. */ + status = cusolverSpCreateCsrqrInfo(&SUN_CUSP_QRINFO(S)); + if (!SUNDIALS_CUSOLVER_VERIFY(status)) + { + SUN_CUSP_LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; + return SUN_CUSP_LASTFLAG(S); + } + + nblock = SUNMatrix_cuSparse_NumBlocks(A); + blocknnz = SUNMatrix_cuSparse_BlockNNZ(A); + blockrows = SUNMatrix_cuSparse_BlockRows(A); + blockcols = SUNMatrix_cuSparse_BlockColumns(A); + d_data = SUNMatrix_cuSparse_Data(A); + d_rowptr = SUNMatrix_cuSparse_IndexPointers(A); + d_colind = SUNMatrix_cuSparse_IndexValues(A); + mat_descr = SUNMatrix_cuSparse_MatDescr(A); + + /* Perform symbolic analysis of sparsity structure */ + status = cusolverSpXcsrqrAnalysisBatched(SUN_CUSOL_HANDLE(S), + blockrows, + blockcols, + blocknnz, + mat_descr, + d_rowptr, + d_colind, + SUN_CUSP_QRINFO(S)); + + if (!SUNDIALS_CUSOLVER_VERIFY(status)) + { + SUN_CUSP_LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; + return SUN_CUSP_LASTFLAG(S); + } + + /* Compute the workspace we will need */ + status = _cusolverSpXcsrqrBufferInfoBatched(SUN_CUSOL_HANDLE(S), + blockrows, + blockcols, + blocknnz, + mat_descr, + d_data, + d_rowptr, + d_colind, + nblock, + SUN_CUSP_QRINFO(S), + &SUN_CUSP_INTERNAL_SIZE(S), + &SUN_CUSP_WORK_SIZE(S)); + + if (!SUNDIALS_CUSOLVER_VERIFY(status)) + { + SUN_CUSP_LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; + return SUN_CUSP_LASTFLAG(S); + } + + cuerr = cudaMalloc((void**) &SUN_CUSP_QRWORKSPACE(S), SUN_CUSP_WORK_SIZE(S)); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) + { + SUN_CUSP_LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; + return SUN_CUSP_LASTFLAG(S); + } + + SUN_CUSP_FIRSTFACTORIZE(S) = SUNFALSE; + } + + SUN_CUSP_LASTFLAG(S) = SUNLS_SUCCESS; + return(SUN_CUSP_LASTFLAG(S)); +} + +int SUNLinSolSolve_cuSolverSp_batchQR(SUNLinearSolver S, SUNMatrix A, + N_Vector x, N_Vector b, realtype tol) +{ + cusolverStatus_t status; + int blockrows, blockcols, blocknnz, nblock; + int *d_rowptr, *d_colind; + realtype *d_data; + cusparseMatDescr_t mat_descr; + + if ((S == NULL) || (A == NULL) || (x == NULL) || (b == NULL)) + return SUNLS_MEM_NULL; + + SUN_CUSP_LASTFLAG(S) = SUNLS_SUCCESS; + + realtype* device_b = N_VGetDeviceArrayPointer_Cuda(b); + realtype* device_x = N_VGetDeviceArrayPointer_Cuda(x); + + if (SUN_CUSP_LASTFLAG(S) != SUNLS_SUCCESS) + return SUN_CUSP_LASTFLAG(S); + + /* solve the system */ + nblock = SUNMatrix_cuSparse_NumBlocks(A); + blocknnz = SUNMatrix_cuSparse_BlockNNZ(A); + blockrows = SUNMatrix_cuSparse_BlockRows(A); + blockcols = SUNMatrix_cuSparse_BlockColumns(A); + d_data = SUNMatrix_cuSparse_Data(A); + d_rowptr = SUNMatrix_cuSparse_IndexPointers(A); + d_colind = SUNMatrix_cuSparse_IndexValues(A); + mat_descr = SUNMatrix_cuSparse_MatDescr(A); + + status = _cusolverSpXcsrqrsvBatched(SUN_CUSOL_HANDLE(S), + blockrows, + blockcols, + blocknnz, + mat_descr, + d_data, + d_rowptr, + d_colind, + device_b, + device_x, + nblock, + SUN_CUSP_QRINFO(S), + SUN_CUSP_QRWORKSPACE(S)); + + if (!SUNDIALS_CUSOLVER_VERIFY(status)) + { + SUN_CUSP_LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; + return SUN_CUSP_LASTFLAG(S); + } + + return SUN_CUSP_LASTFLAG(S); +} + +sunindextype SUNLinSolLastFlag_cuSolverSp_batchQR(SUNLinearSolver S) +{ + if (S == NULL) return -1; + return SUN_CUSP_LASTFLAG(S); +} + +int SUNLinSolFree_cuSolverSp_batchQR(SUNLinearSolver S) +{ + /* return with success if already freed */ + if (S == NULL) return SUNLS_SUCCESS; + + /* free stuff in the content structure */ + cusolverSpDestroyCsrqrInfo(SUN_CUSP_QRINFO(S)); + cudaFree(SUN_CUSP_QRWORKSPACE(S)); + + /* free content structure */ + if (S->content) { + free(S->content); + S->content = NULL; + } + + /* free ops structure */ + if (S->ops) { + free(S->ops); + S->ops = NULL; + } + + /* free the actual SUNLinSol */ + free(S); + S = NULL; + + return(SUNLS_SUCCESS); +} diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/CMakeLists.txt index 2f5374b35..ddba97320 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds, Ashley Crawford @ SMU +# Programmer(s): Daniel R. Reynolds and Ashley Crawford @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,94 +12,130 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the dense SUNLinearSolver library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNLINSOL_DENSE\n\")") - -# Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF(F90_FOUND AND F2003_INTERFACE_ENABLE) +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_DENSE\n\")") -# Add variable sunlinsoldense_SOURCES with the sources for the SUNLINSOLDENSE lib -SET(sunlinsoldense_SOURCES sunlinsol_dense.c) +# Source files for the library +set(sunlinsoldense_SOURCES sunlinsol_dense.c) -# Add variable shared_SOURCES with the common SUNDIALS sources which will -# also be included in the SUNLINSOLDENSE library -SET(shared_SOURCES +# Common SUNDIALS sources included in the library +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c - ${sundials_SOURCE_DIR}/src/sundials/sundials_dense.c - ) + ${sundials_SOURCE_DIR}/src/sundials/sundials_dense.c) -# Add variable sunlinsoldense_HEADERS with the exported SUNLINSOLDENSE header files -SET(sunlinsoldense_HEADERS - ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_dense.h - ) - -# Add source directory to include directories -INCLUDE_DIRECTORIES(.) - -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Exported header files +set(sunlinsoldense_HEADERS + ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_dense.h) # Rules for building and installing the static library: -# - Add the build target for the SUNLINSOLDENSE library +# - Add the build target for the library # - Set the library name and make sure it is not deleted -# - Install the SUNLINSOLDENSE library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunlinsoldense_static STATIC ${sunlinsoldense_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunlinsoldense_static - PROPERTIES OUTPUT_NAME sundials_sunlinsoldense CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunlinsoldense_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +# - Install the library +if(BUILD_STATIC_LIBS) + + add_library(sundials_sunlinsoldense_static + STATIC ${sunlinsoldense_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsoldense_static + PROPERTIES + OUTPUT_NAME sundials_sunlinsoldense + CLEAN_DIRECT_OUTPUT 1) + + # sunlinsoldense depends on sunmatrixdense + target_link_libraries(sundials_sunlinsoldense_static + PUBLIC sundials_sunmatrixdense_static) + + target_compile_definitions(sundials_sunlinsoldense_static + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsoldense_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: -# - Add the build target for the SUNLINSOLDENSE library +# - Add the build target for the library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries -# - Install the SUNLINSOLDENSE library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunlinsoldense_shared SHARED ${sunlinsoldense_SOURCES} ${shared_SOURCES}) - - TARGET_LINK_LIBRARIES(sundials_sunlinsoldense_shared sundials_sunmatrixdense_shared) - - SET_TARGET_PROPERTIES(sundials_sunlinsoldense_shared - PROPERTIES OUTPUT_NAME sundials_sunlinsoldense CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunlinsoldense_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_sunlinsoldense_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) - -# Install the SUNLINSOLDENSE header files -INSTALL(FILES ${sunlinsoldense_HEADERS} DESTINATION include/sunlinsol) - -# If FCMIX is enabled, build and install the FSUNLINSOLDENSE library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunlinsoldense_SOURCES fsunlinsol_dense.c) - - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunlinsoldense_static STATIC ${fsunlinsoldense_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunlinsoldense_static - PROPERTIES OUTPUT_NAME sundials_fsunlinsoldense CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunlinsoldense_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) - - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunlinsoldense_shared ${fsunlinsoldense_SOURCES}) - - # fsunlinsoldense depends on fnvecserial, fsunmatrixdense, sunlinsoldense - TARGET_LINK_LIBRARIES(sundials_fsunlinsoldense_shared +# - Install the library +if(BUILD_SHARED_LIBS) + + add_library(sundials_sunlinsoldense_shared + SHARED ${sunlinsoldense_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsoldense_shared + PROPERTIES + OUTPUT_NAME sundials_sunlinsoldense + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + + # sunlinsoldense depends on sunmatrixdense + target_link_libraries(sundials_sunlinsoldense_shared + PUBLIC sundials_sunmatrixdense_shared) + + target_compile_definitions(sundials_sunlinsoldense_shared + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsoldense_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_SHARED_LIBS) + +# Install the header files +install(FILES ${sunlinsoldense_HEADERS} DESTINATION include/sunlinsol) + +# +message(STATUS "Added SUNLINSOL_DENSE module") + +# If FCMIX is enabled, build and install the Fortran77 library +if(F77_INTERFACE_ENABLE AND F77_FOUND) + + set(fsunlinsoldense_SOURCES fsunlinsol_dense.c) + + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunlinsoldense_static + STATIC ${fsunlinsoldense_SOURCES}) + set_target_properties(sundials_fsunlinsoldense_static + PROPERTIES + OUTPUT_NAME sundials_fsunlinsoldense + CLEAN_DIRECT_OUTPUT 1) + # depends on fnvecserial, fsunmatrixdense, sunlinsoldense + target_link_libraries(sundials_fsunlinsoldense_static + PUBLIC + sundials_fnvecserial_static + sundials_fsunmatrixdense_static + sundials_sunlinsoldense_static) + install(TARGETS sundials_fsunlinsoldense_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) + + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunlinsoldense_shared + SHARED ${fsunlinsoldense_SOURCES}) + set_target_properties(sundials_fsunlinsoldense_shared + PROPERTIES + OUTPUT_NAME sundials_fsunlinsoldense + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + # depends on fnvecserial, fsunmatrixdense, sunlinsoldense + target_link_libraries(sundials_fsunlinsoldense_shared + PUBLIC sundials_fnvecserial_shared sundials_fsunmatrixdense_shared sundials_sunlinsoldense_shared) + install(TARGETS sundials_fsunlinsoldense_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) - SET_TARGET_PROPERTIES(sundials_fsunlinsoldense_shared - PROPERTIES OUTPUT_NAME sundials_fsunlinsoldense CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunlinsoldense_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_fsunlinsoldense_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + # + message(STATUS "Added SUNLINSOL_DENSE F77 interface") -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(F77_INTERFACE_ENABLE AND F77_FOUND) -# -MESSAGE(STATUS "Added SUNLINSOL_DENSE module") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/F90/fsunlinsol_dense.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/F90/fsunlinsol_dense.f90 deleted file mode 100644 index 1374259db..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/F90/fsunlinsol_dense.f90 +++ /dev/null @@ -1,110 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): David J. Gardner @ LLNL -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS dense linear solver using the ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fsunlinsol_dense_mod - - !======= Interfaces ========= - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - type(c_ptr) function FSUNLinSol_Dense(y, A) & - bind(C,name='SUNLinSol_Dense') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: y - type(c_ptr), value :: A - end function FSUNLinSol_Dense - - ! Deprecated - type(c_ptr) function FSUNDenseLinearSolver(y, A) & - bind(C,name='SUNDenseLinearSolver') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: y - type(c_ptr), value :: A - end function FSUNDenseLinearSolver - - ! ================================================================= - ! Destructors - ! ================================================================= - - subroutine FSUNLinSolFree_Dense(LS) & - bind(C,name='SUNLinSolFree_Dense') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end subroutine FSUNLinSolFree_Dense - - ! ================================================================= - ! Operations - ! ================================================================= - - integer(c_int) function FSUNLinSolGetType_Dense(LS) & - bind(C,name='SUNLinSolGetType_Dense') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolGetType_Dense - - integer(c_int) function FSUNLinSolInitialize_Dense(LS) & - bind(C,name='SUNLinSolInitialize_Dense') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolInitialize_Dense - - integer(c_int) function FSUNLinSolSetup_Dense(LS, A) & - bind(C,name='SUNLinSolSetup_Dense') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - end function FSUNLinSolSetup_Dense - - integer(c_int) function FSUNLinSolSolve_Dense(LS, A, x, b, tol) & - bind(C,name='SUNLinSolSolve_Dense') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - type(c_ptr), value :: x - type(c_ptr), value :: b - real(c_double), value :: tol - end function FSUNLinSolSolve_Dense - - integer(c_long) function FSUNLinSolLastFlag_Dense(LS) & - bind(C,name='SUNLinSolLastFlag_Dense') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolLastFlag_Dense - - integer(c_int) function FSUNLinSolSpace_Dense(LS, lenrwLS, leniwLS) & - bind(C,name='SUNLinSolSpace_Dense') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_long) :: lenrwLS - integer(c_long) :: leniwLS - end function FSUNLinSolSpace_Dense - - end interface - -end module fsunlinsol_dense_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fmod/CMakeLists.txt similarity index 67% rename from deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/F90/CMakeLists.txt rename to deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fmod/CMakeLists.txt index 5fcdceb46..a7e86355e 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/F90/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fmod/CMakeLists.txt @@ -1,8 +1,8 @@ # ---------------------------------------------------------------------- -# Programmer: Cody J. Balos @ LLNL +# Programmer(s): Cody J. Balos @ LLNL # ---------------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,22 +12,27 @@ # SUNDIALS Copyright End # ---------------------------------------------------------------------- # CMakeLists.txt file for the F2003 dense SUNLinearSolver object library +# ---------------------------------------------------------------------- -set(sunlinsoldense_SOURCES fsunlinsol_dense.f90) +set(sunlinsoldense_SOURCES fsunlinsol_dense_mod.f90 fsunlinsol_dense_mod.c) if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsoldense_mod_static STATIC + sundials_add_f2003_interface_library(sundials_fsunlinsoldense_mod_static STATIC_OBJECT ${sunlinsoldense_SOURCES} ) + add_dependencies(sundials_fsunlinsoldense_mod_static_obj sundials_fgeneric_static_obj) + target_link_libraries(sundials_fsunlinsoldense_mod_static PUBLIC sundials_fsunmatrixdense_mod_static) set_target_properties(sundials_fsunlinsoldense_mod_static PROPERTIES OUTPUT_NAME sundials_fsunlinsoldense_mod CLEAN_DIRECT_OUTPUT 1) install(TARGETS sundials_fsunlinsoldense_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif(BUILD_STATIC_LIBS) if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsoldense_mod_shared SHARED + sundials_add_f2003_interface_library(sundials_fsunlinsoldense_mod_shared SHARED_OBJECT ${sunlinsoldense_SOURCES} ) + add_dependencies(sundials_fsunlinsoldense_mod_shared_obj sundials_fgeneric_shared_obj) + target_link_libraries(sundials_fsunlinsoldense_mod_shared PUBLIC sundials_fsunmatrixdense_mod_shared) set_target_properties(sundials_fsunlinsoldense_mod_shared PROPERTIES OUTPUT_NAME sundials_fsunlinsoldense_mod CLEAN_DIRECT_OUTPUT 1) set_target_properties(sundials_fsunlinsoldense_mod_shared diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fmod/fsunlinsol_dense_mod.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fmod/fsunlinsol_dense_mod.c new file mode 100644 index 000000000..85dfbd7ca --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fmod/fsunlinsol_dense_mod.c @@ -0,0 +1,349 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_linearsolver.h" + + +#include "sunlinsol/sunlinsol_dense.h" + +SWIGEXPORT SUNLinearSolver _wrap_FSUNLinSol_Dense(N_Vector farg1, SUNMatrix farg2) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (SUNLinearSolver)SUNLinSol_Dense(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT SUNLinearSolver _wrap_FSUNDenseLinearSolver(N_Vector farg1, SUNMatrix farg2) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (SUNLinearSolver)SUNDenseLinearSolver(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetType_Dense(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_Type result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_Type)SUNLinSolGetType_Dense(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetID_Dense(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_ID result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_ID)SUNLinSolGetID_Dense(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolInitialize_Dense(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolInitialize_Dense(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetup_Dense(SUNLinearSolver farg1, SUNMatrix farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNLinSolSetup_Dense(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSolve_Dense(SUNLinearSolver farg1, SUNMatrix farg2, N_Vector farg3, N_Vector farg4, double const *farg5) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype arg5 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype)(*farg5); + result = (int)SUNLinSolSolve_Dense(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNLinSolLastFlag_Dense(SUNLinearSolver farg1) { + int64_t fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + sunindextype result; + + arg1 = (SUNLinearSolver)(farg1); + result = SUNLinSolLastFlag_Dense(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSpace_Dense(SUNLinearSolver farg1, long *farg2, long *farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNLinSolSpace_Dense(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolFree_Dense(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolFree_Dense(arg1); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fmod/fsunlinsol_dense_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fmod/fsunlinsol_dense_mod.f90 new file mode 100644 index 000000000..2f31836ab --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fmod/fsunlinsol_dense_mod.f90 @@ -0,0 +1,299 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunlinsol_dense_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_linearsolver_mod + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FSUNLinSol_Dense + public :: FSUNDenseLinearSolver + public :: FSUNLinSolGetType_Dense + public :: FSUNLinSolGetID_Dense + public :: FSUNLinSolInitialize_Dense + public :: FSUNLinSolSetup_Dense + public :: FSUNLinSolSolve_Dense + public :: FSUNLinSolLastFlag_Dense + public :: FSUNLinSolSpace_Dense + public :: FSUNLinSolFree_Dense + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNLinSol_Dense(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FSUNDenseLinearSolver(farg1, farg2) & +bind(C, name="_wrap_FSUNDenseLinearSolver") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSolGetType_Dense(farg1) & +bind(C, name="_wrap_FSUNLinSolGetType_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetID_Dense(farg1) & +bind(C, name="_wrap_FSUNLinSolGetID_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolInitialize_Dense(farg1) & +bind(C, name="_wrap_FSUNLinSolInitialize_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetup_Dense(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSolSetup_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSolve_Dense(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FSUNLinSolSolve_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolLastFlag_Dense(farg1) & +bind(C, name="_wrap_FSUNLinSolLastFlag_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNLinSolSpace_Dense(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSpace_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolFree_Dense(farg1) & +bind(C, name="_wrap_FSUNLinSolFree_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNLinSol_Dense(y, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(y) +farg2 = c_loc(a) +fresult = swigc_FSUNLinSol_Dense(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNDenseLinearSolver(y, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(y) +farg2 = c_loc(a) +fresult = swigc_FSUNDenseLinearSolver(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSolGetType_Dense(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_Type) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetType_Dense(farg1) +swig_result = fresult +end function + +function FSUNLinSolGetID_Dense(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_ID) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetID_Dense(farg1) +swig_result = fresult +end function + +function FSUNLinSolInitialize_Dense(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolInitialize_Dense(farg1) +swig_result = fresult +end function + +function FSUNLinSolSetup_Dense(s, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(s) +farg2 = c_loc(a) +fresult = swigc_FSUNLinSolSetup_Dense(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolSolve_Dense(s, a, x, b, tol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: b +real(C_DOUBLE), intent(in) :: tol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +real(C_DOUBLE) :: farg5 + +farg1 = c_loc(s) +farg2 = c_loc(a) +farg3 = c_loc(x) +farg4 = c_loc(b) +farg5 = tol +fresult = swigc_FSUNLinSolSolve_Dense(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FSUNLinSolLastFlag_Dense(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolLastFlag_Dense(farg1) +swig_result = fresult +end function + +function FSUNLinSolSpace_Dense(s, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FSUNLinSolSpace_Dense(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolFree_Dense(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolFree_Dense(farg1) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.c index 2330b1d70..1b0fa3081 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.h b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.h index 872bdbad6..700d57ea8 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds, Ashley Crawford @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/sunlinsol_dense.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/sunlinsol_dense.c index 073bc936b..9364373de 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/sunlinsol_dense.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/dense/sunlinsol_dense.c @@ -1,9 +1,8 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds, Ashley Crawford @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -12,10 +11,9 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the dense implementation of + * This is the implementation file for the dense implementation of * the SUNLINSOL package. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include @@ -25,12 +23,9 @@ #define ONE RCONST(1.0) -/* Private function prototypes */ -sunindextype GlobalVectorLength_DenseLS(N_Vector y); - /* * ----------------------------------------------------------------- - * Dense solver structure accessibility macros: + * Dense solver structure accessibility macros: * ----------------------------------------------------------------- */ @@ -61,68 +56,53 @@ SUNLinearSolver SUNDenseLinearSolver(N_Vector y, SUNMatrix A) SUNLinearSolver SUNLinSol_Dense(N_Vector y, SUNMatrix A) { SUNLinearSolver S; - SUNLinearSolver_Ops ops; SUNLinearSolverContent_Dense content; - sunindextype MatrixRows, VecLength; - + sunindextype MatrixRows; + /* Check compatibility with supplied SUNMatrix and N_Vector */ - if (SUNMatGetID(A) != SUNMATRIX_DENSE) - return(NULL); - if (SUNDenseMatrix_Rows(A) != SUNDenseMatrix_Columns(A)) - return(NULL); - MatrixRows = SUNDenseMatrix_Rows(A); + if (SUNMatGetID(A) != SUNMATRIX_DENSE) return(NULL); + + if (SUNDenseMatrix_Rows(A) != SUNDenseMatrix_Columns(A)) return(NULL); + if ( (N_VGetVectorID(y) != SUNDIALS_NVEC_SERIAL) && (N_VGetVectorID(y) != SUNDIALS_NVEC_OPENMP) && (N_VGetVectorID(y) != SUNDIALS_NVEC_PTHREADS) ) return(NULL); - /* optimally this function would be replaced with a generic N_Vector routine */ - VecLength = GlobalVectorLength_DenseLS(y); - if (MatrixRows != VecLength) - return(NULL); - - /* Create linear solver */ + MatrixRows = SUNDenseMatrix_Rows(A); + if (MatrixRows != N_VGetLength(y)) return(NULL); + + /* Create an empty linear solver */ S = NULL; - S = (SUNLinearSolver) malloc(sizeof *S); + S = SUNLinSolNewEmpty(); if (S == NULL) return(NULL); - - /* Create linear solver operation structure */ - ops = NULL; - ops = (SUNLinearSolver_Ops) malloc(sizeof(struct _generic_SUNLinearSolver_Ops)); - if (ops == NULL) { free(S); return(NULL); } /* Attach operations */ - ops->gettype = SUNLinSolGetType_Dense; - ops->initialize = SUNLinSolInitialize_Dense; - ops->setup = SUNLinSolSetup_Dense; - ops->solve = SUNLinSolSolve_Dense; - ops->lastflag = SUNLinSolLastFlag_Dense; - ops->space = SUNLinSolSpace_Dense; - ops->free = SUNLinSolFree_Dense; - ops->setatimes = NULL; - ops->setpreconditioner = NULL; - ops->setscalingvectors = NULL; - ops->numiters = NULL; - ops->resnorm = NULL; - ops->resid = NULL; + S->ops->gettype = SUNLinSolGetType_Dense; + S->ops->getid = SUNLinSolGetID_Dense; + S->ops->initialize = SUNLinSolInitialize_Dense; + S->ops->setup = SUNLinSolSetup_Dense; + S->ops->solve = SUNLinSolSolve_Dense; + S->ops->lastflag = SUNLinSolLastFlag_Dense; + S->ops->space = SUNLinSolSpace_Dense; + S->ops->free = SUNLinSolFree_Dense; /* Create content */ content = NULL; - content = (SUNLinearSolverContent_Dense) malloc(sizeof(struct _SUNLinearSolverContent_Dense)); - if (content == NULL) { free(ops); free(S); return(NULL); } + content = (SUNLinearSolverContent_Dense) malloc(sizeof *content); + if (content == NULL) { SUNLinSolFree(S); return(NULL); } + + /* Attach content */ + S->content = content; /* Fill content */ - content->N = MatrixRows; + content->N = MatrixRows; content->last_flag = 0; - content->pivots = NULL; + content->pivots = NULL; + + /* Allocate content */ content->pivots = (sunindextype *) malloc(MatrixRows * sizeof(sunindextype)); - if (content->pivots == NULL) { - free(content); free(ops); free(S); return(NULL); - } - - /* Attach content and ops */ - S->content = content; - S->ops = ops; + if (content->pivots == NULL) { SUNLinSolFree(S); return(NULL); } return(S); } @@ -138,28 +118,33 @@ SUNLinearSolver_Type SUNLinSolGetType_Dense(SUNLinearSolver S) return(SUNLINEARSOLVER_DIRECT); } +SUNLinearSolver_ID SUNLinSolGetID_Dense(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_DENSE); +} + int SUNLinSolInitialize_Dense(SUNLinearSolver S) { /* all solver-specific memory has already been allocated */ LASTFLAG(S) = SUNLS_SUCCESS; - return(LASTFLAG(S)); + return(SUNLS_SUCCESS); } int SUNLinSolSetup_Dense(SUNLinearSolver S, SUNMatrix A) { realtype **A_cols; sunindextype *pivots; - + /* check for valid inputs */ - if ( (A == NULL) || (S == NULL) ) + if ( (A == NULL) || (S == NULL) ) return(SUNLS_MEM_NULL); - + /* Ensure that A is a dense matrix */ if (SUNMatGetID(A) != SUNMATRIX_DENSE) { LASTFLAG(S) = SUNLS_ILL_INPUT; - return(LASTFLAG(S)); + return(SUNLS_ILL_INPUT); } - + /* access data pointers (return with failure on NULL) */ A_cols = NULL; pivots = NULL; @@ -167,9 +152,9 @@ int SUNLinSolSetup_Dense(SUNLinearSolver S, SUNMatrix A) pivots = PIVOTS(S); if ( (A_cols == NULL) || (pivots == NULL) ) { LASTFLAG(S) = SUNLS_MEM_FAIL; - return(LASTFLAG(S)); + return(SUNLS_MEM_FAIL); } - + /* perform LU factorization of input matrix */ LASTFLAG(S) = denseGETRF(A_cols, SUNDenseMatrix_Rows(A), SUNDenseMatrix_Columns(A), pivots); @@ -180,15 +165,15 @@ int SUNLinSolSetup_Dense(SUNLinearSolver S, SUNMatrix A) return(SUNLS_SUCCESS); } -int SUNLinSolSolve_Dense(SUNLinearSolver S, SUNMatrix A, N_Vector x, - N_Vector b, realtype tol) +int SUNLinSolSolve_Dense(SUNLinearSolver S, SUNMatrix A, N_Vector x, + N_Vector b, realtype tol) { realtype **A_cols, *xdata; sunindextype *pivots; - - if ( (A == NULL) || (S == NULL) || (x == NULL) || (b == NULL) ) + + if ( (A == NULL) || (S == NULL) || (x == NULL) || (b == NULL) ) return(SUNLS_MEM_NULL); - + /* copy b into x */ N_VScale(ONE, b, x); @@ -201,23 +186,24 @@ int SUNLinSolSolve_Dense(SUNLinearSolver S, SUNMatrix A, N_Vector x, pivots = PIVOTS(S); if ( (A_cols == NULL) || (xdata == NULL) || (pivots == NULL) ) { LASTFLAG(S) = SUNLS_MEM_FAIL; - return(LASTFLAG(S)); + return(SUNLS_MEM_FAIL); } - + /* solve using LU factors */ denseGETRS(A_cols, SUNDenseMatrix_Rows(A), pivots, xdata); LASTFLAG(S) = SUNLS_SUCCESS; - return(LASTFLAG(S)); + return(SUNLS_SUCCESS); } -long int SUNLinSolLastFlag_Dense(SUNLinearSolver S) +sunindextype SUNLinSolLastFlag_Dense(SUNLinearSolver S) { /* return the stored 'last_flag' value */ + if (S == NULL) return(-1); return(LASTFLAG(S)); } -int SUNLinSolSpace_Dense(SUNLinearSolver S, - long int *lenrwLS, +int SUNLinSolSpace_Dense(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS) { *leniwLS = 2 + DENSE_CONTENT(S)->N; @@ -228,8 +214,7 @@ int SUNLinSolSpace_Dense(SUNLinearSolver S, int SUNLinSolFree_Dense(SUNLinearSolver S) { /* return if S is already free */ - if (S == NULL) - return(SUNLS_SUCCESS); + if (S == NULL) return(SUNLS_SUCCESS); /* delete items from contents, then delete generic structure */ if (S->content) { @@ -237,35 +222,13 @@ int SUNLinSolFree_Dense(SUNLinearSolver S) free(PIVOTS(S)); PIVOTS(S) = NULL; } - free(S->content); + free(S->content); S->content = NULL; } if (S->ops) { - free(S->ops); + free(S->ops); S->ops = NULL; } free(S); S = NULL; return(SUNLS_SUCCESS); } - -/* - * ----------------------------------------------------------------- - * private functions - * ----------------------------------------------------------------- - */ - -/* Inefficient kludge for determining the number of entries in a N_Vector - object (replace if such a routine is ever added to the N_Vector API). - - Returns "-1" on an error. */ -sunindextype GlobalVectorLength_DenseLS(N_Vector y) -{ - realtype len; - N_Vector tmp = NULL; - tmp = N_VClone(y); - if (tmp == NULL) return(-1); - N_VConst(ONE, tmp); - len = N_VDotProd(tmp, tmp); - N_VDestroy(tmp); - return( (sunindextype) len ); -} diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/CMakeLists.txt index 775c4c1fd..189386fab 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,96 +12,130 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the klu SUNLinearSolver library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNLINSOL_KLU\n\")") - -# Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF(F90_FOUND AND F2003_INTERFACE_ENABLE) +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_KLU\n\")") -# Add variable sunlinsolklu_SOURCES with the sources for the SUNLINSOLKLU lib -SET(sunlinsolklu_SOURCES sunlinsol_klu.c) +# Source files for the library +set(sunlinsolklu_SOURCES sunlinsol_klu.c) -# Add variable shared_SOURCES with the common SUNDIALS sources which will -# also be included in the SUNLINSOLKLU library -SET(shared_SOURCES +# Common SUNDIALS sources included in the library +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c - ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c - ) + ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c) -# Add variable sunlinsolklu_HEADERS with the exported SUNLINSOLKLU header files -SET(sunlinsolklu_HEADERS - ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_klu.h - ) - -# Add source directory to include directories -INCLUDE_DIRECTORIES(.) - -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Exported header files +set(sunlinsolklu_HEADERS + ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_klu.h) # Rules for building and installing the static library: -# - Add the build target for the SUNLINSOLKLU library +# - Add the build target for the library # - Set the library name and make sure it is not deleted -# - Install the SUNLINSOLKLU library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunlinsolklu_static STATIC ${sunlinsolklu_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunlinsolklu_static - PROPERTIES OUTPUT_NAME sundials_sunlinsolklu CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunlinsolklu_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +# - Install the library +if(BUILD_STATIC_LIBS) + + add_library(sundials_sunlinsolklu_static + STATIC ${sunlinsolklu_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolklu_static + PROPERTIES + OUTPUT_NAME sundials_sunlinsolklu + CLEAN_DIRECT_OUTPUT 1) + + # depends on sunmatrixsparse and KLU + target_link_libraries(sundials_sunlinsolklu_static + PUBLIC sundials_sunmatrixsparse_static ${KLU_LIBRARIES}) + + target_compile_definitions(sundials_sunlinsolklu_static + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolklu_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: -# - Add the build target for the SUNLINSOLKLU library +# - Add the build target for the library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries -# - Install the SUNLINSOLKLU library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunlinsolklu_shared SHARED ${sunlinsolklu_SOURCES} ${shared_SOURCES}) - - # sunlinsolklu depends on sunmatrixsparse and KLU - TARGET_LINK_LIBRARIES(sundials_sunlinsolklu_shared - sundials_sunmatrixsparse_shared - ${KLU_LIBRARIES}) - - SET_TARGET_PROPERTIES(sundials_sunlinsolklu_shared - PROPERTIES OUTPUT_NAME sundials_sunlinsolklu CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunlinsolklu_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_sunlinsolklu_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) - -# Install the SUNLINSOLKLU header files -INSTALL(FILES ${sunlinsolklu_HEADERS} DESTINATION include/sunlinsol) - -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunlinsolklu_SOURCES fsunlinsol_klu.c) - - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunlinsolklu_static STATIC ${fsunlinsolklu_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunlinsolklu_static - PROPERTIES OUTPUT_NAME sundials_fsunlinsolklu CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunlinsolklu_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) - - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunlinsolklu_shared ${fsunlinsolklu_SOURCES}) - - # fsunlinsolklu depends on fnvecserial, fsunmatrixsparse, sunlinsolklu - TARGET_LINK_LIBRARIES(sundials_fsunlinsolklu_shared +# - Install the library +if(BUILD_SHARED_LIBS) + + add_library(sundials_sunlinsolklu_shared + SHARED ${sunlinsolklu_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolklu_shared + PROPERTIES + OUTPUT_NAME sundials_sunlinsolklu + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + + # depends on sunmatrixsparse and KLU + target_link_libraries(sundials_sunlinsolklu_shared + PUBLIC sundials_sunmatrixsparse_shared ${KLU_LIBRARIES}) + + target_compile_definitions(sundials_sunlinsolklu_shared + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolklu_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_SHARED_LIBS) + +# Install the header files +install(FILES ${sunlinsolklu_HEADERS} DESTINATION include/sunlinsol) + +# +message(STATUS "Added SUNLINSOL_KLU module") + +# If FCMIX is enabled, build and install the Fortran77 library +if(F77_INTERFACE_ENABLE AND F77_FOUND) + + set(fsunlinsolklu_SOURCES fsunlinsol_klu.c) + + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunlinsolklu_static + STATIC ${fsunlinsolklu_SOURCES}) + set_target_properties(sundials_fsunlinsolklu_static + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolklu + CLEAN_DIRECT_OUTPUT 1) + # depends on fnvecserial, fsunmatrixsparse, sunlinsolklu + target_link_libraries(sundials_fsunlinsolklu_static + PUBLIC + sundials_fnvecserial_static + sundials_fsunmatrixsparse_static + sundials_sunlinsolklu_static) + install(TARGETS sundials_fsunlinsolklu_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) + + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunlinsolklu_shared + SHARED ${fsunlinsolklu_SOURCES}) + set_target_properties(sundials_fsunlinsolklu_shared + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolklu + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + # depends on fnvecserial, fsunmatrixsparse, sunlinsolklu + target_link_libraries(sundials_fsunlinsolklu_shared + PUBLIC sundials_fnvecserial_shared sundials_fsunmatrixsparse_shared sundials_sunlinsolklu_shared) + install(TARGETS sundials_fsunlinsolklu_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) - SET_TARGET_PROPERTIES(sundials_fsunlinsolklu_shared - PROPERTIES OUTPUT_NAME sundials_fsunlinsolklu CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunlinsolklu_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_fsunlinsolklu_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + # + message(STATUS "Added SUNLINSOL_KLU F77 interface") -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(F77_INTERFACE_ENABLE AND F77_FOUND) -# -MESSAGE(STATUS "Added SUNLINSOL_KLU module") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/F90/fsunlinsol_klu.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/F90/fsunlinsol_klu.f90 deleted file mode 100644 index f49adbdfd..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/F90/fsunlinsol_klu.f90 +++ /dev/null @@ -1,129 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): Cody J. Balos @ LLNL -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS sparse matrix using the ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fsunlinsol_klu_mod - - use, intrinsic :: iso_c_binding, only : c_int - - integer(c_int), parameter :: SUNKLU_ORDERING_DEFAULT = 1 ! COLAMD - integer(c_int), parameter :: SUNKLU_REINIT_FULL = 1 - integer(c_int), parameter :: SUNKLU_REINIT_PARTIAL = 2 - - !======= Interfaces ======== - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - type(c_ptr) function FSUNKLU(y, A) & - bind(C,name='SUNKLU') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: y - type(c_ptr), value :: A - end function FSUNKLU - - ! ================================================================= - ! Destructors - ! ================================================================= - - subroutine FSUNLinSolFree_KLU(LS) & - bind(C,name='SUNLinSolFree_KLU') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end subroutine FSUNLinSolFree_KLU - - ! ================================================================= - ! Setter/init routines - ! ================================================================= - - integer(c_int) function FSUNKLUReInit(LS, A, nnz, reinit_type) & - bind(C,name='SUNKLUReInit') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - integer(c_long), value :: nnz - integer(c_int), value :: reinit_type - end function FSUNKLUReInit - - integer(c_int) function FSUNKLUSetOrdering(LS, ordering_choice) & - bind(C,name='SUNKLUSetOrdering') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: ordering_choice - end function FSUNKLUSetOrdering - - ! ================================================================= - ! Operations - ! ================================================================= - - integer(c_int) function FSUNLinSolGetType_KLU(LS) & - bind(C,name='SUNLinSolGetType_KLU') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolGetType_KLU - - integer(c_int) function FSUNLinSolInitialize_KLU(LS) & - bind(C,name='SUNLinSolInitialize_KLU') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolInitialize_KLU - - integer(c_int) function FSUNLinSolSetup_KLU(LS, A) & - bind(C,name='SUNLinSolSetup_KLU') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - end function FSUNLinSolSetup_KLU - - integer(c_int) function FSUNLinSolSolve_KLU(LS, A, x, b, tol) & - bind(C,name='SUNLinSolSolve_KLU') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - type(c_ptr), value :: x - type(c_ptr), value :: b - real(c_double), value :: tol - end function FSUNLinSolSolve_KLU - - integer(c_long) function FSUNLinSolLastFlag_KLU(LS) & - bind(C,name='SUNLinSolLastFlag_KLU') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolLastFlag_KLU - - integer(c_int) function FSUNLinSolSpace_KLU(LS, lenrwLS, leniwLS) & - bind(C,name='SUNLinSolSpace_KLU') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_long), value :: lenrwLS - integer(c_long), value :: leniwLS - end function FSUNLinSolSpace_KLU - - end interface - -end module fsunlinsol_klu_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fmod/CMakeLists.txt similarity index 67% rename from deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/F90/CMakeLists.txt rename to deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fmod/CMakeLists.txt index 8023a096c..e82a64c4b 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/F90/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fmod/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Cody J. Balos @ LLNL +# Programmer(s): Cody J. Balos @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,22 +12,27 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the F2003 KLU SUNLinearSolver object library +# --------------------------------------------------------------- -set(sunlinsolklu_SOURCES fsunlinsol_klu.f90) +set(sunlinsolklu_SOURCES fsunlinsol_klu_mod.f90 fsunlinsol_klu_mod.c) if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolklu_mod_static STATIC + sundials_add_f2003_interface_library(sundials_fsunlinsolklu_mod_static STATIC_OBJECT ${sunlinsolklu_SOURCES} ) + add_dependencies(sundials_fsunlinsolklu_mod_static_obj sundials_fgeneric_static_obj) + target_link_libraries(sundials_fsunlinsolklu_mod_static PUBLIC sundials_fsunmatrixsparse_mod_static) set_target_properties(sundials_fsunlinsolklu_mod_static PROPERTIES OUTPUT_NAME sundials_fsunlinsolklu_mod CLEAN_DIRECT_OUTPUT 1) install(TARGETS sundials_fsunlinsolklu_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif(BUILD_STATIC_LIBS) if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolklu_mod_shared SHARED + sundials_add_f2003_interface_library(sundials_fsunlinsolklu_mod_shared SHARED_OBJECT ${sunlinsolklu_SOURCES} ) + add_dependencies(sundials_fsunlinsolklu_mod_shared_obj sundials_fgeneric_shared_obj) + target_link_libraries(sundials_fsunlinsolklu_mod_shared PUBLIC sundials_fsunmatrixsparse_mod_shared) set_target_properties(sundials_fsunlinsolklu_mod_shared PROPERTIES OUTPUT_NAME sundials_fsunlinsolklu_mod CLEAN_DIRECT_OUTPUT 1) set_target_properties(sundials_fsunlinsolklu_mod_shared diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fmod/fsunlinsol_klu_mod.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fmod/fsunlinsol_klu_mod.c new file mode 100644 index 000000000..53e015d46 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fmod/fsunlinsol_klu_mod.c @@ -0,0 +1,473 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +enum { + SWIG_MEM_OWN = 0x01, + SWIG_MEM_RVALUE = 0x02, + SWIG_MEM_CONST = 0x04 +}; + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_linearsolver.h" + + +#include "sunlinsol/sunlinsol_klu.h" + + +typedef struct { + void* cptr; + int cmemflags; +} SwigClassWrapper; + + +SWIGINTERN SwigClassWrapper SwigClassWrapper_uninitialized() { + SwigClassWrapper result; + result.cptr = NULL; + result.cmemflags = 0; + return result; +} + +SWIGEXPORT SUNLinearSolver _wrap_FSUNLinSol_KLU(N_Vector farg1, SUNMatrix farg2) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (SUNLinearSolver)SUNLinSol_KLU(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_KLUReInit(SUNLinearSolver farg1, SUNMatrix farg2, int64_t const *farg3, int const *farg4) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + sunindextype arg3 ; + int arg4 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (int)(*farg4); + result = (int)SUNLinSol_KLUReInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_KLUSetOrdering(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_KLUSetOrdering(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SUNLinearSolver _wrap_FSUNKLU(N_Vector farg1, SUNMatrix farg2) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (SUNLinearSolver)SUNKLU(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNKLUReInit(SUNLinearSolver farg1, SUNMatrix farg2, int64_t const *farg3, int const *farg4) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + sunindextype arg3 ; + int arg4 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (int)(*farg4); + result = (int)SUNKLUReInit(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNKLUSetOrdering(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNKLUSetOrdering(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SwigClassWrapper _wrap_FSUNLinSol_KLUGetSymbolic(SUNLinearSolver farg1) { + SwigClassWrapper fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + klu_l_symbolic *result = 0 ; + + arg1 = (SUNLinearSolver)(farg1); + result = (klu_l_symbolic *)SUNLinSol_KLUGetSymbolic(arg1); + fresult.cptr = result; + fresult.cmemflags = SWIG_MEM_RVALUE | (0 ? SWIG_MEM_OWN : 0); + return fresult; +} + + +SWIGEXPORT SwigClassWrapper _wrap_FSUNLinSol_KLUGetNumeric(SUNLinearSolver farg1) { + SwigClassWrapper fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + klu_l_numeric *result = 0 ; + + arg1 = (SUNLinearSolver)(farg1); + result = (klu_l_numeric *)SUNLinSol_KLUGetNumeric(arg1); + fresult.cptr = result; + fresult.cmemflags = SWIG_MEM_RVALUE | (0 ? SWIG_MEM_OWN : 0); + return fresult; +} + + +SWIGEXPORT SwigClassWrapper _wrap_FSUNLinSol_KLUGetCommon(SUNLinearSolver farg1) { + SwigClassWrapper fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + klu_l_common *result = 0 ; + + arg1 = (SUNLinearSolver)(farg1); + result = (klu_l_common *)SUNLinSol_KLUGetCommon(arg1); + fresult.cptr = result; + fresult.cmemflags = SWIG_MEM_RVALUE | (0 ? SWIG_MEM_OWN : 0); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetType_KLU(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_Type result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_Type)SUNLinSolGetType_KLU(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetID_KLU(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_ID result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_ID)SUNLinSolGetID_KLU(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolInitialize_KLU(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolInitialize_KLU(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetup_KLU(SUNLinearSolver farg1, SUNMatrix farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNLinSolSetup_KLU(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSolve_KLU(SUNLinearSolver farg1, SUNMatrix farg2, N_Vector farg3, N_Vector farg4, double const *farg5) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype arg5 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype)(*farg5); + result = (int)SUNLinSolSolve_KLU(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNLinSolLastFlag_KLU(SUNLinearSolver farg1) { + int64_t fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + sunindextype result; + + arg1 = (SUNLinearSolver)(farg1); + result = SUNLinSolLastFlag_KLU(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSpace_KLU(SUNLinearSolver farg1, long *farg2, long *farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNLinSolSpace_KLU(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolFree_KLU(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolFree_KLU(arg1); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fmod/fsunlinsol_klu_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fmod/fsunlinsol_klu_mod.f90 new file mode 100644 index 000000000..e15ce5448 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fmod/fsunlinsol_klu_mod.f90 @@ -0,0 +1,508 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunlinsol_klu_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_linearsolver_mod + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: SUNKLU_ORDERING_DEFAULT = 1_C_INT + integer(C_INT), parameter, public :: SUNKLU_REINIT_FULL = 1_C_INT + integer(C_INT), parameter, public :: SUNKLU_REINIT_PARTIAL = 2_C_INT + public :: FSUNLinSol_KLU + public :: FSUNLinSol_KLUReInit + public :: FSUNLinSol_KLUSetOrdering + public :: FSUNKLU + public :: FSUNKLUReInit + public :: FSUNKLUSetOrdering + + integer, parameter :: swig_cmem_own_bit = 0 + integer, parameter :: swig_cmem_rvalue_bit = 1 + integer, parameter :: swig_cmem_const_bit = 2 + type, bind(C) :: SwigClassWrapper + type(C_PTR), public :: cptr = C_NULL_PTR + integer(C_INT), public :: cmemflags = 0 + end type + type, public :: SWIGTYPE_p_klu_l_symbolic + type(SwigClassWrapper), public :: swigdata + end type + public :: FSUNLinSol_KLUGetSymbolic + type, public :: SWIGTYPE_p_klu_l_numeric + type(SwigClassWrapper), public :: swigdata + end type + public :: FSUNLinSol_KLUGetNumeric + type, public :: SWIGTYPE_p_klu_l_common + type(SwigClassWrapper), public :: swigdata + end type + public :: FSUNLinSol_KLUGetCommon + public :: FSUNLinSolGetType_KLU + public :: FSUNLinSolGetID_KLU + public :: FSUNLinSolInitialize_KLU + public :: FSUNLinSolSetup_KLU + public :: FSUNLinSolSolve_KLU + public :: FSUNLinSolLastFlag_KLU + public :: FSUNLinSolSpace_KLU + public :: FSUNLinSolFree_KLU + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNLinSol_KLU(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_KLU") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSol_KLUReInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FSUNLinSol_KLUReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSol_KLUSetOrdering(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_KLUSetOrdering") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNKLU(farg1, farg2) & +bind(C, name="_wrap_FSUNKLU") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FSUNKLUReInit(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FSUNKLUReInit") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT), intent(in) :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FSUNKLUSetOrdering(farg1, farg2) & +bind(C, name="_wrap_FSUNKLUSetOrdering") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSol_KLUGetSymbolic(farg1) & +bind(C, name="_wrap_FSUNLinSol_KLUGetSymbolic") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(C_PTR), value :: farg1 +type(SwigClassWrapper) :: fresult +end function + +function swigc_FSUNLinSol_KLUGetNumeric(farg1) & +bind(C, name="_wrap_FSUNLinSol_KLUGetNumeric") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(C_PTR), value :: farg1 +type(SwigClassWrapper) :: fresult +end function + +function swigc_FSUNLinSol_KLUGetCommon(farg1) & +bind(C, name="_wrap_FSUNLinSol_KLUGetCommon") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +import :: swigclasswrapper +type(C_PTR), value :: farg1 +type(SwigClassWrapper) :: fresult +end function + +function swigc_FSUNLinSolGetType_KLU(farg1) & +bind(C, name="_wrap_FSUNLinSolGetType_KLU") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetID_KLU(farg1) & +bind(C, name="_wrap_FSUNLinSolGetID_KLU") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolInitialize_KLU(farg1) & +bind(C, name="_wrap_FSUNLinSolInitialize_KLU") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetup_KLU(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSolSetup_KLU") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSolve_KLU(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FSUNLinSolSolve_KLU") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolLastFlag_KLU(farg1) & +bind(C, name="_wrap_FSUNLinSolLastFlag_KLU") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNLinSolSpace_KLU(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSpace_KLU") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolFree_KLU(farg1) & +bind(C, name="_wrap_FSUNLinSolFree_KLU") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNLinSol_KLU(y, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(y) +farg2 = c_loc(a) +fresult = swigc_FSUNLinSol_KLU(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSol_KLUReInit(s, a, nnz, reinit_type) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T), intent(in) :: nnz +integer(C_INT), intent(in) :: reinit_type +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT) :: farg4 + +farg1 = c_loc(s) +farg2 = c_loc(a) +farg3 = nnz +farg4 = reinit_type +fresult = swigc_FSUNLinSol_KLUReInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FSUNLinSol_KLUSetOrdering(s, ordering_choice) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: ordering_choice +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = ordering_choice +fresult = swigc_FSUNLinSol_KLUSetOrdering(farg1, farg2) +swig_result = fresult +end function + +function FSUNKLU(y, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(y) +farg2 = c_loc(a) +fresult = swigc_FSUNKLU(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNKLUReInit(s, a, nnz, reinit_type) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T), intent(in) :: nnz +integer(C_INT), intent(in) :: reinit_type +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT) :: farg4 + +farg1 = c_loc(s) +farg2 = c_loc(a) +farg3 = nnz +farg4 = reinit_type +fresult = swigc_FSUNKLUReInit(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FSUNKLUSetOrdering(s, ordering_choice) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: ordering_choice +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = ordering_choice +fresult = swigc_FSUNKLUSetOrdering(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSol_KLUGetSymbolic(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SWIGTYPE_p_klu_l_symbolic) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SwigClassWrapper) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSol_KLUGetSymbolic(farg1) +swig_result%swigdata = fresult +end function + +function FSUNLinSol_KLUGetNumeric(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SWIGTYPE_p_klu_l_numeric) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SwigClassWrapper) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSol_KLUGetNumeric(farg1) +swig_result%swigdata = fresult +end function + +function FSUNLinSol_KLUGetCommon(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SWIGTYPE_p_klu_l_common) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SwigClassWrapper) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSol_KLUGetCommon(farg1) +swig_result%swigdata = fresult +end function + +function FSUNLinSolGetType_KLU(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_Type) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetType_KLU(farg1) +swig_result = fresult +end function + +function FSUNLinSolGetID_KLU(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_ID) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetID_KLU(farg1) +swig_result = fresult +end function + +function FSUNLinSolInitialize_KLU(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolInitialize_KLU(farg1) +swig_result = fresult +end function + +function FSUNLinSolSetup_KLU(s, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(s) +farg2 = c_loc(a) +fresult = swigc_FSUNLinSolSetup_KLU(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolSolve_KLU(s, a, x, b, tol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: b +real(C_DOUBLE), intent(in) :: tol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +real(C_DOUBLE) :: farg5 + +farg1 = c_loc(s) +farg2 = c_loc(a) +farg3 = c_loc(x) +farg4 = c_loc(b) +farg5 = tol +fresult = swigc_FSUNLinSolSolve_KLU(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FSUNLinSolLastFlag_KLU(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolLastFlag_KLU(farg1) +swig_result = fresult +end function + +function FSUNLinSolSpace_KLU(s, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FSUNLinSolSpace_KLU(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolFree_KLU(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolFree_KLU(farg1) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.c index b63ff1e40..a8fad04f8 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -88,19 +88,19 @@ void FSUNKLU_REINIT(int *code, long int *NNZ, int *reinit_type, int *ier) switch(*code) { case FCMIX_CVODE: *ier = SUNLinSol_KLUReInit(F2C_CVODE_linsol, F2C_CVODE_matrix, - *NNZ, *reinit_type); + (sunindextype)(*NNZ), *reinit_type); break; case FCMIX_IDA: *ier = SUNLinSol_KLUReInit(F2C_IDA_linsol, F2C_IDA_matrix, - *NNZ, *reinit_type); + (sunindextype)(*NNZ), *reinit_type); break; case FCMIX_KINSOL: *ier = SUNLinSol_KLUReInit(F2C_KINSOL_linsol, F2C_KINSOL_matrix, - *NNZ, *reinit_type); + (sunindextype)(*NNZ), *reinit_type); break; case FCMIX_ARKODE: *ier = SUNLinSol_KLUReInit(F2C_ARKODE_linsol, F2C_ARKODE_matrix, - *NNZ, *reinit_type); + (sunindextype)(*NNZ), *reinit_type); break; default: *ier = -1; @@ -136,7 +136,7 @@ void FSUNMASSKLU_INIT(int *ier) *ier = 0; if (F2C_ARKODE_mass_sol) SUNLinSolFree(F2C_ARKODE_mass_sol); F2C_ARKODE_mass_sol = NULL; - F2C_ARKODE_mass_sol = SUNLinSol_KLU(F2C_ARKODE_vec, + F2C_ARKODE_mass_sol = SUNLinSol_KLU(F2C_ARKODE_vec, F2C_ARKODE_mass_matrix); if (F2C_ARKODE_mass_sol == NULL) *ier = -1; } @@ -146,7 +146,7 @@ void FSUNMASSKLU_REINIT(long int *NNZ, int *reinit_type, int *ier) { *ier = 0; *ier = SUNLinSol_KLUReInit(F2C_ARKODE_mass_sol, F2C_ARKODE_mass_matrix, - *NNZ, *reinit_type); + (sunindextype)(*NNZ), *reinit_type); } diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.h b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.h index b80ca5c2b..5df359bc1 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/sunlinsol_klu.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/sunlinsol_klu.c index 8038fe1ea..000a4e2dd 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/sunlinsol_klu.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/klu/sunlinsol_klu.c @@ -1,10 +1,9 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU * Based on codes _klu.c, written by Carol Woodward @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -13,10 +12,9 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the KLU implementation of + * This is the implementation file for the KLU implementation of * the SUNLINSOL package. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include @@ -29,12 +27,9 @@ #define TWO RCONST(2.0) #define TWOTHIRDS RCONST(0.666666666666666666666666666666667) -/* Private function prototypes */ -sunindextype GlobalVectorLength_KLU(N_Vector y); - /* * ----------------------------------------------------------------- - * KLU solver structure accessibility macros: + * KLU solver structure accessibility macros: * ----------------------------------------------------------------- */ @@ -74,7 +69,7 @@ int SUNKLUReInit(SUNLinearSolver S, SUNMatrix A, int SUNKLUSetOrdering(SUNLinearSolver S, int ordering_choice) { return(SUNLinSol_KLUSetOrdering(S, ordering_choice)); } - + /* * ----------------------------------------------------------------- * exported functions @@ -88,60 +83,50 @@ int SUNKLUSetOrdering(SUNLinearSolver S, SUNLinearSolver SUNLinSol_KLU(N_Vector y, SUNMatrix A) { SUNLinearSolver S; - SUNLinearSolver_Ops ops; SUNLinearSolverContent_KLU content; - sunindextype MatrixRows, VecLength; int flag; - + /* Check compatibility with supplied SUNMatrix and N_Vector */ - if (SUNMatGetID(A) != SUNMATRIX_SPARSE) - return(NULL); - if (SUNSparseMatrix_Rows(A) != SUNSparseMatrix_Columns(A)) - return(NULL); - MatrixRows = SUNSparseMatrix_Rows(A); + if (SUNMatGetID(A) != SUNMATRIX_SPARSE) return(NULL); + + if (SUNSparseMatrix_Rows(A) != SUNSparseMatrix_Columns(A)) return(NULL); + if ( (N_VGetVectorID(y) != SUNDIALS_NVEC_SERIAL) && (N_VGetVectorID(y) != SUNDIALS_NVEC_OPENMP) && (N_VGetVectorID(y) != SUNDIALS_NVEC_PTHREADS) ) return(NULL); - /* optimally this function would be replaced with a generic N_Vector routine */ - VecLength = GlobalVectorLength_KLU(y); - if (MatrixRows != VecLength) - return(NULL); - - /* Create linear solver */ + if (SUNSparseMatrix_Rows(A) != N_VGetLength(y)) return(NULL); + + /* Create an empty linear solver */ S = NULL; - S = (SUNLinearSolver) malloc(sizeof *S); + S = SUNLinSolNewEmpty(); if (S == NULL) return(NULL); - - /* Create linear solver operation structure */ - ops = NULL; - ops = (SUNLinearSolver_Ops) malloc(sizeof(struct _generic_SUNLinearSolver_Ops)); - if (ops == NULL) { free(S); return(NULL); } /* Attach operations */ - ops->gettype = SUNLinSolGetType_KLU; - ops->initialize = SUNLinSolInitialize_KLU; - ops->setup = SUNLinSolSetup_KLU; - ops->solve = SUNLinSolSolve_KLU; - ops->lastflag = SUNLinSolLastFlag_KLU; - ops->space = SUNLinSolSpace_KLU; - ops->free = SUNLinSolFree_KLU; - ops->setatimes = NULL; - ops->setpreconditioner = NULL; - ops->setscalingvectors = NULL; - ops->numiters = NULL; - ops->resnorm = NULL; - ops->resid = NULL; + S->ops->gettype = SUNLinSolGetType_KLU; + S->ops->getid = SUNLinSolGetID_KLU; + S->ops->initialize = SUNLinSolInitialize_KLU; + S->ops->setup = SUNLinSolSetup_KLU; + S->ops->solve = SUNLinSolSolve_KLU; + S->ops->lastflag = SUNLinSolLastFlag_KLU; + S->ops->space = SUNLinSolSpace_KLU; + S->ops->free = SUNLinSolFree_KLU; /* Create content */ content = NULL; - content = (SUNLinearSolverContent_KLU) malloc(sizeof(struct _SUNLinearSolverContent_KLU)); - if (content == NULL) { free(ops); free(S); return(NULL); } + content = (SUNLinearSolverContent_KLU) malloc(sizeof *content); + if (content == NULL) { SUNLinSolFree(S); return(NULL); } + + /* Attach content */ + S->content = content; /* Fill content */ - content->last_flag = 0; + content->last_flag = 0; content->first_factorize = 1; + content->symbolic = NULL; + content->numeric = NULL; + #if defined(SUNDIALS_INT64_T) if (SUNSparseMatrix_SparseType(A) == CSC_MAT) { content->klu_solver = (KLUSolveFn) &klu_l_solve; @@ -157,15 +142,10 @@ SUNLinearSolver SUNLinSol_KLU(N_Vector y, SUNMatrix A) #else /* incompatible sunindextype for KLU */ #error Incompatible sunindextype for KLU #endif - content->symbolic = NULL; - content->numeric = NULL; + flag = sun_klu_defaults(&(content->common)); - if (flag == 0) { free(content); free(ops); free(S); return(NULL); } + if (flag == 0) { SUNLinSolFree(S); return(NULL); } (content->common).ordering = SUNKLU_ORDERING_DEFAULT; - - /* Attach content and ops */ - S->content = content; - S->ops = ops; return(S); } @@ -179,7 +159,7 @@ int SUNLinSol_KLUReInit(SUNLinearSolver S, SUNMatrix A, sunindextype nnz, int reinit_type) { /* Check for non-NULL SUNLinearSolver */ - if ((S == NULL) || (A == NULL)) + if ((S == NULL) || (A == NULL)) return(SUNLS_MEM_NULL); /* Check for valid SUNMatrix */ @@ -191,7 +171,7 @@ int SUNLinSol_KLUReInit(SUNLinearSolver S, SUNMatrix A, (reinit_type != SUNKLU_REINIT_PARTIAL)) return(SUNLS_ILL_INPUT); - /* Full re-initialization: reallocate matrix for updated storage */ + /* Full re-initialization: reallocate matrix for updated storage */ if (reinit_type == SUNKLU_REINIT_FULL) if (SUNSparseMatrix_Reallocate(A, nnz) != 0) return(SUNLS_MEM_FAIL); @@ -213,7 +193,7 @@ int SUNLinSol_KLUReInit(SUNLinearSolver S, SUNMatrix A, int SUNLinSol_KLUSetOrdering(SUNLinearSolver S, int ordering_choice) { - /* Check for legal ordering_choice */ + /* Check for legal ordering_choice */ if ((ordering_choice < 0) || (ordering_choice > 2)) return(SUNLS_ILL_INPUT); @@ -227,6 +207,29 @@ int SUNLinSol_KLUSetOrdering(SUNLinearSolver S, int ordering_choice) return(LASTFLAG(S)); } + +/* + * ----------------------------------------------------------------- + * accessor functions + * ----------------------------------------------------------------- + */ + +sun_klu_symbolic* SUNLinSol_KLUGetSymbolic(SUNLinearSolver S) +{ + return(SYMBOLIC(S)); +} + +sun_klu_numeric* SUNLinSol_KLUGetNumeric(SUNLinearSolver S) +{ + return(NUMERIC(S)); +} + +sun_klu_common* SUNLinSol_KLUGetCommon(SUNLinearSolver S) +{ + return(&(COMMON(S))); +} + + /* * ----------------------------------------------------------------- * implementation of linear solver operations @@ -239,11 +242,17 @@ SUNLinearSolver_Type SUNLinSolGetType_KLU(SUNLinearSolver S) } +SUNLinearSolver_ID SUNLinSolGetID_KLU(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_KLU); +} + + int SUNLinSolInitialize_KLU(SUNLinearSolver S) { /* Force factorization */ FIRSTFACTORIZE(S) = 1; - + LASTFLAG(S) = SUNLS_SUCCESS; return(LASTFLAG(S)); } @@ -253,7 +262,7 @@ int SUNLinSolSetup_KLU(SUNLinearSolver S, SUNMatrix A) { int retval; realtype uround_twothirds; - + uround_twothirds = SUNRpowerR(UNIT_ROUNDOFF,TWOTHIRDS); /* Ensure that A is a sparse matrix */ @@ -261,16 +270,16 @@ int SUNLinSolSetup_KLU(SUNLinearSolver S, SUNMatrix A) LASTFLAG(S) = SUNLS_ILL_INPUT; return(LASTFLAG(S)); } - - /* On first decomposition, get the symbolic factorization */ + + /* On first decomposition, get the symbolic factorization */ if (FIRSTFACTORIZE(S)) { /* Perform symbolic analysis of sparsity structure */ - if (SYMBOLIC(S)) + if (SYMBOLIC(S)) sun_klu_free_symbolic(&SYMBOLIC(S), &COMMON(S)); - SYMBOLIC(S) = sun_klu_analyze(SUNSparseMatrix_NP(A), - (KLU_INDEXTYPE*) SUNSparseMatrix_IndexPointers(A), - (KLU_INDEXTYPE*) SUNSparseMatrix_IndexValues(A), + SYMBOLIC(S) = sun_klu_analyze(SUNSparseMatrix_NP(A), + (KLU_INDEXTYPE*) SUNSparseMatrix_IndexPointers(A), + (KLU_INDEXTYPE*) SUNSparseMatrix_IndexValues(A), &COMMON(S)); if (SYMBOLIC(S) == NULL) { LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; @@ -280,12 +289,12 @@ int SUNLinSolSetup_KLU(SUNLinearSolver S, SUNMatrix A) /* ------------------------------------------------------------ Compute the LU factorization of the matrix ------------------------------------------------------------*/ - if(NUMERIC(S)) + if(NUMERIC(S)) sun_klu_free_numeric(&NUMERIC(S), &COMMON(S)); - NUMERIC(S) = sun_klu_factor((KLU_INDEXTYPE*) SUNSparseMatrix_IndexPointers(A), - (KLU_INDEXTYPE*) SUNSparseMatrix_IndexValues(A), - SUNSparseMatrix_Data(A), - SYMBOLIC(S), + NUMERIC(S) = sun_klu_factor((KLU_INDEXTYPE*) SUNSparseMatrix_IndexPointers(A), + (KLU_INDEXTYPE*) SUNSparseMatrix_IndexValues(A), + SUNSparseMatrix_Data(A), + SYMBOLIC(S), &COMMON(S)); if (NUMERIC(S) == NULL) { LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; @@ -296,9 +305,9 @@ int SUNLinSolSetup_KLU(SUNLinearSolver S, SUNMatrix A) } else { /* not the first decomposition, so just refactor */ - retval = sun_klu_refactor((KLU_INDEXTYPE*) SUNSparseMatrix_IndexPointers(A), - (KLU_INDEXTYPE*) SUNSparseMatrix_IndexValues(A), - SUNSparseMatrix_Data(A), + retval = sun_klu_refactor((KLU_INDEXTYPE*) SUNSparseMatrix_IndexPointers(A), + (KLU_INDEXTYPE*) SUNSparseMatrix_IndexValues(A), + SUNSparseMatrix_Data(A), SYMBOLIC(S), NUMERIC(S), &COMMON(S)); @@ -306,13 +315,13 @@ int SUNLinSolSetup_KLU(SUNLinearSolver S, SUNMatrix A) LASTFLAG(S) = SUNLS_PACKAGE_FAIL_REC; return(LASTFLAG(S)); } - + /*----------------------------------------------------------- - Check if a cheap estimate of the reciprocal of the condition + Check if a cheap estimate of the reciprocal of the condition number is getting too small. If so, delete the prior numeric factorization and recompute it. -----------------------------------------------------------*/ - + retval = sun_klu_rcond(SYMBOLIC(S), NUMERIC(S), &COMMON(S)); if (retval == 0) { LASTFLAG(S) = SUNLS_PACKAGE_FAIL_REC; @@ -320,11 +329,11 @@ int SUNLinSolSetup_KLU(SUNLinearSolver S, SUNMatrix A) } if ( COMMON(S).rcond < uround_twothirds ) { - - /* Condition number may be getting large. + + /* Condition number may be getting large. Compute more accurate estimate */ - retval = sun_klu_condest((KLU_INDEXTYPE*) SUNSparseMatrix_IndexPointers(A), - SUNSparseMatrix_Data(A), + retval = sun_klu_condest((KLU_INDEXTYPE*) SUNSparseMatrix_IndexPointers(A), + SUNSparseMatrix_Data(A), SYMBOLIC(S), NUMERIC(S), &COMMON(S)); @@ -332,23 +341,23 @@ int SUNLinSolSetup_KLU(SUNLinearSolver S, SUNMatrix A) LASTFLAG(S) = SUNLS_PACKAGE_FAIL_REC; return(LASTFLAG(S)); } - + if ( COMMON(S).condest > (ONE/uround_twothirds) ) { - /* More accurate estimate also says condition number is + /* More accurate estimate also says condition number is large, so recompute the numeric factorization */ sun_klu_free_numeric(&NUMERIC(S), &COMMON(S)); - NUMERIC(S) = sun_klu_factor((KLU_INDEXTYPE*) SUNSparseMatrix_IndexPointers(A), - (KLU_INDEXTYPE*) SUNSparseMatrix_IndexValues(A), - SUNSparseMatrix_Data(A), - SYMBOLIC(S), + NUMERIC(S) = sun_klu_factor((KLU_INDEXTYPE*) SUNSparseMatrix_IndexPointers(A), + (KLU_INDEXTYPE*) SUNSparseMatrix_IndexValues(A), + SUNSparseMatrix_Data(A), + SYMBOLIC(S), &COMMON(S)); if (NUMERIC(S) == NULL) { LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; return(LASTFLAG(S)); } } - + } } @@ -357,16 +366,16 @@ int SUNLinSolSetup_KLU(SUNLinearSolver S, SUNMatrix A) } -int SUNLinSolSolve_KLU(SUNLinearSolver S, SUNMatrix A, N_Vector x, +int SUNLinSolSolve_KLU(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype tol) { int flag; realtype *xdata; - + /* check for valid inputs */ - if ( (A == NULL) || (S == NULL) || (x == NULL) || (b == NULL) ) + if ( (A == NULL) || (S == NULL) || (x == NULL) || (b == NULL) ) return(SUNLS_MEM_NULL); - + /* copy b into x */ N_VScale(ONE, b, x); @@ -376,10 +385,10 @@ int SUNLinSolSolve_KLU(SUNLinearSolver S, SUNMatrix A, N_Vector x, LASTFLAG(S) = SUNLS_MEM_FAIL; return(LASTFLAG(S)); } - + /* Call KLU to solve the linear system */ - flag = SOLVE(S)(SYMBOLIC(S), NUMERIC(S), - SUNSparseMatrix_NP(A), 1, xdata, + flag = SOLVE(S)(SYMBOLIC(S), NUMERIC(S), + SUNSparseMatrix_NP(A), 1, xdata, &COMMON(S)); if (flag == 0) { LASTFLAG(S) = SUNLS_PACKAGE_FAIL_REC; @@ -391,18 +400,19 @@ int SUNLinSolSolve_KLU(SUNLinearSolver S, SUNMatrix A, N_Vector x, } -long int SUNLinSolLastFlag_KLU(SUNLinearSolver S) +sunindextype SUNLinSolLastFlag_KLU(SUNLinearSolver S) { /* return the stored 'last_flag' value */ + if (S == NULL) return(-1); return(LASTFLAG(S)); } -int SUNLinSolSpace_KLU(SUNLinearSolver S, - long int *lenrwLS, +int SUNLinSolSpace_KLU(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS) { - /* since the klu structures are opaque objects, we + /* since the klu structures are opaque objects, we omit those from these results */ *leniwLS = 2; *lenrwLS = 0; @@ -412,46 +422,23 @@ int SUNLinSolSpace_KLU(SUNLinearSolver S, int SUNLinSolFree_KLU(SUNLinearSolver S) { /* return with success if already freed */ - if (S == NULL) - return(SUNLS_SUCCESS); - + if (S == NULL) return(SUNLS_SUCCESS); + /* delete items from the contents structure (if it exists) */ if (S->content) { if (NUMERIC(S)) sun_klu_free_numeric(&NUMERIC(S), &COMMON(S)); if (SYMBOLIC(S)) sun_klu_free_symbolic(&SYMBOLIC(S), &COMMON(S)); - free(S->content); + free(S->content); S->content = NULL; } - + /* delete generic structures */ if (S->ops) { - free(S->ops); + free(S->ops); S->ops = NULL; } free(S); S = NULL; return(SUNLS_SUCCESS); } - -/* - * ----------------------------------------------------------------- - * private functions - * ----------------------------------------------------------------- - */ - -/* Inefficient kludge for determining the number of entries in a N_Vector - object (replace if such a routine is ever added to the N_Vector API). - - Returns "-1" on an error. */ -sunindextype GlobalVectorLength_KLU(N_Vector y) -{ - realtype len; - N_Vector tmp = NULL; - tmp = N_VClone(y); - if (tmp == NULL) return(-1); - N_VConst(ONE, tmp); - len = N_VDotProd(tmp, tmp); - N_VDestroy(tmp); - return( (sunindextype) len ); -} diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/CMakeLists.txt index 1ef5cff24..2bb5a4ef0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,92 +12,121 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the LapackBand SUNLinearSolver library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNLINSOL_LAPACKBAND\n\")") - -# Add variable sunlinsollapackband_SOURCES with the sources for the SUNLINSOLLAPACKBAND lib -SET(sunlinsollapackband_SOURCES sunlinsol_lapackband.c) - -# Add variable shared_SOURCES with the common SUNDIALS sources which will -# also be included in the SUNLINSOLLAPACKBAND library -SET(shared_SOURCES - ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c - ) +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_LAPACKBAND\n\")") -# Add variable sunlinsollapackband_HEADERS with the -# exported SUNLINSOLLAPACKBAND header files -SET(sunlinsollapackband_HEADERS - ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_lapackband.h - ) +# Source files for the library +set(sunlinsollapackband_SOURCES sunlinsol_lapackband.c) -# Add source directory to include directories -INCLUDE_DIRECTORIES(.) +# Common SUNDIALS sources included in the library +set(shared_SOURCES + ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c) -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Exported header files +set(sunlinsollapackband_HEADERS + ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_lapackband.h) # Rules for building and installing the static library: -# - Add the build target for the SUNLINSOLLAPACKBAND library +# - Add the build target for the library # - Set the library name and make sure it is not deleted -# - Install the SUNLINSOLLAPACKBAND library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunlinsollapackband_static STATIC ${sunlinsollapackband_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunlinsollapackband_static - PROPERTIES OUTPUT_NAME sundials_sunlinsollapackband CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunlinsollapackband_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +# - Install the library +if(BUILD_STATIC_LIBS) + + add_library(sundials_sunlinsollapackband_static + STATIC ${sunlinsollapackband_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsollapackband_static + PROPERTIES + OUTPUT_NAME sundials_sunlinsollapackband + CLEAN_DIRECT_OUTPUT 1) + + # depends on sunmatrixband and LAPACK + target_link_libraries(sundials_sunlinsollapackband_static + PUBLIC sundials_sunmatrixband_static ${LAPACK_LIBRARIES}) + + target_compile_definitions(sundials_sunlinsollapackband_static + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsollapackband_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: -# - Add the build target for the SUNLINSOLLAPACKBAND library +# - Add the build target for the library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries -# - Install the SUNLINSOLLAPACKBAND library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunlinsollapackband_shared SHARED ${sunlinsollapackband_SOURCES} ${shared_SOURCES}) - - # sunlinsollapackband depends on sunmatrixband and LAPACK - TARGET_LINK_LIBRARIES(sundials_sunlinsollapackband_shared - sundials_sunmatrixband_shared - ${LAPACK_LIBRARIES}) - - SET_TARGET_PROPERTIES(sundials_sunlinsollapackband_shared - PROPERTIES OUTPUT_NAME sundials_sunlinsollapackband CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunlinsollapackband_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_sunlinsollapackband_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) - -# Install the SUNLINSOLLAPACKBAND header files -INSTALL(FILES ${sunlinsollapackband_HEADERS} DESTINATION include/sunlinsol) - -# If FCMIX is enabled, build and install the FSUNLINSOLLAPACKBAND library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunlinsollapackband_SOURCES fsunlinsol_lapackband.c) - - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunlinsollapackband_static STATIC ${fsunlinsollapackband_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunlinsollapackband_static - PROPERTIES OUTPUT_NAME sundials_fsunlinsollapackband CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunlinsollapackband_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) - - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunlinsollapackband_shared ${fsunlinsollapackband_SOURCES}) - - # fsunlinsollapackband depends on fnvecserial, fsunmatrixband, sunlinsollapackband - TARGET_LINK_LIBRARIES(sundials_fsunlinsollapackband_shared +# - Install the library +if(BUILD_SHARED_LIBS) + + add_library(sundials_sunlinsollapackband_shared + SHARED ${sunlinsollapackband_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsollapackband_shared + PROPERTIES + OUTPUT_NAME sundials_sunlinsollapackband + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + + # depends on sunmatrixband and LAPACK + target_link_libraries(sundials_sunlinsollapackband_shared + PUBLIC sundials_sunmatrixband_shared ${LAPACK_LIBRARIES}) + + install(TARGETS sundials_sunlinsollapackband_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_SHARED_LIBS) + +# Install the header files +install(FILES ${sunlinsollapackband_HEADERS} DESTINATION include/sunlinsol) + +# +message(STATUS "Added SUNLINSOL_LAPACKBAND module") + +# If FCMIX is enabled, build and install the F77 library +if(F77_INTERFACE_ENABLE AND F77_FOUND) + + set(fsunlinsollapackband_SOURCES fsunlinsol_lapackband.c) + + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunlinsollapackband_static + STATIC ${fsunlinsollapackband_SOURCES}) + set_target_properties(sundials_fsunlinsollapackband_static + PROPERTIES + OUTPUT_NAME sundials_fsunlinsollapackband + CLEAN_DIRECT_OUTPUT 1) + # depends on fnvecserial, fsunmatrixband, sunlinsollapackband + target_link_libraries(sundials_fsunlinsollapackband_static + PUBLIC + sundials_fnvecserial_static + sundials_fsunmatrixband_static + sundials_sunlinsollapackband_static) + install(TARGETS sundials_fsunlinsollapackband_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) + + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunlinsollapackband_shared + SHARED ${fsunlinsollapackband_SOURCES}) + set_target_properties(sundials_fsunlinsollapackband_shared + PROPERTIES + OUTPUT_NAME sundials_fsunlinsollapackband + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + # depends on fnvecserial, fsunmatrixband, sunlinsollapackband + target_link_libraries(sundials_fsunlinsollapackband_shared + PUBLIC sundials_fnvecserial_shared sundials_fsunmatrixband_shared sundials_sunlinsollapackband_shared) + install(TARGETS sundials_fsunlinsollapackband_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) - SET_TARGET_PROPERTIES(sundials_fsunlinsollapackband_shared - PROPERTIES OUTPUT_NAME sundials_fsunlinsollapackband CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunlinsollapackband_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_fsunlinsollapackband_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + # + message(STATUS "Added SUNLINSOL_LAPACKBAND F77 interface") -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) - -# -MESSAGE(STATUS "Added SUNLINSOL_LAPACKBAND module") +endif(F77_INTERFACE_ENABLE AND F77_FOUND) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.c index c54b9da2c..6f5d5edb2 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.h b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.h index ef8383d6f..45513e60b 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/sunlinsol_lapackband.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/sunlinsol_lapackband.c index 7c890461c..945515499 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/sunlinsol_lapackband.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackband/sunlinsol_lapackband.c @@ -1,10 +1,9 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU * Based on codes _lapack.c by: Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -13,10 +12,9 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the LAPACK band + * This is the implementation file for the LAPACK band * implementation of the SUNLINSOL package. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include @@ -27,12 +25,9 @@ #define ZERO RCONST(0.0) #define ONE RCONST(1.0) -/* Private function prototypes */ -sunindextype GlobalVectorLength_LapBand(N_Vector y); - /* * ----------------------------------------------------------------- - * Band solver structure accessibility macros: + * Band solver structure accessibility macros: * ----------------------------------------------------------------- */ @@ -62,68 +57,53 @@ SUNLinearSolver SUNLapackBand(N_Vector y, SUNMatrix A) SUNLinearSolver SUNLinSol_LapackBand(N_Vector y, SUNMatrix A) { SUNLinearSolver S; - SUNLinearSolver_Ops ops; SUNLinearSolverContent_LapackBand content; - sunindextype MatrixRows, VecLength; - + sunindextype MatrixRows; + /* Check compatibility with supplied SUNMatrix and N_Vector */ - if (SUNMatGetID(A) != SUNMATRIX_BAND) - return(NULL); - if (SUNBandMatrix_Rows(A) != SUNBandMatrix_Columns(A)) - return(NULL); - MatrixRows = SUNBandMatrix_Rows(A); + if (SUNMatGetID(A) != SUNMATRIX_BAND) return(NULL); + + if (SUNBandMatrix_Rows(A) != SUNBandMatrix_Columns(A)) return(NULL); + if ( (N_VGetVectorID(y) != SUNDIALS_NVEC_SERIAL) && (N_VGetVectorID(y) != SUNDIALS_NVEC_OPENMP) && (N_VGetVectorID(y) != SUNDIALS_NVEC_PTHREADS) ) return(NULL); - /* optimally this function would be replaced with a generic N_Vector routine */ - VecLength = GlobalVectorLength_LapBand(y); - if (MatrixRows != VecLength) - return(NULL); - - /* Create linear solver */ + MatrixRows = SUNBandMatrix_Rows(A); + if (MatrixRows != N_VGetLength(y)) return(NULL); + + /* Create an empty linear solver */ S = NULL; - S = (SUNLinearSolver) malloc(sizeof *S); + S = SUNLinSolNewEmpty(); if (S == NULL) return(NULL); - - /* Create linear solver operation structure */ - ops = NULL; - ops = (SUNLinearSolver_Ops) malloc(sizeof(struct _generic_SUNLinearSolver_Ops)); - if (ops == NULL) { free(S); return(NULL); } /* Attach operations */ - ops->gettype = SUNLinSolGetType_LapackBand; - ops->initialize = SUNLinSolInitialize_LapackBand; - ops->setup = SUNLinSolSetup_LapackBand; - ops->solve = SUNLinSolSolve_LapackBand; - ops->lastflag = SUNLinSolLastFlag_LapackBand; - ops->space = SUNLinSolSpace_LapackBand; - ops->free = SUNLinSolFree_LapackBand; - ops->setatimes = NULL; - ops->setpreconditioner = NULL; - ops->setscalingvectors = NULL; - ops->numiters = NULL; - ops->resnorm = NULL; - ops->resid = NULL; + S->ops->gettype = SUNLinSolGetType_LapackBand; + S->ops->getid = SUNLinSolGetID_LapackBand; + S->ops->initialize = SUNLinSolInitialize_LapackBand; + S->ops->setup = SUNLinSolSetup_LapackBand; + S->ops->solve = SUNLinSolSolve_LapackBand; + S->ops->lastflag = SUNLinSolLastFlag_LapackBand; + S->ops->space = SUNLinSolSpace_LapackBand; + S->ops->free = SUNLinSolFree_LapackBand; /* Create content */ content = NULL; - content = (SUNLinearSolverContent_LapackBand) malloc(sizeof(struct _SUNLinearSolverContent_LapackBand)); - if (content == NULL) { free(ops); free(S); return(NULL); } + content = (SUNLinearSolverContent_LapackBand) malloc(sizeof *content); + if (content == NULL) { SUNLinSolFree(S); return(NULL); } + + /* Attach content */ + S->content = content; /* Fill content */ - content->N = MatrixRows; + content->N = MatrixRows; content->last_flag = 0; - content->pivots = NULL; + content->pivots = NULL; + + /* Allocate content */ content->pivots = (sunindextype *) malloc(MatrixRows * sizeof(sunindextype)); - if (content->pivots == NULL) { - free(content); free(ops); free(S); return(NULL); - } - - /* Attach content and ops */ - S->content = content; - S->ops = ops; + if (content->pivots == NULL) { SUNLinSolFree(S); return(NULL); } return(S); } @@ -141,91 +121,98 @@ SUNLinearSolver_Type SUNLinSolGetType_LapackBand(SUNLinearSolver S) } +SUNLinearSolver_ID SUNLinSolGetID_LapackBand(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_LAPACKBAND); +} + + int SUNLinSolInitialize_LapackBand(SUNLinearSolver S) { /* all solver-specific memory has already been allocated */ LASTFLAG(S) = SUNLS_SUCCESS; - return(LASTFLAG(S)); + return(SUNLS_SUCCESS); } int SUNLinSolSetup_LapackBand(SUNLinearSolver S, SUNMatrix A) { - int n, ml, mu, ldim, ier; + sunindextype n, ml, mu, ldim, ier; /* check for valid inputs */ - if ( (A == NULL) || (S == NULL) ) + if ( (A == NULL) || (S == NULL) ) return(SUNLS_MEM_NULL); - + /* Ensure that A is a band matrix */ if (SUNMatGetID(A) != SUNMATRIX_BAND) { LASTFLAG(S) = SUNLS_ILL_INPUT; - return(LASTFLAG(S)); + return(SUNLS_ILL_INPUT); } - + /* Call LAPACK to do LU factorization of A */ n = SUNBandMatrix_Rows(A); ml = SUNBandMatrix_LowerBandwidth(A); mu = SUNBandMatrix_UpperBandwidth(A); ldim = SUNBandMatrix_LDim(A); - xgbtrf_f77(&n, &n, &ml, &mu, SUNBandMatrix_Data(A), - &ldim, PIVOTS(S), &ier); - - LASTFLAG(S) = (long int) ier; - if (ier > 0) + xgbtrf_f77(&n, &n, &ml, &mu, SUNBandMatrix_Data(A), + &ldim, PIVOTS(S), &ier); + + LASTFLAG(S) = ier; + if (ier > 0) return(SUNLS_LUFACT_FAIL); - if (ier < 0) + if (ier < 0) return(SUNLS_PACKAGE_FAIL_UNREC); return(SUNLS_SUCCESS); } -int SUNLinSolSolve_LapackBand(SUNLinearSolver S, SUNMatrix A, N_Vector x, +int SUNLinSolSolve_LapackBand(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype tol) { - int n, ml, mu, ldim, one, ier; + sunindextype n, ml, mu, ldim, one, ier; realtype *xdata; - + /* check for valid inputs */ - if ( (A == NULL) || (S == NULL) || (x == NULL) || (b == NULL) ) + if ( (A == NULL) || (S == NULL) || (x == NULL) || (b == NULL) ) return(SUNLS_MEM_NULL); - + /* copy b into x */ N_VScale(ONE, b, x); /* access x data array */ xdata = N_VGetArrayPointer(x); if (xdata == NULL) { - LASTFLAG(S) = 1; - return(LASTFLAG(S)); + LASTFLAG(S) = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); } - + /* Call LAPACK to solve the linear system */ n = SUNBandMatrix_Rows(A); ml = SUNBandMatrix_LowerBandwidth(A); mu = SUNBandMatrix_UpperBandwidth(A); ldim = SUNBandMatrix_LDim(A); one = 1; - xgbtrs_f77("N", &n, &ml, &mu, &one, SUNBandMatrix_Data(A), - &ldim, PIVOTS(S), xdata, &n, &ier, 1); - LASTFLAG(S) = (long int) ier; - if (ier < 0) + xgbtrs_f77("N", &n, &ml, &mu, &one, SUNBandMatrix_Data(A), + &ldim, PIVOTS(S), xdata, &n, &ier); + LASTFLAG(S) = ier; + if (ier < 0) return(SUNLS_PACKAGE_FAIL_UNREC); LASTFLAG(S) = SUNLS_SUCCESS; - return(LASTFLAG(S)); + return(SUNLS_SUCCESS); } -long int SUNLinSolLastFlag_LapackBand(SUNLinearSolver S) +sunindextype SUNLinSolLastFlag_LapackBand(SUNLinearSolver S) { /* return the stored 'last_flag' value */ + if (S == NULL) return(-1); return(LASTFLAG(S)); } -int SUNLinSolSpace_LapackBand(SUNLinearSolver S, - long int *lenrwLS, +int SUNLinSolSpace_LapackBand(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS) { *lenrwLS = 0; @@ -236,45 +223,21 @@ int SUNLinSolSpace_LapackBand(SUNLinearSolver S, int SUNLinSolFree_LapackBand(SUNLinearSolver S) { /* return with success if already freed */ - if (S == NULL) - return(SUNLS_SUCCESS); - + if (S == NULL) return(SUNLS_SUCCESS); + /* delete items from contents, then delete generic structure */ if (S->content) { if (PIVOTS(S)) { free(PIVOTS(S)); PIVOTS(S) = NULL; } - free(S->content); + free(S->content); S->content = NULL; } - if (S->ops) { - free(S->ops); + free(S->ops); S->ops = NULL; } free(S); S = NULL; return(SUNLS_SUCCESS); } - -/* - * ----------------------------------------------------------------- - * private functions - * ----------------------------------------------------------------- - */ - -/* Inefficient kludge for determining the number of entries in a N_Vector - object (replace if such a routine is ever added to the N_Vector API). - - Returns "-1" on an error. */ -sunindextype GlobalVectorLength_LapBand(N_Vector y) -{ - realtype len; - N_Vector tmp = NULL; - tmp = N_VClone(y); - if (tmp == NULL) return(-1); - N_VConst(ONE, tmp); - len = N_VDotProd(tmp, tmp); - N_VDestroy(tmp); - return( (sunindextype) len ); -} diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/CMakeLists.txt index 35605825c..c54f9228b 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,98 +12,124 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the LapackDense SUNLinearSolver library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNLINSOL_LAPACKDENSE\n\")") - -# Add variable sunlinsollapackdense_SOURCES with the sources for -# the SUNLINSOLLAPACKDENSE lib -SET(sunlinsollapackdense_SOURCES sunlinsol_lapackdense.c) - -# Add variable shared_SOURCES with the common SUNDIALS sources which will -# also be included in the SUNLINSOLLAPACKDENSE library -SET(shared_SOURCES - ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c - ) +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_LAPACKDENSE\n\")") -# Add variable sunlinsollapackdense_HEADERS with the -# exported SUNLINSOLLAPACKDENSE header files -SET(sunlinsollapackdense_HEADERS - ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_lapackdense.h - ) +# Source files for the library +set(sunlinsollapackdense_SOURCES sunlinsol_lapackdense.c) -# Add source directory to include directories -INCLUDE_DIRECTORIES(.) +# Common SUNDIALS sources included in the library +set(shared_SOURCES + ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c) -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Exported header files +set(sunlinsollapackdense_HEADERS + ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_lapackdense.h) # Rules for building and installing the static library: -# - Add the build target for the SUNLINSOLLAPACKDENSE library +# - Add the build target for the library # - Set the library name and make sure it is not deleted -# - Install the SUNLINSOLLAPACKDENSE library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunlinsollapackdense_static STATIC ${sunlinsollapackdense_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunlinsollapackdense_static - PROPERTIES OUTPUT_NAME sundials_sunlinsollapackdense CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunlinsollapackdense_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +# - Install the library +if(BUILD_STATIC_LIBS) + + add_library(sundials_sunlinsollapackdense_static + STATIC ${sunlinsollapackdense_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsollapackdense_static + PROPERTIES + OUTPUT_NAME sundials_sunlinsollapackdense + CLEAN_DIRECT_OUTPUT 1) + + # depends on sunmatrixdense and LAPACK + target_link_libraries(sundials_sunlinsollapackdense_static + PUBLIC sundials_sunmatrixdense_static ${LAPACK_LIBRARIES}) + + target_compile_definitions(sundials_sunlinsollapackdense_static + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsollapackdense_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: -# - Add the build target for the SUNLINSOLLAPACKDENSE library +# - Add the build target for the library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries -# - Install the SUNLINSOLLAPACKDENSE library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunlinsollapackdense_shared SHARED ${sunlinsollapackdense_SOURCES} ${shared_SOURCES}) - - # sunlinsollapackdense depends on sunmatrixdense and LAPACK - TARGET_LINK_LIBRARIES(sundials_sunlinsollapackdense_shared - sundials_sunmatrixdense_shared - ${LAPACK_LIBRARIES}) - - # if a blas library was provided, assume LAPACK depends on it - IF(BLAS_FOUND) - TARGET_LINK_LIBRARIES(sundials_sunlinsollapackdense_shared ${BLAS_LIBRARIES}) - ENDIF() - - SET_TARGET_PROPERTIES(sundials_sunlinsollapackdense_shared - PROPERTIES OUTPUT_NAME sundials_sunlinsollapackdense CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunlinsollapackdense_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_sunlinsollapackdense_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) - -# Install the SUNLINSOLLAPACKDENSE header files -INSTALL(FILES ${sunlinsollapackdense_HEADERS} DESTINATION include/sunlinsol) - -# If FCMIX is enabled, build and install the FSUNLINSOLLAPACKDENSE library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunlinsollapackdense_SOURCES fsunlinsol_lapackdense.c) - - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunlinsollapackdense_static STATIC ${fsunlinsollapackdense_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunlinsollapackdense_static - PROPERTIES OUTPUT_NAME sundials_fsunlinsollapackdense CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunlinsollapackdense_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) - - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunlinsollapackdense_shared ${fsunlinsollapackdense_SOURCES}) - - # fsunlinsollapack depends on fnvecserial, fsunmatrixdense, sunlinsollapackdense - TARGET_LINK_LIBRARIES(sundials_fsunlinsollapackdense_shared +# - Install the library +if(BUILD_SHARED_LIBS) + + add_library(sundials_sunlinsollapackdense_shared + SHARED ${sunlinsollapackdense_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsollapackdense_shared + PROPERTIES + OUTPUT_NAME sundials_sunlinsollapackdense + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + + # depends on sunmatrixdense and LAPACK + target_link_libraries(sundials_sunlinsollapackdense_shared + PUBLIC sundials_sunmatrixdense_shared ${LAPACK_LIBRARIES}) + + target_compile_definitions(sundials_sunlinsollapackdense_shared + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsollapackdense_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_SHARED_LIBS) + +# Install the header files +install(FILES ${sunlinsollapackdense_HEADERS} DESTINATION include/sunlinsol) + +# +message(STATUS "Added SUNLINSOL_LAPACKDENSE module") + +# If FCMIX is enabled, build and install the Fortran77 library +if(F77_INTERFACE_ENABLE AND F77_FOUND) + + set(fsunlinsollapackdense_SOURCES fsunlinsol_lapackdense.c) + + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunlinsollapackdense_static + STATIC ${fsunlinsollapackdense_SOURCES}) + set_target_properties(sundials_fsunlinsollapackdense_static + PROPERTIES + OUTPUT_NAME sundials_fsunlinsollapackdense + CLEAN_DIRECT_OUTPUT 1) + # depends on fnvecserial, fsunmatrixdense, sunlinsollapackdense + target_link_libraries(sundials_fsunlinsollapackdense_static + PUBLIC + sundials_fnvecserial_static + sundials_fsunmatrixdense_static + sundials_sunlinsollapackdense_static) + install(TARGETS sundials_fsunlinsollapackdense_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) + + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunlinsollapackdense_shared + SHARED ${fsunlinsollapackdense_SOURCES}) + set_target_properties(sundials_fsunlinsollapackdense_shared + PROPERTIES + OUTPUT_NAME sundials_fsunlinsollapackdense + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + # depends on fnvecserial, fsunmatrixdense, sunlinsollapackdense + target_link_libraries(sundials_fsunlinsollapackdense_shared + PUBLIC sundials_fnvecserial_shared sundials_fsunmatrixdense_shared sundials_sunlinsollapackdense_shared) + install(TARGETS sundials_fsunlinsollapackdense_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) - SET_TARGET_PROPERTIES(sundials_fsunlinsollapackdense_shared - PROPERTIES OUTPUT_NAME sundials_fsunlinsollapackdense CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunlinsollapackdense_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_fsunlinsollapackdense_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + # + message(STATUS "Added SUNLINSOL_LAPACKDENSE F77 interface") -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) - -# -MESSAGE(STATUS "Added SUNLINSOL_LAPACKDENSE module") +endif(F77_INTERFACE_ENABLE AND F77_FOUND) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.c index eaed35e1d..5be2f67f3 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.h b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.h index d97a7f534..c1aa7c8ce 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/sunlinsol_lapackdense.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/sunlinsol_lapackdense.c index e3f470732..6d7a0d32e 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/sunlinsol_lapackdense.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/lapackdense/sunlinsol_lapackdense.c @@ -1,10 +1,9 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU * Based on codes _lapack.c by: Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -13,10 +12,9 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the LAPACK dense + * This is the implementation file for the LAPACK dense * implementation of the SUNLINSOL package. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include @@ -27,12 +25,9 @@ #define ZERO RCONST(0.0) #define ONE RCONST(1.0) -/* Private function prototypes */ -sunindextype GlobalVectorLength_LapDense(N_Vector y); - /* * ----------------------------------------------------------------- - * LapackDense solver structure accessibility macros: + * LapackDense solver structure accessibility macros: * ----------------------------------------------------------------- */ @@ -62,69 +57,53 @@ SUNLinearSolver SUNLapackDense(N_Vector y, SUNMatrix A) SUNLinearSolver SUNLinSol_LapackDense(N_Vector y, SUNMatrix A) { SUNLinearSolver S; - SUNLinearSolver_Ops ops; SUNLinearSolverContent_LapackDense content; - sunindextype MatrixRows, VecLength; - + sunindextype MatrixRows; + /* Check compatibility with supplied SUNMatrix and N_Vector */ - if (SUNMatGetID(A) != SUNMATRIX_DENSE) - return(NULL); - if (SUNDenseMatrix_Rows(A) != SUNDenseMatrix_Columns(A)) - return(NULL); - MatrixRows = SUNDenseMatrix_Rows(A); + if (SUNMatGetID(A) != SUNMATRIX_DENSE) return(NULL); + + if (SUNDenseMatrix_Rows(A) != SUNDenseMatrix_Columns(A)) return(NULL); + if ( (N_VGetVectorID(y) != SUNDIALS_NVEC_SERIAL) && (N_VGetVectorID(y) != SUNDIALS_NVEC_OPENMP) && (N_VGetVectorID(y) != SUNDIALS_NVEC_PTHREADS) ) return(NULL); - /* optimally this function would be replaced with a generic N_Vector routine */ - VecLength = GlobalVectorLength_LapDense(y); - if (MatrixRows != VecLength) - return(NULL); - + MatrixRows = SUNDenseMatrix_Rows(A); + if (MatrixRows != N_VGetLength(y)) return(NULL); + /* Create linear solver */ S = NULL; - S = (SUNLinearSolver) malloc(sizeof *S); + S = SUNLinSolNewEmpty(); if (S == NULL) return(NULL); - - /* Create linear solver operation structure */ - ops = NULL; - ops = (SUNLinearSolver_Ops) malloc(sizeof(struct _generic_SUNLinearSolver_Ops)); - if (ops == NULL) { free(S); return(NULL); } /* Attach operations */ - ops->gettype = SUNLinSolGetType_LapackDense; - ops->initialize = SUNLinSolInitialize_LapackDense; - ops->setup = SUNLinSolSetup_LapackDense; - ops->solve = SUNLinSolSolve_LapackDense; - ops->lastflag = SUNLinSolLastFlag_LapackDense; - ops->space = SUNLinSolSpace_LapackDense; - ops->free = SUNLinSolFree_LapackDense; - ops->setatimes = NULL; - ops->setpreconditioner = NULL; - ops->setscalingvectors = NULL; - ops->numiters = NULL; - ops->resnorm = NULL; - ops->resid = NULL; + S->ops->gettype = SUNLinSolGetType_LapackDense; + S->ops->getid = SUNLinSolGetID_LapackDense; + S->ops->initialize = SUNLinSolInitialize_LapackDense; + S->ops->setup = SUNLinSolSetup_LapackDense; + S->ops->solve = SUNLinSolSolve_LapackDense; + S->ops->lastflag = SUNLinSolLastFlag_LapackDense; + S->ops->space = SUNLinSolSpace_LapackDense; + S->ops->free = SUNLinSolFree_LapackDense; /* Create content */ content = NULL; - content = (SUNLinearSolverContent_LapackDense) - malloc(sizeof(struct _SUNLinearSolverContent_LapackDense)); - if (content == NULL) { free(ops); free(S); return(NULL); } + content = (SUNLinearSolverContent_LapackDense) malloc(sizeof *content); + if (content == NULL) { SUNLinSolFree(S); return(NULL); } + + /* Attach content */ + S->content = content; /* Fill content */ - content->N = MatrixRows; + content->N = MatrixRows; content->last_flag = 0; - content->pivots = NULL; + content->pivots = NULL; + + /* Allocate content */ content->pivots = (sunindextype *) malloc(MatrixRows * sizeof(sunindextype)); - if (content->pivots == NULL) { - free(content); free(ops); free(S); return(NULL); - } - - /* Attach content and ops */ - S->content = content; - S->ops = ops; + if (content->pivots == NULL) { SUNLinSolFree(S); return(NULL); } return(S); } @@ -142,47 +121,53 @@ SUNLinearSolver_Type SUNLinSolGetType_LapackDense(SUNLinearSolver S) } +SUNLinearSolver_ID SUNLinSolGetID_LapackDense(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_LAPACKDENSE); +} + + int SUNLinSolInitialize_LapackDense(SUNLinearSolver S) { /* all solver-specific memory has already been allocated */ LASTFLAG(S) = SUNLS_SUCCESS; - return(LASTFLAG(S)); + return(SUNLS_SUCCESS); } int SUNLinSolSetup_LapackDense(SUNLinearSolver S, SUNMatrix A) { - int n, ier; + sunindextype n, ier; /* check for valid inputs */ - if ( (A == NULL) || (S == NULL) ) + if ( (A == NULL) || (S == NULL) ) return(SUNLS_MEM_NULL); - + /* Ensure that A is a dense matrix */ if (SUNMatGetID(A) != SUNMATRIX_DENSE) { LASTFLAG(S) = SUNLS_ILL_INPUT; - return(LASTFLAG(S)); + return(SUNLS_ILL_INPUT); } - + /* Call LAPACK to do LU factorization of A */ n = SUNDenseMatrix_Rows(A); xgetrf_f77(&n, &n, SUNDenseMatrix_Data(A), &n, PIVOTS(S), &ier); - LASTFLAG(S) = (long int) ier; - if (ier > 0) + LASTFLAG(S) = ier; + if (ier > 0) return(SUNLS_LUFACT_FAIL); - if (ier < 0) + if (ier < 0) return(SUNLS_PACKAGE_FAIL_UNREC); return(SUNLS_SUCCESS); } -int SUNLinSolSolve_LapackDense(SUNLinearSolver S, SUNMatrix A, N_Vector x, - N_Vector b, realtype tol) +int SUNLinSolSolve_LapackDense(SUNLinearSolver S, SUNMatrix A, N_Vector x, + N_Vector b, realtype tol) { - int n, one, ier; + sunindextype n, one, ier; realtype *xdata; - - if ( (A == NULL) || (S == NULL) || (x == NULL) || (b == NULL) ) + + if ( (A == NULL) || (S == NULL) || (x == NULL) || (b == NULL) ) return(SUNLS_MEM_NULL); /* copy b into x */ @@ -192,32 +177,33 @@ int SUNLinSolSolve_LapackDense(SUNLinearSolver S, SUNMatrix A, N_Vector x, xdata = N_VGetArrayPointer(x); if (xdata == NULL) { LASTFLAG(S) = SUNLS_MEM_FAIL; - return(LASTFLAG(S)); + return(SUNLS_MEM_FAIL); } - + /* Call LAPACK to solve the linear system */ n = SUNDenseMatrix_Rows(A); one = 1; - xgetrs_f77("N", &n, &one, SUNDenseMatrix_Data(A), - &n, PIVOTS(S), xdata, &n, &ier, 1); - LASTFLAG(S) = (long int) ier; - if (ier < 0) + xgetrs_f77("N", &n, &one, SUNDenseMatrix_Data(A), + &n, PIVOTS(S), xdata, &n, &ier); + LASTFLAG(S) = ier; + if (ier < 0) return(SUNLS_PACKAGE_FAIL_UNREC); LASTFLAG(S) = SUNLS_SUCCESS; - return(LASTFLAG(S)); + return(SUNLS_SUCCESS); } -long int SUNLinSolLastFlag_LapackDense(SUNLinearSolver S) +sunindextype SUNLinSolLastFlag_LapackDense(SUNLinearSolver S) { /* return the stored 'last_flag' value */ + if (S == NULL) return(-1); return(LASTFLAG(S)); } -int SUNLinSolSpace_LapackDense(SUNLinearSolver S, - long int *lenrwLS, +int SUNLinSolSpace_LapackDense(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS) { *lenrwLS = 0; @@ -228,8 +214,7 @@ int SUNLinSolSpace_LapackDense(SUNLinearSolver S, int SUNLinSolFree_LapackDense(SUNLinearSolver S) { /* return if S is already free */ - if (S == NULL) - return(SUNLS_SUCCESS); + if (S == NULL) return(SUNLS_SUCCESS); /* delete items from contents, then delete generic structure */ if (S->content) { @@ -237,35 +222,13 @@ int SUNLinSolFree_LapackDense(SUNLinearSolver S) free(PIVOTS(S)); PIVOTS(S) = NULL; } - free(S->content); + free(S->content); S->content = NULL; } if (S->ops) { - free(S->ops); + free(S->ops); S->ops = NULL; } free(S); S = NULL; return(SUNLS_SUCCESS); } - -/* - * ----------------------------------------------------------------- - * private functions - * ----------------------------------------------------------------- - */ - -/* Inefficient kludge for determining the number of entries in a N_Vector - object (replace if such a routine is ever added to the N_Vector API). - - Returns "-1" on an error. */ -sunindextype GlobalVectorLength_LapDense(N_Vector y) -{ - realtype len; - N_Vector tmp = NULL; - tmp = N_VClone(y); - if (tmp == NULL) return(-1); - N_VConst(ONE, tmp); - len = N_VDotProd(tmp, tmp); - N_VDestroy(tmp); - return( (sunindextype) len ); -} diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/CMakeLists.txt index 969a0ca59..ecb7cb356 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,97 +12,132 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the PCG SUNLinearSolver library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNLINSOL_PCG\n\")") - -# Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF(F90_FOUND AND F2003_INTERFACE_ENABLE) +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_PCG\n\")") -# Add variable sunlinsolpcg_SOURCES with the sources for the SUNLINSOLPCG lib -SET(sunlinsolpcg_SOURCES sunlinsol_pcg.c) +# Source files for the library +set(sunlinsolpcg_SOURCES sunlinsol_pcg.c) -# Add variable shared_SOURCES with the common SUNDIALS sources which will -# also be included in the SUNLINSOLPCG library -SET(shared_SOURCES +# Common SUNDIALS sources included in the library +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c - ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c - ) + ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c) -# Add variable sunlinsolpcg_HEADERS with the exported SUNLINSOLPCG header files -SET(sunlinsolpcg_HEADERS - ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_pcg.h - ) - -# Add source directory to include directories -INCLUDE_DIRECTORIES(.) - -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Exported header files +set(sunlinsolpcg_HEADERS + ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_pcg.h) # Rules for building and installing the static library: -# - Add the build target for the SUNLINSOLPCG library +# - Add the build target for the library # - Set the library name and make sure it is not deleted -# - Install the SUNLINSOLPCG library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunlinsolpcg_static STATIC ${sunlinsolpcg_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunlinsolpcg_static - PROPERTIES OUTPUT_NAME sundials_sunlinsolpcg CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunlinsolpcg_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +# - Install the library +if(BUILD_STATIC_LIBS) + + add_library(sundials_sunlinsolpcg_static + STATIC ${sunlinsolpcg_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolpcg_static + PROPERTIES + OUTPUT_NAME sundials_sunlinsolpcg + CLEAN_DIRECT_OUTPUT 1) + + if(UNIX) + target_link_libraries(sundials_sunlinsolpcg_static + PRIVATE m) + endif() + + target_compile_definitions(sundials_sunlinsolpcg_static + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolpcg_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: -# - Add the build target for the SUNLINSOLPCG library +# - Add the build target for the library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries -# - Install the SUNLINSOLPCG library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunlinsolpcg_shared SHARED ${sunlinsolpcg_SOURCES} ${shared_SOURCES}) - - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_sunlinsolpcg_shared m) - ENDIF() - - SET_TARGET_PROPERTIES(sundials_sunlinsolpcg_shared - PROPERTIES OUTPUT_NAME sundials_sunlinsolpcg CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunlinsolpcg_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_sunlinsolpcg_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) - -# Install the SUNLINSOLPCG header files -INSTALL(FILES ${sunlinsolpcg_HEADERS} DESTINATION include/sunlinsol) - -# If FCMIX is enabled, build and install the FSUNLINSOLPCG library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunlinsolpcg_SOURCES fsunlinsol_pcg.c) - - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunlinsolpcg_static STATIC ${fsunlinsolpcg_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunlinsolpcg_static - PROPERTIES OUTPUT_NAME sundials_fsunlinsolpcg CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunlinsolpcg_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) - - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunlinsolpcg_shared ${fsunlinsolpcg_SOURCES}) - - # fsunlinsolpcg dependes on fnvecserial and sunlinsolpcg_shared - TARGET_LINK_LIBRARIES(sundials_fsunlinsolpcg_shared +# - Install the library +if(BUILD_SHARED_LIBS) + + add_library(sundials_sunlinsolpcg_shared + SHARED ${sunlinsolpcg_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolpcg_shared + PROPERTIES + OUTPUT_NAME sundials_sunlinsolpcg + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + + if(UNIX) + target_link_libraries(sundials_sunlinsolpcg_shared + PRIVATE m) + endif() + + target_compile_definitions(sundials_sunlinsolpcg_shared + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolpcg_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_SHARED_LIBS) + +# Install the header files +install(FILES ${sunlinsolpcg_HEADERS} DESTINATION include/sunlinsol) + +# +message(STATUS "Added SUNLINSOL_PCG module") + +# If FCMIX is enabled, build and install the Fortran77 library +if(F77_INTERFACE_ENABLE AND F77_FOUND) + + set(fsunlinsolpcg_SOURCES fsunlinsol_pcg.c) + + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunlinsolpcg_static + STATIC ${fsunlinsolpcg_SOURCES}) + set_target_properties(sundials_fsunlinsolpcg_static + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolpcg + CLEAN_DIRECT_OUTPUT 1) + # depends on fnvecserial and sunlinsolpcg + target_link_libraries(sundials_fsunlinsolpcg_static + PUBLIC + sundials_fnvecserial_static + sundials_sunlinsolpcg_static) + install(TARGETS sundials_fsunlinsolpcg_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) + + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunlinsolpcg_shared + SHARED ${fsunlinsolpcg_SOURCES}) + set_target_properties(sundials_fsunlinsolpcg_shared + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolpcg + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + # depends on fnvecserial and sunlinsolpcg + target_link_libraries(sundials_fsunlinsolpcg_shared + PUBLIC sundials_fnvecserial_shared sundials_sunlinsolpcg_shared) + install(TARGETS sundials_fsunlinsolpcg_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) - SET_TARGET_PROPERTIES(sundials_fsunlinsolpcg_shared - PROPERTIES OUTPUT_NAME sundials_fsunlinsolpcg CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunlinsolpcg_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_fsunlinsolpcg_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + # + message(STATUS "Added SUNLINSOL_PCG F77 interface") -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(F77_INTERFACE_ENABLE AND F77_FOUND) -# -MESSAGE(STATUS "Added SUNLINSOL_PCG module") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/F90/fsunlinsol_pcg.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/F90/fsunlinsol_pcg.f90 deleted file mode 100644 index fc5c6ca8e..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/F90/fsunlinsol_pcg.f90 +++ /dev/null @@ -1,174 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): Cody J. Balos @ LLNL -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS PCG linear solver using the ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fsunlinsol_pcg_mod - - !======= Interfaces ========= - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - type(c_ptr) function FSUNLinSol_PCG(y, pretype, maxl) & - bind(C,name='SUNLinSol_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: y - integer(c_int), value :: pretype - integer(c_int), value :: maxl - end function FSUNLinSol_PCG - - ! ================================================================= - ! Destructors - ! ================================================================= - - subroutine FSUNLinSolFree_PCG(LS) & - bind(C,name='SUNLinSolFree_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end subroutine FSUNLinSolFree_PCG - - ! ================================================================= - ! Setters - ! ================================================================= - - integer(c_int) function FSUNLinSol_PCGSetPrecType(LS, pretype) & - bind(C,name='SUNLinSol_PCGSetPrecType') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: pretype - end function FSUNLinSol_PCGSetPrecType - - integer(c_int) function FSUNLinSol_SPTFQMRSetMaxl(LS, maxl) & - bind(C,name='SUNLinSol_SPTFQMRSetMaxl') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: maxl - end function FSUNLinSol_SPTFQMRSetMaxl - - ! ================================================================= - ! Operations - ! ================================================================= - - integer(c_int) function FSUNLinSolGetType_PCG(LS) & - bind(C,name='SUNLinSolGetType_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolGetType_PCG - - integer(c_int) function FSUNLinSolInitialize_PCG(LS) & - bind(C,name='SUNLinSolInitialize_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolInitialize_PCG - - integer(c_int) function FSUNLinSolSetATimes_PCG(LS, A_data, ATimes) & - bind(C,name='SUNLinSolSetATimes_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A_data - type(c_funptr), value :: ATimes - end function FSUNLinSolSetATimes_PCG - - integer(c_int) function FSUNLinSolSetPreconditioner_PCG(LS, & - P_data, & - Pset, & - Psol) & - bind(C,name='SUNLinSolSetPreconditioner_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: P_data - type(c_funptr), value :: Pset - type(c_funptr), value :: Psol - end function FSUNLinSolSetPreconditioner_PCG - - integer(c_int) function FSUNLinSolSetScalingVectors_PCG(LS, s1, nul) & - bind(C,name='SUNLinSolSetScalingVectors_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: s1 - type(c_ptr), value :: nul - end function FSUNLinSolSetScalingVectors_PCG - - integer(c_int) function FSUNLinSolSetup_PCG(LS, nul) & - bind(C,name='SUNLinSolSetup_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: nul - end function FSUNLinSolSetup_PCG - - integer(c_int) function FSUNLinSolSolve_PCG(LS, nul, x, b, tol) & - bind(C,name='SUNLinSolSolve_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: nul - type(c_ptr), value :: x - type(c_ptr), value :: b - real(c_double), value :: tol - end function FSUNLinSolSolve_PCG - - integer(c_int) function FSUNLinSolNumIters_PCG(LS) & - bind(C,name='SUNLinSolNumIters_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolNumIters_PCG - - real(c_double) function FSUNLinSolResNorm_PCG(LS) & - bind(C,name='SUNLinSolResNorm_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolResNorm_PCG - - type(c_ptr) function FSUNLinSolResid_PCG(LS) & - bind(C,name='SUNLinSolResid_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolResid_PCG - - integer(c_long) function FSUNLinSolLastFlag_PCG(LS) & - bind(C,name='SUNLinSolLastFlag_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolLastFlag_PCG - - integer(c_int) function FSUNLinSolSpace_PCG(LS, lenrwLS, leniwLS) & - bind(C,name='SUNLinSolSpace_PCG') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_long) :: lenrwLS - integer(c_long) :: leniwLS - end function FSUNLinSolSpace_PCG - - end interface - -end module fsunlinsol_pcg_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fmod/CMakeLists.txt similarity index 75% rename from deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/F90/CMakeLists.txt rename to deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fmod/CMakeLists.txt index d923bdabc..1feb56c7f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/F90/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fmod/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Cody J. Balos @ LLNL +# Programmer(s): Cody J. Balos @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,22 +12,25 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the F2003 PCG SUNLinearSolver object library +# --------------------------------------------------------------- -set(sunlinsolpcg_SOURCES fsunlinsol_pcg.f90) +set(sunlinsolpcg_SOURCES fsunlinsol_pcg_mod.f90 fsunlinsol_pcg_mod.c) if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolpcg_mod_static STATIC + sundials_add_f2003_interface_library(sundials_fsunlinsolpcg_mod_static STATIC_OBJECT ${sunlinsolpcg_SOURCES} ) + add_dependencies(sundials_fsunlinsolpcg_mod_static_obj sundials_fgeneric_static_obj) set_target_properties(sundials_fsunlinsolpcg_mod_static PROPERTIES OUTPUT_NAME sundials_fsunlinsolpcg_mod CLEAN_DIRECT_OUTPUT 1) install(TARGETS sundials_fsunlinsolpcg_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif(BUILD_STATIC_LIBS) if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolpcg_mod_shared SHARED + sundials_add_f2003_interface_library(sundials_fsunlinsolpcg_mod_shared SHARED_OBJECT ${sunlinsolpcg_SOURCES} ) + add_dependencies(sundials_fsunlinsolpcg_mod_shared_obj sundials_fgeneric_shared_obj) set_target_properties(sundials_fsunlinsolpcg_mod_shared PROPERTIES OUTPUT_NAME sundials_fsunlinsolpcg_mod CLEAN_DIRECT_OUTPUT 1) set_target_properties(sundials_fsunlinsolpcg_mod_shared diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fmod/fsunlinsol_pcg_mod.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fmod/fsunlinsol_pcg_mod.c new file mode 100644 index 000000000..84a66ec97 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fmod/fsunlinsol_pcg_mod.c @@ -0,0 +1,495 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_linearsolver.h" + + +#include "sunlinsol/sunlinsol_pcg.h" + +SWIGEXPORT SUNLinearSolver _wrap_FSUNLinSol_PCG(N_Vector farg1, int const *farg2, int const *farg3) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int arg3 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (SUNLinearSolver)SUNLinSol_PCG(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_PCGSetPrecType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_PCGSetPrecType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_PCGSetMaxl(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_PCGSetMaxl(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SUNLinearSolver _wrap_FSUNPCG(N_Vector farg1, int const *farg2, int const *farg3) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int arg3 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (SUNLinearSolver)SUNPCG(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNPCGSetPrecType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNPCGSetPrecType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNPCGSetMaxl(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNPCGSetMaxl(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetType_PCG(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_Type result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_Type)SUNLinSolGetType_PCG(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetID_PCG(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_ID result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_ID)SUNLinSolGetID_PCG(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolInitialize_PCG(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolInitialize_PCG(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetATimes_PCG(SUNLinearSolver farg1, void *farg2, ATimesFn farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + void *arg2 = (void *) 0 ; + ATimesFn arg3 = (ATimesFn) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (void *)(farg2); + arg3 = (ATimesFn)(farg3); + result = (int)SUNLinSolSetATimes_PCG(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetPreconditioner_PCG(SUNLinearSolver farg1, void *farg2, PSetupFn farg3, PSolveFn farg4) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + void *arg2 = (void *) 0 ; + PSetupFn arg3 = (PSetupFn) 0 ; + PSolveFn arg4 = (PSolveFn) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (void *)(farg2); + arg3 = (PSetupFn)(farg3); + arg4 = (PSolveFn)(farg4); + result = (int)SUNLinSolSetPreconditioner_PCG(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetScalingVectors_PCG(SUNLinearSolver farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)SUNLinSolSetScalingVectors_PCG(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetup_PCG(SUNLinearSolver farg1, SUNMatrix farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNLinSolSetup_PCG(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSolve_PCG(SUNLinearSolver farg1, SUNMatrix farg2, N_Vector farg3, N_Vector farg4, double const *farg5) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype arg5 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype)(*farg5); + result = (int)SUNLinSolSolve_PCG(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolNumIters_PCG(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolNumIters_PCG(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FSUNLinSolResNorm_PCG(SUNLinearSolver farg1) { + double fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + realtype result; + + arg1 = (SUNLinearSolver)(farg1); + result = (realtype)SUNLinSolResNorm_PCG(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FSUNLinSolResid_PCG(SUNLinearSolver farg1) { + N_Vector fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + N_Vector result; + + arg1 = (SUNLinearSolver)(farg1); + result = (N_Vector)SUNLinSolResid_PCG(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNLinSolLastFlag_PCG(SUNLinearSolver farg1) { + int64_t fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + sunindextype result; + + arg1 = (SUNLinearSolver)(farg1); + result = SUNLinSolLastFlag_PCG(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSpace_PCG(SUNLinearSolver farg1, long *farg2, long *farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNLinSolSpace_PCG(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolFree_PCG(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolFree_PCG(arg1); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fmod/fsunlinsol_pcg_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fmod/fsunlinsol_pcg_mod.f90 new file mode 100644 index 000000000..ad98912e4 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fmod/fsunlinsol_pcg_mod.f90 @@ -0,0 +1,572 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunlinsol_pcg_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_linearsolver_mod + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: SUNPCG_MAXL_DEFAULT = 5_C_INT + public :: FSUNLinSol_PCG + public :: FSUNLinSol_PCGSetPrecType + public :: FSUNLinSol_PCGSetMaxl + public :: FSUNPCG + public :: FSUNPCGSetPrecType + public :: FSUNPCGSetMaxl + public :: FSUNLinSolGetType_PCG + public :: FSUNLinSolGetID_PCG + public :: FSUNLinSolInitialize_PCG + public :: FSUNLinSolSetATimes_PCG + public :: FSUNLinSolSetPreconditioner_PCG + public :: FSUNLinSolSetScalingVectors_PCG + public :: FSUNLinSolSetup_PCG + public :: FSUNLinSolSolve_PCG + public :: FSUNLinSolNumIters_PCG + public :: FSUNLinSolResNorm_PCG + public :: FSUNLinSolResid_PCG + public :: FSUNLinSolLastFlag_PCG + public :: FSUNLinSolSpace_PCG + public :: FSUNLinSolFree_PCG + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNLinSol_PCG(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSol_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSol_PCGSetPrecType(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_PCGSetPrecType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSol_PCGSetMaxl(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_PCGSetMaxl") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNPCG(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNPCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNPCGSetPrecType(farg1, farg2) & +bind(C, name="_wrap_FSUNPCGSetPrecType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNPCGSetMaxl(farg1, farg2) & +bind(C, name="_wrap_FSUNPCGSetMaxl") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetType_PCG(farg1) & +bind(C, name="_wrap_FSUNLinSolGetType_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetID_PCG(farg1) & +bind(C, name="_wrap_FSUNLinSolGetID_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolInitialize_PCG(farg1) & +bind(C, name="_wrap_FSUNLinSolInitialize_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetATimes_PCG(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSetATimes_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetPreconditioner_PCG(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FSUNLinSolSetPreconditioner_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetScalingVectors_PCG(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSetScalingVectors_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetup_PCG(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSolSetup_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSolve_PCG(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FSUNLinSolSolve_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolNumIters_PCG(farg1) & +bind(C, name="_wrap_FSUNLinSolNumIters_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolResNorm_PCG(farg1) & +bind(C, name="_wrap_FSUNLinSolResNorm_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FSUNLinSolResid_PCG(farg1) & +bind(C, name="_wrap_FSUNLinSolResid_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSolLastFlag_PCG(farg1) & +bind(C, name="_wrap_FSUNLinSolLastFlag_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNLinSolSpace_PCG(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSpace_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolFree_PCG(farg1) & +bind(C, name="_wrap_FSUNLinSolFree_PCG") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNLinSol_PCG(y, pretype, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +integer(C_INT), intent(in) :: pretype +integer(C_INT), intent(in) :: maxl +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = c_loc(y) +farg2 = pretype +farg3 = maxl +fresult = swigc_FSUNLinSol_PCG(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSol_PCGSetPrecType(s, pretype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: pretype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = pretype +fresult = swigc_FSUNLinSol_PCGSetPrecType(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSol_PCGSetMaxl(s, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: maxl +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = maxl +fresult = swigc_FSUNLinSol_PCGSetMaxl(farg1, farg2) +swig_result = fresult +end function + +function FSUNPCG(y, pretype, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +integer(C_INT), intent(in) :: pretype +integer(C_INT), intent(in) :: maxl +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = c_loc(y) +farg2 = pretype +farg3 = maxl +fresult = swigc_FSUNPCG(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNPCGSetPrecType(s, pretype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: pretype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = pretype +fresult = swigc_FSUNPCGSetPrecType(farg1, farg2) +swig_result = fresult +end function + +function FSUNPCGSetMaxl(s, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: maxl +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = maxl +fresult = swigc_FSUNPCGSetMaxl(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolGetType_PCG(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_Type) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetType_PCG(farg1) +swig_result = fresult +end function + +function FSUNLinSolGetID_PCG(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_ID) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetID_PCG(farg1) +swig_result = fresult +end function + +function FSUNLinSolInitialize_PCG(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolInitialize_PCG(farg1) +swig_result = fresult +end function + +function FSUNLinSolSetATimes_PCG(s, a_data, atimes) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: a_data +type(C_FUNPTR), intent(in), value :: atimes +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = c_loc(s) +farg2 = a_data +farg3 = atimes +fresult = swigc_FSUNLinSolSetATimes_PCG(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolSetPreconditioner_PCG(s, p_data, pset, psol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: p_data +type(C_FUNPTR), intent(in), value :: pset +type(C_FUNPTR), intent(in), value :: psol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = c_loc(s) +farg2 = p_data +farg3 = pset +farg4 = psol +fresult = swigc_FSUNLinSolSetPreconditioner_PCG(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FSUNLinSolSetScalingVectors_PCG(s, s1, nul) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(N_Vector), target, intent(inout) :: s1 +type(N_Vector), target, intent(inout) :: nul +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(s1) +farg3 = c_loc(nul) +fresult = swigc_FSUNLinSolSetScalingVectors_PCG(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolSetup_PCG(s, nul) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: nul +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(s) +farg2 = c_loc(nul) +fresult = swigc_FSUNLinSolSetup_PCG(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolSolve_PCG(s, nul, x, b, tol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: nul +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: b +real(C_DOUBLE), intent(in) :: tol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +real(C_DOUBLE) :: farg5 + +farg1 = c_loc(s) +farg2 = c_loc(nul) +farg3 = c_loc(x) +farg4 = c_loc(b) +farg5 = tol +fresult = swigc_FSUNLinSolSolve_PCG(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FSUNLinSolNumIters_PCG(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolNumIters_PCG(farg1) +swig_result = fresult +end function + +function FSUNLinSolResNorm_PCG(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolResNorm_PCG(farg1) +swig_result = fresult +end function + +function FSUNLinSolResid_PCG(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolResid_PCG(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSolLastFlag_PCG(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolLastFlag_PCG(farg1) +swig_result = fresult +end function + +function FSUNLinSolSpace_PCG(s, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FSUNLinSolSpace_PCG(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolFree_PCG(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolFree_PCG(farg1) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.c index 03b049926..05f494794 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.h b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.h index 5a7da10d4..a56dfec0f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/sunlinsol_pcg.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/sunlinsol_pcg.c index 80e5226cc..b7239fb47 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/sunlinsol_pcg.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/pcg/sunlinsol_pcg.c @@ -1,10 +1,9 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds, Ashley Crawford @ SMU * Based on sundials_pcg.c code, written by Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -13,10 +12,9 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the PCG implementation of + * This is the implementation file for the PCG implementation of * the SUNLINSOL package. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include @@ -29,7 +27,7 @@ /* * ----------------------------------------------------------------- - * PCG solver structure accessibility macros: + * PCG solver structure accessibility macros: * ----------------------------------------------------------------- */ @@ -65,9 +63,8 @@ int SUNPCGSetMaxl(SUNLinearSolver S, int maxl) SUNLinearSolver SUNLinSol_PCG(N_Vector y, int pretype, int maxl) { SUNLinearSolver S; - SUNLinearSolver_Ops ops; SUNLinearSolverContent_PCG content; - + /* check for legal pretype and maxl values; if illegal use defaults */ if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) && (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) @@ -77,70 +74,74 @@ SUNLinearSolver SUNLinSol_PCG(N_Vector y, int pretype, int maxl) /* Create linear solver */ S = NULL; - S = (SUNLinearSolver) malloc(sizeof *S); + S = SUNLinSolNewEmpty(); if (S == NULL) return(NULL); - - /* Create linear solver operation structure */ - ops = NULL; - ops = (SUNLinearSolver_Ops) malloc(sizeof(struct _generic_SUNLinearSolver_Ops)); - if (ops == NULL) { free(S); return(NULL); } /* Attach operations */ - ops->gettype = SUNLinSolGetType_PCG; - ops->setatimes = SUNLinSolSetATimes_PCG; - ops->setpreconditioner = SUNLinSolSetPreconditioner_PCG; - ops->setscalingvectors = SUNLinSolSetScalingVectors_PCG; - ops->initialize = SUNLinSolInitialize_PCG; - ops->setup = SUNLinSolSetup_PCG; - ops->solve = SUNLinSolSolve_PCG; - ops->numiters = SUNLinSolNumIters_PCG; - ops->resnorm = SUNLinSolResNorm_PCG; - ops->resid = SUNLinSolResid_PCG; - ops->lastflag = SUNLinSolLastFlag_PCG; - ops->space = SUNLinSolSpace_PCG; - ops->free = SUNLinSolFree_PCG; + S->ops->gettype = SUNLinSolGetType_PCG; + S->ops->getid = SUNLinSolGetID_PCG; + S->ops->setatimes = SUNLinSolSetATimes_PCG; + S->ops->setpreconditioner = SUNLinSolSetPreconditioner_PCG; + S->ops->setscalingvectors = SUNLinSolSetScalingVectors_PCG; + S->ops->initialize = SUNLinSolInitialize_PCG; + S->ops->setup = SUNLinSolSetup_PCG; + S->ops->solve = SUNLinSolSolve_PCG; + S->ops->numiters = SUNLinSolNumIters_PCG; + S->ops->resnorm = SUNLinSolResNorm_PCG; + S->ops->resid = SUNLinSolResid_PCG; + S->ops->lastflag = SUNLinSolLastFlag_PCG; + S->ops->space = SUNLinSolSpace_PCG; + S->ops->free = SUNLinSolFree_PCG; /* Create content */ content = NULL; - content = (SUNLinearSolverContent_PCG) malloc(sizeof(struct _SUNLinearSolverContent_PCG)); - if (content == NULL) { free(ops); free(S); return(NULL); } + content = (SUNLinearSolverContent_PCG) malloc(sizeof *content); + if (content == NULL) { SUNLinSolFree(S); return(NULL); } + + /* Attach content */ + S->content = content; /* Fill content */ content->last_flag = 0; - content->maxl = maxl; - content->pretype = pretype; - content->numiters = 0; - content->resnorm = ZERO; + content->maxl = maxl; + content->pretype = pretype; + content->numiters = 0; + content->resnorm = ZERO; + content->r = NULL; + content->p = NULL; + content->z = NULL; + content->Ap = NULL; + content->s = NULL; + content->ATimes = NULL; + content->ATData = NULL; + content->Psetup = NULL; + content->Psolve = NULL; + content->PData = NULL; + + /* Allocate content */ content->r = N_VClone(y); - if (content->r == NULL) return NULL; + if (content->r == NULL) { SUNLinSolFree(S); return NULL; } + content->p = N_VClone(y); - if (content->p == NULL) return NULL; + if (content->p == NULL) { SUNLinSolFree(S); return NULL; } + content->z = N_VClone(y); - if (content->z == NULL) return NULL; + if (content->z == NULL) { SUNLinSolFree(S); return NULL; } + content->Ap = N_VClone(y); - if (content->Ap == NULL) return NULL; - content->s = NULL; - content->ATimes = NULL; - content->ATData = NULL; - content->Psetup = NULL; - content->Psolve = NULL; - content->PData = NULL; - - /* Attach content and ops */ - S->content = content; - S->ops = ops; + if (content->Ap == NULL) { SUNLinSolFree(S); return NULL; } return(S); } /* ---------------------------------------------------------------------------- - * Function to set the type of preconditioning for PCG to use + * Function to set the type of preconditioning for PCG to use */ -SUNDIALS_EXPORT int SUNLinSol_PCGSetPrecType(SUNLinearSolver S, int pretype) +SUNDIALS_EXPORT int SUNLinSol_PCGSetPrecType(SUNLinearSolver S, int pretype) { - /* Check for legal pretype */ + /* Check for legal pretype */ if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) && (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) { return(SUNLS_ILL_INPUT); @@ -156,15 +157,15 @@ SUNDIALS_EXPORT int SUNLinSol_PCGSetPrecType(SUNLinearSolver S, int pretype) /* ---------------------------------------------------------------------------- - * Function to set the maximum number of iterations for PCG to use + * Function to set the maximum number of iterations for PCG to use */ -SUNDIALS_EXPORT int SUNLinSol_PCGSetMaxl(SUNLinearSolver S, int maxl) +SUNDIALS_EXPORT int SUNLinSol_PCGSetMaxl(SUNLinearSolver S, int maxl) { /* Check for non-NULL SUNLinearSolver */ if (S == NULL) return(SUNLS_MEM_NULL); - /* Check for legal pretype */ + /* Check for legal pretype */ if (maxl <= 0) maxl = SUNPCG_MAXL_DEFAULT; @@ -185,15 +186,22 @@ SUNLinearSolver_Type SUNLinSolGetType_PCG(SUNLinearSolver S) return(SUNLINEARSOLVER_ITERATIVE); } + +SUNLinearSolver_ID SUNLinSolGetID_PCG(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_PCG); +} + + int SUNLinSolInitialize_PCG(SUNLinearSolver S) { /* ensure valid options */ - if (S == NULL) return(SUNLS_MEM_NULL); - if ( (PRETYPE(S) != PREC_LEFT) && - (PRETYPE(S) != PREC_RIGHT) && + if (S == NULL) return(SUNLS_MEM_NULL); + if ( (PRETYPE(S) != PREC_LEFT) && + (PRETYPE(S) != PREC_RIGHT) && (PRETYPE(S) != PREC_BOTH) ) PRETYPE(S) = PREC_NONE; - if (PCG_CONTENT(S)->maxl <= 0) + if (PCG_CONTENT(S)->maxl <= 0) PCG_CONTENT(S)->maxl = SUNPCG_MAXL_DEFAULT; /* no additional memory to allocate */ @@ -204,7 +212,7 @@ int SUNLinSolInitialize_PCG(SUNLinearSolver S) } -int SUNLinSolSetATimes_PCG(SUNLinearSolver S, void* ATData, +int SUNLinSolSetATimes_PCG(SUNLinearSolver S, void* ATData, ATimesFn ATimes) { /* set function pointers to integrator-supplied ATimes routine @@ -253,25 +261,25 @@ int SUNLinSolSetup_PCG(SUNLinearSolver S, SUNMatrix nul) if (S == NULL) return(SUNLS_MEM_NULL); Psetup = PCG_CONTENT(S)->Psetup; PData = PCG_CONTENT(S)->PData; - - /* no solver-specific setup is required, but if user-supplied + + /* no solver-specific setup is required, but if user-supplied Psetup routine exists, call that here */ if (Psetup != NULL) { ier = Psetup(PData); if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_PSET_FAIL_UNREC : SUNLS_PSET_FAIL_REC; return(LASTFLAG(S)); } } - - /* return with success */ + + /* return with success */ LASTFLAG(S) = SUNLS_SUCCESS; return(LASTFLAG(S)); } -int SUNLinSolSolve_PCG(SUNLinearSolver S, SUNMatrix nul, N_Vector x, +int SUNLinSolSolve_PCG(SUNLinearSolver S, SUNMatrix nul, N_Vector x, N_Vector b, realtype delta) { /* local data and shortcut variables */ @@ -306,8 +314,8 @@ int SUNLinSolSolve_PCG(SUNLinearSolver S, SUNMatrix nul, N_Vector x, converged = SUNFALSE; /* set booleantype flags for internal solver options */ - UsePrec = ( (pretype == PREC_BOTH) || - (pretype == PREC_LEFT) || + UsePrec = ( (pretype == PREC_BOTH) || + (pretype == PREC_LEFT) || (pretype == PREC_RIGHT) ); UseScaling = (w != NULL); @@ -316,7 +324,7 @@ int SUNLinSolSolve_PCG(SUNLinearSolver S, SUNMatrix nul, N_Vector x, else { ier = atimes(A_data, x, r); if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; return(LASTFLAG(S)); } @@ -336,7 +344,7 @@ int SUNLinSolSolve_PCG(SUNLinearSolver S, SUNMatrix nul, N_Vector x, if (UsePrec) { ier = psolve(P_data, r, z, delta, PREC_LEFT); /* z = P^{-1}r */ if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; return(LASTFLAG(S)); } @@ -358,7 +366,7 @@ int SUNLinSolSolve_PCG(SUNLinearSolver S, SUNMatrix nul, N_Vector x, /* Generate Ap = A*p */ ier = atimes(A_data, p, Ap); if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; return(LASTFLAG(S)); } @@ -385,7 +393,7 @@ int SUNLinSolSolve_PCG(SUNLinearSolver S, SUNMatrix nul, N_Vector x, if (UsePrec) { ier = psolve(P_data, r, z, delta, PREC_LEFT); if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; return(LASTFLAG(S)); } @@ -395,7 +403,7 @@ int SUNLinSolSolve_PCG(SUNLinearSolver S, SUNMatrix nul, N_Vector x, /* update rz */ rz_old = rz; rz = N_VDotProd(r, z); - + /* Calculate beta = / */ beta = rz / rz_old; @@ -440,7 +448,7 @@ N_Vector SUNLinSolResid_PCG(SUNLinearSolver S) } -long int SUNLinSolLastFlag_PCG(SUNLinearSolver S) +sunindextype SUNLinSolLastFlag_PCG(SUNLinearSolver S) { /* return the stored 'last_flag' value */ if (S == NULL) return(-1); @@ -448,8 +456,8 @@ long int SUNLinSolLastFlag_PCG(SUNLinearSolver S) } -int SUNLinSolSpace_PCG(SUNLinearSolver S, - long int *lenrwLS, +int SUNLinSolSpace_PCG(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS) { sunindextype liw1, lrw1; @@ -463,19 +471,27 @@ int SUNLinSolFree_PCG(SUNLinearSolver S) { if (S == NULL) return(SUNLS_SUCCESS); - /* delete items from within the content structure */ - if (PCG_CONTENT(S)->r) - N_VDestroy(PCG_CONTENT(S)->r); - if (PCG_CONTENT(S)->p) - N_VDestroy(PCG_CONTENT(S)->p); - if (PCG_CONTENT(S)->z) - N_VDestroy(PCG_CONTENT(S)->z); - if (PCG_CONTENT(S)->Ap) - N_VDestroy(PCG_CONTENT(S)->Ap); - - /* delete generic structures */ - free(S->content); S->content = NULL; - free(S->ops); S->ops = NULL; + if (S->content) { + /* delete items from within the content structure */ + if (PCG_CONTENT(S)->r) { + N_VDestroy(PCG_CONTENT(S)->r); + PCG_CONTENT(S)->r = NULL; + } + if (PCG_CONTENT(S)->p) { + N_VDestroy(PCG_CONTENT(S)->p); + PCG_CONTENT(S)->p = NULL; + } + if (PCG_CONTENT(S)->z) { + N_VDestroy(PCG_CONTENT(S)->z); + PCG_CONTENT(S)->z = NULL; + } + if (PCG_CONTENT(S)->Ap) { + N_VDestroy(PCG_CONTENT(S)->Ap); + PCG_CONTENT(S)->Ap = NULL; + } + free(S->content); S->content = NULL; + } + if (S->ops) { free(S->ops); S->ops = NULL; } free(S); S = NULL; - return 0; + return(SUNLS_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/CMakeLists.txt index 1690d9cdb..bc357d066 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,97 +12,132 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the SPBCGS SUNLinearSolver library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNLINSOL_SPBCGS\n\")") - -# Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF(F90_FOUND AND F2003_INTERFACE_ENABLE) +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_SPBCGS\n\")") -# Add variable sunlinsolspbcgs_SOURCES with the sources for the SUNLINSOLSPBCGS lib -SET(sunlinsolspbcgs_SOURCES sunlinsol_spbcgs.c) +# Source files for the library +set(sunlinsolspbcgs_SOURCES sunlinsol_spbcgs.c) -# Add variable shared_SOURCES with the common SUNDIALS sources which will -# also be included in the SUNLINSOLSPBCGS library -SET(shared_SOURCES +# Common SUNDIALS sources included in the library +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c - ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c - ) + ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c) -# Add variable sunlinsolspbcgs_HEADERS with the exported SUNLINSOLSPBCGS header files -SET(sunlinsolspbcgs_HEADERS - ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_spbcgs.h - ) - -# Add source directory to include directories -INCLUDE_DIRECTORIES(.) - -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Exported header files +set(sunlinsolspbcgs_HEADERS + ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_spbcgs.h) # Rules for building and installing the static library: -# - Add the build target for the SUNLINSOLSPBCGS library +# - Add the build target for the library # - Set the library name and make sure it is not deleted -# - Install the SUNLINSOLSPBCGS library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunlinsolspbcgs_static STATIC ${sunlinsolspbcgs_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunlinsolspbcgs_static - PROPERTIES OUTPUT_NAME sundials_sunlinsolspbcgs CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunlinsolspbcgs_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +# - Install the library +if(BUILD_STATIC_LIBS) + + add_library(sundials_sunlinsolspbcgs_static + STATIC ${sunlinsolspbcgs_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolspbcgs_static + PROPERTIES + OUTPUT_NAME sundials_sunlinsolspbcgs + CLEAN_DIRECT_OUTPUT 1) + + if(UNIX) + target_link_libraries(sundials_sunlinsolspbcgs_static + PRIVATE m) + endif() + + target_compile_definitions(sundials_sunlinsolspbcgs_static + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolspbcgs_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: -# - Add the build target for the SUNLINSOLSPBCGS library +# - Add the build target for the library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries -# - Install the SUNLINSOLSPBCGS library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunlinsolspbcgs_shared SHARED ${sunlinsolspbcgs_SOURCES} ${shared_SOURCES}) - - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_sunlinsolspbcgs_shared m) - ENDIF() - - SET_TARGET_PROPERTIES(sundials_sunlinsolspbcgs_shared - PROPERTIES OUTPUT_NAME sundials_sunlinsolspbcgs CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunlinsolspbcgs_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_sunlinsolspbcgs_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) - -# Install the SUNLINSOLSPBCGS header files -INSTALL(FILES ${sunlinsolspbcgs_HEADERS} DESTINATION include/sunlinsol) - -# If FCMIX is enabled, build and install the FSUNLINSOLSPBCGS library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunlinsolspbcgs_SOURCES fsunlinsol_spbcgs.c) - - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunlinsolspbcgs_static STATIC ${fsunlinsolspbcgs_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunlinsolspbcgs_static - PROPERTIES OUTPUT_NAME sundials_fsunlinsolspbcgs CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunlinsolspbcgs_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) - - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunlinsolspbcgs_shared ${fsunlinsolspbcgs_SOURCES}) - - # fsunlinsolspbcgs depdens on fnvecserial and sunlinsolspbcgs - TARGET_LINK_LIBRARIES(sundials_fsunlinsolspbcgs_shared +# - Install the library +if(BUILD_SHARED_LIBS) + + add_library(sundials_sunlinsolspbcgs_shared + SHARED ${sunlinsolspbcgs_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolspbcgs_shared + PROPERTIES + OUTPUT_NAME sundials_sunlinsolspbcgs + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + + if(UNIX) + target_link_libraries(sundials_sunlinsolspbcgs_shared + PRIVATE m) + endif() + + target_compile_definitions(sundials_sunlinsolspbcgs_shared + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolspbcgs_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_SHARED_LIBS) + +# Install the header files +install(FILES ${sunlinsolspbcgs_HEADERS} DESTINATION include/sunlinsol) + +# +message(STATUS "Added SUNLINSOL_SPBCGS module") + +# If FCMIX is enabled, build and install the Fortran77 library +if(F77_INTERFACE_ENABLE AND F77_FOUND) + + set(fsunlinsolspbcgs_SOURCES fsunlinsol_spbcgs.c) + + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunlinsolspbcgs_static + STATIC ${fsunlinsolspbcgs_SOURCES}) + set_target_properties(sundials_fsunlinsolspbcgs_static + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolspbcgs + CLEAN_DIRECT_OUTPUT 1) + # depends on fnvecserial and sunlinsolspbcgs + target_link_libraries(sundials_fsunlinsolspbcgs_static + PUBLIC + sundials_fnvecserial_static + sundials_sunlinsolspbcgs_static) + install(TARGETS sundials_fsunlinsolspbcgs_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) + + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunlinsolspbcgs_shared + SHARED ${fsunlinsolspbcgs_SOURCES}) + set_target_properties(sundials_fsunlinsolspbcgs_shared + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolspbcgs + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + # depends on fnvecserial and sunlinsolspbcgs + target_link_libraries(sundials_fsunlinsolspbcgs_shared + PUBLIC sundials_fnvecserial_shared sundials_sunlinsolspbcgs_shared) + install(TARGETS sundials_fsunlinsolspbcgs_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) - SET_TARGET_PROPERTIES(sundials_fsunlinsolspbcgs_shared - PROPERTIES OUTPUT_NAME sundials_fsunlinsolspbcgs CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunlinsolspbcgs_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_fsunlinsolspbcgs_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + # + message(STATUS "Added SUNLINSOL_SPBCGS F77 interface") -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(F77_INTERFACE_ENABLE AND F77_FOUND) -# -MESSAGE(STATUS "Added SUNLINSOL_SPBCGS module") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/F90/fsunlinsol_spbcgs.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/F90/fsunlinsol_spbcgs.f90 deleted file mode 100644 index 13d26183f..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/F90/fsunlinsol_spbcgs.f90 +++ /dev/null @@ -1,174 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): Cody J. Balos @ LLNL -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS SPBCGS linear solver using the ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fsunlinsol_spbcgs_mod - - !======= Interfaces ========= - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - type(c_ptr) function FSUNLinSol_SPBCGS(y, pretype, maxl) & - bind(C,name='SUNLinSol_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: y - integer(c_int), value :: pretype - integer(c_int), value :: maxl - end function FSUNLinSol_SPBCGS - - ! ================================================================= - ! Destructors - ! ================================================================= - - subroutine FSUNLinSolFree_SPBCGS(LS) & - bind(C,name='SUNLinSolFree_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end subroutine FSUNLinSolFree_SPBCGS - - ! ================================================================= - ! Setters - ! ================================================================= - - integer(c_int) function FSUNLinSol_SPBCGSSetPrecType(LS, pretype) & - bind(C,name='SUNLinSol_SPBCGSSetPrecType') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: pretype - end function FSUNLinSol_SPBCGSSetPrecType - - integer(c_int) function FSUNLinSol_SPTFQMRSetMaxl(LS, maxl) & - bind(C,name='SUNLinSol_SPTFQMRSetMaxl') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: maxl - end function FSUNLinSol_SPTFQMRSetMaxl - - ! ================================================================= - ! Operations - ! ================================================================= - - integer(c_int) function FSUNLinSolGetType_SPBCGS(LS) & - bind(C,name='SUNLinSolGetType_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolGetType_SPBCGS - - integer(c_int) function FSUNLinSolInitialize_SPBCGS(LS) & - bind(C,name='SUNLinSolInitialize_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolInitialize_SPBCGS - - integer(c_int) function FSUNLinSolSetATimes_SPBCGS(LS, A_data, ATimes) & - bind(C,name='SUNLinSolSetATimes_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A_data - type(c_funptr), value :: ATimes - end function FSUNLinSolSetATimes_SPBCGS - - integer(c_int) function FSUNLinSolSetPreconditioner_SPBCGS(LS, & - P_data, & - Pset, & - Psol) & - bind(C,name='SUNLinSolSetPreconditioner_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: P_data - type(c_funptr), value :: Pset - type(c_funptr), value :: Psol - end function FSUNLinSolSetPreconditioner_SPBCGS - - integer(c_int) function FSUNLinSolSetScalingVectors_SPBCGS(LS, s1, s2) & - bind(C,name='SUNLinSolSetScalingVectors_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: s1 - type(c_ptr), value :: s2 - end function FSUNLinSolSetScalingVectors_SPBCGS - - integer(c_int) function FSUNLinSolSetup_SPBCGS(LS, A) & - bind(C,name='SUNLinSolSetup_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - end function FSUNLinSolSetup_SPBCGS - - integer(c_int) function FSUNLinSolSolve_SPBCGS(LS, A, x, b, tol) & - bind(C,name='SUNLinSolSolve_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - type(c_ptr), value :: x - type(c_ptr), value :: b - real(c_double), value :: tol - end function FSUNLinSolSolve_SPBCGS - - integer(c_int) function FSUNLinSolNumIters_SPBCGS(LS) & - bind(C,name='SUNLinSolNumIters_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolNumIters_SPBCGS - - real(c_double) function FSUNLinSolResNorm_SPBCGS(LS) & - bind(C,name='SUNLinSolResNorm_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolResNorm_SPBCGS - - type(c_ptr) function FSUNLinSolResid_SPBCGS(LS) & - bind(C,name='SUNLinSolResid_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolResid_SPBCGS - - integer(c_long) function FSUNLinSolLastFlag_SPBCGS(LS) & - bind(C,name='SUNLinSolLastFlag_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolLastFlag_SPBCGS - - integer(c_int) function FSUNLinSolSpace_SPBCGS(LS, lenrwLS, leniwLS) & - bind(C,name='SUNLinSolSpace_SPBCGS') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_long) :: lenrwLS - integer(c_long) :: leniwLS - end function FSUNLinSolSpace_SPBCGS - - end interface - -end module fsunlinsol_spbcgs_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fmod/CMakeLists.txt similarity index 75% rename from deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/F90/CMakeLists.txt rename to deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fmod/CMakeLists.txt index 35292f1e5..dcf096039 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/F90/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fmod/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Cody J. Balos @ LLNL +# Programmer(s): Cody J. Balos @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,22 +12,25 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the F2003 SPBCGS SUNLinearSolver object library +# --------------------------------------------------------------- -set(sunlinsolspbcgs_SOURCES fsunlinsol_spbcgs.f90) +set(sunlinsolspbcgs_SOURCES fsunlinsol_spbcgs_mod.f90 fsunlinsol_spbcgs_mod.c) if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolspbcgs_mod_static STATIC + sundials_add_f2003_interface_library(sundials_fsunlinsolspbcgs_mod_static STATIC_OBJECT ${sunlinsolspbcgs_SOURCES} ) + add_dependencies(sundials_fsunlinsolspbcgs_mod_static_obj sundials_fgeneric_static_obj) set_target_properties(sundials_fsunlinsolspbcgs_mod_static PROPERTIES OUTPUT_NAME sundials_fsunlinsolspbcgs_mod CLEAN_DIRECT_OUTPUT 1) install(TARGETS sundials_fsunlinsolspbcgs_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif(BUILD_STATIC_LIBS) if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolspbcgs_mod_shared SHARED + sundials_add_f2003_interface_library(sundials_fsunlinsolspbcgs_mod_shared SHARED_OBJECT ${sunlinsolspbcgs_SOURCES} ) + add_dependencies(sundials_fsunlinsolspbcgs_mod_shared_obj sundials_fgeneric_shared_obj) set_target_properties(sundials_fsunlinsolspbcgs_mod_shared PROPERTIES OUTPUT_NAME sundials_fsunlinsolspbcgs_mod CLEAN_DIRECT_OUTPUT 1) set_target_properties(sundials_fsunlinsolspbcgs_mod_shared diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fmod/fsunlinsol_spbcgs_mod.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fmod/fsunlinsol_spbcgs_mod.c new file mode 100644 index 000000000..932a0ebcd --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fmod/fsunlinsol_spbcgs_mod.c @@ -0,0 +1,495 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_linearsolver.h" + + +#include "sunlinsol/sunlinsol_spbcgs.h" + +SWIGEXPORT SUNLinearSolver _wrap_FSUNLinSol_SPBCGS(N_Vector farg1, int const *farg2, int const *farg3) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int arg3 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (SUNLinearSolver)SUNLinSol_SPBCGS(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_SPBCGSSetPrecType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_SPBCGSSetPrecType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_SPBCGSSetMaxl(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_SPBCGSSetMaxl(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SUNLinearSolver _wrap_FSUNSPBCGS(N_Vector farg1, int const *farg2, int const *farg3) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int arg3 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (SUNLinearSolver)SUNSPBCGS(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSPBCGSSetPrecType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNSPBCGSSetPrecType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSPBCGSSetMaxl(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNSPBCGSSetMaxl(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetType_SPBCGS(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_Type result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_Type)SUNLinSolGetType_SPBCGS(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetID_SPBCGS(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_ID result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_ID)SUNLinSolGetID_SPBCGS(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolInitialize_SPBCGS(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolInitialize_SPBCGS(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetATimes_SPBCGS(SUNLinearSolver farg1, void *farg2, ATimesFn farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + void *arg2 = (void *) 0 ; + ATimesFn arg3 = (ATimesFn) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (void *)(farg2); + arg3 = (ATimesFn)(farg3); + result = (int)SUNLinSolSetATimes_SPBCGS(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetPreconditioner_SPBCGS(SUNLinearSolver farg1, void *farg2, PSetupFn farg3, PSolveFn farg4) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + void *arg2 = (void *) 0 ; + PSetupFn arg3 = (PSetupFn) 0 ; + PSolveFn arg4 = (PSolveFn) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (void *)(farg2); + arg3 = (PSetupFn)(farg3); + arg4 = (PSolveFn)(farg4); + result = (int)SUNLinSolSetPreconditioner_SPBCGS(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetScalingVectors_SPBCGS(SUNLinearSolver farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)SUNLinSolSetScalingVectors_SPBCGS(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetup_SPBCGS(SUNLinearSolver farg1, SUNMatrix farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNLinSolSetup_SPBCGS(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSolve_SPBCGS(SUNLinearSolver farg1, SUNMatrix farg2, N_Vector farg3, N_Vector farg4, double const *farg5) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype arg5 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype)(*farg5); + result = (int)SUNLinSolSolve_SPBCGS(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolNumIters_SPBCGS(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolNumIters_SPBCGS(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FSUNLinSolResNorm_SPBCGS(SUNLinearSolver farg1) { + double fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + realtype result; + + arg1 = (SUNLinearSolver)(farg1); + result = (realtype)SUNLinSolResNorm_SPBCGS(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FSUNLinSolResid_SPBCGS(SUNLinearSolver farg1) { + N_Vector fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + N_Vector result; + + arg1 = (SUNLinearSolver)(farg1); + result = (N_Vector)SUNLinSolResid_SPBCGS(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNLinSolLastFlag_SPBCGS(SUNLinearSolver farg1) { + int64_t fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + sunindextype result; + + arg1 = (SUNLinearSolver)(farg1); + result = SUNLinSolLastFlag_SPBCGS(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSpace_SPBCGS(SUNLinearSolver farg1, long *farg2, long *farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNLinSolSpace_SPBCGS(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolFree_SPBCGS(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolFree_SPBCGS(arg1); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fmod/fsunlinsol_spbcgs_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fmod/fsunlinsol_spbcgs_mod.f90 new file mode 100644 index 000000000..6ea416a18 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fmod/fsunlinsol_spbcgs_mod.f90 @@ -0,0 +1,572 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunlinsol_spbcgs_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_linearsolver_mod + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: SUNSPBCGS_MAXL_DEFAULT = 5_C_INT + public :: FSUNLinSol_SPBCGS + public :: FSUNLinSol_SPBCGSSetPrecType + public :: FSUNLinSol_SPBCGSSetMaxl + public :: FSUNSPBCGS + public :: FSUNSPBCGSSetPrecType + public :: FSUNSPBCGSSetMaxl + public :: FSUNLinSolGetType_SPBCGS + public :: FSUNLinSolGetID_SPBCGS + public :: FSUNLinSolInitialize_SPBCGS + public :: FSUNLinSolSetATimes_SPBCGS + public :: FSUNLinSolSetPreconditioner_SPBCGS + public :: FSUNLinSolSetScalingVectors_SPBCGS + public :: FSUNLinSolSetup_SPBCGS + public :: FSUNLinSolSolve_SPBCGS + public :: FSUNLinSolNumIters_SPBCGS + public :: FSUNLinSolResNorm_SPBCGS + public :: FSUNLinSolResid_SPBCGS + public :: FSUNLinSolLastFlag_SPBCGS + public :: FSUNLinSolSpace_SPBCGS + public :: FSUNLinSolFree_SPBCGS + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNLinSol_SPBCGS(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSol_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSol_SPBCGSSetPrecType(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_SPBCGSSetPrecType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSol_SPBCGSSetMaxl(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_SPBCGSSetMaxl") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSPBCGS(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNSPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNSPBCGSSetPrecType(farg1, farg2) & +bind(C, name="_wrap_FSUNSPBCGSSetPrecType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSPBCGSSetMaxl(farg1, farg2) & +bind(C, name="_wrap_FSUNSPBCGSSetMaxl") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetType_SPBCGS(farg1) & +bind(C, name="_wrap_FSUNLinSolGetType_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetID_SPBCGS(farg1) & +bind(C, name="_wrap_FSUNLinSolGetID_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolInitialize_SPBCGS(farg1) & +bind(C, name="_wrap_FSUNLinSolInitialize_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetATimes_SPBCGS(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSetATimes_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetPreconditioner_SPBCGS(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FSUNLinSolSetPreconditioner_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetScalingVectors_SPBCGS(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSetScalingVectors_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetup_SPBCGS(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSolSetup_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSolve_SPBCGS(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FSUNLinSolSolve_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolNumIters_SPBCGS(farg1) & +bind(C, name="_wrap_FSUNLinSolNumIters_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolResNorm_SPBCGS(farg1) & +bind(C, name="_wrap_FSUNLinSolResNorm_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FSUNLinSolResid_SPBCGS(farg1) & +bind(C, name="_wrap_FSUNLinSolResid_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSolLastFlag_SPBCGS(farg1) & +bind(C, name="_wrap_FSUNLinSolLastFlag_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNLinSolSpace_SPBCGS(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSpace_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolFree_SPBCGS(farg1) & +bind(C, name="_wrap_FSUNLinSolFree_SPBCGS") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNLinSol_SPBCGS(y, pretype, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +integer(C_INT), intent(in) :: pretype +integer(C_INT), intent(in) :: maxl +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = c_loc(y) +farg2 = pretype +farg3 = maxl +fresult = swigc_FSUNLinSol_SPBCGS(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSol_SPBCGSSetPrecType(s, pretype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: pretype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = pretype +fresult = swigc_FSUNLinSol_SPBCGSSetPrecType(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSol_SPBCGSSetMaxl(s, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: maxl +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = maxl +fresult = swigc_FSUNLinSol_SPBCGSSetMaxl(farg1, farg2) +swig_result = fresult +end function + +function FSUNSPBCGS(y, pretype, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +integer(C_INT), intent(in) :: pretype +integer(C_INT), intent(in) :: maxl +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = c_loc(y) +farg2 = pretype +farg3 = maxl +fresult = swigc_FSUNSPBCGS(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNSPBCGSSetPrecType(s, pretype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: pretype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = pretype +fresult = swigc_FSUNSPBCGSSetPrecType(farg1, farg2) +swig_result = fresult +end function + +function FSUNSPBCGSSetMaxl(s, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: maxl +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = maxl +fresult = swigc_FSUNSPBCGSSetMaxl(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolGetType_SPBCGS(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_Type) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetType_SPBCGS(farg1) +swig_result = fresult +end function + +function FSUNLinSolGetID_SPBCGS(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_ID) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetID_SPBCGS(farg1) +swig_result = fresult +end function + +function FSUNLinSolInitialize_SPBCGS(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolInitialize_SPBCGS(farg1) +swig_result = fresult +end function + +function FSUNLinSolSetATimes_SPBCGS(s, a_data, atimes) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: a_data +type(C_FUNPTR), intent(in), value :: atimes +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = c_loc(s) +farg2 = a_data +farg3 = atimes +fresult = swigc_FSUNLinSolSetATimes_SPBCGS(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolSetPreconditioner_SPBCGS(s, p_data, pset, psol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: p_data +type(C_FUNPTR), intent(in), value :: pset +type(C_FUNPTR), intent(in), value :: psol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = c_loc(s) +farg2 = p_data +farg3 = pset +farg4 = psol +fresult = swigc_FSUNLinSolSetPreconditioner_SPBCGS(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FSUNLinSolSetScalingVectors_SPBCGS(s, s1, s2) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(N_Vector), target, intent(inout) :: s1 +type(N_Vector), target, intent(inout) :: s2 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(s1) +farg3 = c_loc(s2) +fresult = swigc_FSUNLinSolSetScalingVectors_SPBCGS(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolSetup_SPBCGS(s, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(s) +farg2 = c_loc(a) +fresult = swigc_FSUNLinSolSetup_SPBCGS(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolSolve_SPBCGS(s, a, x, b, tol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: b +real(C_DOUBLE), intent(in) :: tol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +real(C_DOUBLE) :: farg5 + +farg1 = c_loc(s) +farg2 = c_loc(a) +farg3 = c_loc(x) +farg4 = c_loc(b) +farg5 = tol +fresult = swigc_FSUNLinSolSolve_SPBCGS(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FSUNLinSolNumIters_SPBCGS(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolNumIters_SPBCGS(farg1) +swig_result = fresult +end function + +function FSUNLinSolResNorm_SPBCGS(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolResNorm_SPBCGS(farg1) +swig_result = fresult +end function + +function FSUNLinSolResid_SPBCGS(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolResid_SPBCGS(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSolLastFlag_SPBCGS(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolLastFlag_SPBCGS(farg1) +swig_result = fresult +end function + +function FSUNLinSolSpace_SPBCGS(s, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FSUNLinSolSpace_SPBCGS(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolFree_SPBCGS(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolFree_SPBCGS(farg1) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c index 8987e29ed..8420e2981 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.h b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.h index 4cd668b54..27566f1b3 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c index d6eb3290f..625a0dcb0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c @@ -1,11 +1,10 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU - * Based on sundials_spbcgs.c code, written by Peter Brown and + * Based on sundials_spbcgs.c code, written by Peter Brown and * Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -14,10 +13,9 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the SPBCGS implementation of + * This is the implementation file for the SPBCGS implementation of * the SUNLINSOL package. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include @@ -30,7 +28,7 @@ /* * ----------------------------------------------------------------- - * SPBCGS solver structure accessibility macros: + * SPBCGS solver structure accessibility macros: * ----------------------------------------------------------------- */ @@ -66,9 +64,8 @@ int SUNSPBCGSSetMaxl(SUNLinearSolver S, int maxl) SUNLinearSolver SUNLinSol_SPBCGS(N_Vector y, int pretype, int maxl) { SUNLinearSolver S; - SUNLinearSolver_Ops ops; SUNLinearSolverContent_SPBCGS content; - + /* check for legal pretype and maxl values; if illegal use defaults */ if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) && (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) @@ -85,77 +82,87 @@ SUNLinearSolver SUNLinSol_SPBCGS(N_Vector y, int pretype, int maxl) /* Create linear solver */ S = NULL; - S = (SUNLinearSolver) malloc(sizeof *S); + S = SUNLinSolNewEmpty(); if (S == NULL) return(NULL); - - /* Create linear solver operation structure */ - ops = NULL; - ops = (SUNLinearSolver_Ops) malloc(sizeof(struct _generic_SUNLinearSolver_Ops)); - if (ops == NULL) { free(S); return(NULL); } /* Attach operations */ - ops->gettype = SUNLinSolGetType_SPBCGS; - ops->setatimes = SUNLinSolSetATimes_SPBCGS; - ops->setpreconditioner = SUNLinSolSetPreconditioner_SPBCGS; - ops->setscalingvectors = SUNLinSolSetScalingVectors_SPBCGS; - ops->initialize = SUNLinSolInitialize_SPBCGS; - ops->setup = SUNLinSolSetup_SPBCGS; - ops->solve = SUNLinSolSolve_SPBCGS; - ops->numiters = SUNLinSolNumIters_SPBCGS; - ops->resnorm = SUNLinSolResNorm_SPBCGS; - ops->resid = SUNLinSolResid_SPBCGS; - ops->lastflag = SUNLinSolLastFlag_SPBCGS; - ops->space = SUNLinSolSpace_SPBCGS; - ops->free = SUNLinSolFree_SPBCGS; + S->ops->gettype = SUNLinSolGetType_SPBCGS; + S->ops->getid = SUNLinSolGetID_SPBCGS; + S->ops->setatimes = SUNLinSolSetATimes_SPBCGS; + S->ops->setpreconditioner = SUNLinSolSetPreconditioner_SPBCGS; + S->ops->setscalingvectors = SUNLinSolSetScalingVectors_SPBCGS; + S->ops->initialize = SUNLinSolInitialize_SPBCGS; + S->ops->setup = SUNLinSolSetup_SPBCGS; + S->ops->solve = SUNLinSolSolve_SPBCGS; + S->ops->numiters = SUNLinSolNumIters_SPBCGS; + S->ops->resnorm = SUNLinSolResNorm_SPBCGS; + S->ops->resid = SUNLinSolResid_SPBCGS; + S->ops->lastflag = SUNLinSolLastFlag_SPBCGS; + S->ops->space = SUNLinSolSpace_SPBCGS; + S->ops->free = SUNLinSolFree_SPBCGS; /* Create content */ content = NULL; - content = (SUNLinearSolverContent_SPBCGS) malloc(sizeof(struct _SUNLinearSolverContent_SPBCGS)); - if (content == NULL) { free(ops); free(S); return(NULL); } + content = (SUNLinearSolverContent_SPBCGS) malloc(sizeof *content); + if (content == NULL) { SUNLinSolFree(S); return(NULL); } + + /* Attach content */ + S->content = content; /* Fill content */ content->last_flag = 0; - content->maxl = maxl; - content->pretype = pretype; - content->numiters = 0; - content->resnorm = ZERO; + content->maxl = maxl; + content->pretype = pretype; + content->numiters = 0; + content->resnorm = ZERO; + content->r_star = NULL; + content->r = NULL; + content->p = NULL; + content->q = NULL; + content->u = NULL; + content->Ap = NULL; + content->vtemp = NULL; + content->s1 = NULL; + content->s2 = NULL; + content->ATimes = NULL; + content->ATData = NULL; + content->Psetup = NULL; + content->Psolve = NULL; + content->PData = NULL; + + /* Allocate content */ content->r_star = N_VClone(y); - if (content->r_star == NULL) return(NULL); + if (content->r_star == NULL) { SUNLinSolFree(S); return(NULL); } + content->r = N_VClone(y); - if (content->r == NULL) return(NULL); + if (content->r == NULL) { SUNLinSolFree(S); return(NULL); } + content->p = N_VClone(y); - if (content->p == NULL) return(NULL); + if (content->p == NULL) { SUNLinSolFree(S); return(NULL); } + content->q = N_VClone(y); - if (content->q == NULL) return(NULL); + if (content->q == NULL) { SUNLinSolFree(S); return(NULL); } + content->u = N_VClone(y); - if (content->u == NULL) return(NULL); + if (content->u == NULL) { SUNLinSolFree(S); return(NULL); } + content->Ap = N_VClone(y); - if (content->Ap == NULL) return(NULL); + if (content->Ap == NULL) { SUNLinSolFree(S); return(NULL); } + content->vtemp = N_VClone(y); - if (content->vtemp == NULL) return(NULL); - content->s1 = NULL; - content->s2 = NULL; - content->ATimes = NULL; - content->ATData = NULL; - content->Psetup = NULL; - content->Psolve = NULL; - content->PData = NULL; - - /* Attach content and ops */ - S->content = content; - S->ops = ops; + if (content->vtemp == NULL) { SUNLinSolFree(S); return(NULL); } return(S); } /* ---------------------------------------------------------------------------- - * Function to set the type of preconditioning for SPBCGS to use + * Function to set the type of preconditioning for SPBCGS to use */ -SUNDIALS_EXPORT int SUNLinSol_SPBCGSSetPrecType(SUNLinearSolver S, int pretype) +SUNDIALS_EXPORT int SUNLinSol_SPBCGSSetPrecType(SUNLinearSolver S, int pretype) { - /* Check for legal pretype */ + /* Check for legal pretype */ if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) && (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) { return(SUNLS_ILL_INPUT); @@ -171,15 +178,15 @@ SUNDIALS_EXPORT int SUNLinSol_SPBCGSSetPrecType(SUNLinearSolver S, int pretype) /* ---------------------------------------------------------------------------- - * Function to set the maximum number of iterations for SPBCGS to use + * Function to set the maximum number of iterations for SPBCGS to use */ -SUNDIALS_EXPORT int SUNLinSol_SPBCGSSetMaxl(SUNLinearSolver S, int maxl) +SUNDIALS_EXPORT int SUNLinSol_SPBCGSSetMaxl(SUNLinearSolver S, int maxl) { /* Check for non-NULL SUNLinearSolver */ if (S == NULL) return(SUNLS_MEM_NULL); - /* Check for legal pretype */ + /* Check for legal pretype */ if (maxl <= 0) maxl = SUNSPBCGS_MAXL_DEFAULT; @@ -201,26 +208,32 @@ SUNLinearSolver_Type SUNLinSolGetType_SPBCGS(SUNLinearSolver S) } +SUNLinearSolver_ID SUNLinSolGetID_SPBCGS(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_SPBCGS); +} + + int SUNLinSolInitialize_SPBCGS(SUNLinearSolver S) { /* ensure valid options */ - if (S == NULL) return(SUNLS_MEM_NULL); - if ( (PRETYPE(S) != PREC_LEFT) && - (PRETYPE(S) != PREC_RIGHT) && + if (S == NULL) return(SUNLS_MEM_NULL); + if ( (PRETYPE(S) != PREC_LEFT) && + (PRETYPE(S) != PREC_RIGHT) && (PRETYPE(S) != PREC_BOTH) ) PRETYPE(S) = PREC_NONE; - if (SPBCGS_CONTENT(S)->maxl <= 0) + if (SPBCGS_CONTENT(S)->maxl <= 0) SPBCGS_CONTENT(S)->maxl = SUNSPBCGS_MAXL_DEFAULT; /* no additional memory to allocate */ - + /* return with success */ LASTFLAG(S) = SUNLS_SUCCESS; return(LASTFLAG(S)); } -int SUNLinSolSetATimes_SPBCGS(SUNLinearSolver S, void* ATData, +int SUNLinSolSetATimes_SPBCGS(SUNLinearSolver S, void* ATData, ATimesFn ATimes) { /* set function pointers to integrator-supplied ATimes routine @@ -250,7 +263,7 @@ int SUNLinSolSetPreconditioner_SPBCGS(SUNLinearSolver S, void* PData, int SUNLinSolSetScalingVectors_SPBCGS(SUNLinearSolver S, N_Vector s1, N_Vector s2) { - /* set N_Vector pointers to integrator-supplied scaling vectors, + /* set N_Vector pointers to integrator-supplied scaling vectors, and return with success */ if (S == NULL) return(SUNLS_MEM_NULL); SPBCGS_CONTENT(S)->s1 = s1; @@ -270,25 +283,25 @@ int SUNLinSolSetup_SPBCGS(SUNLinearSolver S, SUNMatrix A) if (S == NULL) return(SUNLS_MEM_NULL); Psetup = SPBCGS_CONTENT(S)->Psetup; PData = SPBCGS_CONTENT(S)->PData; - - /* no solver-specific setup is required, but if user-supplied + + /* no solver-specific setup is required, but if user-supplied Psetup routine exists, call that here */ if (Psetup != NULL) { ier = Psetup(PData); if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_PSET_FAIL_UNREC : SUNLS_PSET_FAIL_REC; return(LASTFLAG(S)); } } - - /* return with success */ + + /* return with success */ LASTFLAG(S) = SUNLS_SUCCESS; return(LASTFLAG(S)); } -int SUNLinSolSolve_SPBCGS(SUNLinearSolver S, SUNMatrix A, N_Vector x, +int SUNLinSolSolve_SPBCGS(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype delta) { /* local data and shortcut variables */ @@ -306,7 +319,7 @@ int SUNLinSolSolve_SPBCGS(SUNLinearSolver S, SUNMatrix A, N_Vector x, /* local variables for fused vector operations */ realtype cv[3]; N_Vector Xv[3]; - + /* Make local shorcuts to solver variables. */ if (S == NULL) return(SUNLS_MEM_NULL); l_max = SPBCGS_CONTENT(S)->maxl; @@ -331,9 +344,9 @@ int SUNLinSolSolve_SPBCGS(SUNLinearSolver S, SUNMatrix A, N_Vector x, converged = SUNFALSE; /* set booleantype flags for internal solver options */ - preOnLeft = ( (PRETYPE(S) == PREC_LEFT) || + preOnLeft = ( (PRETYPE(S) == PREC_LEFT) || (PRETYPE(S) == PREC_BOTH) ); - preOnRight = ( (PRETYPE(S) == PREC_RIGHT) || + preOnRight = ( (PRETYPE(S) == PREC_RIGHT) || (PRETYPE(S) == PREC_BOTH) ); scale_x = (sx != NULL); scale_b = (sb != NULL); @@ -561,12 +574,12 @@ int SUNLinSolSolve_SPBCGS(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_VScale(ONE, vtemp, x); } - if (converged == SUNTRUE) + if (converged == SUNTRUE) LASTFLAG(S) = SUNLS_SUCCESS; - else + else LASTFLAG(S) = SUNLS_RES_REDUCED; return(LASTFLAG(S)); - + } else { LASTFLAG(S) = SUNLS_CONV_FAIL; @@ -598,7 +611,7 @@ N_Vector SUNLinSolResid_SPBCGS(SUNLinearSolver S) } -long int SUNLinSolLastFlag_SPBCGS(SUNLinearSolver S) +sunindextype SUNLinSolLastFlag_SPBCGS(SUNLinearSolver S) { /* return the stored 'last_flag' value */ if (S == NULL) return(-1); @@ -606,8 +619,8 @@ long int SUNLinSolLastFlag_SPBCGS(SUNLinearSolver S) } -int SUNLinSolSpace_SPBCGS(SUNLinearSolver S, - long int *lenrwLS, +int SUNLinSolSpace_SPBCGS(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS) { sunindextype liw1, lrw1; @@ -625,25 +638,39 @@ int SUNLinSolFree_SPBCGS(SUNLinearSolver S) { if (S == NULL) return(SUNLS_SUCCESS); - /* delete items from within the content structure */ - if (SPBCGS_CONTENT(S)->r_star) - N_VDestroy(SPBCGS_CONTENT(S)->r_star); - if (SPBCGS_CONTENT(S)->r) - N_VDestroy(SPBCGS_CONTENT(S)->r); - if (SPBCGS_CONTENT(S)->p) - N_VDestroy(SPBCGS_CONTENT(S)->p); - if (SPBCGS_CONTENT(S)->q) - N_VDestroy(SPBCGS_CONTENT(S)->q); - if (SPBCGS_CONTENT(S)->u) - N_VDestroy(SPBCGS_CONTENT(S)->u); - if (SPBCGS_CONTENT(S)->Ap) - N_VDestroy(SPBCGS_CONTENT(S)->Ap); - if (SPBCGS_CONTENT(S)->vtemp) - N_VDestroy(SPBCGS_CONTENT(S)->vtemp); - - /* delete generic structures */ - free(S->content); S->content = NULL; - free(S->ops); S->ops = NULL; + if (S->content) { + /* delete items from within the content structure */ + if (SPBCGS_CONTENT(S)->r_star) { + N_VDestroy(SPBCGS_CONTENT(S)->r_star); + SPBCGS_CONTENT(S)->r_star = NULL; + } + if (SPBCGS_CONTENT(S)->r) { + N_VDestroy(SPBCGS_CONTENT(S)->r); + SPBCGS_CONTENT(S)->r = NULL; + } + if (SPBCGS_CONTENT(S)->p) { + N_VDestroy(SPBCGS_CONTENT(S)->p); + SPBCGS_CONTENT(S)->p = NULL; + } + if (SPBCGS_CONTENT(S)->q) { + N_VDestroy(SPBCGS_CONTENT(S)->q); + SPBCGS_CONTENT(S)->q = NULL; + } + if (SPBCGS_CONTENT(S)->u) { + N_VDestroy(SPBCGS_CONTENT(S)->u); + SPBCGS_CONTENT(S)->u = NULL; + } + if (SPBCGS_CONTENT(S)->Ap) { + N_VDestroy(SPBCGS_CONTENT(S)->Ap); + SPBCGS_CONTENT(S)->Ap = NULL; + } + if (SPBCGS_CONTENT(S)->vtemp) { + N_VDestroy(SPBCGS_CONTENT(S)->vtemp); + SPBCGS_CONTENT(S)->vtemp = NULL; + } + free(S->content); S->content = NULL; + } + if (S->ops) { free(S->ops); S->ops = NULL; } free(S); S = NULL; return(SUNLS_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/CMakeLists.txt index 7192ff4b0..e0226c251 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,97 +12,132 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the SPFGMR SUNLinearSolver library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNLINSOL_SPFGMR\n\")") - -# Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF(F90_FOUND AND F2003_INTERFACE_ENABLE) +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_SPFGMR\n\")") -# Add variable sunlinsolspfgmr_SOURCES with the sources for the SUNLINSOLSPFGMR lib -SET(sunlinsolspfgmr_SOURCES sunlinsol_spfgmr.c) +# Source files for the library +set(sunlinsolspfgmr_SOURCES sunlinsol_spfgmr.c) -# Add variable shared_SOURCES with the common SUNDIALS sources which will -# also be included in the SUNLINSOLSPFGMR library -SET(shared_SOURCES +# Common SUNDIALS sources included in the library +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c - ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c - ) + ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c) -# Add variable sunlinsolspfgmr_HEADERS with the exported SUNLINSOLSPFGMR header files -SET(sunlinsolspfgmr_HEADERS - ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_spfgmr.h - ) - -# Add source directory to include directories -INCLUDE_DIRECTORIES(.) - -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Exported header files +set(sunlinsolspfgmr_HEADERS + ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_spfgmr.h) # Rules for building and installing the static library: -# - Add the build target for the SUNLINSOLSPFGMR library +# - Add the build target for the library # - Set the library name and make sure it is not deleted -# - Install the SUNLINSOLSPFGMR library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunlinsolspfgmr_static STATIC ${sunlinsolspfgmr_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunlinsolspfgmr_static - PROPERTIES OUTPUT_NAME sundials_sunlinsolspfgmr CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunlinsolspfgmr_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +# - Install the library +if(BUILD_STATIC_LIBS) + + add_library(sundials_sunlinsolspfgmr_static + STATIC ${sunlinsolspfgmr_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolspfgmr_static + PROPERTIES + OUTPUT_NAME sundials_sunlinsolspfgmr + CLEAN_DIRECT_OUTPUT 1) + + if(UNIX) + target_link_libraries(sundials_sunlinsolspfgmr_static + PRIVATE m) + endif() + + target_compile_definitions(sundials_sunlinsolspfgmr_static + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolspfgmr_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: -# - Add the build target for the SUNLINSOLSPFGMR library +# - Add the build target for the library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries -# - Install the SUNLINSOLSPFGMR library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunlinsolspfgmr_shared SHARED ${sunlinsolspfgmr_SOURCES} ${shared_SOURCES}) - - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_sunlinsolspfgmr_shared m) - ENDIF() - - SET_TARGET_PROPERTIES(sundials_sunlinsolspfgmr_shared - PROPERTIES OUTPUT_NAME sundials_sunlinsolspfgmr CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunlinsolspfgmr_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_sunlinsolspfgmr_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) - -# Install the SUNLINSOLSPFGMR header files -INSTALL(FILES ${sunlinsolspfgmr_HEADERS} DESTINATION include/sunlinsol) - -# If FCMIX is enabled, build and install the FSUNLINSOLSPFGMR library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunlinsolspfgmr_SOURCES fsunlinsol_spfgmr.c) - - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunlinsolspfgmr_static STATIC ${fsunlinsolspfgmr_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunlinsolspfgmr_static - PROPERTIES OUTPUT_NAME sundials_fsunlinsolspfgmr CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunlinsolspfgmr_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) - - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunlinsolspfgmr_shared ${fsunlinsolspfgmr_SOURCES}) - - # fsunlinsolspfgmr depends on fnvecserial and sunlinsolspfgmr - TARGET_LINK_LIBRARIES(sundials_fsunlinsolspfgmr_shared +# - Install the library +if(BUILD_SHARED_LIBS) + + add_library(sundials_sunlinsolspfgmr_shared + SHARED ${sunlinsolspfgmr_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolspfgmr_shared + PROPERTIES + OUTPUT_NAME sundials_sunlinsolspfgmr + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + + if(UNIX) + target_link_libraries(sundials_sunlinsolspfgmr_shared + PRIVATE m) + endif() + + target_compile_definitions(sundials_sunlinsolspfgmr_shared + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolspfgmr_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_SHARED_LIBS) + +# Install the header files +install(FILES ${sunlinsolspfgmr_HEADERS} DESTINATION include/sunlinsol) + +# +message(STATUS "Added SUNLINSOL_SPFGMR module") + +# If FCMIX is enabled, build and install the Fortran77 library +if(F77_INTERFACE_ENABLE AND F77_FOUND) + + set(fsunlinsolspfgmr_SOURCES fsunlinsol_spfgmr.c) + + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunlinsolspfgmr_static + STATIC ${fsunlinsolspfgmr_SOURCES}) + set_target_properties(sundials_fsunlinsolspfgmr_static + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolspfgmr + CLEAN_DIRECT_OUTPUT 1) + # depends on fnvecserial and sunlinsolspfgmr + target_link_libraries(sundials_fsunlinsolspfgmr_static + PUBLIC + sundials_fnvecserial_static + sundials_sunlinsolspfgmr_static) + install(TARGETS sundials_fsunlinsolspfgmr_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) + + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunlinsolspfgmr_shared + SHARED ${fsunlinsolspfgmr_SOURCES}) + set_target_properties(sundials_fsunlinsolspfgmr_shared + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolspfgmr + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + # depends on fnvecserial and sunlinsolspfgmr + target_link_libraries(sundials_fsunlinsolspfgmr_shared + PUBLIC sundials_fnvecserial_shared sundials_sunlinsolspfgmr_shared) + install(TARGETS sundials_fsunlinsolspfgmr_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) - SET_TARGET_PROPERTIES(sundials_fsunlinsolspfgmr_shared - PROPERTIES OUTPUT_NAME sundials_fsunlinsolspfgmr CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunlinsolspfgmr_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_fsunlinsolspfgmr_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + # + message(STATUS "Added SUNLINSOL_SPFGMR F77 interface") -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(F77_INTERFACE_ENABLE AND F77_FOUND) -# -MESSAGE(STATUS "Added SUNLINSOL_SPFGMR module") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/F90/fsunlinsol_spfgmr.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/F90/fsunlinsol_spfgmr.f90 deleted file mode 100644 index 80a9faaf1..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/F90/fsunlinsol_spfgmr.f90 +++ /dev/null @@ -1,182 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): Cody J. Balos @ LLNL -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS SPGMR linear solver using the ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fsunlinsol_spfgmr_mod - - !======= Interfaces ========= - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - type(c_ptr) function FSUNLinSol_SPFGMR(y, pretype, maxl) & - bind(C,name='SUNLinSol_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: y - integer(c_int), value :: pretype - integer(c_int), value :: maxl - end function FSUNLinSol_SPFGMR - - ! ================================================================= - ! Destructors - ! ================================================================= - - subroutine FSUNLinSolFree_SPFGMR(LS) & - bind(C,name='SUNLinSolFree_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end subroutine FSUNLinSolFree_SPFGMR - - ! ================================================================= - ! Setters - ! ================================================================= - - integer(c_int) function FSUNLinSol_SPFGMRSetPrecType(LS, pretype) & - bind(C,name='SUNLinSol_SPFGMRSetPrecType') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: pretype - end function FSUNLinSol_SPFGMRSetPrecType - - integer(c_int) function FSUNLinSol_SPFGMRSetGSType(LS, gstype) & - bind(C,name='SUNLinSol_SPFGMRSetGSType') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: gstype - end function FSUNLinSol_SPFGMRSetGSType - - integer(c_int) function FSUNLinSol_SPFGMRSetMaxRestarts(LS, maxrs) & - bind(C,name='SUNLinSol_SPFGMRSetMaxRestarts') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: maxrs - end function FSUNLinSol_SPFGMRSetMaxRestarts - - ! ================================================================= - ! Operations - ! ================================================================= - - integer(c_int) function FSUNLinSolGetType_SPFGMR(LS) & - bind(C,name='SUNLinSolGetType_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolGetType_SPFGMR - - integer(c_int) function FSUNLinSolInitialize_SPFGMR(LS) & - bind(C,name='SUNLinSolInitialize_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolInitialize_SPFGMR - - integer(c_int) function FSUNLinSolSetATimes_SPFGMR(LS, A_data, ATimes) & - bind(C,name='SUNLinSolSetATimes_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A_data - type(c_funptr), value :: ATimes - end function FSUNLinSolSetATimes_SPFGMR - - integer(c_int) function FSUNLinSolSetPreconditioner_SPFGMR(LS, & - P_data, & - Pset, & - Psol) & - bind(C,name='SUNLinSolSetPreconditioner_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: P_data - type(c_funptr), value :: Pset - type(c_funptr), value :: Psol - end function FSUNLinSolSetPreconditioner_SPFGMR - - integer(c_int) function FSUNLinSolSetScalingVectors_SPFGMR(LS, s1, s2) & - bind(C,name='SUNLinSolSetScalingVectors_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: s1 - type(c_ptr), value :: s2 - end function FSUNLinSolSetScalingVectors_SPFGMR - - integer(c_int) function FSUNLinSolSetup_SPFGMR(LS, A) & - bind(C,name='SUNLinSolSetup_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - end function FSUNLinSolSetup_SPFGMR - - integer(c_int) function FSUNLinSolSolve_SPFGMR(LS, A, x, b, tol) & - bind(C,name='SUNLinSolSolve_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - type(c_ptr), value :: x - type(c_ptr), value :: b - real(c_double), value :: tol - end function FSUNLinSolSolve_SPFGMR - - integer(c_int) function FSUNLinSolNumIters_SPFGMR(LS) & - bind(C,name='SUNLinSolNumIters_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolNumIters_SPFGMR - - real(c_double) function FSUNLinSolResNorm_SPFGMR(LS) & - bind(C,name='SUNLinSolResNorm_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolResNorm_SPFGMR - - type(c_ptr) function FSUNLinSolResid_SPFGMR(LS) & - bind(C,name='SUNLinSolResid_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolResid_SPFGMR - - integer(c_long) function FSUNLinSolLastFlag_SPFGMR(LS) & - bind(C,name='SUNLinSolLastFlag_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolLastFlag_SPFGMR - - integer(c_int) function FSUNLinSolSpace_SPFGMR(LS, lenrwLS, leniwLS) & - bind(C,name='SUNLinSolSpace_SPFGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_long) :: lenrwLS - integer(c_long) :: leniwLS - end function FSUNLinSolSpace_SPFGMR - - end interface - -end module fsunlinsol_spfgmr_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fmod/CMakeLists.txt similarity index 75% rename from deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/F90/CMakeLists.txt rename to deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fmod/CMakeLists.txt index 398086c83..ad00458d5 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/F90/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fmod/CMakeLists.txt @@ -1,8 +1,8 @@ # ------------------------------------------------------------------------ -# Programmer: Cody J. Balos @ LLNL +# Programmer(s): Cody J. Balos @ LLNL # ------------------------------------------------------------------------ # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,22 +12,25 @@ # SUNDIALS Copyright End # ------------------------------------------------------------------------ # CMakeLists.txt file for the F2003 SPFGMR SUNLinearSolbver object library +# ------------------------------------------------------------------------ -set(sunlinsolspfgmr_SOURCES fsunlinsol_spfgmr.f90) +set(sunlinsolspfgmr_SOURCES fsunlinsol_spfgmr_mod.f90 fsunlinsol_spfgmr_mod.c) if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolspfgmr_mod_static STATIC + sundials_add_f2003_interface_library(sundials_fsunlinsolspfgmr_mod_static STATIC_OBJECT ${sunlinsolspfgmr_SOURCES} ) + add_dependencies(sundials_fsunlinsolspfgmr_mod_static_obj sundials_fgeneric_static_obj) set_target_properties(sundials_fsunlinsolspfgmr_mod_static PROPERTIES OUTPUT_NAME sundials_fsunlinsolspfgmr_mod CLEAN_DIRECT_OUTPUT 1) install(TARGETS sundials_fsunlinsolspfgmr_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif(BUILD_STATIC_LIBS) if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolspfgmr_mod_shared SHARED + sundials_add_f2003_interface_library(sundials_fsunlinsolspfgmr_mod_shared SHARED_OBJECT ${sunlinsolspfgmr_SOURCES} ) + add_dependencies(sundials_fsunlinsolspfgmr_mod_shared_obj sundials_fgeneric_shared_obj) set_target_properties(sundials_fsunlinsolspfgmr_mod_shared PROPERTIES OUTPUT_NAME sundials_fsunlinsolspfgmr_mod CLEAN_DIRECT_OUTPUT 1) set_target_properties(sundials_fsunlinsolspfgmr_mod_shared diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fmod/fsunlinsol_spfgmr_mod.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fmod/fsunlinsol_spfgmr_mod.c new file mode 100644 index 000000000..66276be71 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fmod/fsunlinsol_spfgmr_mod.c @@ -0,0 +1,523 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_linearsolver.h" + + +#include "sunlinsol/sunlinsol_spfgmr.h" + +SWIGEXPORT SUNLinearSolver _wrap_FSUNLinSol_SPFGMR(N_Vector farg1, int const *farg2, int const *farg3) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int arg3 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (SUNLinearSolver)SUNLinSol_SPFGMR(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_SPFGMRSetPrecType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_SPFGMRSetPrecType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_SPFGMRSetGSType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_SPFGMRSetGSType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_SPFGMRSetMaxRestarts(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_SPFGMRSetMaxRestarts(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SUNLinearSolver _wrap_FSUNSPFGMR(N_Vector farg1, int const *farg2, int const *farg3) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int arg3 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (SUNLinearSolver)SUNSPFGMR(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSPFGMRSetPrecType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNSPFGMRSetPrecType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSPFGMRSetGSType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNSPFGMRSetGSType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSPFGMRSetMaxRestarts(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNSPFGMRSetMaxRestarts(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetType_SPFGMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_Type result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_Type)SUNLinSolGetType_SPFGMR(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetID_SPFGMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_ID result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_ID)SUNLinSolGetID_SPFGMR(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolInitialize_SPFGMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolInitialize_SPFGMR(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetATimes_SPFGMR(SUNLinearSolver farg1, void *farg2, ATimesFn farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + void *arg2 = (void *) 0 ; + ATimesFn arg3 = (ATimesFn) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (void *)(farg2); + arg3 = (ATimesFn)(farg3); + result = (int)SUNLinSolSetATimes_SPFGMR(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetPreconditioner_SPFGMR(SUNLinearSolver farg1, void *farg2, PSetupFn farg3, PSolveFn farg4) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + void *arg2 = (void *) 0 ; + PSetupFn arg3 = (PSetupFn) 0 ; + PSolveFn arg4 = (PSolveFn) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (void *)(farg2); + arg3 = (PSetupFn)(farg3); + arg4 = (PSolveFn)(farg4); + result = (int)SUNLinSolSetPreconditioner_SPFGMR(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetScalingVectors_SPFGMR(SUNLinearSolver farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)SUNLinSolSetScalingVectors_SPFGMR(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetup_SPFGMR(SUNLinearSolver farg1, SUNMatrix farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNLinSolSetup_SPFGMR(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSolve_SPFGMR(SUNLinearSolver farg1, SUNMatrix farg2, N_Vector farg3, N_Vector farg4, double const *farg5) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype arg5 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype)(*farg5); + result = (int)SUNLinSolSolve_SPFGMR(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolNumIters_SPFGMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolNumIters_SPFGMR(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FSUNLinSolResNorm_SPFGMR(SUNLinearSolver farg1) { + double fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + realtype result; + + arg1 = (SUNLinearSolver)(farg1); + result = (realtype)SUNLinSolResNorm_SPFGMR(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FSUNLinSolResid_SPFGMR(SUNLinearSolver farg1) { + N_Vector fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + N_Vector result; + + arg1 = (SUNLinearSolver)(farg1); + result = (N_Vector)SUNLinSolResid_SPFGMR(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNLinSolLastFlag_SPFGMR(SUNLinearSolver farg1) { + int64_t fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + sunindextype result; + + arg1 = (SUNLinearSolver)(farg1); + result = SUNLinSolLastFlag_SPFGMR(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSpace_SPFGMR(SUNLinearSolver farg1, long *farg2, long *farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNLinSolSpace_SPFGMR(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolFree_SPFGMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolFree_SPFGMR(arg1); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fmod/fsunlinsol_spfgmr_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fmod/fsunlinsol_spfgmr_mod.f90 new file mode 100644 index 000000000..64206fcaf --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fmod/fsunlinsol_spfgmr_mod.f90 @@ -0,0 +1,625 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunlinsol_spfgmr_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_linearsolver_mod + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: SUNSPFGMR_MAXL_DEFAULT = 5_C_INT + integer(C_INT), parameter, public :: SUNSPFGMR_MAXRS_DEFAULT = 0_C_INT + public :: FSUNLinSol_SPFGMR + public :: FSUNLinSol_SPFGMRSetPrecType + public :: FSUNLinSol_SPFGMRSetGSType + public :: FSUNLinSol_SPFGMRSetMaxRestarts + public :: FSUNSPFGMR + public :: FSUNSPFGMRSetPrecType + public :: FSUNSPFGMRSetGSType + public :: FSUNSPFGMRSetMaxRestarts + public :: FSUNLinSolGetType_SPFGMR + public :: FSUNLinSolGetID_SPFGMR + public :: FSUNLinSolInitialize_SPFGMR + public :: FSUNLinSolSetATimes_SPFGMR + public :: FSUNLinSolSetPreconditioner_SPFGMR + public :: FSUNLinSolSetScalingVectors_SPFGMR + public :: FSUNLinSolSetup_SPFGMR + public :: FSUNLinSolSolve_SPFGMR + public :: FSUNLinSolNumIters_SPFGMR + public :: FSUNLinSolResNorm_SPFGMR + public :: FSUNLinSolResid_SPFGMR + public :: FSUNLinSolLastFlag_SPFGMR + public :: FSUNLinSolSpace_SPFGMR + public :: FSUNLinSolFree_SPFGMR + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNLinSol_SPFGMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSol_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSol_SPFGMRSetPrecType(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_SPFGMRSetPrecType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSol_SPFGMRSetGSType(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_SPFGMRSetGSType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSol_SPFGMRSetMaxRestarts(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_SPFGMRSetMaxRestarts") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSPFGMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNSPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNSPFGMRSetPrecType(farg1, farg2) & +bind(C, name="_wrap_FSUNSPFGMRSetPrecType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSPFGMRSetGSType(farg1, farg2) & +bind(C, name="_wrap_FSUNSPFGMRSetGSType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSPFGMRSetMaxRestarts(farg1, farg2) & +bind(C, name="_wrap_FSUNSPFGMRSetMaxRestarts") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetType_SPFGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolGetType_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetID_SPFGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolGetID_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolInitialize_SPFGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolInitialize_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetATimes_SPFGMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSetATimes_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetPreconditioner_SPFGMR(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FSUNLinSolSetPreconditioner_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetScalingVectors_SPFGMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSetScalingVectors_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetup_SPFGMR(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSolSetup_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSolve_SPFGMR(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FSUNLinSolSolve_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolNumIters_SPFGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolNumIters_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolResNorm_SPFGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolResNorm_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FSUNLinSolResid_SPFGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolResid_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSolLastFlag_SPFGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolLastFlag_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNLinSolSpace_SPFGMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSpace_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolFree_SPFGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolFree_SPFGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNLinSol_SPFGMR(y, pretype, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +integer(C_INT), intent(in) :: pretype +integer(C_INT), intent(in) :: maxl +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = c_loc(y) +farg2 = pretype +farg3 = maxl +fresult = swigc_FSUNLinSol_SPFGMR(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSol_SPFGMRSetPrecType(s, pretype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: pretype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = pretype +fresult = swigc_FSUNLinSol_SPFGMRSetPrecType(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSol_SPFGMRSetGSType(s, gstype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: gstype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = gstype +fresult = swigc_FSUNLinSol_SPFGMRSetGSType(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSol_SPFGMRSetMaxRestarts(s, maxrs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: maxrs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = maxrs +fresult = swigc_FSUNLinSol_SPFGMRSetMaxRestarts(farg1, farg2) +swig_result = fresult +end function + +function FSUNSPFGMR(y, pretype, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +integer(C_INT), intent(in) :: pretype +integer(C_INT), intent(in) :: maxl +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = c_loc(y) +farg2 = pretype +farg3 = maxl +fresult = swigc_FSUNSPFGMR(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNSPFGMRSetPrecType(s, pretype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: pretype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = pretype +fresult = swigc_FSUNSPFGMRSetPrecType(farg1, farg2) +swig_result = fresult +end function + +function FSUNSPFGMRSetGSType(s, gstype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: gstype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = gstype +fresult = swigc_FSUNSPFGMRSetGSType(farg1, farg2) +swig_result = fresult +end function + +function FSUNSPFGMRSetMaxRestarts(s, maxrs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: maxrs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = maxrs +fresult = swigc_FSUNSPFGMRSetMaxRestarts(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolGetType_SPFGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_Type) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetType_SPFGMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolGetID_SPFGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_ID) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetID_SPFGMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolInitialize_SPFGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolInitialize_SPFGMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolSetATimes_SPFGMR(s, a_data, atimes) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: a_data +type(C_FUNPTR), intent(in), value :: atimes +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = c_loc(s) +farg2 = a_data +farg3 = atimes +fresult = swigc_FSUNLinSolSetATimes_SPFGMR(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolSetPreconditioner_SPFGMR(s, p_data, pset, psol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: p_data +type(C_FUNPTR), intent(in), value :: pset +type(C_FUNPTR), intent(in), value :: psol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = c_loc(s) +farg2 = p_data +farg3 = pset +farg4 = psol +fresult = swigc_FSUNLinSolSetPreconditioner_SPFGMR(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FSUNLinSolSetScalingVectors_SPFGMR(s, s1, s2) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(N_Vector), target, intent(inout) :: s1 +type(N_Vector), target, intent(inout) :: s2 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(s1) +farg3 = c_loc(s2) +fresult = swigc_FSUNLinSolSetScalingVectors_SPFGMR(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolSetup_SPFGMR(s, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(s) +farg2 = c_loc(a) +fresult = swigc_FSUNLinSolSetup_SPFGMR(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolSolve_SPFGMR(s, a, x, b, tol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: b +real(C_DOUBLE), intent(in) :: tol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +real(C_DOUBLE) :: farg5 + +farg1 = c_loc(s) +farg2 = c_loc(a) +farg3 = c_loc(x) +farg4 = c_loc(b) +farg5 = tol +fresult = swigc_FSUNLinSolSolve_SPFGMR(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FSUNLinSolNumIters_SPFGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolNumIters_SPFGMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolResNorm_SPFGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolResNorm_SPFGMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolResid_SPFGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolResid_SPFGMR(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSolLastFlag_SPFGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolLastFlag_SPFGMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolSpace_SPFGMR(s, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FSUNLinSolSpace_SPFGMR(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolFree_SPFGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolFree_SPFGMR(farg1) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.c index add542fb5..402e4c6bb 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.h b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.h index e5b25f20f..ef08c8acf 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/sunlinsol_spfgmr.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/sunlinsol_spfgmr.c index 51da6ebfc..cbf1b81b7 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/sunlinsol_spfgmr.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spfgmr/sunlinsol_spfgmr.c @@ -1,11 +1,10 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU - * Based on sundials_spfgmr.c code, written by Daniel R. Reynolds + * Based on sundials_spfgmr.c code, written by Daniel R. Reynolds * and Hilari C. Tiedeman @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -14,10 +13,9 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the SPFGMR implementation of + * This is the implementation file for the SPFGMR implementation of * the SUNLINSOL package. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include @@ -30,7 +28,7 @@ /* * ----------------------------------------------------------------- - * SPFGMR solver structure accessibility macros: + * SPFGMR solver structure accessibility macros: * ----------------------------------------------------------------- */ @@ -68,10 +66,9 @@ int SUNSPFGMRSetMaxRestarts(SUNLinearSolver S, int maxrs) SUNLinearSolver SUNLinSol_SPFGMR(N_Vector y, int pretype, int maxl) { SUNLinearSolver S; - SUNLinearSolver_Ops ops; SUNLinearSolverContent_SPFGMR content; - - /* set preconditioning flag (enabling any preconditioner implies right + + /* set preconditioning flag (enabling any preconditioner implies right preconditioning, since SPFGMR does not support left preconditioning) */ pretype = ( (pretype == PREC_LEFT) || (pretype == PREC_RIGHT) || @@ -89,77 +86,77 @@ SUNLinearSolver SUNLinSol_SPFGMR(N_Vector y, int pretype, int maxl) /* Create linear solver */ S = NULL; - S = (SUNLinearSolver) malloc(sizeof *S); + S = SUNLinSolNewEmpty(); if (S == NULL) return(NULL); - - /* Create linear solver operation structure */ - ops = NULL; - ops = (SUNLinearSolver_Ops) malloc(sizeof(struct _generic_SUNLinearSolver_Ops)); - if (ops == NULL) { free(S); return(NULL); } /* Attach operations */ - ops->gettype = SUNLinSolGetType_SPFGMR; - ops->setatimes = SUNLinSolSetATimes_SPFGMR; - ops->setpreconditioner = SUNLinSolSetPreconditioner_SPFGMR; - ops->setscalingvectors = SUNLinSolSetScalingVectors_SPFGMR; - ops->initialize = SUNLinSolInitialize_SPFGMR; - ops->setup = SUNLinSolSetup_SPFGMR; - ops->solve = SUNLinSolSolve_SPFGMR; - ops->numiters = SUNLinSolNumIters_SPFGMR; - ops->resnorm = SUNLinSolResNorm_SPFGMR; - ops->resid = SUNLinSolResid_SPFGMR; - ops->lastflag = SUNLinSolLastFlag_SPFGMR; - ops->space = SUNLinSolSpace_SPFGMR; - ops->free = SUNLinSolFree_SPFGMR; + S->ops->gettype = SUNLinSolGetType_SPFGMR; + S->ops->getid = SUNLinSolGetID_SPFGMR; + S->ops->setatimes = SUNLinSolSetATimes_SPFGMR; + S->ops->setpreconditioner = SUNLinSolSetPreconditioner_SPFGMR; + S->ops->setscalingvectors = SUNLinSolSetScalingVectors_SPFGMR; + S->ops->initialize = SUNLinSolInitialize_SPFGMR; + S->ops->setup = SUNLinSolSetup_SPFGMR; + S->ops->solve = SUNLinSolSolve_SPFGMR; + S->ops->numiters = SUNLinSolNumIters_SPFGMR; + S->ops->resnorm = SUNLinSolResNorm_SPFGMR; + S->ops->resid = SUNLinSolResid_SPFGMR; + S->ops->lastflag = SUNLinSolLastFlag_SPFGMR; + S->ops->space = SUNLinSolSpace_SPFGMR; + S->ops->free = SUNLinSolFree_SPFGMR; /* Create content */ content = NULL; - content = (SUNLinearSolverContent_SPFGMR) malloc(sizeof(struct _SUNLinearSolverContent_SPFGMR)); - if (content == NULL) { free(ops); free(S); return(NULL); } + content = (SUNLinearSolverContent_SPFGMR) malloc(sizeof *content); + if (content == NULL) { SUNLinSolFree(S); return(NULL); } + + /* Attach content */ + S->content = content; /* Fill content */ - content->last_flag = 0; - content->maxl = maxl; - content->pretype = pretype; - content->gstype = SUNSPFGMR_GSTYPE_DEFAULT; + content->last_flag = 0; + content->maxl = maxl; + content->pretype = pretype; + content->gstype = SUNSPFGMR_GSTYPE_DEFAULT; content->max_restarts = SUNSPFGMR_MAXRS_DEFAULT; - content->numiters = 0; - content->resnorm = ZERO; + content->numiters = 0; + content->resnorm = ZERO; + content->xcor = NULL; + content->vtemp = NULL; + content->s1 = NULL; + content->s2 = NULL; + content->ATimes = NULL; + content->ATData = NULL; + content->Psetup = NULL; + content->Psolve = NULL; + content->PData = NULL; + content->V = NULL; + content->Z = NULL; + content->Hes = NULL; + content->givens = NULL; + content->yg = NULL; + content->cv = NULL; + content->Xv = NULL; + + /* Allocate content */ content->xcor = N_VClone(y); - if (content->xcor == NULL) return(NULL); + if (content->xcor == NULL) { SUNLinSolFree(S); return(NULL); } + content->vtemp = N_VClone(y); - if (content->vtemp == NULL) return(NULL); - content->s1 = NULL; - content->s2 = NULL; - content->ATimes = NULL; - content->ATData = NULL; - content->Psetup = NULL; - content->Psolve = NULL; - content->PData = NULL; - content->V = NULL; - content->Z = NULL; - content->Hes = NULL; - content->givens = NULL; - content->yg = NULL; - content->cv = NULL; - content->Xv = NULL; - - /* Attach content and ops */ - S->content = content; - S->ops = ops; + if (content->vtemp == NULL) { SUNLinSolFree(S); return(NULL); } return(S); } /* ---------------------------------------------------------------------------- - * Function to toggle preconditioning on/off -- turns on if pretype is any + * Function to toggle preconditioning on/off -- turns on if pretype is any * one of PREC_LEFT, PREC_RIGHT or PREC_BOTH; otherwise turns off */ -SUNDIALS_EXPORT int SUNLinSol_SPFGMRSetPrecType(SUNLinearSolver S, int pretype) +SUNDIALS_EXPORT int SUNLinSol_SPFGMRSetPrecType(SUNLinearSolver S, int pretype) { - /* Check for legal pretype */ + /* Check for legal pretype */ pretype = ( (pretype == PREC_LEFT) || (pretype == PREC_RIGHT) || (pretype == PREC_BOTH) ) ? PREC_RIGHT : PREC_NONE; @@ -179,7 +176,7 @@ SUNDIALS_EXPORT int SUNLinSol_SPFGMRSetPrecType(SUNLinearSolver S, int pretype) SUNDIALS_EXPORT int SUNLinSol_SPFGMRSetGSType(SUNLinearSolver S, int gstype) { - /* Check for legal gstype */ + /* Check for legal gstype */ if ((gstype != MODIFIED_GS) && (gstype != CLASSICAL_GS)) { return(SUNLS_ILL_INPUT); } @@ -199,7 +196,7 @@ SUNDIALS_EXPORT int SUNLinSol_SPFGMRSetGSType(SUNLinearSolver S, int gstype) SUNDIALS_EXPORT int SUNLinSol_SPFGMRSetMaxRestarts(SUNLinearSolver S, int maxrs) { - /* Illegal maxrs implies use of default value */ + /* Illegal maxrs implies use of default value */ if (maxrs < 0) maxrs = SUNSPFGMR_MAXRS_DEFAULT; @@ -224,20 +221,26 @@ SUNLinearSolver_Type SUNLinSolGetType_SPFGMR(SUNLinearSolver S) } +SUNLinearSolver_ID SUNLinSolGetID_SPFGMR(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_SPFGMR); +} + + int SUNLinSolInitialize_SPFGMR(SUNLinearSolver S) { int k; SUNLinearSolverContent_SPFGMR content; /* set shortcut to SPFGMR memory structure */ - if (S == NULL) return(SUNLS_MEM_NULL); + if (S == NULL) return(SUNLS_MEM_NULL); content = SPFGMR_CONTENT(S); /* ensure valid options */ - if (content->max_restarts < 0) + if (content->max_restarts < 0) content->max_restarts = SUNSPFGMR_MAXRS_DEFAULT; - if ( (content->pretype != PREC_LEFT) && - (content->pretype != PREC_RIGHT) && + if ( (content->pretype != PREC_LEFT) && + (content->pretype != PREC_RIGHT) && (content->pretype != PREC_BOTH) ) content->pretype = PREC_NONE; @@ -264,7 +267,7 @@ int SUNLinSolInitialize_SPFGMR(SUNLinearSolver S) return(SUNLS_MEM_FAIL); } } - + /* Hessenberg matrix Hes */ if (content->Hes == NULL) { content->Hes = (realtype **) malloc((content->maxl+1)*sizeof(realtype *)); @@ -284,7 +287,7 @@ int SUNLinSolInitialize_SPFGMR(SUNLinearSolver S) } } } - + /* Givens rotation components */ if (content->givens == NULL) { content->givens = (realtype *) malloc(2*content->maxl*sizeof(realtype)); @@ -294,7 +297,7 @@ int SUNLinSolInitialize_SPFGMR(SUNLinearSolver S) return(SUNLS_MEM_FAIL); } } - + /* y and g vectors */ if (content->yg == NULL) { content->yg = (realtype *) malloc((content->maxl+1)*sizeof(realtype)); @@ -318,7 +321,7 @@ int SUNLinSolInitialize_SPFGMR(SUNLinearSolver S) /* Xv vector for fused vector ops */ if (content->Xv == NULL) { content->Xv = (N_Vector *) malloc((content->maxl+1)*sizeof(N_Vector)); - if (content->Xv == NULL) { + if (content->Xv == NULL) { SUNLinSolFree(S); content->last_flag = SUNLS_MEM_FAIL; return(SUNLS_MEM_FAIL); @@ -331,10 +334,10 @@ int SUNLinSolInitialize_SPFGMR(SUNLinearSolver S) } -int SUNLinSolSetATimes_SPFGMR(SUNLinearSolver S, void* ATData, +int SUNLinSolSetATimes_SPFGMR(SUNLinearSolver S, void* ATData, ATimesFn ATimes) { - /* set function pointers to integrator-supplied ATimes routine + /* set function pointers to integrator-supplied ATimes routine and data, and return with success */ if (S == NULL) return(SUNLS_MEM_NULL); SPFGMR_CONTENT(S)->ATimes = ATimes; @@ -361,7 +364,7 @@ int SUNLinSolSetPreconditioner_SPFGMR(SUNLinearSolver S, void* PData, int SUNLinSolSetScalingVectors_SPFGMR(SUNLinearSolver S, N_Vector s1, N_Vector s2) { - /* set N_Vector pointers to integrator-supplied scaling vectors, + /* set N_Vector pointers to integrator-supplied scaling vectors, and return with success */ if (S == NULL) return(SUNLS_MEM_NULL); SPFGMR_CONTENT(S)->s1 = s1; @@ -381,24 +384,24 @@ int SUNLinSolSetup_SPFGMR(SUNLinearSolver S, SUNMatrix A) if (S == NULL) return(SUNLS_MEM_NULL); Psetup = SPFGMR_CONTENT(S)->Psetup; PData = SPFGMR_CONTENT(S)->PData; - - /* no solver-specific setup is required, but if user-supplied + + /* no solver-specific setup is required, but if user-supplied Psetup routine exists, call that here */ if (Psetup != NULL) { ier = Psetup(PData); if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_PSET_FAIL_UNREC : SUNLS_PSET_FAIL_REC; return(LASTFLAG(S)); } } - - /* return with success */ + + /* return with success */ return(SUNLS_SUCCESS); } -int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, +int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype delta) { /* local data and shortcut variables */ @@ -448,7 +451,7 @@ int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, /* set booleantype flags for internal solver options */ preOnRight = ( (SPFGMR_CONTENT(S)->pretype == PREC_LEFT) || - (SPFGMR_CONTENT(S)->pretype == PREC_RIGHT) || + (SPFGMR_CONTENT(S)->pretype == PREC_RIGHT) || (SPFGMR_CONTENT(S)->pretype == PREC_BOTH) ); scale1 = (s1 != NULL); scale2 = (s2 != NULL); @@ -459,7 +462,7 @@ int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, } else { ier = atimes(A_data, x, vtemp); if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; return(LASTFLAG(S)); } @@ -468,7 +471,7 @@ int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, /* Apply left scaling to vtemp = r_0 to fill V[0]. */ if (scale1) { - N_VProd(s1, vtemp, V[0]); + N_VProd(s1, vtemp, V[0]); } else { N_VScale(ONE, vtemp, V[0]); } @@ -488,7 +491,7 @@ int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, /* Begin outer iterations: up to (max_restarts + 1) attempts. */ for (ntries=0; ntries<=max_restarts; ntries++) { - + /* Initialize the Hessenberg matrix Hes and Givens rotation product. Normalize the initial vector V[0]. */ for (i=0; i<=l_max; i++) @@ -496,21 +499,21 @@ int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, Hes[i][j] = ZERO; rotation_product = ONE; N_VScale(ONE/r_norm, V[0], V[0]); - + /* Inner loop: generate Krylov sequence and Arnoldi basis. */ for (l=0; l0; i--) { @@ -600,13 +603,13 @@ int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, s_product *= givens[2*i-1]; } yg[0] = s_product; - + /* Scale r_norm and yg. */ r_norm *= s_product; for (i=0; i<=krydim; i++) yg[i] *= r_norm; r_norm = SUNRabs(r_norm); - + /* Multiply yg by V_(krydim+1) to get last residual vector; restart. */ for (k=0; k<=krydim; k++) { cv[k] = yg[k]; @@ -614,9 +617,9 @@ int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, } ier = N_VLinearCombination(krydim+1, cv, Xv, V[0]); if (ier != SUNLS_SUCCESS) return(SUNLS_VECTOROP_ERR); - + } - + /* Failed to converge, even after allowed restarts. If the residual norm was reduced below its initial value, compute and return x anyway. Otherwise return failure flag. */ @@ -628,7 +631,7 @@ int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, } LASTFLAG(S) = SUNLS_CONV_FAIL; - return(LASTFLAG(S)); + return(LASTFLAG(S)); } @@ -655,7 +658,7 @@ N_Vector SUNLinSolResid_SPFGMR(SUNLinearSolver S) } -long int SUNLinSolLastFlag_SPFGMR(SUNLinearSolver S) +sunindextype SUNLinSolLastFlag_SPFGMR(SUNLinearSolver S) { /* return the stored 'last_flag' value */ if (S == NULL) return(-1); @@ -663,8 +666,8 @@ long int SUNLinSolLastFlag_SPFGMR(SUNLinearSolver S) } -int SUNLinSolSpace_SPFGMR(SUNLinearSolver S, - long int *lenrwLS, +int SUNLinSolSpace_SPFGMR(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS) { int maxl; @@ -685,35 +688,54 @@ int SUNLinSolFree_SPFGMR(SUNLinearSolver S) if (S == NULL) return(SUNLS_SUCCESS); - /* delete items from within the content structure */ - if (SPFGMR_CONTENT(S)->xcor) - N_VDestroy(SPFGMR_CONTENT(S)->xcor); - if (SPFGMR_CONTENT(S)->vtemp) - N_VDestroy(SPFGMR_CONTENT(S)->vtemp); - if (SPFGMR_CONTENT(S)->V) - N_VDestroyVectorArray(SPFGMR_CONTENT(S)->V, - SPFGMR_CONTENT(S)->maxl+1); - if (SPFGMR_CONTENT(S)->Z) - N_VDestroyVectorArray(SPFGMR_CONTENT(S)->Z, - SPFGMR_CONTENT(S)->maxl+1); - if (SPFGMR_CONTENT(S)->Hes) { - for (k=0; k<=SPFGMR_CONTENT(S)->maxl; k++) - if (SPFGMR_CONTENT(S)->Hes[k]) - free(SPFGMR_CONTENT(S)->Hes[k]); - free(SPFGMR_CONTENT(S)->Hes); + if (S->content) { + /* delete items from within the content structure */ + if (SPFGMR_CONTENT(S)->xcor) { + N_VDestroy(SPFGMR_CONTENT(S)->xcor); + SPFGMR_CONTENT(S)->xcor = NULL; + } + if (SPFGMR_CONTENT(S)->vtemp) { + N_VDestroy(SPFGMR_CONTENT(S)->vtemp); + SPFGMR_CONTENT(S)->vtemp = NULL; + } + if (SPFGMR_CONTENT(S)->V) { + N_VDestroyVectorArray(SPFGMR_CONTENT(S)->V, + SPFGMR_CONTENT(S)->maxl+1); + SPFGMR_CONTENT(S)->V = NULL; + } + if (SPFGMR_CONTENT(S)->Z) { + N_VDestroyVectorArray(SPFGMR_CONTENT(S)->Z, + SPFGMR_CONTENT(S)->maxl+1); + SPFGMR_CONTENT(S)->Z = NULL; + } + if (SPFGMR_CONTENT(S)->Hes) { + for (k=0; k<=SPFGMR_CONTENT(S)->maxl; k++) + if (SPFGMR_CONTENT(S)->Hes[k]) { + free(SPFGMR_CONTENT(S)->Hes[k]); + SPFGMR_CONTENT(S)->Hes[k] = NULL; + } + free(SPFGMR_CONTENT(S)->Hes); + SPFGMR_CONTENT(S)->Hes = NULL; + } + if (SPFGMR_CONTENT(S)->givens) { + free(SPFGMR_CONTENT(S)->givens); + SPFGMR_CONTENT(S)->givens = NULL; + } + if (SPFGMR_CONTENT(S)->yg) { + free(SPFGMR_CONTENT(S)->yg); + SPFGMR_CONTENT(S)->yg = NULL; + } + if (SPFGMR_CONTENT(S)->cv) { + free(SPFGMR_CONTENT(S)->cv); + SPFGMR_CONTENT(S)->cv = NULL; + } + if (SPFGMR_CONTENT(S)->Xv) { + free(SPFGMR_CONTENT(S)->Xv); + SPFGMR_CONTENT(S)->Xv = NULL; + } + free(S->content); S->content = NULL; } - if (SPFGMR_CONTENT(S)->givens) - free(SPFGMR_CONTENT(S)->givens); - if (SPFGMR_CONTENT(S)->yg) - free(SPFGMR_CONTENT(S)->yg); - if (SPFGMR_CONTENT(S)->cv) - free(SPFGMR_CONTENT(S)->cv); - if (SPFGMR_CONTENT(S)->Xv) - free(SPFGMR_CONTENT(S)->Xv); - - /* delete generic structures */ - free(S->content); S->content = NULL; - free(S->ops); S->ops = NULL; + if (S->ops) { free(S->ops); S->ops = NULL; } free(S); S = NULL; return(SUNLS_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/CMakeLists.txt index 0693a503e..1a0c436d3 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,97 +12,132 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the SPGMR SUNLinearSolver library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNLINSOL_SPGMR\n\")") - -# Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF() +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_SPGMR\n\")") -# Add variable sunlinsolspgmr_SOURCES with the sources for the SUNLINSOLSPGMR lib -SET(sunlinsolspgmr_SOURCES sunlinsol_spgmr.c) +# Source files for the library +set(sunlinsolspgmr_SOURCES sunlinsol_spgmr.c) -# Add variable shared_SOURCES with the common SUNDIALS sources which will -# also be included in the SUNLINSOLSPGMR library -SET(shared_SOURCES +# Common SUNDIALS sources included in the library +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c - ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c - ) + ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c) -# Add variable sunlinsolspgmr_HEADERS with the exported SUNLINSOLSPGMR header files -SET(sunlinsolspgmr_HEADERS - ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_spgmr.h - ) - -# Add source directory to include directories -INCLUDE_DIRECTORIES(.) - -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Exported header files +set(sunlinsolspgmr_HEADERS + ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_spgmr.h) # Rules for building and installing the static library: -# - Add the build target for the SUNLINSOLSPGMR library +# - Add the build target for the library # - Set the library name and make sure it is not deleted -# - Install the SUNLINSOLSPGMR library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunlinsolspgmr_static STATIC ${sunlinsolspgmr_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunlinsolspgmr_static - PROPERTIES OUTPUT_NAME sundials_sunlinsolspgmr CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunlinsolspgmr_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +# - Install the library +if(BUILD_STATIC_LIBS) + + add_library(sundials_sunlinsolspgmr_static + STATIC ${sunlinsolspgmr_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolspgmr_static + PROPERTIES + OUTPUT_NAME sundials_sunlinsolspgmr + CLEAN_DIRECT_OUTPUT 1) + + if(UNIX) + target_link_libraries(sundials_sunlinsolspgmr_static + PRIVATE m) + endif() + + target_compile_definitions(sundials_sunlinsolspgmr_static + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolspgmr_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: -# - Add the build target for the SUNLINSOLSPGMR library +# - Add the build target for the library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries -# - Install the SUNLINSOLSPGMR library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunlinsolspgmr_shared SHARED ${sunlinsolspgmr_SOURCES} ${shared_SOURCES}) - - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_sunlinsolspgmr_shared m) - ENDIF() - - SET_TARGET_PROPERTIES(sundials_sunlinsolspgmr_shared - PROPERTIES OUTPUT_NAME sundials_sunlinsolspgmr CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunlinsolspgmr_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_sunlinsolspgmr_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) - -# Install the SUNLINSOLSPGMR header files -INSTALL(FILES ${sunlinsolspgmr_HEADERS} DESTINATION include/sunlinsol) - -# If FCMIX is enabled, build and install the FSUNLINSOLSPGMR library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunlinsolspgmr_SOURCES fsunlinsol_spgmr.c) - - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunlinsolspgmr_static STATIC ${fsunlinsolspgmr_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunlinsolspgmr_static - PROPERTIES OUTPUT_NAME sundials_fsunlinsolspgmr CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunlinsolspgmr_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) - - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunlinsolspgmr_shared ${fsunlinsolspgmr_SOURCES}) - - # fsunlinsolspgmr depends on fnvecserial and sunlinsolspgmr - TARGET_LINK_LIBRARIES(sundials_fsunlinsolspgmr_shared +# - Install the library +if(BUILD_SHARED_LIBS) + + add_library(sundials_sunlinsolspgmr_shared + SHARED ${sunlinsolspgmr_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolspgmr_shared + PROPERTIES + OUTPUT_NAME sundials_sunlinsolspgmr + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + + if(UNIX) + target_link_libraries(sundials_sunlinsolspgmr_shared + PRIVATE m) + endif() + + target_compile_definitions(sundials_sunlinsolspgmr_shared + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolspgmr_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_SHARED_LIBS) + +# Install the header files +install(FILES ${sunlinsolspgmr_HEADERS} DESTINATION include/sunlinsol) + +# +message(STATUS "Added SUNLINSOL_SPGMR module") + +# If FCMIX is enabled, build and install the Fortran77 library +if(F77_INTERFACE_ENABLE AND F77_FOUND) + + set(fsunlinsolspgmr_SOURCES fsunlinsol_spgmr.c) + + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunlinsolspgmr_static + STATIC ${fsunlinsolspgmr_SOURCES}) + set_target_properties(sundials_fsunlinsolspgmr_static + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolspgmr + CLEAN_DIRECT_OUTPUT 1) + # depends on fnvecserial and sunlinsolspgmr + target_link_libraries(sundials_fsunlinsolspgmr_static + PUBLIC + sundials_fnvecserial_static + sundials_sunlinsolspgmr_static) + install(TARGETS sundials_fsunlinsolspgmr_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) + + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunlinsolspgmr_shared + SHARED ${fsunlinsolspgmr_SOURCES}) + set_target_properties(sundials_fsunlinsolspgmr_shared + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolspgmr + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + # depends on fnvecserial and sunlinsolspgmr + target_link_libraries(sundials_fsunlinsolspgmr_shared + PUBLIC sundials_fnvecserial_shared sundials_sunlinsolspgmr_shared) + install(TARGETS sundials_fsunlinsolspgmr_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) - SET_TARGET_PROPERTIES(sundials_fsunlinsolspgmr_shared - PROPERTIES OUTPUT_NAME sundials_fsunlinsolspgmr CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunlinsolspgmr_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_fsunlinsolspgmr_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + # + message(STATUS "Added SUNLINSOL_SPGMR F77 interface") -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(F77_INTERFACE_ENABLE AND F77_FOUND) -# -MESSAGE(STATUS "Added SUNLINSOL_SPGMR module") +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/F90/fsunlinsol_spgmr.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/F90/fsunlinsol_spgmr.f90 deleted file mode 100644 index 5859dd775..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/F90/fsunlinsol_spgmr.f90 +++ /dev/null @@ -1,182 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): Cody J. Balos @ LLNL -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS SPGMR linear solver using the ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fsunlinsol_spgmr_mod - - !======= Interfaces ========= - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - type(c_ptr) function FSUNLinSol_SPGMR(y, pretype, maxl) & - bind(C,name='SUNLinSol_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: y - integer(c_int), value :: pretype - integer(c_int), value :: maxl - end function FSUNLinSol_SPGMR - - ! ================================================================= - ! Destructors - ! ================================================================= - - subroutine FSUNLinSolFree_SPGMR(LS) & - bind(C,name='SUNLinSolFree_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end subroutine FSUNLinSolFree_SPGMR - - ! ================================================================= - ! Setters - ! ================================================================= - - integer(c_int) function FSUNLinSol_SPGMRSetPrecType(LS, pretype) & - bind(C,name='SUNLinSol_SPGMRSetPrecType') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: pretype - end function FSUNLinSol_SPGMRSetPrecType - - integer(c_int) function FSUNLinSol_SPGMRSetGSType(LS, gstype) & - bind(C,name='SUNLinSol_SPGMRSetGSType') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: gstype - end function FSUNLinSol_SPGMRSetGSType - - integer(c_int) function FSUNLinSol_SPGMRSetMaxRestarts(LS, maxrs) & - bind(C,name='SUNLinSol_SPGMRSetMaxRestarts') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: maxrs - end function FSUNLinSol_SPGMRSetMaxRestarts - - ! ================================================================= - ! Operations - ! ================================================================= - - integer(c_int) function FSUNLinSolGetType_SPGMR(LS) & - bind(C,name='SUNLinSolGetType_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolGetType_SPGMR - - integer(c_int) function FSUNLinSolInitialize_SPGMR(LS) & - bind(C,name='SUNLinSolInitialize_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolInitialize_SPGMR - - integer(c_int) function FSUNLinSolSetATimes_SPGMR(LS, A_data, ATimes) & - bind(C,name='SUNLinSolSetATimes_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A_data - type(c_funptr), value :: ATimes - end function FSUNLinSolSetATimes_SPGMR - - integer(c_int) function FSUNLinSolSetPreconditioner_SPGMR(LS, & - P_data, & - Pset, & - Psol) & - bind(C,name='SUNLinSolSetPreconditioner_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: P_data - type(c_funptr), value :: Pset - type(c_funptr), value :: Psol - end function FSUNLinSolSetPreconditioner_SPGMR - - integer(c_int) function FSUNLinSolSetScalingVectors_SPGMR(LS, s1, s2) & - bind(C,name='SUNLinSolSetScalingVectors_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: s1 - type(c_ptr), value :: s2 - end function FSUNLinSolSetScalingVectors_SPGMR - - integer(c_int) function FSUNLinSolSetup_SPGMR(LS, A) & - bind(C,name='SUNLinSolSetup_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - end function FSUNLinSolSetup_SPGMR - - integer(c_int) function FSUNLinSolSolve_SPGMR(LS, A, x, b, tol) & - bind(C,name='SUNLinSolSolve_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - type(c_ptr), value :: x - type(c_ptr), value :: b - real(c_double), value :: tol - end function FSUNLinSolSolve_SPGMR - - integer(c_int) function FSUNLinSolNumIters_SPGMR(LS) & - bind(C,name='SUNLinSolNumIters_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolNumIters_SPGMR - - real(c_double) function FSUNLinSolResNorm_SPGMR(LS) & - bind(C,name='SUNLinSolResNorm_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolResNorm_SPGMR - - type(c_ptr) function FSUNLinSolResid_SPGMR(LS) & - bind(C,name='SUNLinSolResid_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolResid_SPGMR - - integer(c_long) function FSUNLinSolLastFlag_SPGMR(LS) & - bind(C,name='SUNLinSolLastFlag_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolLastFlag_SPGMR - - integer(c_int) function FSUNLinSolSpace_SPGMR(LS, lenrwLS, leniwLS) & - bind(C,name='SUNLinSolSpace_SPGMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_long) :: lenrwLS - integer(c_long) :: leniwLS - end function FSUNLinSolSpace_SPGMR - - end interface - -end module fsunlinsol_spgmr_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fmod/CMakeLists.txt similarity index 75% rename from deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/F90/CMakeLists.txt rename to deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fmod/CMakeLists.txt index ba4d01c7b..b9dcf1cd1 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/F90/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fmod/CMakeLists.txt @@ -1,8 +1,8 @@ # ------------------------------------------------------------------------ -# Programmer: Cody J. Balos @ LLNL +# Programmer(s): Cody J. Balos @ LLNL # ------------------------------------------------------------------------ # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,22 +12,25 @@ # SUNDIALS Copyright End # ------------------------------------------------------------------------ # CMakeLists.txt file for the F2003 SPGMR SUNLinearSolver object library +# ------------------------------------------------------------------------ -set(sunlinsolspgmr_SOURCES fsunlinsol_spgmr.f90) +set(sunlinsolspgmr_SOURCES fsunlinsol_spgmr_mod.f90 fsunlinsol_spgmr_mod.c) if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolspgmr_mod_static STATIC + sundials_add_f2003_interface_library(sundials_fsunlinsolspgmr_mod_static STATIC_OBJECT ${sunlinsolspgmr_SOURCES} ) + add_dependencies(sundials_fsunlinsolspgmr_mod_static_obj sundials_fgeneric_static_obj) set_target_properties(sundials_fsunlinsolspgmr_mod_static PROPERTIES OUTPUT_NAME sundials_fsunlinsolspgmr_mod CLEAN_DIRECT_OUTPUT 1) install(TARGETS sundials_fsunlinsolspgmr_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif(BUILD_STATIC_LIBS) if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolspgmr_mod_shared SHARED + sundials_add_f2003_interface_library(sundials_fsunlinsolspgmr_mod_shared SHARED_OBJECT ${sunlinsolspgmr_SOURCES} ) + add_dependencies(sundials_fsunlinsolspgmr_mod_shared_obj sundials_fgeneric_shared_obj) set_target_properties(sundials_fsunlinsolspgmr_mod_shared PROPERTIES OUTPUT_NAME sundials_fsunlinsolspgmr_mod CLEAN_DIRECT_OUTPUT 1) set_target_properties(sundials_fsunlinsolspgmr_mod_shared diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fmod/fsunlinsol_spgmr_mod.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fmod/fsunlinsol_spgmr_mod.c new file mode 100644 index 000000000..00d334c5a --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fmod/fsunlinsol_spgmr_mod.c @@ -0,0 +1,523 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_linearsolver.h" + + +#include "sunlinsol/sunlinsol_spgmr.h" + +SWIGEXPORT SUNLinearSolver _wrap_FSUNLinSol_SPGMR(N_Vector farg1, int const *farg2, int const *farg3) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int arg3 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (SUNLinearSolver)SUNLinSol_SPGMR(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_SPGMRSetPrecType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_SPGMRSetPrecType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_SPGMRSetGSType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_SPGMRSetGSType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_SPGMRSetMaxRestarts(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_SPGMRSetMaxRestarts(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SUNLinearSolver _wrap_FSUNSPGMR(N_Vector farg1, int const *farg2, int const *farg3) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int arg3 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (SUNLinearSolver)SUNSPGMR(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSPGMRSetPrecType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNSPGMRSetPrecType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSPGMRSetGSType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNSPGMRSetGSType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSPGMRSetMaxRestarts(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNSPGMRSetMaxRestarts(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetType_SPGMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_Type result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_Type)SUNLinSolGetType_SPGMR(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetID_SPGMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_ID result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_ID)SUNLinSolGetID_SPGMR(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolInitialize_SPGMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolInitialize_SPGMR(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetATimes_SPGMR(SUNLinearSolver farg1, void *farg2, ATimesFn farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + void *arg2 = (void *) 0 ; + ATimesFn arg3 = (ATimesFn) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (void *)(farg2); + arg3 = (ATimesFn)(farg3); + result = (int)SUNLinSolSetATimes_SPGMR(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetPreconditioner_SPGMR(SUNLinearSolver farg1, void *farg2, PSetupFn farg3, PSolveFn farg4) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + void *arg2 = (void *) 0 ; + PSetupFn arg3 = (PSetupFn) 0 ; + PSolveFn arg4 = (PSolveFn) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (void *)(farg2); + arg3 = (PSetupFn)(farg3); + arg4 = (PSolveFn)(farg4); + result = (int)SUNLinSolSetPreconditioner_SPGMR(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetScalingVectors_SPGMR(SUNLinearSolver farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)SUNLinSolSetScalingVectors_SPGMR(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetup_SPGMR(SUNLinearSolver farg1, SUNMatrix farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNLinSolSetup_SPGMR(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSolve_SPGMR(SUNLinearSolver farg1, SUNMatrix farg2, N_Vector farg3, N_Vector farg4, double const *farg5) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype arg5 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype)(*farg5); + result = (int)SUNLinSolSolve_SPGMR(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolNumIters_SPGMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolNumIters_SPGMR(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FSUNLinSolResNorm_SPGMR(SUNLinearSolver farg1) { + double fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + realtype result; + + arg1 = (SUNLinearSolver)(farg1); + result = (realtype)SUNLinSolResNorm_SPGMR(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FSUNLinSolResid_SPGMR(SUNLinearSolver farg1) { + N_Vector fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + N_Vector result; + + arg1 = (SUNLinearSolver)(farg1); + result = (N_Vector)SUNLinSolResid_SPGMR(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNLinSolLastFlag_SPGMR(SUNLinearSolver farg1) { + int64_t fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + sunindextype result; + + arg1 = (SUNLinearSolver)(farg1); + result = SUNLinSolLastFlag_SPGMR(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSpace_SPGMR(SUNLinearSolver farg1, long *farg2, long *farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNLinSolSpace_SPGMR(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolFree_SPGMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolFree_SPGMR(arg1); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fmod/fsunlinsol_spgmr_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fmod/fsunlinsol_spgmr_mod.f90 new file mode 100644 index 000000000..e0bae5ae7 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fmod/fsunlinsol_spgmr_mod.f90 @@ -0,0 +1,625 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunlinsol_spgmr_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_linearsolver_mod + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: SUNSPGMR_MAXL_DEFAULT = 5_C_INT + integer(C_INT), parameter, public :: SUNSPGMR_MAXRS_DEFAULT = 0_C_INT + public :: FSUNLinSol_SPGMR + public :: FSUNLinSol_SPGMRSetPrecType + public :: FSUNLinSol_SPGMRSetGSType + public :: FSUNLinSol_SPGMRSetMaxRestarts + public :: FSUNSPGMR + public :: FSUNSPGMRSetPrecType + public :: FSUNSPGMRSetGSType + public :: FSUNSPGMRSetMaxRestarts + public :: FSUNLinSolGetType_SPGMR + public :: FSUNLinSolGetID_SPGMR + public :: FSUNLinSolInitialize_SPGMR + public :: FSUNLinSolSetATimes_SPGMR + public :: FSUNLinSolSetPreconditioner_SPGMR + public :: FSUNLinSolSetScalingVectors_SPGMR + public :: FSUNLinSolSetup_SPGMR + public :: FSUNLinSolSolve_SPGMR + public :: FSUNLinSolNumIters_SPGMR + public :: FSUNLinSolResNorm_SPGMR + public :: FSUNLinSolResid_SPGMR + public :: FSUNLinSolLastFlag_SPGMR + public :: FSUNLinSolSpace_SPGMR + public :: FSUNLinSolFree_SPGMR + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNLinSol_SPGMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSol_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSol_SPGMRSetPrecType(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_SPGMRSetPrecType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSol_SPGMRSetGSType(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_SPGMRSetGSType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSol_SPGMRSetMaxRestarts(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_SPGMRSetMaxRestarts") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSPGMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNSPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNSPGMRSetPrecType(farg1, farg2) & +bind(C, name="_wrap_FSUNSPGMRSetPrecType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSPGMRSetGSType(farg1, farg2) & +bind(C, name="_wrap_FSUNSPGMRSetGSType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSPGMRSetMaxRestarts(farg1, farg2) & +bind(C, name="_wrap_FSUNSPGMRSetMaxRestarts") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetType_SPGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolGetType_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetID_SPGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolGetID_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolInitialize_SPGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolInitialize_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetATimes_SPGMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSetATimes_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetPreconditioner_SPGMR(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FSUNLinSolSetPreconditioner_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetScalingVectors_SPGMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSetScalingVectors_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetup_SPGMR(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSolSetup_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSolve_SPGMR(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FSUNLinSolSolve_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolNumIters_SPGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolNumIters_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolResNorm_SPGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolResNorm_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FSUNLinSolResid_SPGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolResid_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSolLastFlag_SPGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolLastFlag_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNLinSolSpace_SPGMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSpace_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolFree_SPGMR(farg1) & +bind(C, name="_wrap_FSUNLinSolFree_SPGMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNLinSol_SPGMR(y, pretype, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +integer(C_INT), intent(in) :: pretype +integer(C_INT), intent(in) :: maxl +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = c_loc(y) +farg2 = pretype +farg3 = maxl +fresult = swigc_FSUNLinSol_SPGMR(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSol_SPGMRSetPrecType(s, pretype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: pretype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = pretype +fresult = swigc_FSUNLinSol_SPGMRSetPrecType(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSol_SPGMRSetGSType(s, gstype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: gstype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = gstype +fresult = swigc_FSUNLinSol_SPGMRSetGSType(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSol_SPGMRSetMaxRestarts(s, maxrs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: maxrs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = maxrs +fresult = swigc_FSUNLinSol_SPGMRSetMaxRestarts(farg1, farg2) +swig_result = fresult +end function + +function FSUNSPGMR(y, pretype, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +integer(C_INT), intent(in) :: pretype +integer(C_INT), intent(in) :: maxl +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = c_loc(y) +farg2 = pretype +farg3 = maxl +fresult = swigc_FSUNSPGMR(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNSPGMRSetPrecType(s, pretype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: pretype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = pretype +fresult = swigc_FSUNSPGMRSetPrecType(farg1, farg2) +swig_result = fresult +end function + +function FSUNSPGMRSetGSType(s, gstype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: gstype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = gstype +fresult = swigc_FSUNSPGMRSetGSType(farg1, farg2) +swig_result = fresult +end function + +function FSUNSPGMRSetMaxRestarts(s, maxrs) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: maxrs +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = maxrs +fresult = swigc_FSUNSPGMRSetMaxRestarts(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolGetType_SPGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_Type) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetType_SPGMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolGetID_SPGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_ID) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetID_SPGMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolInitialize_SPGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolInitialize_SPGMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolSetATimes_SPGMR(s, a_data, atimes) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: a_data +type(C_FUNPTR), intent(in), value :: atimes +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = c_loc(s) +farg2 = a_data +farg3 = atimes +fresult = swigc_FSUNLinSolSetATimes_SPGMR(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolSetPreconditioner_SPGMR(s, p_data, pset, psol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: p_data +type(C_FUNPTR), intent(in), value :: pset +type(C_FUNPTR), intent(in), value :: psol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = c_loc(s) +farg2 = p_data +farg3 = pset +farg4 = psol +fresult = swigc_FSUNLinSolSetPreconditioner_SPGMR(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FSUNLinSolSetScalingVectors_SPGMR(s, s1, s2) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(N_Vector), target, intent(inout) :: s1 +type(N_Vector), target, intent(inout) :: s2 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(s1) +farg3 = c_loc(s2) +fresult = swigc_FSUNLinSolSetScalingVectors_SPGMR(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolSetup_SPGMR(s, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(s) +farg2 = c_loc(a) +fresult = swigc_FSUNLinSolSetup_SPGMR(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolSolve_SPGMR(s, a, x, b, tol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: b +real(C_DOUBLE), intent(in) :: tol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +real(C_DOUBLE) :: farg5 + +farg1 = c_loc(s) +farg2 = c_loc(a) +farg3 = c_loc(x) +farg4 = c_loc(b) +farg5 = tol +fresult = swigc_FSUNLinSolSolve_SPGMR(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FSUNLinSolNumIters_SPGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolNumIters_SPGMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolResNorm_SPGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolResNorm_SPGMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolResid_SPGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolResid_SPGMR(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSolLastFlag_SPGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolLastFlag_SPGMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolSpace_SPGMR(s, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FSUNLinSolSpace_SPGMR(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolFree_SPGMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolFree_SPGMR(farg1) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.c index 5e9c2379d..66f5a3962 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.h b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.h index be3a82f96..16ecf1c0e 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/sunlinsol_spgmr.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/sunlinsol_spgmr.c index 533ca7ff2..5ae129dbd 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/sunlinsol_spgmr.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/spgmr/sunlinsol_spgmr.c @@ -1,11 +1,10 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU - * Based on sundials_spgmr.c code, written by Scott D. Cohen, + * Based on sundials_spgmr.c code, written by Scott D. Cohen, * Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -14,10 +13,9 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the SPGMR implementation of + * This is the implementation file for the SPGMR implementation of * the SUNLINSOL package. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include @@ -30,10 +28,10 @@ /* * ----------------------------------------------------------------- - * SPGMR solver structure accessibility macros: + * SPGMR solver structure accessibility macros: * ----------------------------------------------------------------- */ - + #define SPGMR_CONTENT(S) ( (SUNLinearSolverContent_SPGMR)(S->content) ) #define LASTFLAG(S) ( SPGMR_CONTENT(S)->last_flag ) @@ -67,9 +65,8 @@ int SUNSPGMRSetMaxRestarts(SUNLinearSolver S, int maxrs) SUNLinearSolver SUNLinSol_SPGMR(N_Vector y, int pretype, int maxl) { SUNLinearSolver S; - SUNLinearSolver_Ops ops; SUNLinearSolverContent_SPGMR content; - + /* check for legal pretype and maxl values; if illegal use defaults */ if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) && (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) @@ -86,75 +83,75 @@ SUNLinearSolver SUNLinSol_SPGMR(N_Vector y, int pretype, int maxl) /* Create linear solver */ S = NULL; - S = (SUNLinearSolver) malloc(sizeof *S); + S = SUNLinSolNewEmpty(); if (S == NULL) return(NULL); - - /* Create linear solver operation structure */ - ops = NULL; - ops = (SUNLinearSolver_Ops) malloc(sizeof(struct _generic_SUNLinearSolver_Ops)); - if (ops == NULL) { free(S); return(NULL); } /* Attach operations */ - ops->gettype = SUNLinSolGetType_SPGMR; - ops->setatimes = SUNLinSolSetATimes_SPGMR; - ops->setpreconditioner = SUNLinSolSetPreconditioner_SPGMR; - ops->setscalingvectors = SUNLinSolSetScalingVectors_SPGMR; - ops->initialize = SUNLinSolInitialize_SPGMR; - ops->setup = SUNLinSolSetup_SPGMR; - ops->solve = SUNLinSolSolve_SPGMR; - ops->numiters = SUNLinSolNumIters_SPGMR; - ops->resnorm = SUNLinSolResNorm_SPGMR; - ops->resid = SUNLinSolResid_SPGMR; - ops->lastflag = SUNLinSolLastFlag_SPGMR; - ops->space = SUNLinSolSpace_SPGMR; - ops->free = SUNLinSolFree_SPGMR; + S->ops->gettype = SUNLinSolGetType_SPGMR; + S->ops->getid = SUNLinSolGetID_SPGMR; + S->ops->setatimes = SUNLinSolSetATimes_SPGMR; + S->ops->setpreconditioner = SUNLinSolSetPreconditioner_SPGMR; + S->ops->setscalingvectors = SUNLinSolSetScalingVectors_SPGMR; + S->ops->initialize = SUNLinSolInitialize_SPGMR; + S->ops->setup = SUNLinSolSetup_SPGMR; + S->ops->solve = SUNLinSolSolve_SPGMR; + S->ops->numiters = SUNLinSolNumIters_SPGMR; + S->ops->resnorm = SUNLinSolResNorm_SPGMR; + S->ops->resid = SUNLinSolResid_SPGMR; + S->ops->lastflag = SUNLinSolLastFlag_SPGMR; + S->ops->space = SUNLinSolSpace_SPGMR; + S->ops->free = SUNLinSolFree_SPGMR; /* Create content */ content = NULL; - content = (SUNLinearSolverContent_SPGMR) malloc(sizeof(struct _SUNLinearSolverContent_SPGMR)); - if (content == NULL) { free(ops); free(S); return(NULL); } + content = (SUNLinearSolverContent_SPGMR) malloc(sizeof *content); + if (content == NULL) { SUNLinSolFree(S); return(NULL); } + + /* Attach content */ + S->content = content; /* Fill content */ - content->last_flag = 0; - content->maxl = maxl; - content->pretype = pretype; - content->gstype = SUNSPGMR_GSTYPE_DEFAULT; + content->last_flag = 0; + content->maxl = maxl; + content->pretype = pretype; + content->gstype = SUNSPGMR_GSTYPE_DEFAULT; content->max_restarts = SUNSPGMR_MAXRS_DEFAULT; - content->numiters = 0; - content->resnorm = ZERO; + content->numiters = 0; + content->resnorm = ZERO; + content->xcor = NULL; + content->vtemp = NULL; + content->s1 = NULL; + content->s2 = NULL; + content->ATimes = NULL; + content->ATData = NULL; + content->Psetup = NULL; + content->Psolve = NULL; + content->PData = NULL; + content->V = NULL; + content->Hes = NULL; + content->givens = NULL; + content->yg = NULL; + content->cv = NULL; + content->Xv = NULL; + + /* Allocate content */ content->xcor = N_VClone(y); - if (content->xcor == NULL) return(NULL); + if (content->xcor == NULL) { SUNLinSolFree(S); return(NULL); } + content->vtemp = N_VClone(y); - if (content->vtemp == NULL) return(NULL); - content->s1 = NULL; - content->s2 = NULL; - content->ATimes = NULL; - content->ATData = NULL; - content->Psetup = NULL; - content->Psolve = NULL; - content->PData = NULL; - content->V = NULL; - content->Hes = NULL; - content->givens = NULL; - content->yg = NULL; - content->cv = NULL; - content->Xv = NULL; - - /* Attach content and ops */ - S->content = content; - S->ops = ops; + if (content->vtemp == NULL) { SUNLinSolFree(S); return(NULL); } return(S); } /* ---------------------------------------------------------------------------- - * Function to set the type of preconditioning for SPGMR to use + * Function to set the type of preconditioning for SPGMR to use */ -SUNDIALS_EXPORT int SUNLinSol_SPGMRSetPrecType(SUNLinearSolver S, int pretype) +SUNDIALS_EXPORT int SUNLinSol_SPGMRSetPrecType(SUNLinearSolver S, int pretype) { - /* Check for legal pretype */ + /* Check for legal pretype */ if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) && (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) { return(SUNLS_ILL_INPUT); @@ -175,7 +172,7 @@ SUNDIALS_EXPORT int SUNLinSol_SPGMRSetPrecType(SUNLinearSolver S, int pretype) SUNDIALS_EXPORT int SUNLinSol_SPGMRSetGSType(SUNLinearSolver S, int gstype) { - /* Check for legal gstype */ + /* Check for legal gstype */ if ((gstype != MODIFIED_GS) && (gstype != CLASSICAL_GS)) { return(SUNLS_ILL_INPUT); } @@ -195,7 +192,7 @@ SUNDIALS_EXPORT int SUNLinSol_SPGMRSetGSType(SUNLinearSolver S, int gstype) SUNDIALS_EXPORT int SUNLinSol_SPGMRSetMaxRestarts(SUNLinearSolver S, int maxrs) { - /* Illegal maxrs implies use of default value */ + /* Illegal maxrs implies use of default value */ if (maxrs < 0) maxrs = SUNSPGMR_MAXRS_DEFAULT; @@ -220,20 +217,26 @@ SUNLinearSolver_Type SUNLinSolGetType_SPGMR(SUNLinearSolver S) } +SUNLinearSolver_ID SUNLinSolGetID_SPGMR(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_SPGMR); +} + + int SUNLinSolInitialize_SPGMR(SUNLinearSolver S) { int k; SUNLinearSolverContent_SPGMR content; /* set shortcut to SPGMR memory structure */ - if (S == NULL) return(SUNLS_MEM_NULL); + if (S == NULL) return(SUNLS_MEM_NULL); content = SPGMR_CONTENT(S); /* ensure valid options */ - if (content->max_restarts < 0) + if (content->max_restarts < 0) content->max_restarts = SUNSPGMR_MAXRS_DEFAULT; - if ( (content->pretype != PREC_LEFT) && - (content->pretype != PREC_RIGHT) && + if ( (content->pretype != PREC_LEFT) && + (content->pretype != PREC_RIGHT) && (content->pretype != PREC_BOTH) ) content->pretype = PREC_NONE; @@ -250,10 +253,10 @@ int SUNLinSolInitialize_SPGMR(SUNLinearSolver S) return(SUNLS_MEM_FAIL); } } - + /* Hessenberg matrix Hes */ if (content->Hes == NULL) { - content->Hes = (realtype **) malloc((content->maxl+1)*sizeof(realtype *)); + content->Hes = (realtype **) malloc((content->maxl+1)*sizeof(realtype *)); if (content->Hes == NULL) { SUNLinSolFree(S); content->last_flag = SUNLS_MEM_FAIL; @@ -270,7 +273,7 @@ int SUNLinSolInitialize_SPGMR(SUNLinearSolver S) } } } - + /* Givens rotation components */ if (content->givens == NULL) { content->givens = (realtype *) malloc(2*content->maxl*sizeof(realtype)); @@ -280,7 +283,7 @@ int SUNLinSolInitialize_SPGMR(SUNLinearSolver S) return(SUNLS_MEM_FAIL); } } - + /* y and g vectors */ if (content->yg == NULL) { content->yg = (realtype *) malloc((content->maxl+1)*sizeof(realtype)); @@ -317,10 +320,10 @@ int SUNLinSolInitialize_SPGMR(SUNLinearSolver S) } -int SUNLinSolSetATimes_SPGMR(SUNLinearSolver S, void* ATData, +int SUNLinSolSetATimes_SPGMR(SUNLinearSolver S, void* ATData, ATimesFn ATimes) { - /* set function pointers to integrator-supplied ATimes routine + /* set function pointers to integrator-supplied ATimes routine and data, and return with success */ if (S == NULL) return(SUNLS_MEM_NULL); SPGMR_CONTENT(S)->ATimes = ATimes; @@ -347,7 +350,7 @@ int SUNLinSolSetPreconditioner_SPGMR(SUNLinearSolver S, void* PData, int SUNLinSolSetScalingVectors_SPGMR(SUNLinearSolver S, N_Vector s1, N_Vector s2) { - /* set N_Vector pointers to integrator-supplied scaling vectors, + /* set N_Vector pointers to integrator-supplied scaling vectors, and return with success */ if (S == NULL) return(SUNLS_MEM_NULL); SPGMR_CONTENT(S)->s1 = s1; @@ -367,24 +370,24 @@ int SUNLinSolSetup_SPGMR(SUNLinearSolver S, SUNMatrix A) if (S == NULL) return(SUNLS_MEM_NULL); Psetup = SPGMR_CONTENT(S)->Psetup; PData = SPGMR_CONTENT(S)->PData; - - /* no solver-specific setup is required, but if user-supplied + + /* no solver-specific setup is required, but if user-supplied Psetup routine exists, call that here */ if (Psetup != NULL) { ier = Psetup(PData); if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_PSET_FAIL_UNREC : SUNLS_PSET_FAIL_REC; return(LASTFLAG(S)); } } - - /* return with success */ + + /* return with success */ return(SUNLS_SUCCESS); } -int SUNLinSolSolve_SPGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, +int SUNLinSolSolve_SPGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype delta) { /* local data and shortcut variables */ @@ -433,9 +436,9 @@ int SUNLinSolSolve_SPGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, converged = SUNFALSE; /* set booleantype flags for internal solver options */ - preOnLeft = ( (SPGMR_CONTENT(S)->pretype == PREC_LEFT) || + preOnLeft = ( (SPGMR_CONTENT(S)->pretype == PREC_LEFT) || (SPGMR_CONTENT(S)->pretype == PREC_BOTH) ); - preOnRight = ( (SPGMR_CONTENT(S)->pretype == PREC_RIGHT) || + preOnRight = ( (SPGMR_CONTENT(S)->pretype == PREC_RIGHT) || (SPGMR_CONTENT(S)->pretype == PREC_BOTH) ); scale1 = (s1 != NULL); scale2 = (s2 != NULL); @@ -446,7 +449,7 @@ int SUNLinSolSolve_SPGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, } else { ier = atimes(A_data, x, vtemp); if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; return(LASTFLAG(S)); } @@ -458,23 +461,23 @@ int SUNLinSolSolve_SPGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, if (preOnLeft) { ier = psolve(P_data, V[0], vtemp, delta, PREC_LEFT); if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; return(LASTFLAG(S)); } } else { N_VScale(ONE, V[0], vtemp); } - + if (scale1) { - N_VProd(s1, vtemp, V[0]); + N_VProd(s1, vtemp, V[0]); } else { N_VScale(ONE, vtemp, V[0]); } /* Set r_norm = beta to L2 norm of V[0] = s1 P1_inv r_0, and return if small */ - *res_norm = r_norm = beta = SUNRsqrt(N_VDotProd(V[0], V[0])); + *res_norm = r_norm = beta = SUNRsqrt(N_VDotProd(V[0], V[0])); if (r_norm <= delta) { LASTFLAG(S) = SUNLS_SUCCESS; return(LASTFLAG(S)); @@ -486,67 +489,67 @@ int SUNLinSolSolve_SPGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, /* Set xcor = 0 */ N_VConst(ZERO, xcor); - /* Begin outer iterations: up to (max_restarts + 1) attempts */ + /* Begin outer iterations: up to (max_restarts + 1) attempts */ for (ntries=0; ntries<=max_restarts; ntries++) { - + /* Initialize the Hessenberg matrix Hes and Givens rotation product. Normalize the initial vector V[0] */ for (i=0; i<=l_max; i++) for (j=0; j0; i--) { @@ -631,13 +634,13 @@ int SUNLinSolSolve_SPGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, s_product *= givens[2*i-1]; } yg[0] = s_product; - + /* Scale r_norm and yg */ r_norm *= s_product; for (i=0; i<=krydim; i++) yg[i] *= r_norm; r_norm = SUNRabs(r_norm); - + /* Multiply yg by V_(krydim+1) to get last residual vector; restart */ for (k=0; k<=krydim; k++) { cv[k] = yg[k]; @@ -645,20 +648,20 @@ int SUNLinSolSolve_SPGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, } ier = N_VLinearCombination(krydim+1, cv, Xv, V[0]); if (ier != SUNLS_SUCCESS) return(SUNLS_VECTOROP_ERR); - + } - + /* Failed to converge, even after allowed restarts. If the residual norm was reduced below its initial value, compute and return x anyway. Otherwise return failure flag. */ if (rho < beta) { - - /* Apply right scaling and right precond.: vtemp = P2_inv s2_inv xcor */ + + /* Apply right scaling and right precond.: vtemp = P2_inv s2_inv xcor */ if (scale2) N_VDiv(xcor, s2, xcor); if (preOnRight) { ier = psolve(P_data, xcor, vtemp, delta, PREC_RIGHT); if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; return(LASTFLAG(S)); } @@ -668,7 +671,7 @@ int SUNLinSolSolve_SPGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, /* Add vtemp to initial x to get final solution x, and return */ N_VLinearSum(ONE, x, ONE, vtemp, x); - + LASTFLAG(S) = SUNLS_RES_REDUCED; return(LASTFLAG(S)); } @@ -701,7 +704,7 @@ N_Vector SUNLinSolResid_SPGMR(SUNLinearSolver S) } -long int SUNLinSolLastFlag_SPGMR(SUNLinearSolver S) +sunindextype SUNLinSolLastFlag_SPGMR(SUNLinearSolver S) { /* return the stored 'last_flag' value */ if (S == NULL) return(-1); @@ -709,8 +712,8 @@ long int SUNLinSolLastFlag_SPGMR(SUNLinearSolver S) } -int SUNLinSolSpace_SPGMR(SUNLinearSolver S, - long int *lenrwLS, +int SUNLinSolSpace_SPGMR(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS) { int maxl; @@ -732,32 +735,49 @@ int SUNLinSolFree_SPGMR(SUNLinearSolver S) if (S == NULL) return(SUNLS_SUCCESS); - /* delete items from within the content structure */ - if (SPGMR_CONTENT(S)->xcor) - N_VDestroy(SPGMR_CONTENT(S)->xcor); - if (SPGMR_CONTENT(S)->vtemp) - N_VDestroy(SPGMR_CONTENT(S)->vtemp); - if (SPGMR_CONTENT(S)->V) - N_VDestroyVectorArray(SPGMR_CONTENT(S)->V, - SPGMR_CONTENT(S)->maxl+1); - if (SPGMR_CONTENT(S)->Hes) { - for (k=0; k<=SPGMR_CONTENT(S)->maxl; k++) - if (SPGMR_CONTENT(S)->Hes[k]) - free(SPGMR_CONTENT(S)->Hes[k]); - free(SPGMR_CONTENT(S)->Hes); + if (S->content) { + /* delete items from within the content structure */ + if (SPGMR_CONTENT(S)->xcor) { + N_VDestroy(SPGMR_CONTENT(S)->xcor); + SPGMR_CONTENT(S)->xcor = NULL; + } + if (SPGMR_CONTENT(S)->vtemp) { + N_VDestroy(SPGMR_CONTENT(S)->vtemp); + SPGMR_CONTENT(S)->vtemp = NULL; + } + if (SPGMR_CONTENT(S)->V) { + N_VDestroyVectorArray(SPGMR_CONTENT(S)->V, + SPGMR_CONTENT(S)->maxl+1); + SPGMR_CONTENT(S)->V = NULL; + } + if (SPGMR_CONTENT(S)->Hes) { + for (k=0; k<=SPGMR_CONTENT(S)->maxl; k++) + if (SPGMR_CONTENT(S)->Hes[k]) { + free(SPGMR_CONTENT(S)->Hes[k]); + SPGMR_CONTENT(S)->Hes[k] = NULL; + } + free(SPGMR_CONTENT(S)->Hes); + SPGMR_CONTENT(S)->Hes = NULL; + } + if (SPGMR_CONTENT(S)->givens) { + free(SPGMR_CONTENT(S)->givens); + SPGMR_CONTENT(S)->givens = NULL; + } + if (SPGMR_CONTENT(S)->yg) { + free(SPGMR_CONTENT(S)->yg); + SPGMR_CONTENT(S)->yg = NULL; + } + if (SPGMR_CONTENT(S)->cv) { + free(SPGMR_CONTENT(S)->cv); + SPGMR_CONTENT(S)->cv = NULL; + } + if (SPGMR_CONTENT(S)->Xv) { + free(SPGMR_CONTENT(S)->Xv); + SPGMR_CONTENT(S)->Xv = NULL; + } + free(S->content); S->content = NULL; } - if (SPGMR_CONTENT(S)->givens) - free(SPGMR_CONTENT(S)->givens); - if (SPGMR_CONTENT(S)->yg) - free(SPGMR_CONTENT(S)->yg); - if (SPGMR_CONTENT(S)->cv) - free(SPGMR_CONTENT(S)->cv); - if (SPGMR_CONTENT(S)->Xv) - free(SPGMR_CONTENT(S)->Xv); - - /* delete generic structures */ - free(S->content); S->content = NULL; - free(S->ops); S->ops = NULL; + if (S->ops) { free(S->ops); S->ops = NULL; } free(S); S = NULL; return(SUNLS_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/CMakeLists.txt index 6c74a2f4b..0a6b41994 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,96 +12,132 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the SPTFQMR SUNLinearSolver library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNLINSOL_SPTFQMR\n\")") - -# Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF(F90_FOUND AND F2003_INTERFACE_ENABLE) +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_SPTFQMR\n\")") -# Add variable sunlinsolsptfqmr_SOURCES with the sources for the SUNLINSOLSPTFQMR lib -SET(sunlinsolsptfqmr_SOURCES sunlinsol_sptfqmr.c) +# Source files for the library +set(sunlinsolsptfqmr_SOURCES sunlinsol_sptfqmr.c) -# Add variable shared_SOURCES with the common SUNDIALS sources which will -# also be included in the SUNLINSOLSPTFQMR library -SET(shared_SOURCES +# Common SUNDIALS sources included in the library +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c - ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c - ) + ${sundials_SOURCE_DIR}/src/sundials/sundials_iterative.c) -# Add variable sunlinsolsptfqmr_HEADERS with the exported SUNLINSOLSPTFQMR header files -SET(sunlinsolsptfqmr_HEADERS - ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_sptfqmr.h - ) - -# Add source directory to include directories -INCLUDE_DIRECTORIES(.) - -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Exported header files +set(sunlinsolsptfqmr_HEADERS + ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_sptfqmr.h) # Rules for building and installing the static library: -# - Add the build target for the SUNLINSOLSPTFQMR library +# - Add the build target for the library # - Set the library name and make sure it is not deleted -# - Install the SUNLINSOLSPTFQMR library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunlinsolsptfqmr_static STATIC ${sunlinsolsptfqmr_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunlinsolsptfqmr_static - PROPERTIES OUTPUT_NAME sundials_sunlinsolsptfqmr CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunlinsolsptfqmr_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +# - Install the library +if(BUILD_STATIC_LIBS) + + add_library(sundials_sunlinsolsptfqmr_static + STATIC ${sunlinsolsptfqmr_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolsptfqmr_static + PROPERTIES + OUTPUT_NAME sundials_sunlinsolsptfqmr + CLEAN_DIRECT_OUTPUT 1) + + if(UNIX) + target_link_libraries(sundials_sunlinsolsptfqmr_static + PRIVATE m) + endif() + + target_compile_definitions(sundials_sunlinsolsptfqmr_static + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolsptfqmr_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: -# - Add the build target for the SUNLINSOLSPTFQMR library +# - Add the build target for the library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries -# - Install the SUNLINSOLSPTFQMR library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunlinsolsptfqmr_shared SHARED ${sunlinsolsptfqmr_SOURCES} ${shared_SOURCES}) - - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_sunlinsolsptfqmr_shared m) - ENDIF() - - SET_TARGET_PROPERTIES(sundials_sunlinsolsptfqmr_shared - PROPERTIES OUTPUT_NAME sundials_sunlinsolsptfqmr CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunlinsolsptfqmr_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_sunlinsolsptfqmr_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) - -# Install the SUNLINSOLSPTFQMR header files -INSTALL(FILES ${sunlinsolsptfqmr_HEADERS} DESTINATION include/sunlinsol) - -# If FCMIX is enabled, build and install the FSUNLINSOLSPTFQMR library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunlinsolsptfqmr_SOURCES fsunlinsol_sptfqmr.c) - - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunlinsolsptfqmr_static STATIC ${fsunlinsolsptfqmr_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunlinsolsptfqmr_static - PROPERTIES OUTPUT_NAME sundials_fsunlinsolsptfqmr CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunlinsolsptfqmr_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) - - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunlinsolsptfqmr_shared ${fsunlinsolsptfqmr_SOURCES}) - - # fsunlinsolsptfqmr depends on fnvecserial and sunlinsolsptfqmr - TARGET_LINK_LIBRARIES(sundials_fsunlinsolsptfqmr_shared +# - Install the library +if(BUILD_SHARED_LIBS) + + add_library(sundials_sunlinsolsptfqmr_shared + SHARED ${sunlinsolsptfqmr_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolsptfqmr_shared + PROPERTIES + OUTPUT_NAME sundials_sunlinsolsptfqmr + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + + if(UNIX) + target_link_libraries(sundials_sunlinsolsptfqmr_shared + PRIVATE m) + endif() + + target_compile_definitions(sundials_sunlinsolsptfqmr_shared + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolsptfqmr_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_SHARED_LIBS) + +# Install the header files +install(FILES ${sunlinsolsptfqmr_HEADERS} DESTINATION include/sunlinsol) + +# +message(STATUS "Added SUNLINSOL_SPTFQMR module") + +# If FCMIX is enabled, build and install the Fortran77 library +if(F77_INTERFACE_ENABLE AND F77_FOUND) + + set(fsunlinsolsptfqmr_SOURCES fsunlinsol_sptfqmr.c) + + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunlinsolsptfqmr_static + STATIC ${fsunlinsolsptfqmr_SOURCES}) + set_target_properties(sundials_fsunlinsolsptfqmr_static + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolsptfqmr + CLEAN_DIRECT_OUTPUT 1) + # depends on fnvecserial and sunlinsolsptfqmr + target_link_libraries(sundials_fsunlinsolsptfqmr_static + PUBLIC + sundials_fnvecserial_static + sundials_sunlinsolsptfqmr_static) + install(TARGETS sundials_fsunlinsolsptfqmr_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) + + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunlinsolsptfqmr_shared + SHARED ${fsunlinsolsptfqmr_SOURCES}) + set_target_properties(sundials_fsunlinsolsptfqmr_shared + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolsptfqmr + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + # depends on fnvecserial and sunlinsolsptfqmr + target_link_libraries(sundials_fsunlinsolsptfqmr_shared + PUBLIC sundials_fnvecserial_shared sundials_sunlinsolsptfqmr_shared) + install(TARGETS sundials_fsunlinsolsptfqmr_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) - SET_TARGET_PROPERTIES(sundials_fsunlinsolsptfqmr_shared - PROPERTIES OUTPUT_NAME sundials_fsunlinsolsptfqmr CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunlinsolsptfqmr_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_fsunlinsolsptfqmr_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) + # + message(STATUS "Added SUNLINSOL_SPTFQMR F77 interface") -# -MESSAGE(STATUS "Added SUNLINSOL_SPTFQMR module") +endif(F77_INTERFACE_ENABLE AND F77_FOUND) + +# Add F90 module if F2003 interface is enabled +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/F90/fsunlinsol_sptfqmr.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/F90/fsunlinsol_sptfqmr.f90 deleted file mode 100644 index 12fdf1dfe..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/F90/fsunlinsol_sptfqmr.f90 +++ /dev/null @@ -1,174 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): Cody J. Balos @ LLNL -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS SPTFQMR linear solver using the ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fsunlinsol_sptfqmr_mod - - !======= Interfaces ========= - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - type(c_ptr) function FSUNLinSol_SPTFQMR(y, pretype, maxl) & - bind(C,name='SUNLinSol_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: y - integer(c_int), value :: pretype - integer(c_int), value :: maxl - end function FSUNLinSol_SPTFQMR - - ! ================================================================= - ! Destructors - ! ================================================================= - - subroutine FSUNLinSolFree_SPTFQMR(LS) & - bind(C,name='SUNLinSolFree_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end subroutine FSUNLinSolFree_SPTFQMR - - ! ================================================================= - ! Setters - ! ================================================================= - - integer(c_int) function FSUNLinSol_SPTFQMRSetPrecType(LS, pretype) & - bind(C,name='SUNLinSol_SPTFQMRSetPrecType') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: pretype - end function FSUNLinSol_SPTFQMRSetPrecType - - integer(c_int) function FSUNLinSol_SPTFQMRSetMaxl(LS, maxl) & - bind(C,name='SUNLinSol_SPTFQMRSetMaxl') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_int), value :: maxl - end function FSUNLinSol_SPTFQMRSetMaxl - - ! ================================================================= - ! Operations - ! ================================================================= - - integer(c_int) function FSUNLinSolGetType_SPTFQMR(LS) & - bind(C,name='SUNLinSolGetType_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolGetType_SPTFQMR - - integer(c_int) function FSUNLinSolInitialize_SPTFQMR(LS) & - bind(C,name='SUNLinSolInitialize_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolInitialize_SPTFQMR - - integer(c_int) function FSUNLinSolSetATimes_SPTFQMR(LS, A_data, ATimes) & - bind(C,name='SUNLinSolSetATimes_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A_data - type(c_funptr), value :: ATimes - end function FSUNLinSolSetATimes_SPTFQMR - - integer(c_int) function FSUNLinSolSetPreconditioner_SPTFQMR(LS, & - P_data, & - Pset, & - Psol) & - bind(C,name='SUNLinSolSetPreconditioner_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: P_data - type(c_funptr), value :: Pset - type(c_funptr), value :: Psol - end function FSUNLinSolSetPreconditioner_SPTFQMR - - integer(c_int) function FSUNLinSolSetScalingVectors_SPTFQMR(LS, s1, s2) & - bind(C,name='SUNLinSolSetScalingVectors_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: s1 - type(c_ptr), value :: s2 - end function FSUNLinSolSetScalingVectors_SPTFQMR - - integer(c_int) function FSUNLinSolSetup_SPTFQMR(LS, A) & - bind(C,name='SUNLinSolSetup_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - end function FSUNLinSolSetup_SPTFQMR - - integer(c_int) function FSUNLinSolSolve_SPTFQMR(LS, A, x, b, tol) & - bind(C,name='SUNLinSolSolve_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - type(c_ptr), value :: A - type(c_ptr), value :: x - type(c_ptr), value :: b - real(c_double), value :: tol - end function FSUNLinSolSolve_SPTFQMR - - integer(c_int) function FSUNLinSolNumIters_SPTFQMR(LS) & - bind(C,name='SUNLinSolNumIters_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolNumIters_SPTFQMR - - real(c_double) function FSUNLinSolResNorm_SPTFQMR(LS) & - bind(C,name='SUNLinSolResNorm_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolResNorm_SPTFQMR - - type(c_ptr) function FSUNLinSolResid_SPTFQMR(LS) & - bind(C,name='SUNLinSolResid_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolResid_SPTFQMR - - integer(c_long) function FSUNLinSolLastFlag_SPTFQMR(LS) & - bind(C,name='SUNLinSolLastFlag_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - end function FSUNLinSolLastFlag_SPTFQMR - - integer(c_int) function FSUNLinSolSpace_SPTFQMR(LS, lenrwLS, leniwLS) & - bind(C,name='SUNLinSolSpace_SPTFQMR') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: LS - integer(c_long) :: lenrwLS - integer(c_long) :: leniwLS - end function FSUNLinSolSpace_SPTFQMR - - end interface - -end module fsunlinsol_sptfqmr_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fmod/CMakeLists.txt similarity index 74% rename from deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/F90/CMakeLists.txt rename to deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fmod/CMakeLists.txt index b4326cd6f..671572f17 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/F90/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fmod/CMakeLists.txt @@ -1,8 +1,8 @@ # ------------------------------------------------------------------------ -# Programmer: Cody J. Balos @ LLNL +# Programmer(s): Cody J. Balos @ LLNL # ------------------------------------------------------------------------ # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,22 +12,25 @@ # SUNDIALS Copyright End # ------------------------------------------------------------------------ # CMakeLists.txt file for the F2003 SPTFQMR SUNLinearSolver object library +# ------------------------------------------------------------------------ -set(sunlinsolsptfqmr_SOURCES fsunlinsol_sptfqmr.f90) +set(sunlinsolsptfqmr_SOURCES fsunlinsol_sptfqmr_mod.f90 fsunlinsol_sptfqmr_mod.c) if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolsptfqmr_mod_static STATIC + sundials_add_f2003_interface_library(sundials_fsunlinsolsptfqmr_mod_static STATIC_OBJECT ${sunlinsolsptfqmr_SOURCES} ) + add_dependencies(sundials_fsunlinsolsptfqmr_mod_static_obj sundials_fgeneric_static_obj) set_target_properties(sundials_fsunlinsolsptfqmr_mod_static PROPERTIES OUTPUT_NAME sundials_fsunlinsolsptfqmr_mod CLEAN_DIRECT_OUTPUT 1) install(TARGETS sundials_fsunlinsolsptfqmr_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif(BUILD_STATIC_LIBS) if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fsunlinsolsptfqmr_mod_shared SHARED + sundials_add_f2003_interface_library(sundials_fsunlinsolsptfqmr_mod_shared SHARED_OBJECT ${sunlinsolsptfqmr_SOURCES} ) + add_dependencies(sundials_fsunlinsolsptfqmr_mod_shared_obj sundials_fgeneric_shared_obj) set_target_properties(sundials_fsunlinsolsptfqmr_mod_shared PROPERTIES OUTPUT_NAME sundials_fsunlinsolsptfqmr_mod CLEAN_DIRECT_OUTPUT 1) set_target_properties(sundials_fsunlinsolsptfqmr_mod_shared diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fmod/fsunlinsol_sptfqmr_mod.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fmod/fsunlinsol_sptfqmr_mod.c new file mode 100644 index 000000000..a48255e91 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fmod/fsunlinsol_sptfqmr_mod.c @@ -0,0 +1,495 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_linearsolver.h" + + +#include "sunlinsol/sunlinsol_sptfqmr.h" + +SWIGEXPORT SUNLinearSolver _wrap_FSUNLinSol_SPTFQMR(N_Vector farg1, int const *farg2, int const *farg3) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int arg3 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (SUNLinearSolver)SUNLinSol_SPTFQMR(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_SPTFQMRSetPrecType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_SPTFQMRSetPrecType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSol_SPTFQMRSetMaxl(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNLinSol_SPTFQMRSetMaxl(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SUNLinearSolver _wrap_FSUNSPTFQMR(N_Vector farg1, int const *farg2, int const *farg3) { + SUNLinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + int arg3 ; + SUNLinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + arg3 = (int)(*farg3); + result = (SUNLinearSolver)SUNSPTFQMR(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSPTFQMRSetPrecType(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNSPTFQMRSetPrecType(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSPTFQMRSetMaxl(SUNLinearSolver farg1, int const *farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNSPTFQMRSetMaxl(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetType_SPTFQMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_Type result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_Type)SUNLinSolGetType_SPTFQMR(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolGetID_SPTFQMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNLinearSolver_ID result; + + arg1 = (SUNLinearSolver)(farg1); + result = (SUNLinearSolver_ID)SUNLinSolGetID_SPTFQMR(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolInitialize_SPTFQMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolInitialize_SPTFQMR(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetATimes_SPTFQMR(SUNLinearSolver farg1, void *farg2, ATimesFn farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + void *arg2 = (void *) 0 ; + ATimesFn arg3 = (ATimesFn) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (void *)(farg2); + arg3 = (ATimesFn)(farg3); + result = (int)SUNLinSolSetATimes_SPTFQMR(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetPreconditioner_SPTFQMR(SUNLinearSolver farg1, void *farg2, PSetupFn farg3, PSolveFn farg4) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + void *arg2 = (void *) 0 ; + PSetupFn arg3 = (PSetupFn) 0 ; + PSolveFn arg4 = (PSolveFn) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (void *)(farg2); + arg3 = (PSetupFn)(farg3); + arg4 = (PSolveFn)(farg4); + result = (int)SUNLinSolSetPreconditioner_SPTFQMR(arg1,arg2,arg3,arg4); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetScalingVectors_SPTFQMR(SUNLinearSolver farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)SUNLinSolSetScalingVectors_SPTFQMR(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSetup_SPTFQMR(SUNLinearSolver farg1, SUNMatrix farg2) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNLinSolSetup_SPTFQMR(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSolve_SPTFQMR(SUNLinearSolver farg1, SUNMatrix farg2, N_Vector farg3, N_Vector farg4, double const *farg5) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype arg5 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype)(*farg5); + result = (int)SUNLinSolSolve_SPTFQMR(arg1,arg2,arg3,arg4,arg5); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolNumIters_SPTFQMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolNumIters_SPTFQMR(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double _wrap_FSUNLinSolResNorm_SPTFQMR(SUNLinearSolver farg1) { + double fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + realtype result; + + arg1 = (SUNLinearSolver)(farg1); + result = (realtype)SUNLinSolResNorm_SPTFQMR(arg1); + fresult = (realtype)(result); + return fresult; +} + + +SWIGEXPORT N_Vector _wrap_FSUNLinSolResid_SPTFQMR(SUNLinearSolver farg1) { + N_Vector fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + N_Vector result; + + arg1 = (SUNLinearSolver)(farg1); + result = (N_Vector)SUNLinSolResid_SPTFQMR(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNLinSolLastFlag_SPTFQMR(SUNLinearSolver farg1) { + int64_t fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + sunindextype result; + + arg1 = (SUNLinearSolver)(farg1); + result = SUNLinSolLastFlag_SPTFQMR(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolSpace_SPTFQMR(SUNLinearSolver farg1, long *farg2, long *farg3) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNLinSolSpace_SPTFQMR(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNLinSolFree_SPTFQMR(SUNLinearSolver farg1) { + int fresult ; + SUNLinearSolver arg1 = (SUNLinearSolver) 0 ; + int result; + + arg1 = (SUNLinearSolver)(farg1); + result = (int)SUNLinSolFree_SPTFQMR(arg1); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fmod/fsunlinsol_sptfqmr_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fmod/fsunlinsol_sptfqmr_mod.f90 new file mode 100644 index 000000000..218d2e1c8 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fmod/fsunlinsol_sptfqmr_mod.f90 @@ -0,0 +1,572 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunlinsol_sptfqmr_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_linearsolver_mod + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_matrix_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: SUNSPTFQMR_MAXL_DEFAULT = 5_C_INT + public :: FSUNLinSol_SPTFQMR + public :: FSUNLinSol_SPTFQMRSetPrecType + public :: FSUNLinSol_SPTFQMRSetMaxl + public :: FSUNSPTFQMR + public :: FSUNSPTFQMRSetPrecType + public :: FSUNSPTFQMRSetMaxl + public :: FSUNLinSolGetType_SPTFQMR + public :: FSUNLinSolGetID_SPTFQMR + public :: FSUNLinSolInitialize_SPTFQMR + public :: FSUNLinSolSetATimes_SPTFQMR + public :: FSUNLinSolSetPreconditioner_SPTFQMR + public :: FSUNLinSolSetScalingVectors_SPTFQMR + public :: FSUNLinSolSetup_SPTFQMR + public :: FSUNLinSolSolve_SPTFQMR + public :: FSUNLinSolNumIters_SPTFQMR + public :: FSUNLinSolResNorm_SPTFQMR + public :: FSUNLinSolResid_SPTFQMR + public :: FSUNLinSolLastFlag_SPTFQMR + public :: FSUNLinSolSpace_SPTFQMR + public :: FSUNLinSolFree_SPTFQMR + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNLinSol_SPTFQMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSol_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSol_SPTFQMRSetPrecType(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_SPTFQMRSetPrecType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSol_SPTFQMRSetMaxl(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSol_SPTFQMRSetMaxl") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSPTFQMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNSPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNSPTFQMRSetPrecType(farg1, farg2) & +bind(C, name="_wrap_FSUNSPTFQMRSetPrecType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSPTFQMRSetMaxl(farg1, farg2) & +bind(C, name="_wrap_FSUNSPTFQMRSetMaxl") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetType_SPTFQMR(farg1) & +bind(C, name="_wrap_FSUNLinSolGetType_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolGetID_SPTFQMR(farg1) & +bind(C, name="_wrap_FSUNLinSolGetID_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolInitialize_SPTFQMR(farg1) & +bind(C, name="_wrap_FSUNLinSolInitialize_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetATimes_SPTFQMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSetATimes_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetPreconditioner_SPTFQMR(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FSUNLinSolSetPreconditioner_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_FUNPTR), value :: farg3 +type(C_FUNPTR), value :: farg4 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetScalingVectors_SPTFQMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSetScalingVectors_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSetup_SPTFQMR(farg1, farg2) & +bind(C, name="_wrap_FSUNLinSolSetup_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolSolve_SPTFQMR(farg1, farg2, farg3, farg4, farg5) & +bind(C, name="_wrap_FSUNLinSolSolve_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolNumIters_SPTFQMR(farg1) & +bind(C, name="_wrap_FSUNLinSolNumIters_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolResNorm_SPTFQMR(farg1) & +bind(C, name="_wrap_FSUNLinSolResNorm_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE) :: fresult +end function + +function swigc_FSUNLinSolResid_SPTFQMR(farg1) & +bind(C, name="_wrap_FSUNLinSolResid_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNLinSolLastFlag_SPTFQMR(farg1) & +bind(C, name="_wrap_FSUNLinSolLastFlag_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNLinSolSpace_SPTFQMR(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNLinSolSpace_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNLinSolFree_SPTFQMR(farg1) & +bind(C, name="_wrap_FSUNLinSolFree_SPTFQMR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNLinSol_SPTFQMR(y, pretype, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +integer(C_INT), intent(in) :: pretype +integer(C_INT), intent(in) :: maxl +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = c_loc(y) +farg2 = pretype +farg3 = maxl +fresult = swigc_FSUNLinSol_SPTFQMR(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSol_SPTFQMRSetPrecType(s, pretype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: pretype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = pretype +fresult = swigc_FSUNLinSol_SPTFQMRSetPrecType(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSol_SPTFQMRSetMaxl(s, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: maxl +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = maxl +fresult = swigc_FSUNLinSol_SPTFQMRSetMaxl(farg1, farg2) +swig_result = fresult +end function + +function FSUNSPTFQMR(y, pretype, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNLinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +integer(C_INT), intent(in) :: pretype +integer(C_INT), intent(in) :: maxl +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 +integer(C_INT) :: farg3 + +farg1 = c_loc(y) +farg2 = pretype +farg3 = maxl +fresult = swigc_FSUNSPTFQMR(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNSPTFQMRSetPrecType(s, pretype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: pretype +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = pretype +fresult = swigc_FSUNSPTFQMRSetPrecType(farg1, farg2) +swig_result = fresult +end function + +function FSUNSPTFQMRSetMaxl(s, maxl) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT), intent(in) :: maxl +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(s) +farg2 = maxl +fresult = swigc_FSUNSPTFQMRSetMaxl(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolGetType_SPTFQMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_Type) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetType_SPTFQMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolGetID_SPTFQMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNLinearSolver_ID) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolGetID_SPTFQMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolInitialize_SPTFQMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolInitialize_SPTFQMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolSetATimes_SPTFQMR(s, a_data, atimes) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: a_data +type(C_FUNPTR), intent(in), value :: atimes +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_FUNPTR) :: farg3 + +farg1 = c_loc(s) +farg2 = a_data +farg3 = atimes +fresult = swigc_FSUNLinSolSetATimes_SPTFQMR(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolSetPreconditioner_SPTFQMR(s, p_data, pset, psol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: p_data +type(C_FUNPTR), intent(in), value :: pset +type(C_FUNPTR), intent(in), value :: psol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_FUNPTR) :: farg3 +type(C_FUNPTR) :: farg4 + +farg1 = c_loc(s) +farg2 = p_data +farg3 = pset +farg4 = psol +fresult = swigc_FSUNLinSolSetPreconditioner_SPTFQMR(farg1, farg2, farg3, farg4) +swig_result = fresult +end function + +function FSUNLinSolSetScalingVectors_SPTFQMR(s, s1, s2) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(N_Vector), target, intent(inout) :: s1 +type(N_Vector), target, intent(inout) :: s2 +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(s1) +farg3 = c_loc(s2) +fresult = swigc_FSUNLinSolSetScalingVectors_SPTFQMR(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolSetup_SPTFQMR(s, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(s) +farg2 = c_loc(a) +fresult = swigc_FSUNLinSolSetup_SPTFQMR(farg1, farg2) +swig_result = fresult +end function + +function FSUNLinSolSolve_SPTFQMR(s, a, x, b, tol) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(SUNMatrix), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: b +real(C_DOUBLE), intent(in) :: tol +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +real(C_DOUBLE) :: farg5 + +farg1 = c_loc(s) +farg2 = c_loc(a) +farg3 = c_loc(x) +farg4 = c_loc(b) +farg5 = tol +fresult = swigc_FSUNLinSolSolve_SPTFQMR(farg1, farg2, farg3, farg4, farg5) +swig_result = fresult +end function + +function FSUNLinSolNumIters_SPTFQMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolNumIters_SPTFQMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolResNorm_SPTFQMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +real(C_DOUBLE) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolResNorm_SPTFQMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolResid_SPTFQMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(N_Vector), pointer :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolResid_SPTFQMR(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNLinSolLastFlag_SPTFQMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolLastFlag_SPTFQMR(farg1) +swig_result = fresult +end function + +function FSUNLinSolSpace_SPTFQMR(s, lenrwls, leniwls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_LONG), dimension(*), target, intent(inout) :: lenrwls +integer(C_LONG), dimension(*), target, intent(inout) :: leniwls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(s) +farg2 = c_loc(lenrwls(1)) +farg3 = c_loc(leniwls(1)) +fresult = swigc_FSUNLinSolSpace_SPTFQMR(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNLinSolFree_SPTFQMR(s) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNLinearSolver), target, intent(inout) :: s +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(s) +fresult = swigc_FSUNLinSolFree_SPTFQMR(farg1) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.c index f85870486..828cd7c27 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.h b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.h index 7e3aa4b1d..64ade540f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/sunlinsol_sptfqmr.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/sunlinsol_sptfqmr.c index e66b15937..4b64b2e4e 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/sunlinsol_sptfqmr.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/sptfqmr/sunlinsol_sptfqmr.c @@ -1,10 +1,9 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU * Based on sundials_sptfqmr.c code, written by Aaron Collier @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -13,10 +12,9 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the SPTFQMR implementation of + * This is the implementation file for the SPTFQMR implementation of * the SUNLINSOL package. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include @@ -29,15 +27,13 @@ /* * ----------------------------------------------------------------- - * SPTFQMR solver structure accessibility macros: + * SPTFQMR solver structure accessibility macros: * ----------------------------------------------------------------- */ - #define SPTFQMR_CONTENT(S) ( (SUNLinearSolverContent_SPTFQMR)(S->content) ) #define LASTFLAG(S) ( SPTFQMR_CONTENT(S)->last_flag ) - /* * ----------------------------------------------------------------- * deprecated wrapper functions @@ -66,9 +62,8 @@ int SUNSPTFQMRSetMaxl(SUNLinearSolver S, int maxl) SUNLinearSolver SUNLinSol_SPTFQMR(N_Vector y, int pretype, int maxl) { SUNLinearSolver S; - SUNLinearSolver_Ops ops; SUNLinearSolverContent_SPTFQMR content; - + /* check for legal pretype and maxl values; if illegal use defaults */ if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) && (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) @@ -85,83 +80,99 @@ SUNLinearSolver SUNLinSol_SPTFQMR(N_Vector y, int pretype, int maxl) /* Create linear solver */ S = NULL; - S = (SUNLinearSolver) malloc(sizeof *S); + S = SUNLinSolNewEmpty(); if (S == NULL) return(NULL); - - /* Create linear solver operation structure */ - ops = NULL; - ops = (SUNLinearSolver_Ops) malloc(sizeof(struct _generic_SUNLinearSolver_Ops)); - if (ops == NULL) { free(S); return(NULL); } /* Attach operations */ - ops->gettype = SUNLinSolGetType_SPTFQMR; - ops->setatimes = SUNLinSolSetATimes_SPTFQMR; - ops->setpreconditioner = SUNLinSolSetPreconditioner_SPTFQMR; - ops->setscalingvectors = SUNLinSolSetScalingVectors_SPTFQMR; - ops->initialize = SUNLinSolInitialize_SPTFQMR; - ops->setup = SUNLinSolSetup_SPTFQMR; - ops->solve = SUNLinSolSolve_SPTFQMR; - ops->numiters = SUNLinSolNumIters_SPTFQMR; - ops->resnorm = SUNLinSolResNorm_SPTFQMR; - ops->resid = SUNLinSolResid_SPTFQMR; - ops->lastflag = SUNLinSolLastFlag_SPTFQMR; - ops->space = SUNLinSolSpace_SPTFQMR; - ops->free = SUNLinSolFree_SPTFQMR; + S->ops->gettype = SUNLinSolGetType_SPTFQMR; + S->ops->getid = SUNLinSolGetID_SPTFQMR; + S->ops->setatimes = SUNLinSolSetATimes_SPTFQMR; + S->ops->setpreconditioner = SUNLinSolSetPreconditioner_SPTFQMR; + S->ops->setscalingvectors = SUNLinSolSetScalingVectors_SPTFQMR; + S->ops->initialize = SUNLinSolInitialize_SPTFQMR; + S->ops->setup = SUNLinSolSetup_SPTFQMR; + S->ops->solve = SUNLinSolSolve_SPTFQMR; + S->ops->numiters = SUNLinSolNumIters_SPTFQMR; + S->ops->resnorm = SUNLinSolResNorm_SPTFQMR; + S->ops->resid = SUNLinSolResid_SPTFQMR; + S->ops->lastflag = SUNLinSolLastFlag_SPTFQMR; + S->ops->space = SUNLinSolSpace_SPTFQMR; + S->ops->free = SUNLinSolFree_SPTFQMR; /* Create content */ content = NULL; - content = (SUNLinearSolverContent_SPTFQMR) malloc(sizeof(struct _SUNLinearSolverContent_SPTFQMR)); - if (content == NULL) { free(ops); free(S); return(NULL); } + content = (SUNLinearSolverContent_SPTFQMR) malloc(sizeof *content); + if (content == NULL) { SUNLinSolFree(S); return(NULL); } + + /* Attach content */ + S->content = content; /* Fill content */ content->last_flag = 0; - content->maxl = maxl; - content->pretype = pretype; - content->numiters = 0; - content->resnorm = ZERO; + content->maxl = maxl; + content->pretype = pretype; + content->numiters = 0; + content->resnorm = ZERO; + content->r_star = NULL; + content->q = NULL; + content->d = NULL; + content->v = NULL; + content->p = NULL; + content->r = NULL; + content->u = NULL; + content->vtemp1 = NULL; + content->vtemp2 = NULL; + content->vtemp3 = NULL; + content->s1 = NULL; + content->s2 = NULL; + content->ATimes = NULL; + content->ATData = NULL; + content->Psetup = NULL; + content->Psolve = NULL; + content->PData = NULL; + + /* Allocate content */ content->r_star = N_VClone(y); - if (content->r_star == NULL) return(NULL); + if (content->r_star == NULL) { SUNLinSolFree(S); return(NULL); } + content->q = N_VClone(y); - if (content->q == NULL) return(NULL); + if (content->q == NULL) { SUNLinSolFree(S); return(NULL); } + content->d = N_VClone(y); - if (content->d == NULL) return(NULL); + if (content->d == NULL) { SUNLinSolFree(S); return(NULL); } + content->v = N_VClone(y); - if (content->v == NULL) return(NULL); + if (content->v == NULL) { SUNLinSolFree(S); return(NULL); } + content->p = N_VClone(y); - if (content->p == NULL) return(NULL); + if (content->p == NULL) { SUNLinSolFree(S); return(NULL); } + content->r = N_VCloneVectorArray(2, y); - if (content->r == NULL) return(NULL); + if (content->r == NULL) { SUNLinSolFree(S); return(NULL); } + content->u = N_VClone(y); - if (content->u == NULL) return(NULL); + if (content->u == NULL) { SUNLinSolFree(S); return(NULL); } + content->vtemp1 = N_VClone(y); - if (content->vtemp1 == NULL) return(NULL); + if (content->vtemp1 == NULL) { SUNLinSolFree(S); return(NULL); } + content->vtemp2 = N_VClone(y); - if (content->vtemp2 == NULL) return(NULL); + if (content->vtemp2 == NULL) { SUNLinSolFree(S); return(NULL); } + content->vtemp3 = N_VClone(y); - if (content->vtemp3 == NULL) return(NULL); - content->s1 = NULL; - content->s2 = NULL; - content->ATimes = NULL; - content->ATData = NULL; - content->Psetup = NULL; - content->Psolve = NULL; - content->PData = NULL; - - /* Attach content and ops */ - S->content = content; - S->ops = ops; + if (content->vtemp3 == NULL) { SUNLinSolFree(S); return(NULL); } return(S); } /* ---------------------------------------------------------------------------- - * Function to set the type of preconditioning for SPTFQMR to use + * Function to set the type of preconditioning for SPTFQMR to use */ -SUNDIALS_EXPORT int SUNLinSol_SPTFQMRSetPrecType(SUNLinearSolver S, int pretype) +SUNDIALS_EXPORT int SUNLinSol_SPTFQMRSetPrecType(SUNLinearSolver S, int pretype) { - /* Check for legal pretype */ + /* Check for legal pretype */ if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) && (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) { return(SUNLS_ILL_INPUT); @@ -177,15 +188,15 @@ SUNDIALS_EXPORT int SUNLinSol_SPTFQMRSetPrecType(SUNLinearSolver S, int pretype) /* ---------------------------------------------------------------------------- - * Function to set the maximum number of iterations for SPTFQMR to use + * Function to set the maximum number of iterations for SPTFQMR to use */ -SUNDIALS_EXPORT int SUNLinSol_SPTFQMRSetMaxl(SUNLinearSolver S, int maxl) +SUNDIALS_EXPORT int SUNLinSol_SPTFQMRSetMaxl(SUNLinearSolver S, int maxl) { /* Check for non-NULL SUNLinearSolver */ if (S == NULL) return(SUNLS_MEM_NULL); - /* Check for legal pretype */ + /* Check for legal pretype */ if (maxl <= 0) maxl = SUNSPTFQMR_MAXL_DEFAULT; @@ -207,31 +218,37 @@ SUNLinearSolver_Type SUNLinSolGetType_SPTFQMR(SUNLinearSolver S) } +SUNLinearSolver_ID SUNLinSolGetID_SPTFQMR(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_SPTFQMR); +} + + int SUNLinSolInitialize_SPTFQMR(SUNLinearSolver S) { SUNLinearSolverContent_SPTFQMR content; /* set shortcut to SPTFQMR memory structure */ - if (S == NULL) return(SUNLS_MEM_NULL); + if (S == NULL) return(SUNLS_MEM_NULL); content = SPTFQMR_CONTENT(S); /* ensure valid options */ - if ( (content->pretype != PREC_LEFT) && - (content->pretype != PREC_RIGHT) && + if ( (content->pretype != PREC_LEFT) && + (content->pretype != PREC_RIGHT) && (content->pretype != PREC_BOTH) ) content->pretype = PREC_NONE; - if (content->maxl <= 0) + if (content->maxl <= 0) content->maxl = SUNSPTFQMR_MAXL_DEFAULT; /* no additional memory to allocate */ - + /* return with success */ content->last_flag = SUNLS_SUCCESS; return(SUNLS_SUCCESS); } -int SUNLinSolSetATimes_SPTFQMR(SUNLinearSolver S, void* ATData, +int SUNLinSolSetATimes_SPTFQMR(SUNLinearSolver S, void* ATData, ATimesFn ATimes) { /* set function pointers to integrator-supplied ATimes routine @@ -262,7 +279,7 @@ int SUNLinSolSetScalingVectors_SPTFQMR(SUNLinearSolver S, N_Vector s1, N_Vector s2) { - /* set N_Vector pointers to integrator-supplied scaling vectors, + /* set N_Vector pointers to integrator-supplied scaling vectors, and return with success */ if (S == NULL) return(SUNLS_MEM_NULL); SPTFQMR_CONTENT(S)->s1 = s1; @@ -282,24 +299,24 @@ int SUNLinSolSetup_SPTFQMR(SUNLinearSolver S, SUNMatrix A) if (S == NULL) return(SUNLS_MEM_NULL); Psetup = SPTFQMR_CONTENT(S)->Psetup; PData = SPTFQMR_CONTENT(S)->PData; - - /* no solver-specific setup is required, but if user-supplied + + /* no solver-specific setup is required, but if user-supplied Psetup routine exists, call that here */ if (Psetup != NULL) { ier = Psetup(PData); if (ier != 0) { - LASTFLAG(S) = (ier < 0) ? + LASTFLAG(S) = (ier < 0) ? SUNLS_PSET_FAIL_UNREC : SUNLS_PSET_FAIL_REC; return(LASTFLAG(S)); } } - - /* return with success */ + + /* return with success */ return(SUNLS_SUCCESS); } -int SUNLinSolSolve_SPTFQMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, +int SUNLinSolSolve_SPTFQMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype delta) { /* local data and shortcut variables */ @@ -320,7 +337,7 @@ int SUNLinSolSolve_SPTFQMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, /* local variables for fused vector operations */ realtype cv[3]; N_Vector Xv[3]; - + /* Make local shorcuts to solver variables. */ if (S == NULL) return(SUNLS_MEM_NULL); l_max = SPTFQMR_CONTENT(S)->maxl; @@ -350,9 +367,9 @@ int SUNLinSolSolve_SPTFQMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, b_ok = SUNFALSE; /* set booleantype flags for internal solver options */ - preOnLeft = ( (SPTFQMR_CONTENT(S)->pretype == PREC_LEFT) || + preOnLeft = ( (SPTFQMR_CONTENT(S)->pretype == PREC_LEFT) || (SPTFQMR_CONTENT(S)->pretype == PREC_BOTH) ); - preOnRight = ( (SPTFQMR_CONTENT(S)->pretype == PREC_RIGHT) || + preOnRight = ( (SPTFQMR_CONTENT(S)->pretype == PREC_RIGHT) || (SPTFQMR_CONTENT(S)->pretype == PREC_BOTH) ); scale_x = (sx != NULL); scale_b = (sb != NULL); @@ -588,7 +605,7 @@ int SUNLinSolSolve_SPTFQMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_VLinearSum(ONE, vtemp3, -ONE, vtemp2, vtemp1); *res_norm = r_curr_norm = SUNRsqrt(N_VDotProd(vtemp1, vtemp1)); - /* Exit inner loop if inequality condition is satisfied + /* Exit inner loop if inequality condition is satisfied (meaning exit if we have converged) */ if (r_curr_norm <= delta) { converged = SUNTRUE; @@ -674,9 +691,9 @@ int SUNLinSolSolve_SPTFQMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, } N_VScale(ONE, vtemp1, x); } - if (converged == SUNTRUE) + if (converged == SUNTRUE) LASTFLAG(S) = SUNLS_SUCCESS; - else + else LASTFLAG(S) = SUNLS_RES_REDUCED; return(LASTFLAG(S)); } @@ -711,7 +728,7 @@ N_Vector SUNLinSolResid_SPTFQMR(SUNLinearSolver S) } -long int SUNLinSolLastFlag_SPTFQMR(SUNLinearSolver S) +sunindextype SUNLinSolLastFlag_SPTFQMR(SUNLinearSolver S) { /* return the stored 'last_flag' value */ if (S == NULL) return(-1); @@ -719,8 +736,8 @@ long int SUNLinSolLastFlag_SPTFQMR(SUNLinearSolver S) } -int SUNLinSolSpace_SPTFQMR(SUNLinearSolver S, - long int *lenrwLS, +int SUNLinSolSpace_SPTFQMR(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS) { sunindextype liw1, lrw1; @@ -737,31 +754,51 @@ int SUNLinSolFree_SPTFQMR(SUNLinearSolver S) { if (S == NULL) return(SUNLS_SUCCESS); - /* delete items from within the content structure */ - if (SPTFQMR_CONTENT(S)->r_star) - N_VDestroy(SPTFQMR_CONTENT(S)->r_star); - if (SPTFQMR_CONTENT(S)->q) - N_VDestroy(SPTFQMR_CONTENT(S)->q); - if (SPTFQMR_CONTENT(S)->d) - N_VDestroy(SPTFQMR_CONTENT(S)->d); - if (SPTFQMR_CONTENT(S)->v) - N_VDestroy(SPTFQMR_CONTENT(S)->v); - if (SPTFQMR_CONTENT(S)->p) - N_VDestroy(SPTFQMR_CONTENT(S)->p); - if (SPTFQMR_CONTENT(S)->r) - N_VDestroyVectorArray(SPTFQMR_CONTENT(S)->r, 2); - if (SPTFQMR_CONTENT(S)->u) - N_VDestroy(SPTFQMR_CONTENT(S)->u); - if (SPTFQMR_CONTENT(S)->vtemp1) - N_VDestroy(SPTFQMR_CONTENT(S)->vtemp1); - if (SPTFQMR_CONTENT(S)->vtemp2) - N_VDestroy(SPTFQMR_CONTENT(S)->vtemp2); - if (SPTFQMR_CONTENT(S)->vtemp3) - N_VDestroy(SPTFQMR_CONTENT(S)->vtemp3); - - /* delete generic structures */ - free(S->content); S->content = NULL; - free(S->ops); S->ops = NULL; + if (S->content) { + /* delete items from within the content structure */ + if (SPTFQMR_CONTENT(S)->r_star) { + N_VDestroy(SPTFQMR_CONTENT(S)->r_star); + SPTFQMR_CONTENT(S)->r_star = NULL; + } + if (SPTFQMR_CONTENT(S)->q) { + N_VDestroy(SPTFQMR_CONTENT(S)->q); + SPTFQMR_CONTENT(S)->q = NULL; + } + if (SPTFQMR_CONTENT(S)->d) { + N_VDestroy(SPTFQMR_CONTENT(S)->d); + SPTFQMR_CONTENT(S)->d = NULL; + } + if (SPTFQMR_CONTENT(S)->v) { + N_VDestroy(SPTFQMR_CONTENT(S)->v); + SPTFQMR_CONTENT(S)->v = NULL; + } + if (SPTFQMR_CONTENT(S)->p) { + N_VDestroy(SPTFQMR_CONTENT(S)->p); + SPTFQMR_CONTENT(S)->p = NULL; + } + if (SPTFQMR_CONTENT(S)->r) { + N_VDestroyVectorArray(SPTFQMR_CONTENT(S)->r, 2); + SPTFQMR_CONTENT(S)->r = NULL; + } + if (SPTFQMR_CONTENT(S)->u) { + N_VDestroy(SPTFQMR_CONTENT(S)->u); + SPTFQMR_CONTENT(S)->u = NULL; + } + if (SPTFQMR_CONTENT(S)->vtemp1) { + N_VDestroy(SPTFQMR_CONTENT(S)->vtemp1); + SPTFQMR_CONTENT(S)->vtemp1 = NULL; + } + if (SPTFQMR_CONTENT(S)->vtemp2) { + N_VDestroy(SPTFQMR_CONTENT(S)->vtemp2); + SPTFQMR_CONTENT(S)->vtemp2 = NULL; + } + if (SPTFQMR_CONTENT(S)->vtemp3) { + N_VDestroy(SPTFQMR_CONTENT(S)->vtemp3); + SPTFQMR_CONTENT(S)->vtemp3 = NULL; + } + free(S->content); S->content = NULL; + } + if (S->ops) { free(S->ops); S->ops = NULL; } free(S); S = NULL; return(SUNLS_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superludist/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superludist/CMakeLists.txt new file mode 100644 index 000000000..dedd8e6a3 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superludist/CMakeLists.txt @@ -0,0 +1,102 @@ +# ------------------------------------------------------------------------------ +# Programmer(s): Cody J. Balos @ LLNL +# ------------------------------------------------------------------------------ +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# ----------------------------------------------------------------------------- +# CMakeLists.txt file for the superlu-dist SUNLinearSolver library +# ----------------------------------------------------------------------------- + +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_SUPERLUDIST\n\")") + +# Source files for the library +set(sunlinsolsuperludist_SOURCES sunlinsol_superludist.c) + +# Common SUNDIALS sources included in the library +set(shared_SOURCES + ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c) + +# Exported header files +set(sunlinsolsuperludist_HEADERS + ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_superludist.h) + +# Use MPI +set(CMAKE_C_COMPILER ${MPI_C_COMPILER}) +set(CMAKE_CXX_COMPILER ${MPI_CXX_COMPILER}) + +# Rules for building and installing the static library: +# - Add the build target for the library +# - Set the library name and make sure it is not deleted +# - Install the library +if(BUILD_STATIC_LIBS) + + add_library(sundials_sunlinsolsuperludist_static + STATIC ${sunlinsolsuperludist_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolsuperludist_static + PROPERTIES + OUTPUT_NAME sundials_sunlinsolsuperludist + CLEAN_DIRECT_OUTPUT 1) + + target_link_libraries(sundials_sunlinsolsuperludist_static + PUBLIC sundials_sunmatrixslunrloc_static SuperLU_DIST::SuperLU_DIST + PRIVATE m) + + if(SUPERLUDIST_OpenMP) + target_compile_options(sundials_sunlinsolsuperludist_static + PUBLIC ${OpenMP_C_FLAGS}) + endif() + + target_compile_definitions(sundials_sunlinsolsuperludist_static + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolsuperludist_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_STATIC_LIBS) + +# Rules for building and installing the shared library: +# - Add the build target for the library +# - Set the library name and make sure it is not deleted +# - Set VERSION and SOVERSION for shared libraries +# - Install the library +if(BUILD_SHARED_LIBS) + + add_library(sundials_sunlinsolsuperludist_shared + SHARED ${sunlinsolsuperludist_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolsuperludist_shared + PROPERTIES + OUTPUT_NAME sundials_sunlinsolsuperludist + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + + target_link_libraries(sundials_sunlinsolsuperludist_shared + PUBLIC sundials_sunmatrixslunrloc_shared SuperLU_DIST::SuperLU_DIST + PRIVATE m) + + if(SUPERLUDIST_OpenMP) + target_compile_options(sundials_sunlinsolsuperludist_shared + PUBLIC ${OpenMP_C_FLAGS}) + endif() + + target_compile_definitions(sundials_sunlinsolsuperludist_shared + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolsuperludist_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_SHARED_LIBS) + +# Install the header files +install(FILES ${sunlinsolsuperludist_HEADERS} DESTINATION include/sunlinsol) + +message(STATUS "Added SUNLINSOL_SUPERLUDIST module") diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superludist/sunlinsol_superludist.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superludist/sunlinsol_superludist.c new file mode 100644 index 000000000..526832e93 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superludist/sunlinsol_superludist.c @@ -0,0 +1,292 @@ +/* ----------------------------------------------------------------------------- + * Programmer(s): Cody J. Balos @ LLNL + * ----------------------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------------------- + * This is the implementation file for the SuperLU-DIST implementation of the + * SUNLINSOL package. + * ---------------------------------------------------------------------------*/ + +#include +#include + +#include +#include +#include +#include + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#define TWO RCONST(2.0) + +/* + * ----------------------------------------------------------------- + * SuperLUDIST solver structure accessibility macros: + * ----------------------------------------------------------------- + */ + +#define SLUDIST_CONTENT(S) ( (SUNLinearSolverContent_SuperLUDIST)(S->content) ) +#define SLU_FIRSTFACTORIZE(S) ( SLUDIST_CONTENT(S)->first_factorize ) +#define SLU_BERR(S) ( SLUDIST_CONTENT(S)->berr ) +#define SLU_GRID(S) ( SLUDIST_CONTENT(S)->grid ) +#define SLU_LASTFLAG(S) ( SLUDIST_CONTENT(S)->last_flag ) +#define SLU_LU(S) ( SLUDIST_CONTENT(S)->lu ) +#define SLU_OPTIONS(S) ( SLUDIST_CONTENT(S)->options ) +#define SLU_SCALEPERM(S) ( SLUDIST_CONTENT(S)->scaleperm ) +#define SLU_SOLVESTRUCT(S) ( SLUDIST_CONTENT(S)->solve ) +#define SLU_STAT(S) ( SLUDIST_CONTENT(S)->stat ) +#define SLU_SIZE(S) ( SLUDIST_CONTENT(S)->N ) + +/* + * ---------------------------------------------------------------------------- + * Implementations of exported functions. + * ---------------------------------------------------------------------------- + */ + +SUNLinearSolver SUNLinSol_SuperLUDIST(N_Vector y, SUNMatrix A, gridinfo_t *grid, + LUstruct_t *lu, ScalePermstruct_t *scaleperm, + SOLVEstruct_t *solve, SuperLUStat_t *stat, + superlu_dist_options_t *options) +{ + SUNLinearSolver S; + SUNLinearSolverContent_SuperLUDIST content; + SuperMatrix *Asuper; + NRformat_loc *Astore; + + /* Check that required arguments are not NULL */ + if (y == NULL || A == NULL || grid == NULL || lu == NULL || + scaleperm == NULL || solve == NULL || stat == NULL || options == NULL) + return(NULL); + + /* Check compatibility with supplied SUNMatrix and N_Vector */ + if (SUNMatGetID(A) != SUNMATRIX_SLUNRLOC) return(NULL); + + Asuper = SUNMatrix_SLUNRloc_SuperMatrix(A); + Astore = (NRformat_loc *) Asuper->Store; + + /* Check that the matrix is square */ + if (Asuper->nrow != Asuper->ncol) return(NULL); + + /* Create an empty linear solver */ + S = NULL; + S = SUNLinSolNewEmpty(); + if (S == NULL) return(NULL); + + /* Attach operations */ + S->ops->gettype = SUNLinSolGetType_SuperLUDIST; + S->ops->getid = SUNLinSolGetID_SuperLUDIST; + S->ops->initialize = SUNLinSolInitialize_SuperLUDIST; + S->ops->setup = SUNLinSolSetup_SuperLUDIST; + S->ops->solve = SUNLinSolSolve_SuperLUDIST; + S->ops->lastflag = SUNLinSolLastFlag_SuperLUDIST; + S->ops->space = SUNLinSolSpace_SuperLUDIST; + S->ops->free = SUNLinSolFree_SuperLUDIST; + + /* Create content */ + content = NULL; + content = (SUNLinearSolverContent_SuperLUDIST) malloc(sizeof *content); + if (content == NULL) { SUNLinSolFree(S); return(NULL); } + + /* Attach content */ + S->content = content; + + /* Fill content */ + content->grid = grid; + content->lu = lu; + content->N = Astore->m_loc; + content->options = options; + content->scaleperm = scaleperm; + content->solve = solve; + content->stat = stat; + content->berr = ZERO; + content->last_flag = 0; + + return(S); +} + +/* + * ----------------------------------------------------------------- + * Implementation of accessor functions. + * ----------------------------------------------------------------- + */ + +realtype SUNLinSol_SuperLUDIST_GetBerr(SUNLinearSolver LS) +{ + return(SLU_BERR(LS)); +} + +gridinfo_t* SUNLinSol_SuperLUDIST_GetGridinfo(SUNLinearSolver LS) +{ + return(SLU_GRID(LS)); +} + +LUstruct_t* SUNLinSol_SuperLUDIST_GetLUstruct(SUNLinearSolver LS) +{ + return(SLU_LU(LS)); +} + +superlu_dist_options_t* SUNLinSol_SuperLUDIST_GetSuperLUOptions(SUNLinearSolver LS) +{ + return(SLU_OPTIONS(LS)); +} + +ScalePermstruct_t* SUNLinSol_SuperLUDIST_GetScalePermstruct(SUNLinearSolver LS) +{ + return(SLU_SCALEPERM(LS)); +} + +SOLVEstruct_t* SUNLinSol_SuperLUDIST_GetSOLVEstruct(SUNLinearSolver LS) +{ + return(SLU_SOLVESTRUCT(LS)); +} + +SuperLUStat_t* SUNLinSol_SuperLUDIST_GetSuperLUStat(SUNLinearSolver LS) +{ + return(SLU_STAT(LS)); +} + +/* + * ----------------------------------------------------------------- + * Implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_SuperLUDIST(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_DIRECT); +} + +SUNLinearSolver_ID SUNLinSolGetID_SuperLUDIST(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_SUPERLUDIST); +} + +int SUNLinSolInitialize_SuperLUDIST(SUNLinearSolver S) +{ + SLU_FIRSTFACTORIZE(S) = SUNTRUE; + + SLU_LASTFLAG(S) = SUNLS_SUCCESS; + return(SLU_LASTFLAG(S)); +} + +int SUNLinSolSetup_SuperLUDIST(SUNLinearSolver S, SUNMatrix A) +{ + if (SLU_FIRSTFACTORIZE(S)) { + /* Force factorization on next solve. */ + SLU_OPTIONS(S)->Fact = DOFACT; + + /* if the solve struct was already initialized, we need to + finalize the last solve to avoid leaking memory */ + if (SLU_OPTIONS(S)->SolveInitialized == YES) { + Destroy_LU(SLU_SIZE(S), SLU_GRID(S), SLU_LU(S)); + dSolveFinalize(SLU_OPTIONS(S), SLU_SOLVESTRUCT(S)); + } + } else { + /* Force factorization on next solve, but reuse column permutation */ + SLU_OPTIONS(S)->Fact = SamePattern; + } + + SLU_LASTFLAG(S) = SUNLS_SUCCESS; + return(SLU_LASTFLAG(S)); +} + +int SUNLinSolSolve_SuperLUDIST(SUNLinearSolver S, SUNMatrix A, + N_Vector x, N_Vector b, realtype tol) +{ + int retval; + realtype *xdata; + SuperMatrix *Asuper; + NRformat_loc *Astore; + + if ((S == NULL) || (A == NULL) || (x == NULL) || (b == NULL)) + return(SUNLS_MEM_NULL); + + Asuper = SUNMatrix_SLUNRloc_SuperMatrix(A); + Astore = (NRformat_loc *) Asuper->Store; + + /* Copy b into x, and use xdata with SuperLU-DIST because + SuperLU reuses b to store the solution vector. */ + N_VScale(ONE, b, x); + xdata = N_VGetArrayPointer(x); + if (xdata == NULL) { + SLU_LASTFLAG(S) = SUNLS_MEM_FAIL; + return(SLU_LASTFLAG(S)); + } + + /* Call SuperLU-DIST to solve the linear system */ + pdgssvx(SLU_OPTIONS(S), Asuper, SLU_SCALEPERM(S), xdata, Astore->m_loc, 1, + SLU_GRID(S), SLU_LU(S), SLU_SOLVESTRUCT(S), &SLU_BERR(S), SLU_STAT(S), + &retval); + + if (retval != 0) { + /* retval should never be < 0, and if it is > than ncol it means a memory + allocation error occured. If 0 < retval <= ncol, then U is singular and + the solve couldn't be completed. */ + if (retval < 0 || retval > Asuper->ncol) + SLU_LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; + else + SLU_LASTFLAG(S) = SUNLS_PACKAGE_FAIL_REC; + return(SLU_LASTFLAG(S)); + } + + /* Tell SuperLU-DIST that A is already factored so do not factorize */ + SLU_OPTIONS(S)->Fact = FACTORED; + + SLU_LASTFLAG(S) = SUNLS_SUCCESS; + return(SLU_LASTFLAG(S)); +} + +sunindextype SUNLinSolLastFlag_SuperLUDIST(SUNLinearSolver S) +{ + if (S == NULL) return(-1); + return(SLU_LASTFLAG(S)); +} + +int SUNLinSolFree_SuperLUDIST(SUNLinearSolver S) +{ + /* return with success if already freed */ + if (S == NULL) return(SUNLS_SUCCESS); + + /* Call SuperLU DIST destroy/finalize routines, + but don't free the sturctures themselves - that is the user's job */ + Destroy_LU(SLU_SIZE(S), SLU_GRID(S), SLU_LU(S)); + dSolveFinalize(SLU_OPTIONS(S), SLU_SOLVESTRUCT(S)); + + /* free content structure */ + if (S->content) { + free(S->content); + S->content = NULL; + } + + /* free ops structure */ + if (S->ops) { + free(S->ops); + S->ops = NULL; + } + + /* free the actual SUNLinSol */ + free(S); + S = NULL; + + return(SUNLS_SUCCESS); +} + +int SUNLinSolSpace_SuperLUDIST(SUNLinearSolver S, long int *leniwLS, + long int *lenrwLS) +{ + /* since the SuperLU_DIST structures are opaque objects, we + omit those from these results */ + + *leniwLS = 2; /* last_flag, N */ + *lenrwLS = 1; /* berr */ + + return(SUNLS_SUCCESS); +} diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/CMakeLists.txt index 8c1cf2cb5..a000e4abe 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,101 +12,142 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the superlumt SUNLinearSolver library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNLINSOL_SUPERLUMT\n\")") - -# Add variable sunlinsolsuperlumt_SOURCES with the sources for the SUNLINSOLSUPERLUMT lib -SET(sunlinsolsuperlumt_SOURCES sunlinsol_superlumt.c) +install(CODE "MESSAGE(\"\nInstall SUNLINSOL_SUPERLUMT\n\")") -# Add variable shared_SOURCES with the common SUNDIALS sources which will -# also be included in the SUNLINSOLSUPERLUMT library -SET(shared_SOURCES - ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c - ) +# Source files for the library +set(sunlinsolsuperlumt_SOURCES sunlinsol_superlumt.c) -# Add variable sunlinsolsuperlumt_HEADERS with the exported SUNLINSOLSUPERLUMT header files -SET(sunlinsolsuperlumt_HEADERS - ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_superlumt.h - ) +# Common SUNDIALS sources included in the library +set(shared_SOURCES + ${sundials_SOURCE_DIR}/src/sundials/sundials_linearsolver.c) -# Add source directory to include directories -INCLUDE_DIRECTORIES(.) +# Exported header files +set(sunlinsolsuperlumt_HEADERS + ${sundials_SOURCE_DIR}/include/sunlinsol/sunlinsol_superlumt.h) -# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +# Include OpenMP flags if SuperLU_MT is using OpenMP +if(SUPERLUMT_THREAD_TYPE STREQUAL "OPENMP") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +endif() # Rules for building and installing the static library: -# - Add the build target for the SUNLINSOLSUPERLUMT library +# - Add the build target for the library # - Set the library name and make sure it is not deleted -# - Install the SUNLINSOLSUPERLUMT library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunlinsolsuperlumt_static STATIC ${sunlinsolsuperlumt_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunlinsolsuperlumt_static - PROPERTIES OUTPUT_NAME sundials_sunlinsolsuperlumt CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunlinsolsuperlumt_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) +# - Install the library +if(BUILD_STATIC_LIBS) + + add_library(sundials_sunlinsolsuperlumt_static + STATIC ${sunlinsolsuperlumt_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolsuperlumt_static + PROPERTIES + OUTPUT_NAME sundials_sunlinsolsuperlumt + CLEAN_DIRECT_OUTPUT 1) + + # depends on sunmatrixsparse and SuperLU_MT + target_link_libraries(sundials_sunlinsolsuperlumt_static + PUBLIC sundials_sunmatrixsparse_static SuperLU_MT::SuperLU_MT) + + # link to Pthread library if SuperLU_MT is using Pthreads + if(SUPERLUMT_THREAD_TYPE STREQUAL "PTHREAD") + target_link_libraries(sundials_sunlinsolsuperlumt_static + PUBLIC Threads::Threads) + endif() + + target_compile_definitions(sundials_sunlinsolsuperlumt_static + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolsuperlumt_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: -# - Add the build target for the SUNLINSOLSUPERLUMT library +# - Add the build target for the library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries -# - Install the SUNLINSOLSUPERLUMT library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunlinsolsuperlumt_shared SHARED ${sunlinsolsuperlumt_SOURCES} ${shared_SOURCES}) - - # sunlinsolsuperlumt depends on sunmatrixsparse and SuperLU_MT - TARGET_LINK_LIBRARIES(sundials_sunlinsolsuperlumt_shared - sundials_sunmatrixsparse_shared - ${SUPERLUMT_LIBRARIES}) - - # if a blas library is provided, assume SuperLU_MT depends on it - IF(BLAS_FOUND) - TARGET_LINK_LIBRARIES(sundials_sunlinsolsuperlumt_shared ${BLAS_LIBRARIES}) - ENDIF() - - # if a blas library was not provided but a lapack library was set, assume - # SuperLU_MT depends depends on a blas library provided in LAPACK_LIBRARIES - IF((NOT BLAS_FOUND) AND LAPACK_FOUND) - TARGET_LINK_LIBRARIES(sundials_sunlinsolsuperlumt_shared ${LAPACK_LIBRARIES}) - ENDIF() - - SET_TARGET_PROPERTIES(sundials_sunlinsolsuperlumt_shared - PROPERTIES OUTPUT_NAME sundials_sunlinsolsuperlumt CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunlinsolsuperlumt_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_sunlinsolsuperlumt_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) - -# Install the SUNLINSOLSUPERLUMT header files -INSTALL(FILES ${sunlinsolsuperlumt_HEADERS} DESTINATION include/sunlinsol) - -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunlinsolsuperlumt_SOURCES fsunlinsol_superlumt.c) - - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunlinsolsuperlumt_static STATIC ${fsunlinsolsuperlumt_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunlinsolsuperlumt_static - PROPERTIES OUTPUT_NAME sundials_fsunlinsolsuperlumt CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunlinsolsuperlumt_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) - - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunlinsolsuperlumt_shared ${fsunlinsolsuperlumt_SOURCES}) - - # fsunlinsolsuperlumt dependes on fnvecserial, fsunmatrixsparse, sunlinsolsuperlumt - TARGET_LINK_LIBRARIES(sundials_fsunlinsolsuperlumt_shared +# - Install the library +if(BUILD_SHARED_LIBS) + + add_library(sundials_sunlinsolsuperlumt_shared + SHARED ${sunlinsolsuperlumt_SOURCES} ${shared_SOURCES}) + + set_target_properties(sundials_sunlinsolsuperlumt_shared + PROPERTIES + OUTPUT_NAME sundials_sunlinsolsuperlumt + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + + # depends on sunmatrixsparse and SuperLU_MT + target_link_libraries(sundials_sunlinsolsuperlumt_shared + PUBLIC sundials_sunmatrixsparse_shared SuperLU_MT::SuperLU_MT) + + # link to Pthread library if SuperLU_MT is using Pthreads + if(SUPERLUMT_THREAD_TYPE STREQUAL "PTHREAD") + target_link_libraries(sundials_sunlinsolsuperlumt_shared + PUBLIC Threads::Threads) + endif() + + target_compile_definitions(sundials_sunlinsolsuperlumt_shared + PUBLIC -DBUILD_SUNDIALS_LIBRARY) + + install(TARGETS sundials_sunlinsolsuperlumt_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif(BUILD_SHARED_LIBS) + +# Install the header files +install(FILES ${sunlinsolsuperlumt_HEADERS} DESTINATION include/sunlinsol) + +# +message(STATUS "Added SUNLINSOL_SUPERLUMT module") + +# If FCMIX is enabled, build and install the Fortran77 library +if(F77_INTERFACE_ENABLE AND F77_FOUND) + + set(fsunlinsolsuperlumt_SOURCES fsunlinsol_superlumt.c) + + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunlinsolsuperlumt_static + STATIC ${fsunlinsolsuperlumt_SOURCES}) + set_target_properties(sundials_fsunlinsolsuperlumt_static + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolsuperlumt + CLEAN_DIRECT_OUTPUT 1) + # depends on fnvecserial, fsunmatrixsparse, sunlinsolsuperlumt + target_link_libraries(sundials_fsunlinsolsuperlumt_static + PUBLIC + sundials_fnvecserial_static + sundials_fsunmatrixsparse_static + sundials_sunlinsolsuperlumt_static) + install(TARGETS sundials_fsunlinsolsuperlumt_static + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) + + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunlinsolsuperlumt_shared + SHARED ${fsunlinsolsuperlumt_SOURCES}) + set_target_properties(sundials_fsunlinsolsuperlumt_shared + PROPERTIES + OUTPUT_NAME sundials_fsunlinsolsuperlumt + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunlinsollib_VERSION} + SOVERSION ${sunlinsollib_SOVERSION}) + # depends on fnvecserial, fsunmatrixsparse, sunlinsolsuperlumt + target_link_libraries(sundials_fsunlinsolsuperlumt_shared + PUBLIC sundials_fnvecserial_shared sundials_fsunmatrixsparse_shared sundials_sunlinsolsuperlumt_shared) + install(TARGETS sundials_fsunlinsolsuperlumt_shared + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) - SET_TARGET_PROPERTIES(sundials_fsunlinsolsuperlumt_shared - PROPERTIES OUTPUT_NAME sundials_fsunlinsolsuperlumt CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunlinsolsuperlumt_shared - PROPERTIES VERSION ${sunlinsollib_VERSION} SOVERSION ${sunlinsollib_SOVERSION}) - INSTALL(TARGETS sundials_fsunlinsolsuperlumt_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + # + message(STATUS "Added SUNLINSOL_SUPERLUMT F77 interface") -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) - -# -MESSAGE(STATUS "Added SUNLINSOL_SUPERLUMT module") +endif(F77_INTERFACE_ENABLE AND F77_FOUND) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.c index 711ba5c95..959d23c9f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.h b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.h index c39357633..4ee88783a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/sunlinsol_superlumt.c b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/sunlinsol_superlumt.c index 8aa3ca214..792236bfc 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/sunlinsol_superlumt.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunlinsol/superlumt/sunlinsol_superlumt.c @@ -1,11 +1,11 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU - * Based on codes _superlumt.c, written by - * Carol S. Woodward @ LLNL + * ----------------------------------------------------------------- + * Based on codes _superlumt.c, written by + * Carol S. Woodward @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -14,10 +14,9 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the SuperLUMT implementation of - * the SUNLINSOL package. - * ----------------------------------------------------------------- - */ + * This is the implementation file for the SuperLUMT implementation + * of the SUNLINSOL package. + * -----------------------------------------------------------------*/ #include #include @@ -29,12 +28,9 @@ #define ONE RCONST(1.0) #define TWO RCONST(2.0) -/* Private function prototypes */ -sunindextype GlobalVectorLength_SuperLUMT(N_Vector y); - /* * ----------------------------------------------------------------- - * SuperLUMT solver structure accessibility macros: + * SuperLUMT solver structure accessibility macros: * ----------------------------------------------------------------- */ @@ -81,123 +77,97 @@ int SUNSuperLUMTSetOrdering(SUNLinearSolver S, int ordering_choice) SUNLinearSolver SUNLinSol_SuperLUMT(N_Vector y, SUNMatrix A, int num_threads) { SUNLinearSolver S; - SUNLinearSolver_Ops ops; SUNLinearSolverContent_SuperLUMT content; - sunindextype MatrixRows, VecLength; + sunindextype MatrixRows; /* Check compatibility with supplied SUNMatrix and N_Vector */ - if (SUNMatGetID(A) != SUNMATRIX_SPARSE) - return(NULL); - if (SUNSparseMatrix_Rows(A) != SUNSparseMatrix_Columns(A)) - return(NULL); - MatrixRows = SUNSparseMatrix_Rows(A); + if (SUNMatGetID(A) != SUNMATRIX_SPARSE) return(NULL); + + if (SUNSparseMatrix_Rows(A) != SUNSparseMatrix_Columns(A)) return(NULL); + if ( (N_VGetVectorID(y) != SUNDIALS_NVEC_SERIAL) && (N_VGetVectorID(y) != SUNDIALS_NVEC_OPENMP) && (N_VGetVectorID(y) != SUNDIALS_NVEC_PTHREADS) ) return(NULL); - /* optimally this function would be replaced with a generic N_Vector routine */ - VecLength = GlobalVectorLength_SuperLUMT(y); - if (MatrixRows != VecLength) - return(NULL); - - /* Create linear solver */ + MatrixRows = SUNSparseMatrix_Rows(A); + if (MatrixRows != N_VGetLength(y)) return(NULL); + + /* Create an empty linear solver */ S = NULL; - S = (SUNLinearSolver) malloc(sizeof *S); + S = SUNLinSolNewEmpty(); if (S == NULL) return(NULL); - - /* Create linear solver operation structure */ - ops = NULL; - ops = (SUNLinearSolver_Ops) malloc(sizeof(struct _generic_SUNLinearSolver_Ops)); - if (ops == NULL) { free(S); return(NULL); } /* Attach operations */ - ops->gettype = SUNLinSolGetType_SuperLUMT; - ops->initialize = SUNLinSolInitialize_SuperLUMT; - ops->setup = SUNLinSolSetup_SuperLUMT; - ops->solve = SUNLinSolSolve_SuperLUMT; - ops->lastflag = SUNLinSolLastFlag_SuperLUMT; - ops->space = SUNLinSolSpace_SuperLUMT; - ops->free = SUNLinSolFree_SuperLUMT; - ops->setatimes = NULL; - ops->setpreconditioner = NULL; - ops->setscalingvectors = NULL; - ops->numiters = NULL; - ops->resnorm = NULL; - ops->resid = NULL; + S->ops->gettype = SUNLinSolGetType_SuperLUMT; + S->ops->getid = SUNLinSolGetID_SuperLUMT; + S->ops->initialize = SUNLinSolInitialize_SuperLUMT; + S->ops->setup = SUNLinSolSetup_SuperLUMT; + S->ops->solve = SUNLinSolSolve_SuperLUMT; + S->ops->lastflag = SUNLinSolLastFlag_SuperLUMT; + S->ops->space = SUNLinSolSpace_SuperLUMT; + S->ops->free = SUNLinSolFree_SuperLUMT; /* Create content */ content = NULL; - content = (SUNLinearSolverContent_SuperLUMT) - malloc(sizeof(struct _SUNLinearSolverContent_SuperLUMT)); - if (content == NULL) { free(ops); free(S); return(NULL); } + content = (SUNLinearSolverContent_SuperLUMT) malloc(sizeof *content); + if (content == NULL) { SUNLinSolFree(S); return(NULL); } + + /* Attach content */ + S->content = content; /* Fill content */ - content->N = MatrixRows; - content->last_flag = 0; - content->num_threads = num_threads; + content->N = MatrixRows; + content->last_flag = 0; + content->num_threads = num_threads; content->diag_pivot_thresh = ONE; - content->ordering = SUNSLUMT_ORDERING_DEFAULT; - - content->perm_r = NULL; + content->ordering = SUNSLUMT_ORDERING_DEFAULT; + content->perm_r = NULL; + content->perm_c = NULL; + content->Gstat = NULL; + content->A = NULL; + content->AC = NULL; + content->L = NULL; + content->U = NULL; + content->B = NULL; + content->options = NULL; + + /* Allocate content */ content->perm_r = (sunindextype *) malloc(MatrixRows*sizeof(sunindextype)); - if (content->perm_r == NULL) { - free(content); free(ops); free(S); return(NULL); } + if (content->perm_r == NULL) { SUNLinSolFree(S); return(NULL); } - content->perm_c = NULL; content->perm_c = (sunindextype *) malloc(MatrixRows*sizeof(sunindextype)); - if (content->perm_c == NULL) { - free(content->perm_r); free(content); free(ops); free(S); return(NULL); } + if (content->perm_c == NULL) { SUNLinSolFree(S); return(NULL); } content->Gstat = (Gstat_t *) malloc(sizeof(Gstat_t)); - if (content->Gstat == NULL) { - free(content->perm_c); free(content->perm_r); free(content); free(ops); - free(S); return(NULL); } + if (content->Gstat == NULL) { SUNLinSolFree(S); return(NULL); } content->A = (SuperMatrix *) malloc(sizeof(SuperMatrix)); - if (content->A == NULL) { - free(content->Gstat); free(content->perm_c); free(content->perm_r); - free(content); free(ops); free(S); return(NULL); } + if (content->A == NULL) { SUNLinSolFree(S); return(NULL); } content->A->Store = NULL; content->AC = (SuperMatrix *) malloc(sizeof(SuperMatrix)); - if (content->AC == NULL) { - free(content->A); free(content->Gstat); free(content->perm_c); - free(content->perm_r); free(content); free(ops); free(S); return(NULL); } + if (content->AC == NULL) { SUNLinSolFree(S); return(NULL); } content->AC->Store = NULL; content->L = (SuperMatrix *) malloc(sizeof(SuperMatrix)); - if (content->L == NULL) { - free(content->AC); free(content->A); free(content->Gstat); free(content->perm_c); - free(content->perm_r); free(content); free(ops); free(S); return(NULL); } + if (content->L == NULL) { SUNLinSolFree(S); return(NULL); } content->L->Store = NULL; content->U = (SuperMatrix *) malloc(sizeof(SuperMatrix)); - if (content->U == NULL) { - free(content->L); free(content->AC); free(content->A); free(content->Gstat); - free(content->perm_c); free(content->perm_r); free(content); free(ops); free(S); - return(NULL); } + if (content->U == NULL) { SUNLinSolFree(S); return(NULL); } content->U->Store = NULL; content->B = (SuperMatrix *) malloc(sizeof(SuperMatrix)); - if (content->B == NULL) { - free(content->U); free(content->L); free(content->AC); free(content->A); - free(content->Gstat); free(content->perm_c); free(content->perm_r); free(content); - free(ops); free(S); return(NULL); } + if (content->B == NULL) { SUNLinSolFree(S); return(NULL); } content->B->Store = NULL; - xCreate_Dense_Matrix(content->B, MatrixRows, 1, NULL, MatrixRows, SLU_DN, SLU_D, SLU_GE); - + xCreate_Dense_Matrix(content->B, MatrixRows, 1, NULL, MatrixRows, SLU_DN, + SLU_D, SLU_GE); + content->options = (superlumt_options_t *) malloc(sizeof(superlumt_options_t)); - if (content->options == NULL) { - free(content->B); free(content->U); free(content->L); free(content->AC); - free(content->A); free(content->Gstat); free(content->perm_c); free(content->perm_r); - free(content); free(ops); free(S); return(NULL); } + if (content->options == NULL) { SUNLinSolFree(S); return(NULL); } StatAlloc(MatrixRows, num_threads, sp_ienv(1), sp_ienv(2), content->Gstat); - /* Attach content and ops */ - S->content = content; - S->ops = ops; - return(S); } @@ -208,7 +178,7 @@ SUNLinearSolver SUNLinSol_SuperLUMT(N_Vector y, SUNMatrix A, int num_threads) int SUNLinSol_SuperLUMTSetOrdering(SUNLinearSolver S, int ordering_choice) { - /* Check for legal ordering_choice */ + /* Check for legal ordering_choice */ if ((ordering_choice < 0) || (ordering_choice > 3)) return(SUNLS_ILL_INPUT); @@ -234,6 +204,12 @@ SUNLinearSolver_Type SUNLinSolGetType_SuperLUMT(SUNLinearSolver S) } +SUNLinearSolver_ID SUNLinSolGetID_SuperLUMT(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_SUPERLUMT); +} + + int SUNLinSolInitialize_SuperLUMT(SUNLinearSolver S) { /* force a first factorization */ @@ -241,7 +217,7 @@ int SUNLinSolInitialize_SuperLUMT(SUNLinearSolver S) /* Initialize statistics variables */ StatInit(SIZE(S), NUMTHREADS(S), GSTAT(S)); - + LASTFLAG(S) = SUNLS_SUCCESS; return(LASTFLAG(S)); } @@ -256,7 +232,7 @@ int SUNLinSolSetup_SuperLUMT(SUNLinearSolver S, SUNMatrix A) trans_t trans; yes_no_t refact, usepr; void *work; - + /* Set option values for SuperLU_MT */ panel_size = sp_ienv(1); relax = sp_ienv(2); @@ -270,15 +246,15 @@ int SUNLinSolSetup_SuperLUMT(SUNLinearSolver S, SUNMatrix A) /* free and reallocate sparse matrix */ if (SM_A(S)->Store) SUPERLU_FREE(SM_A(S)->Store); - xCreate_CompCol_Matrix(SM_A(S), SUNSparseMatrix_Rows(A), + xCreate_CompCol_Matrix(SM_A(S), SUNSparseMatrix_Rows(A), SUNSparseMatrix_Columns(A), - SUNSparseMatrix_NNZ(A), - SUNSparseMatrix_Data(A), - (int_t*) SUNSparseMatrix_IndexValues(A), - (int_t*) SUNSparseMatrix_IndexPointers(A), + SUNSparseMatrix_NNZ(A), + SUNSparseMatrix_Data(A), + (int_t*) SUNSparseMatrix_IndexValues(A), + (int_t*) SUNSparseMatrix_IndexPointers(A), SLU_NC, SLU_D, SLU_GE); - /* On first decomposition, set up reusable pieces */ + /* On first decomposition, set up reusable pieces */ if (FIRSTFACTORIZE(S)) { /* Get column permutation vector perm_c[], according to ordering */ @@ -289,17 +265,17 @@ int SUNLinSolSetup_SuperLUMT(SUNLinearSolver S, SUNMatrix A) } else { /* Re-initialize statistics variables */ - StatInit(SIZE(S), NUMTHREADS(S), GSTAT(S)); + StatInit(SIZE(S), NUMTHREADS(S), GSTAT(S)); Destroy_CompCol_Permuted(SM_AC(S)); refact = YES; - + } - /* Initialize the option structure using the user-input parameters. - Subsequent calls will re-initialize options. Apply perm_c to + /* Initialize the option structure using the user-input parameters. + Subsequent calls will re-initialize options. Apply perm_c to columns of original A to form AC */ - pxgstrf_init(NUMTHREADS(S), fact, trans, refact, panel_size, relax, - DIAGPIVOTTHRESH(S), usepr, drop_tol, (int_t *) PERMC(S), (int_t *) PERMR(S), + pxgstrf_init(NUMTHREADS(S), fact, trans, refact, panel_size, relax, + DIAGPIVOTTHRESH(S), usepr, drop_tol, (int_t *) PERMC(S), (int_t *) PERMR(S), work, lwork, SM_A(S), SM_AC(S), OPTIONS(S), GSTAT(S)); /* Compute the LU factorization of A. @@ -307,24 +283,24 @@ int SUNLinSolSetup_SuperLUMT(SUNLinearSolver S, SUNMatrix A) pxgstrf(OPTIONS(S), SM_AC(S), (int_t *) PERMR(S), SM_L(S), SM_U(S), GSTAT(S), &retval); if (retval != 0) { - LASTFLAG(S) = (retval < 0) ? + LASTFLAG(S) = (retval < 0) ? SUNLS_PACKAGE_FAIL_UNREC : SUNLS_PACKAGE_FAIL_REC; return(LASTFLAG(S)); } - + LASTFLAG(S) = SUNLS_SUCCESS; return(LASTFLAG(S)); } -int SUNLinSolSolve_SuperLUMT(SUNLinearSolver S, SUNMatrix A, N_Vector x, +int SUNLinSolSolve_SuperLUMT(SUNLinearSolver S, SUNMatrix A, N_Vector x, N_Vector b, realtype tol) { int_t retval; realtype *xdata; DNformat *Bstore; trans_t trans; - + /* copy b into x */ N_VScale(ONE, b, x); @@ -337,7 +313,7 @@ int SUNLinSolSolve_SuperLUMT(SUNLinearSolver S, SUNMatrix A, N_Vector x, Bstore = (DNformat *) (SM_B(S)->Store); Bstore->nzval = xdata; - + /* Call SuperLUMT to solve the linear system using L and U */ trans = (SUNSparseMatrix_SparseType(A) == CSC_MAT) ? NOTRANS : TRANS; xgstrs(trans, SM_L(S), SM_U(S), (int_t *) PERMR(S), (int_t *) PERMC(S), SM_B(S), GSTAT(S), &retval); @@ -345,24 +321,25 @@ int SUNLinSolSolve_SuperLUMT(SUNLinearSolver S, SUNMatrix A, N_Vector x, LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; return(LASTFLAG(S)); } - + LASTFLAG(S) = SUNLS_SUCCESS; return(LASTFLAG(S)); } -long int SUNLinSolLastFlag_SuperLUMT(SUNLinearSolver S) +sunindextype SUNLinSolLastFlag_SuperLUMT(SUNLinearSolver S) { /* return the stored 'last_flag' value */ + if (S == NULL) return(-1); return(LASTFLAG(S)); } -int SUNLinSolSpace_SuperLUMT(SUNLinearSolver S, - long int *lenrwLS, +int SUNLinSolSpace_SuperLUMT(SUNLinearSolver S, + long int *lenrwLS, long int *leniwLS) { - /* since the SuperLU_MT structures are opaque objects, we + /* since the SuperLU_MT structures are opaque objects, we omit those from these results */ *leniwLS = 5 + 2*SIZE(S); *lenrwLS = 1; @@ -372,60 +349,75 @@ int SUNLinSolSpace_SuperLUMT(SUNLinearSolver S, int SUNLinSolFree_SuperLUMT(SUNLinearSolver S) { /* return with success if already freed */ - if (S == NULL) - return(SUNLS_SUCCESS); - + if (S == NULL) return(SUNLS_SUCCESS); + /* delete items from the contents structure (if it exists) */ if (S->content) { - pxgstrf_finalize(OPTIONS(S), SM_AC(S)); - free(PERMR(S)); - free(PERMC(S)); - free(OPTIONS(S)); - Destroy_SuperNode_SCP(SM_L(S)); - Destroy_CompCol_NCP(SM_U(S)); - StatFree(GSTAT(S)); - free(GSTAT(S)); - - Destroy_SuperMatrix_Store(SM_B(S)); - SUPERLU_FREE(SM_A(S)->Store); - - free(SM_B(S)); - free(SM_A(S)); - free(SM_AC(S)); - free(SM_L(S)); - free(SM_U(S)); - - free(S->content); + if (OPTIONS(S) && SM_AC(S)) { + pxgstrf_finalize(OPTIONS(S), SM_AC(S)); + } + if (PERMR(S)) { + free(PERMR(S)); + PERMR(S) = NULL; + } + if (PERMC(S)) { + free(PERMC(S)); + PERMC(S) = NULL; + } + if (OPTIONS(S)) { + free(OPTIONS(S)); + OPTIONS(S) = NULL; + } + if (SM_L(S)) { + Destroy_SuperNode_SCP(SM_L(S)); + SM_L(S) = NULL; + } + if (SM_U(S)) { + Destroy_CompCol_NCP(SM_U(S)); + SM_U(S) = NULL; + } + if (GSTAT(S)) { + StatFree(GSTAT(S)); + free(GSTAT(S)); + GSTAT(S) = NULL; + } + if (SM_B(S)) { + Destroy_SuperMatrix_Store(SM_B(S)); + SM_B(S) = NULL; + } + if (SM_A(S)) { + if (SM_A(S)->Store) { + SUPERLU_FREE(SM_A(S)->Store); + SM_A(S)->Store = NULL; + } + free(SM_A(S)); + SM_A(S) = NULL; + } + if (SM_B(S)) { + free(SM_B(S)); + SM_B(S) = NULL; + } + if (SM_AC(S)) { + free(SM_AC(S)); + SM_AC(S) = NULL; + } + if (SM_L(S)) { + free(SM_L(S)); + SM_L(S) = NULL; + } + if (SM_U(S)) { + free(SM_U(S)); + SM_U(S) = NULL; + } + free(S->content); S->content = NULL; } - + /* delete generic structures */ if (S->ops) { - free(S->ops); + free(S->ops); S->ops = NULL; } free(S); S = NULL; return(SUNLS_SUCCESS); } - -/* - * ----------------------------------------------------------------- - * private functions - * ----------------------------------------------------------------- - */ - -/* Inefficient kludge for determining the number of entries in a N_Vector - object (replace if such a routine is ever added to the N_Vector API). - - Returns "-1" on an error. */ -sunindextype GlobalVectorLength_SuperLUMT(N_Vector y) -{ - realtype len; - N_Vector tmp = NULL; - tmp = N_VClone(y); - if (tmp == NULL) return(-1); - N_VConst(ONE, tmp); - len = N_VDotProd(tmp, tmp); - N_VDestroy(tmp); - return( (sunindextype) len ); -} diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/CMakeLists.txt index 31c51213a..934f8aceb 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/CMakeLists.txt @@ -2,7 +2,7 @@ # Programmer(s): Cody J. Balos @ LLNL # ------------------------------------------------------------------------------ # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -19,3 +19,12 @@ add_subdirectory(band) add_subdirectory(dense) add_subdirectory(sparse) +if(SUPERLUDIST_ENABLE AND SUPERLUDIST_FOUND) + add_subdirectory(slunrloc) +endif(SUPERLUDIST_ENABLE AND SUPERLUDIST_FOUND) + +if(CUDA_ENABLE AND CMAKE_CUDA_COMPILER) + if(SUNDIALS_INDEX_SIZE MATCHES "32") + add_subdirectory(cusparse) + endif() +endif(CUDA_ENABLE AND CMAKE_CUDA_COMPILER) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/CMakeLists.txt index cc77429a4..893173a2f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU +# Programmer(s): Daniel R. Reynolds @ SMU # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,94 +12,95 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the band SUNMatrix library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNMATRIX_BAND\n\")") +install(CODE "MESSAGE(\"\nInstall SUNMATRIX_BAND\n\")") # Add variable sunmatrixband_SOURCES with the sources for the SUNMATRIXBAND lib -SET(sunmatrixband_SOURCES sunmatrix_band.c) +set(sunmatrixband_SOURCES sunmatrix_band.c) # Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF(F90_FOUND AND F2003_INTERFACE_ENABLE) +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the SUNMATRIXBAND library -SET(shared_SOURCES +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_matrix.c ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c ) # Add variable sunmatrixband_HEADERS with the exported SUNMATRIXBAND header files -SET(sunmatrixband_HEADERS +set(sunmatrixband_HEADERS ${sundials_SOURCE_DIR}/include/sunmatrix/sunmatrix_band.h ) # Add source directory to include directories -INCLUDE_DIRECTORIES(.) +include_directories(.) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) # Rules for building and installing the static library: # - Add the build target for the SUNMATRIXBAND library # - Set the library name and make sure it is not deleted # - Install the SUNMATRIXBAND library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunmatrixband_static STATIC ${sunmatrixband_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunmatrixband_static +if(BUILD_STATIC_LIBS) + add_library(sundials_sunmatrixband_static STATIC ${sunmatrixband_SOURCES} ${shared_SOURCES}) + set_target_properties(sundials_sunmatrixband_static PROPERTIES OUTPUT_NAME sundials_sunmatrixband CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunmatrixband_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) + install(TARGETS sundials_sunmatrixband_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: # - Add the build target for the SUNMATRIXBAND library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries # - Install the SUNMATRIXBAND library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunmatrixband_shared SHARED ${sunmatrixband_SOURCES} ${shared_SOURCES}) +if(BUILD_SHARED_LIBS) + add_library(sundials_sunmatrixband_shared SHARED ${sunmatrixband_SOURCES} ${shared_SOURCES}) - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_sunmatrixband_shared m) - ENDIF() + if(UNIX) + target_link_libraries(sundials_sunmatrixband_shared m) + endif() - SET_TARGET_PROPERTIES(sundials_sunmatrixband_shared + set_target_properties(sundials_sunmatrixband_shared PROPERTIES OUTPUT_NAME sundials_sunmatrixband CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunmatrixband_shared + set_target_properties(sundials_sunmatrixband_shared PROPERTIES VERSION ${sunmatrixlib_VERSION} SOVERSION ${sunmatrixlib_SOVERSION}) - INSTALL(TARGETS sundials_sunmatrixband_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) + install(TARGETS sundials_sunmatrixband_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_SHARED_LIBS) # Install the SUNMATRIXBAND header files -INSTALL(FILES ${sunmatrixband_HEADERS} DESTINATION include/sunmatrix) +install(FILES ${sunmatrixband_HEADERS} DESTINATION include/sunmatrix) # If FCMIX is enabled, build and install the FSUNMATRIXBAND library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunmatrixband_SOURCES fsunmatrix_band.c) +if(F77_INTERFACE_ENABLE AND F77_FOUND) + set(fsunmatrixband_SOURCES fsunmatrix_band.c) - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunmatrixband_static STATIC ${fsunmatrixband_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunmatrixband_static + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunmatrixband_static STATIC ${fsunmatrixband_SOURCES}) + set_target_properties(sundials_fsunmatrixband_static PROPERTIES OUTPUT_NAME sundials_fsunmatrixband CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunmatrixband_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) + install(TARGETS sundials_fsunmatrixband_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunmatrixband_shared ${fsunmatrixband_SOURCES}) + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunmatrixband_shared ${fsunmatrixband_SOURCES}) # fsunmatrixband depends on sunmatrixband - TARGET_LINK_LIBRARIES(sundials_fsunmatrixband_shared sundials_sunmatrixband_shared) + target_link_libraries(sundials_fsunmatrixband_shared sundials_sunmatrixband_shared) - SET_TARGET_PROPERTIES(sundials_fsunmatrixband_shared + set_target_properties(sundials_fsunmatrixband_shared PROPERTIES OUTPUT_NAME sundials_fsunmatrixband CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunmatrixband_shared + set_target_properties(sundials_fsunmatrixband_shared PROPERTIES VERSION ${sunmatrixlib_VERSION} SOVERSION ${sunmatrixlib_SOVERSION}) - INSTALL(TARGETS sundials_fsunmatrixband_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + install(TARGETS sundials_fsunmatrixband_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(F77_INTERFACE_ENABLE AND F77_FOUND) # -MESSAGE(STATUS "Added SUNMATRIX_BAND module") +message(STATUS "Added SUNMATRIX_BAND module") diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/F90/fsunmatrix_band.f90 b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/F90/fsunmatrix_band.f90 deleted file mode 100644 index b96a71bb5..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/F90/fsunmatrix_band.f90 +++ /dev/null @@ -1,222 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): David J. Gardner @ LLNL -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS band matrix using the ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fsunmatrix_band_mod - - !======= Interfaces ========= - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - type(c_ptr) function FSUNBandMatrix(N, mu, ml, smu) & - bind(C,name='SUNBandMatrix') - use, intrinsic :: iso_c_binding - implicit none - integer(c_long), value :: N - integer(c_long), value :: mu - integer(c_long), value :: ml - integer(c_long), value :: smu - end function FSUNBandMatrix - - ! ================================================================= - ! Destructors - ! ================================================================= - - subroutine FSUNMatDestroy_Band(A) & - bind(C,name='SUNMatDestroy_Band') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end subroutine FSUNMatDestroy_Band - - ! ================================================================= - ! Other routines - ! ================================================================= - - ! ----------------------------------------------------------------- - ! NOT INTERFACED SUNBandMatrix_Print - ! ----------------------------------------------------------------- - - integer(c_long) function FSUNBandMatrix_Rows(A) & - bind(C,name='SUNBandMatrix_Rows') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNBandMatrix_Rows - - integer(c_long) function FSUNBandMatrix_Columns(A) & - bind(C,name='SUNBandMatrix_Columns') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNBandMatrix_Columns - - integer(c_long) function FSUNBandMatrix_LowerBandwidth(A) & - bind(C,name='SUNBandMatrix_LowerBandwidth') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNBandMatrix_LowerBandwidth - - integer(c_long) function FSUNBandMatrix_UpperBandwidth(A) & - bind(C,name='SUNBandMatrix_UpperBandwidth') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNBandMatrix_UpperBandwidth - - integer(c_long) function FSUNBandMatrix_StoredUpperBandwidth(A) & - bind(C,name='SUNBandMatrix_StoredUpperBandwidth') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNBandMatrix_StoredUpperBandwidth - - integer(c_long) function FSUNBandMatrix_LDim(A) & - bind(C,name='SUNBandMatrix_LDim') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNBandMatrix_LDim - - type(c_ptr) function FSUNBandMatrix_Data(A) & - bind(C,name='SUNBandMatrix_Data') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNBandMatrix_Data - - ! ----------------------------------------------------------------- - ! NOT INTERFACED SUNBandMatrix_Cols - ! ----------------------------------------------------------------- - - type(c_ptr) function FSUNBandMatrix_Column(A, j) & - bind(C,name='SUNBandMatrix_Column') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - integer(c_long), value :: j - end function FSUNBandMatrix_Column - - ! ================================================================= - ! Operations - ! ================================================================= - - integer(c_int) function FSUNMatGetID_Band(A) & - bind(C,name='SUNMatGetID_Band') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNMatGetID_Band - - type(c_ptr) function FSUNMatClone_Band(A) & - bind(C,name='SUNMatClone_Band') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNMatClone_Band - - integer(c_int) function FSUNMatZero_Band(A) & - bind(C,name='SUNMatZero_Band') - use, intrinsic :: iso_c_binding - type(c_ptr), value :: A - end function FSUNMatZero_Band - - integer(c_int) function FSUNMatCopy_Band(A, B) & - bind(C,name='SUNMatCopy_Band') - use, intrinsic :: iso_c_binding - type(c_ptr), value :: A - type(c_ptr), value :: B - end function FSUNMatCopy_Band - - integer(c_int) function FSUNMatScaleAdd_Band(c, A, B) & - bind(C,name='SUNMatScaleAdd_Band') - use, intrinsic :: iso_c_binding - real(c_double), value :: c - type(c_ptr), value :: A - type(c_ptr), value :: B - end function FSUNMatScaleAdd_Band - - integer(c_int) function FSUNMatScaleAddI_Band(c, A) & - bind(C,name='SUNMatScaleAddI_Band') - use, intrinsic :: iso_c_binding - real(c_double), value :: c - type(c_ptr), value :: A - end function FSUNMatScaleAddI_Band - - integer(c_int) function FSUNMatMatvec_Band(A, x, y) & - bind(C,name='SUNMatMatvec_Band') - use, intrinsic :: iso_c_binding - type(c_ptr), value :: A - type(c_ptr), value :: x - type(c_ptr), value :: y - end function FSUNMatMatvec_Band - - integer(c_int) function FSUNMatSpace_Band(A, lenrw, leniw) & - bind(C,name='SUNMatSpace_Band') - use, intrinsic :: iso_c_binding - type(c_ptr), value :: A - integer(c_long) :: lenrw - integer(c_long) :: leniw - end function FSUNMatSpace_Band - - end interface - -contains - - ! ================================================================ - ! Helpful routines - ! ================================================================ - - ! ---------------------------------------------------------------- - ! FSUNMatGetData_Band - ! - ! Extracts data array from a SUNDIALS Band Matrix - ! ---------------------------------------------------------------- - - subroutine FSUNMatGetData_Band(A, f_array) - - !======= Inclusions =========== - use, intrinsic :: iso_c_binding - - !======= Declarations ========= - implicit none - - ! calling variables - type(c_ptr) :: A - real(c_double), pointer :: f_array(:) - - ! internal variables - type(c_ptr) :: c_array - integer(c_long) :: ldim - - !======= Internals ============ - - ! get data pointer from N_Vector - c_array = FSUNBandMatrix_Data(A) - - ! get length of the data array - ldim = FSUNBandMatrix_LDim(A) - - ! convert 1D data array - call c_f_pointer(c_array, f_array, (/ldim/)) - - end subroutine FSUNMatGetData_Band - -end module fsunmatrix_band_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fmod/CMakeLists.txt similarity index 75% rename from deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/F90/CMakeLists.txt rename to deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fmod/CMakeLists.txt index 81c5ac603..40fb51f9a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/F90/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fmod/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Cody J. Balos @ LLNL +# Programmer(s): Cody J. Balos @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,22 +12,25 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the F2003 band SUNMatrix object library +# --------------------------------------------------------------- -set(sunmatrixband_SOURCES fsunmatrix_band.f90) +set(sunmatrixband_SOURCES fsunmatrix_band_mod.f90 fsunmatrix_band_mod.c) if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fsunmatrixband_mod_static STATIC + sundials_add_f2003_interface_library(sundials_fsunmatrixband_mod_static STATIC_OBJECT ${sunmatrixband_SOURCES} ) + add_dependencies(sundials_fsunmatrixband_mod_static_obj sundials_fgeneric_static_obj) set_target_properties(sundials_fsunmatrixband_mod_static PROPERTIES OUTPUT_NAME sundials_fsunmatrixband_mod CLEAN_DIRECT_OUTPUT 1) install(TARGETS sundials_fsunmatrixband_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif(BUILD_STATIC_LIBS) if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fsunmatrixband_mod_shared SHARED + sundials_add_f2003_interface_library(sundials_fsunmatrixband_mod_shared SHARED_OBJECT ${sunmatrixband_SOURCES} ) + add_dependencies(sundials_fsunmatrixband_mod_shared_obj sundials_fgeneric_shared_obj) set_target_properties(sundials_fsunmatrixband_mod_shared PROPERTIES OUTPUT_NAME sundials_fsunmatrixband_mod CLEAN_DIRECT_OUTPUT 1) set_target_properties(sundials_fsunmatrixband_mod_shared diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fmod/fsunmatrix_band_mod.c b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fmod/fsunmatrix_band_mod.c new file mode 100644 index 000000000..95223729c --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fmod/fsunmatrix_band_mod.c @@ -0,0 +1,485 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_matrix.h" + + +#include "sunmatrix/sunmatrix_band.h" + +SWIGEXPORT SUNMatrix _wrap_FSUNBandMatrix(int64_t const *farg1, int64_t const *farg2, int64_t const *farg3) { + SUNMatrix fresult ; + sunindextype arg1 ; + sunindextype arg2 ; + sunindextype arg3 ; + SUNMatrix result; + + arg1 = (sunindextype)(*farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + result = (SUNMatrix)SUNBandMatrix(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT SUNMatrix _wrap_FSUNBandMatrixStorage(int64_t const *farg1, int64_t const *farg2, int64_t const *farg3, int64_t const *farg4) { + SUNMatrix fresult ; + sunindextype arg1 ; + sunindextype arg2 ; + sunindextype arg3 ; + sunindextype arg4 ; + SUNMatrix result; + + arg1 = (sunindextype)(*farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (sunindextype)(*farg4); + result = (SUNMatrix)SUNBandMatrixStorage(arg1,arg2,arg3,arg4); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FSUNBandMatrix_Print(SUNMatrix farg1, void *farg2) { + SUNMatrix arg1 = (SUNMatrix) 0 ; + FILE *arg2 = (FILE *) 0 ; + + arg1 = (SUNMatrix)(farg1); + arg2 = (FILE *)(farg2); + SUNBandMatrix_Print(arg1,arg2); +} + + +SWIGEXPORT int64_t _wrap_FSUNBandMatrix_Rows(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNBandMatrix_Rows(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNBandMatrix_Columns(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNBandMatrix_Columns(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNBandMatrix_LowerBandwidth(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNBandMatrix_LowerBandwidth(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNBandMatrix_UpperBandwidth(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNBandMatrix_UpperBandwidth(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNBandMatrix_StoredUpperBandwidth(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNBandMatrix_StoredUpperBandwidth(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNBandMatrix_LDim(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNBandMatrix_LDim(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT double * _wrap_FSUNBandMatrix_Data(SUNMatrix farg1) { + double * fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + realtype *result = 0 ; + + arg1 = (SUNMatrix)(farg1); + result = (realtype *)SUNBandMatrix_Data(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FSUNBandMatrix_Cols(SUNMatrix farg1) { + void * fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + realtype **result = 0 ; + + arg1 = (SUNMatrix)(farg1); + result = (realtype **)SUNBandMatrix_Cols(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT double * _wrap_FSUNBandMatrix_Column(SUNMatrix farg1, int64_t const *farg2) { + double * fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype arg2 ; + realtype *result = 0 ; + + arg1 = (SUNMatrix)(farg1); + arg2 = (sunindextype)(*farg2); + result = (realtype *)SUNBandMatrix_Column(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatGetID_Band(SUNMatrix farg1) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix_ID result; + + arg1 = (SUNMatrix)(farg1); + result = (SUNMatrix_ID)SUNMatGetID_Band(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SUNMatrix _wrap_FSUNMatClone_Band(SUNMatrix farg1) { + SUNMatrix fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix result; + + arg1 = (SUNMatrix)(farg1); + result = (SUNMatrix)SUNMatClone_Band(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FSUNMatDestroy_Band(SUNMatrix farg1) { + SUNMatrix arg1 = (SUNMatrix) 0 ; + + arg1 = (SUNMatrix)(farg1); + SUNMatDestroy_Band(arg1); +} + + +SWIGEXPORT int _wrap_FSUNMatZero_Band(SUNMatrix farg1) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + result = (int)SUNMatZero_Band(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatCopy_Band(SUNMatrix farg1, SUNMatrix farg2) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNMatCopy_Band(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatScaleAdd_Band(double const *farg1, SUNMatrix farg2, SUNMatrix farg3) { + int fresult ; + realtype arg1 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + SUNMatrix arg3 = (SUNMatrix) 0 ; + int result; + + arg1 = (realtype)(*farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (SUNMatrix)(farg3); + result = (int)SUNMatScaleAdd_Band(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatScaleAddI_Band(double const *farg1, SUNMatrix farg2) { + int fresult ; + realtype arg1 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (realtype)(*farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNMatScaleAddI_Band(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatMatvec_Band(SUNMatrix farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)SUNMatMatvec_Band(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatSpace_Band(SUNMatrix farg1, long *farg2, long *farg3) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNMatSpace_Band(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fmod/fsunmatrix_band_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fmod/fsunmatrix_band_mod.f90 new file mode 100644 index 000000000..d0691362d --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fmod/fsunmatrix_band_mod.f90 @@ -0,0 +1,550 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunmatrix_band_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_matrix_mod + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FSUNBandMatrix + public :: FSUNBandMatrixStorage + public :: FSUNBandMatrix_Print + public :: FSUNBandMatrix_Rows + public :: FSUNBandMatrix_Columns + public :: FSUNBandMatrix_LowerBandwidth + public :: FSUNBandMatrix_UpperBandwidth + public :: FSUNBandMatrix_StoredUpperBandwidth + public :: FSUNBandMatrix_LDim + public :: FSUNBandMatrix_Data + public :: FSUNBandMatrix_Cols + public :: FSUNBandMatrix_Column + public :: FSUNMatGetID_Band + public :: FSUNMatClone_Band + public :: FSUNMatDestroy_Band + public :: FSUNMatZero_Band + public :: FSUNMatCopy_Band + public :: FSUNMatScaleAdd_Band + public :: FSUNMatScaleAddI_Band + public :: FSUNMatMatvec_Band + public :: FSUNMatSpace_Band + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNBandMatrix(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNBandMatrix") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNBandMatrixStorage(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FSUNBandMatrixStorage") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT64_T), intent(in) :: farg4 +type(C_PTR) :: fresult +end function + +subroutine swigc_FSUNBandMatrix_Print(farg1, farg2) & +bind(C, name="_wrap_FSUNBandMatrix_Print") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_FSUNBandMatrix_Rows(farg1) & +bind(C, name="_wrap_FSUNBandMatrix_Rows") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNBandMatrix_Columns(farg1) & +bind(C, name="_wrap_FSUNBandMatrix_Columns") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNBandMatrix_LowerBandwidth(farg1) & +bind(C, name="_wrap_FSUNBandMatrix_LowerBandwidth") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNBandMatrix_UpperBandwidth(farg1) & +bind(C, name="_wrap_FSUNBandMatrix_UpperBandwidth") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNBandMatrix_StoredUpperBandwidth(farg1) & +bind(C, name="_wrap_FSUNBandMatrix_StoredUpperBandwidth") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNBandMatrix_LDim(farg1) & +bind(C, name="_wrap_FSUNBandMatrix_LDim") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNBandMatrix_Data(farg1) & +bind(C, name="_wrap_FSUNBandMatrix_Data") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNBandMatrix_Cols(farg1) & +bind(C, name="_wrap_FSUNBandMatrix_Cols") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNBandMatrix_Column(farg1, farg2) & +bind(C, name="_wrap_FSUNBandMatrix_Column") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FSUNMatGetID_Band(farg1) & +bind(C, name="_wrap_FSUNMatGetID_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatClone_Band(farg1) & +bind(C, name="_wrap_FSUNMatClone_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FSUNMatDestroy_Band(farg1) & +bind(C, name="_wrap_FSUNMatDestroy_Band") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FSUNMatZero_Band(farg1) & +bind(C, name="_wrap_FSUNMatZero_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatCopy_Band(farg1, farg2) & +bind(C, name="_wrap_FSUNMatCopy_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatScaleAdd_Band(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNMatScaleAdd_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatScaleAddI_Band(farg1, farg2) & +bind(C, name="_wrap_FSUNMatScaleAddI_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatMatvec_Band(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNMatMatvec_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatSpace_Band(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNMatSpace_Band") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNBandMatrix(n, mu, ml) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), pointer :: swig_result +integer(C_INT64_T), intent(in) :: n +integer(C_INT64_T), intent(in) :: mu +integer(C_INT64_T), intent(in) :: ml +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 + +farg1 = n +farg2 = mu +farg3 = ml +fresult = swigc_FSUNBandMatrix(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNBandMatrixStorage(n, mu, ml, smu) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), pointer :: swig_result +integer(C_INT64_T), intent(in) :: n +integer(C_INT64_T), intent(in) :: mu +integer(C_INT64_T), intent(in) :: ml +integer(C_INT64_T), intent(in) :: smu +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT64_T) :: farg4 + +farg1 = n +farg2 = mu +farg3 = ml +farg4 = smu +fresult = swigc_FSUNBandMatrixStorage(farg1, farg2, farg3, farg4) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FSUNBandMatrix_Print(a, outfile) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: outfile +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(a) +farg2 = outfile +call swigc_FSUNBandMatrix_Print(farg1, farg2) +end subroutine + +function FSUNBandMatrix_Rows(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNBandMatrix_Rows(farg1) +swig_result = fresult +end function + +function FSUNBandMatrix_Columns(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNBandMatrix_Columns(farg1) +swig_result = fresult +end function + +function FSUNBandMatrix_LowerBandwidth(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNBandMatrix_LowerBandwidth(farg1) +swig_result = fresult +end function + +function FSUNBandMatrix_UpperBandwidth(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNBandMatrix_UpperBandwidth(farg1) +swig_result = fresult +end function + +function FSUNBandMatrix_StoredUpperBandwidth(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNBandMatrix_StoredUpperBandwidth(farg1) +swig_result = fresult +end function + +function FSUNBandMatrix_LDim(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNBandMatrix_LDim(farg1) +swig_result = fresult +end function + +function FSUNBandMatrix_Data(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNBandMatrix_Data(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +function FSUNBandMatrix_Cols(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNBandMatrix_Cols(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNBandMatrix_Column(a, j) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T), intent(in) :: j +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 + +farg1 = c_loc(a) +farg2 = j +fresult = swigc_FSUNBandMatrix_Column(farg1, farg2) +call c_f_pointer(fresult, swig_result, [1]) +end function + +function FSUNMatGetID_Band(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNMatrix_ID) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatGetID_Band(farg1) +swig_result = fresult +end function + +function FSUNMatClone_Band(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatClone_Band(farg1) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FSUNMatDestroy_Band(a) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +call swigc_FSUNMatDestroy_Band(farg1) +end subroutine + +function FSUNMatZero_Band(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatZero_Band(farg1) +swig_result = fresult +end function + +function FSUNMatCopy_Band(a, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(SUNMatrix), target, intent(inout) :: b +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(a) +farg2 = c_loc(b) +fresult = swigc_FSUNMatCopy_Band(farg1, farg2) +swig_result = fresult +end function + +function FSUNMatScaleAdd_Band(c, a, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +real(C_DOUBLE), intent(in) :: c +type(SUNMatrix), target, intent(inout) :: a +type(SUNMatrix), target, intent(inout) :: b +integer(C_INT) :: fresult +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(a) +farg3 = c_loc(b) +fresult = swigc_FSUNMatScaleAdd_Band(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNMatScaleAddI_Band(c, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +real(C_DOUBLE), intent(in) :: c +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c +farg2 = c_loc(a) +fresult = swigc_FSUNMatScaleAddI_Band(farg1, farg2) +swig_result = fresult +end function + +function FSUNMatMatvec_Band(a, x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(a) +farg2 = c_loc(x) +farg3 = c_loc(y) +fresult = swigc_FSUNMatMatvec_Band(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNMatSpace_Band(a, lenrw, leniw) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_LONG), dimension(*), target, intent(inout) :: lenrw +integer(C_LONG), dimension(*), target, intent(inout) :: leniw +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(a) +farg2 = c_loc(lenrw(1)) +farg3 = c_loc(leniw(1)) +fresult = swigc_FSUNMatSpace_Band(farg1, farg2, farg3) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.c b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.c index 5f2b010e0..a15a31c59 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -33,7 +33,7 @@ SUNMatrix F2C_ARKODE_mass_matrix; /* Fortran callable interfaces */ -void FSUNBANDMAT_INIT(int *code, long int *N, long int *mu, +void FSUNBANDMAT_INIT(int *code, long int *N, long int *mu, long int *ml, int *ier) { *ier = 0; @@ -42,25 +42,33 @@ void FSUNBANDMAT_INIT(int *code, long int *N, long int *mu, case FCMIX_CVODE: if (F2C_CVODE_matrix) SUNMatDestroy(F2C_CVODE_matrix); F2C_CVODE_matrix = NULL; - F2C_CVODE_matrix = SUNBandMatrix(*N, *mu, *ml); + F2C_CVODE_matrix = SUNBandMatrix((sunindextype)(*N), + (sunindextype)(*mu), + (sunindextype)(*ml)); if (F2C_CVODE_matrix == NULL) *ier = -1; break; case FCMIX_IDA: if (F2C_IDA_matrix) SUNMatDestroy(F2C_IDA_matrix); F2C_IDA_matrix = NULL; - F2C_IDA_matrix = SUNBandMatrix(*N, *mu, *ml); + F2C_IDA_matrix = SUNBandMatrix((sunindextype)(*N), + (sunindextype)(*mu), + (sunindextype)(*ml)); if (F2C_IDA_matrix == NULL) *ier = -1; break; case FCMIX_KINSOL: if (F2C_KINSOL_matrix) SUNMatDestroy(F2C_KINSOL_matrix); F2C_KINSOL_matrix = NULL; - F2C_KINSOL_matrix = SUNBandMatrix(*N, *mu, *ml); + F2C_KINSOL_matrix = SUNBandMatrix((sunindextype)(*N), + (sunindextype)(*mu), + (sunindextype)(*ml)); if (F2C_KINSOL_matrix == NULL) *ier = -1; break; case FCMIX_ARKODE: if (F2C_ARKODE_matrix) SUNMatDestroy(F2C_ARKODE_matrix); F2C_ARKODE_matrix = NULL; - F2C_ARKODE_matrix = SUNBandMatrix(*N, *mu, *ml); + F2C_ARKODE_matrix = SUNBandMatrix((sunindextype)(*N), + (sunindextype)(*mu), + (sunindextype)(*ml)); if (F2C_ARKODE_matrix == NULL) *ier = -1; break; default: @@ -69,12 +77,14 @@ void FSUNBANDMAT_INIT(int *code, long int *N, long int *mu, } -void FSUNBANDMASSMAT_INIT(long int *N, long int *mu, +void FSUNBANDMASSMAT_INIT(long int *N, long int *mu, long int *ml, int *ier) { *ier = 0; if (F2C_ARKODE_mass_matrix) SUNMatDestroy(F2C_ARKODE_mass_matrix); F2C_ARKODE_mass_matrix = NULL; - F2C_ARKODE_mass_matrix = SUNBandMatrix(*N, *mu, *ml); + F2C_ARKODE_mass_matrix = SUNBandMatrix((sunindextype)(*N), + (sunindextype)(*mu), + (sunindextype)(*ml)); if (F2C_ARKODE_mass_matrix == NULL) *ier = -1; } diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.h b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.h index b9276c32a..18d912807 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/sunmatrix_band.c b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/sunmatrix_band.c index 267f8a384..b6d902104 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/sunmatrix_band.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/band/sunmatrix_band.c @@ -6,7 +6,7 @@ * Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -59,64 +59,56 @@ SUNMatrix SUNBandMatrixStorage(sunindextype N, sunindextype mu, sunindextype ml, sunindextype smu) { SUNMatrix A; - SUNMatrix_Ops ops; SUNMatrixContent_Band content; sunindextype j, colSize; /* return with NULL matrix on illegal dimension input */ if ( (N <= 0) || (smu < 0) || (ml < 0) ) return(NULL); - /* Create matrix */ + /* Create an empty matrix object */ A = NULL; - A = (SUNMatrix) malloc(sizeof *A); + A = SUNMatNewEmpty(); if (A == NULL) return(NULL); - - /* Create matrix operation structure */ - ops = NULL; - ops = (SUNMatrix_Ops) malloc(sizeof(struct _generic_SUNMatrix_Ops)); - if (ops == NULL) { free(A); return(NULL); } /* Attach operations */ - ops->getid = SUNMatGetID_Band; - ops->clone = SUNMatClone_Band; - ops->destroy = SUNMatDestroy_Band; - ops->zero = SUNMatZero_Band; - ops->copy = SUNMatCopy_Band; - ops->scaleadd = SUNMatScaleAdd_Band; - ops->scaleaddi = SUNMatScaleAddI_Band; - ops->matvec = SUNMatMatvec_Band; - ops->space = SUNMatSpace_Band; + A->ops->getid = SUNMatGetID_Band; + A->ops->clone = SUNMatClone_Band; + A->ops->destroy = SUNMatDestroy_Band; + A->ops->zero = SUNMatZero_Band; + A->ops->copy = SUNMatCopy_Band; + A->ops->scaleadd = SUNMatScaleAdd_Band; + A->ops->scaleaddi = SUNMatScaleAddI_Band; + A->ops->matvec = SUNMatMatvec_Band; + A->ops->space = SUNMatSpace_Band; /* Create content */ content = NULL; - content = (SUNMatrixContent_Band) malloc(sizeof(struct _SUNMatrixContent_Band)); - if (content == NULL) { free(ops); free(A); return(NULL); } + content = (SUNMatrixContent_Band) malloc(sizeof *content); + if (content == NULL) { SUNMatDestroy(A); return(NULL); } + + /* Attach content */ + A->content = content; /* Fill content */ - colSize = smu + ml + 1; - content->M = N; - content->N = N; - content->mu = mu; - content->ml = ml; - content->s_mu = smu; - content->ldim = colSize; + colSize = smu + ml + 1; + content->M = N; + content->N = N; + content->mu = mu; + content->ml = ml; + content->s_mu = smu; + content->ldim = colSize; content->ldata = N * colSize; - content->data = NULL; + content->data = NULL; + content->cols = NULL; + + /* Allocate content */ content->data = (realtype *) calloc(N * colSize, sizeof(realtype)); - if (content->data == NULL) { - free(content); free(ops); free(A); return(NULL); - } - content->cols = NULL; + if (content->data == NULL) { SUNMatDestroy(A); return(NULL); } + content->cols = (realtype **) malloc(N * sizeof(realtype *)); - if (content->cols == NULL) { - free(content->data); free(content); free(ops); free(A); return(NULL); - } + if (content->cols == NULL) { SUNMatDestroy(A); return(NULL); } for (j=0; jcols[j] = content->data + j * colSize; - /* Attach content and ops */ - A->content = content; - A->ops = ops; - return(A); } @@ -164,7 +156,7 @@ sunindextype SUNBandMatrix_Rows(SUNMatrix A) if (SUNMatGetID(A) == SUNMATRIX_BAND) return SM_ROWS_B(A); else - return -1; + return SUNMAT_ILL_INPUT; } sunindextype SUNBandMatrix_Columns(SUNMatrix A) @@ -172,7 +164,7 @@ sunindextype SUNBandMatrix_Columns(SUNMatrix A) if (SUNMatGetID(A) == SUNMATRIX_BAND) return SM_COLUMNS_B(A); else - return -1; + return SUNMAT_ILL_INPUT; } sunindextype SUNBandMatrix_LowerBandwidth(SUNMatrix A) @@ -180,7 +172,7 @@ sunindextype SUNBandMatrix_LowerBandwidth(SUNMatrix A) if (SUNMatGetID(A) == SUNMATRIX_BAND) return SM_LBAND_B(A); else - return -1; + return SUNMAT_ILL_INPUT; } sunindextype SUNBandMatrix_UpperBandwidth(SUNMatrix A) @@ -188,7 +180,7 @@ sunindextype SUNBandMatrix_UpperBandwidth(SUNMatrix A) if (SUNMatGetID(A) == SUNMATRIX_BAND) return SM_UBAND_B(A); else - return -1; + return SUNMAT_ILL_INPUT; } sunindextype SUNBandMatrix_StoredUpperBandwidth(SUNMatrix A) @@ -196,7 +188,7 @@ sunindextype SUNBandMatrix_StoredUpperBandwidth(SUNMatrix A) if (SUNMatGetID(A) == SUNMATRIX_BAND) return SM_SUBAND_B(A); else - return -1; + return SUNMAT_ILL_INPUT; } sunindextype SUNBandMatrix_LDim(SUNMatrix A) @@ -204,7 +196,7 @@ sunindextype SUNBandMatrix_LDim(SUNMatrix A) if (SUNMatGetID(A) == SUNMATRIX_BAND) return SM_LDIM_B(A); else - return -1; + return SUNMAT_ILL_INPUT; } realtype* SUNBandMatrix_Data(SUNMatrix A) @@ -251,20 +243,29 @@ SUNMatrix SUNMatClone_Band(SUNMatrix A) void SUNMatDestroy_Band(SUNMatrix A) { - if (A == NULL) return; - if (A->ops) free(A->ops); - A->ops = NULL; - if (A->content == NULL) { - free(A); A = NULL; - return; + if (A == NULL) return; + + /* free content */ + if (A->content != NULL) { + /* free data array */ + if (SM_DATA_B(A)) { + free(SM_DATA_B(A)); + SM_DATA_B(A) = NULL; + } + /* free column pointers */ + if (SM_COLS_B(A)) { + free(SM_COLS_B(A)); + SM_COLS_B(A) = NULL; + } + /* free content struct */ + free(A->content); + A->content = NULL; } - if (SM_DATA_B(A)) free(SM_DATA_B(A)); - SM_DATA_B(A) = NULL; - if (SM_COLS_B(A)) free(SM_COLS_B(A)); - SM_COLS_B(A) = NULL; - if (A->content) free(A->content); - A->content = NULL; + + /* free ops and matrix */ + if (A->ops) { free(A->ops); A->ops = NULL; } free(A); A = NULL; + return; } @@ -275,13 +276,13 @@ int SUNMatZero_Band(SUNMatrix A) /* Verify that A is a band matrix */ if (SUNMatGetID(A) != SUNMATRIX_BAND) - return 1; + return SUNMAT_ILL_INPUT; /* Perform operation */ Adata = SM_DATA_B(A); for (i=0; i SM_UBAND_B(B)) || @@ -312,15 +313,15 @@ int SUNMatCopy_Band(SUNMatrix A, SUNMatrix B) } /* Perform operation */ - if (SUNMatZero_Band(B) != 0) - return 1; + if (SUNMatZero_Band(B) != SUNMAT_SUCCESS) + return SUNMAT_OPERATION_FAIL; for (j=0; j SM_UBAND_B(A)) || @@ -364,7 +365,7 @@ int SUNMatScaleAdd_Band(realtype c, SUNMatrix A, SUNMatrix B) for (i=-SM_UBAND_B(B); i<=SM_LBAND_B(B); i++) A_colj[i] = c*A_colj[i] + B_colj[i]; } - return 0; + return SUNMAT_SUCCESS; } int SUNMatMatvec_Band(SUNMatrix A, N_Vector x, N_Vector y) @@ -374,13 +375,13 @@ int SUNMatMatvec_Band(SUNMatrix A, N_Vector x, N_Vector y) /* Verify that A, x and y are compatible */ if (!SMCompatible2_Band(A, x, y)) - return 1; + return SUNMAT_ILL_INPUT; /* access vector data (return if failure) */ xd = N_VGetArrayPointer(x); yd = N_VGetArrayPointer(y); if ((xd == NULL) || (yd == NULL) || (xd == yd)) - return 1; + return SUNMAT_MEM_FAIL; /* Perform operation */ for (i=0; icontent = NULL; SUNMatDestroy_Band(C); - return 0; + return SUNMAT_SUCCESS; } diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/cusparse/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/cusparse/CMakeLists.txt new file mode 100644 index 000000000..c78986c13 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/cusparse/CMakeLists.txt @@ -0,0 +1,75 @@ +# --------------------------------------------------------------- +# Programmer(s): Cody J. Balos @ LLNL +# --------------------------------------------------------------- +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# --------------------------------------------------------------- +# CMakeLists.txt file for the CUDA cuSPARSE SUNMatrix +# --------------------------------------------------------------- + +install(CODE "MESSAGE(\"\nInstall SUNMATRIX_CUSPARSE\n\")") + +# Add variable cusparse_SOURCES with the sources for the cusparse lib +set(cusparse_SOURCES + sunmatrix_cusparse.cu + ) + +# Add variable shared_SOURCES with the common SUNDIALS sources which will +# also be included in the NVECCUDA library +set(shared_SOURCES + ${sundials_SOURCE_DIR}/src/sundials/sundials_matrix.c + ) + +# Add variable cusparse_HEADERS with the exported cusparse header files +set(cusparse_HEADERS sunmatrix_cusparse.h) +add_prefix(${sundials_SOURCE_DIR}/include/sunmatrix/ cusparse_HEADERS) + +# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY +add_definitions(-DBUILD_SUNDIALS_LIBRARY) + +if(BUILD_STATIC_LIBS) + add_library(sundials_sunmatrixcusparse_static STATIC ${cusparse_SOURCES} ${shared_SOURCES}) + target_link_libraries(sundials_sunmatrixcusparse_static + PUBLIC + sundials_nveccuda_static + ${CUDA_cusparse_LIBRARY} + PRIVATE + ${CUDA_cusolver_LIBRARY}) + target_include_directories(sundials_sunmatrixcusparse_static + PRIVATE . ${sundials_SOURCE_DIR}/src/sundials) + set_target_properties(sundials_sunmatrixcusparse_static PROPERTIES + OUTPUT_NAME sundials_sunmatrixcusparse + CLEAN_DIRECT_OUTPUT 1) + install(TARGETS sundials_sunmatrixcusparse_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_STATIC_LIBS) + +if(BUILD_SHARED_LIBS) + add_library(sundials_sunmatrixcusparse_shared SHARED ${cusparse_SOURCES} ${shared_SOURCES}) + target_link_libraries(sundials_sunmatrixcusparse_shared + PUBLIC + sundials_nveccuda_shared + ${CUDA_cusparse_LIBRARY} + PRIVATE + ${CUDA_cusolver_LIBRARY}) + target_include_directories(sundials_sunmatrixcusparse_shared + PRIVATE . ${sundials_SOURCE_DIR}/src/sundials) + set_target_properties(sundials_sunmatrixcusparse_shared PROPERTIES + OUTPUT_NAME sundials_sunmatrixcusparse + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunmatrixlib_VERSION} + SOVERSION ${sunmatrixlib_SOVERSION}) + install(TARGETS sundials_sunmatrixcusparse_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_SHARED_LIBS) + +# Install the CUDA NVector header files +install(FILES ${cusparse_HEADERS} DESTINATION include/sunmatrix) + +# +message(STATUS "Added sunmatrix_cusparse module") diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/cusparse/cusparse_kernels.cuh b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/cusparse/cusparse_kernels.cuh new file mode 100644 index 000000000..0a18bde97 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/cusparse/cusparse_kernels.cuh @@ -0,0 +1,175 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Cody J. Balos @ LLNL + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------- + * This is the header file is for the cuSPARSE implementation of the + * SUNMATRIX module. + * ----------------------------------------------------------------- + */ + + +#ifndef _SUNCUSPARSE_MATRIX_KERNELS_CUH_ +#define _SUNCUSPARSE_MATRIX_KERNELS_CUH_ + +#include +#include + +namespace sundials +{ +namespace device +{ +namespace sunmatrix_cusparse +{ + +template +__global__ void +scaleAddIKernelCSR(I m, T c, T* A, const I* rowptr, const I* colind) +{ + // REQUIRES THE DIAGONAL TO BE PRESENT! + + // Each thread loops over one row of the matrix so memory accesses by a thread are stride-1. + // If there aren't enough threads to cover all rows, then some threads will be reused for + // more than one row. + for (I row = blockIdx.x*blockDim.x + threadIdx.x; + row < m; + row += blockDim.x * gridDim.x) + { + I tmp = rowptr[row]; + I rownnz = rowptr[row+1] - tmp; + I idx = tmp; + for (I j = 0; j < rownnz; j++) + { + if (colind[idx+j] == row) A[idx+j] = c*A[idx+j] + 1.0; + else A[idx+j] = c*A[idx+j]; + } + } +} + +template +__global__ void +scaleAddIKernelBCSR(I m, I nblocks, I blocknnz, T c, T* A, const I* rowptr, const I* colind) +{ + // REQUIRES THE DIAGONAL TO BE PRESENT! + + // Ideally each thread block will be in charge of one block of the matrix. + for (I block = blockIdx.x; + block < nblocks; + block += gridDim.x) + { + // Each thread loops over one row of the matrix so memory accesses by a thread are stride-1. + // If there aren't enough threads to cover all rows, then some threads will be reused for + // more than one row. + for (I row = threadIdx.x; + row < m; + row += blockDim.x) + { + I tmp = rowptr[row]; + I rownnz = rowptr[row+1] - tmp; + I idxl = tmp; + I idxg = block*blocknnz + tmp; + for (I j = 0; j < rownnz; j++) + { + if (colind[idxl+j] == row) A[idxg+j] = c*A[idxg+j] + 1.0; + else A[idxg+j] = c*A[idxg+j]; + } + } + } +} + +template +__global__ void +scaleAddKernelCSR(I nnz, T c, T* A, const T* B) +{ + // REQUIRES A AND B TO HAVE THE SAME SPARSITY PATTERN + for (I i = blockIdx.x * blockDim.x + threadIdx.x; + i < nnz; + i += blockDim.x * gridDim.x) + { + A[i] = c*A[i] + B[i]; + } +} + +template +__global__ void +matvecBCSR(I m, I nblocks, I blocknnz, const T* A, const I* rowptr, const I* colind, const T* x, T* y) +{ + // Zero out result vector + for (I i = blockIdx.x * blockDim.x + threadIdx.x; + i < nblocks*blocknnz; + i += blockDim.x * gridDim.x) + { + y[i] = 0.0; + } + + __syncthreads(); + + // Ideally each thread block will be in charge of one block of the matrix. + for (I block = blockIdx.x; + block < nblocks; + block += gridDim.x) + { + // Each thread loops over one row of the matrix so memory accesses by a thread are stride-1. + // If there aren't enough threads to cover all rows, then some threads will be reused for + // more than one row. + for (I row = threadIdx.x; + row < m; + row += blockDim.x) + { + I tmp = rowptr[row]; + I rownnz = rowptr[row+1] - tmp; // number of nnz in this row + I idxl = tmp; // local (to this block) starting nonzero index + I idxg = block*blocknnz + tmp; // global (overall matrix) starting nonzero index + I rowg = block*m+row; // global (overall matrix) row + I colg = block*m; // global (overall matrix) starting column + for (I j = 0; j < rownnz; j++) + { + y[rowg] += A[idxg+j] * x[ colg+colind[idxl+j] ]; + } + } + } +} + +// kernels for debugging +#ifdef SUNDIALS_DEBUG + +template +__global__ void +print_kernel(I m, I nnz, I blocknnz, T* A, const I* rowptr, const I* colind) +{ + for (I i = blockIdx.x * blockDim.x + threadIdx.x; + i < nnz; + i += blockDim.x * gridDim.x) + { + printf("A[%d] = %f\n", i, A[i]); + } + for (I i = blockIdx.x * blockDim.x + threadIdx.x; + i < m+1; + i += blockDim.x * gridDim.x) + { + printf("rowptr[%d] = %d\n", i, rowptr[i]); + } + for (I i = blockIdx.x * blockDim.x + threadIdx.x; + i < blocknnz; + i += blockDim.x * gridDim.x) + { + printf("colind[%d] = %d\n", i, colind[i]); + } +} + +#endif + +} // namespace sunmatrix_cusparse +} // namespace device +} // namespace sundials + +#endif \ No newline at end of file diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/cusparse/sunmatrix_cusparse.cu b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/cusparse/sunmatrix_cusparse.cu new file mode 100644 index 000000000..ba4dc297b --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/cusparse/sunmatrix_cusparse.cu @@ -0,0 +1,1132 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Cody J. Balos @ LLNL + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------- + * This is the header file is for the cuSPARSE implementation of the + * SUNMATRIX module. + * ----------------------------------------------------------------- + */ + +#include +#include + +#include +#include + +#include "sundials_cuda.h" +#include "sundials_debug.h" +#include "cusparse_kernels.cuh" + +/* Use the namespace for the kernels */ +using namespace sundials::device::sunmatrix_cusparse; + +/* Constants */ +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +#define MAX_THREAD_PER_BLOCK(val) ( (val > 16*CUDA_WARP_SIZE) ? (16*CUDA_WARP_SIZE) : (val) ) + +/* Private function prototypes */ +static booleantype SMCompatible_cuSparse(SUNMatrix A, SUNMatrix B); +static SUNMatrix SUNMatrix_cuSparse_NewEmpty(); + +/* Macros for handling the different function names based on precision */ +#if defined(SUNDIALS_DOUBLE_PRECISION) +#define cusparseXcsrmv cusparseDcsrmv +#elif defined(SUNDIALS_SINGLE_PRECISION) +#define cusparseXcsrmv cusparseScsrmv +#endif + +/* Content accessor macros */ +#define SMCU_CONTENT_S(A) ( (SUNMatrix_Content_cuSparse)(A->content) ) +#define SMCU_ROWS_S(A) ( SMCU_CONTENT_S(A)->M ) +#define SMCU_COLUMNS_S(A) ( SMCU_CONTENT_S(A)->N ) +#define SMCU_NNZ_S(A) ( SMCU_CONTENT_S(A)->NNZ ) +#define SMCU_NBLOCKS_S(A) ( SMCU_CONTENT_S(A)->nblocks ) +#define SMCU_BLOCKROWS_S(A) ( SMCU_CONTENT_S(A)->blockrows ) +#define SMCU_BLOCKCOLS_S(A) ( SMCU_CONTENT_S(A)->blockcols ) +#define SMCU_BLOCKNNZ_S(A) ( SMCU_CONTENT_S(A)->blocknnz ) +#define SMCU_NP_S(A) ( SMCU_CONTENT_S(A)->NP ) +#define SMCU_SPARSETYPE_S(A) ( SMCU_CONTENT_S(A)->sparse_type ) +#define SMCU_OWNDATA_S(A) ( SMCU_CONTENT_S(A)->own_data ) +#define SMCU_DATA_S(A) ( SMCU_CONTENT_S(A)->data ) +#define SMCU_INDEXVALS_S(A) ( SMCU_CONTENT_S(A)->colind ) +#define SMCU_INDEXPTRS_S(A) ( SMCU_CONTENT_S(A)->rowptrs ) +#define SMCU_MATDESCR_S(A) ( SMCU_CONTENT_S(A)->mat_descr ) +#define SMCU_CUSPHANDLE_S(A) ( SMCU_CONTENT_S(A)->cusp_handle ) +#define SMCU_FIXEDPATTERN_S(A)( SMCU_CONTENT_S(A)->fixed_pattern ) + + +/* ------------------------------------------------------------------ + * Constructors. + * ------------------------------------------------------------------ */ + + +SUNMatrix SUNMatrix_cuSparse_NewCSR(int M, int N, int NNZ, cusparseHandle_t cusp) +{ + /* return with NULL matrix on illegal input */ + if ( (M <= 0) || (N <= 0) || (NNZ < 0) ) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatrix_NewCSR_cuSparse: illegal value(s) for M, N, or NNZ\n"); + return NULL; + } + + SUNMatrix A = SUNMatrix_cuSparse_NewEmpty(); + if (A == NULL) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatrix_NewCSR_cuSparse: SUNMatrix_cuSparse_NewEmpty returned NULL\n"); + return NULL; + } + + /* Allocate device memory for the matrix */ + int *d_colind, *d_rowptr; + realtype *d_values; + + d_colind = NULL; + d_rowptr = NULL; + d_values = NULL; + + cudaError_t cuerr; + cuerr = cudaMalloc((void **) &d_colind, sizeof(*d_colind) * NNZ); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) + { + SUNMatDestroy(A); + return NULL; + } + cuerr = cudaMalloc((void **) &d_rowptr, sizeof(*d_rowptr) * (M+1)); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) + { + SUNMatDestroy(A); + cudaFree(d_colind); + return NULL; + } + cuerr = cudaMalloc((void **) &d_values, sizeof(*d_values) * NNZ); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) + { + SUNMatDestroy(A); + cudaFree(d_colind); + cudaFree(d_rowptr); + return NULL; + } + + /* Choose sensible defaults */ + cusparseStatus_t cusparse_status = CUSPARSE_STATUS_SUCCESS; + cusparseMatDescr_t mat_descr; + cusparse_status = cusparseCreateMatDescr(&mat_descr); + if (!SUNDIALS_CUSPARSE_VERIFY(cusparse_status)) + { + cudaFree(d_rowptr); cudaFree(d_colind); + cudaFree(d_values); SUNMatDestroy(A); + return NULL; + } + + cusparse_status = cusparseSetMatType(mat_descr, CUSPARSE_MATRIX_TYPE_GENERAL); + if (!SUNDIALS_CUSPARSE_VERIFY(cusparse_status)) + { + cudaFree(d_rowptr); cudaFree(d_colind); + cudaFree(d_values); SUNMatDestroy(A); + cusparseDestroyMatDescr(mat_descr); + return NULL; + } + + cusparse_status = cusparseSetMatIndexBase(mat_descr, CUSPARSE_INDEX_BASE_ZERO); + if (!SUNDIALS_CUSPARSE_VERIFY(cusparse_status)) + { + cudaFree(d_rowptr); cudaFree(d_colind); + cudaFree(d_values); SUNMatDestroy(A); + cusparseDestroyMatDescr(mat_descr); + return NULL; + } + + /* Fill the content */ + SMCU_CONTENT_S(A)->M = M; + SMCU_CONTENT_S(A)->N = N; + SMCU_CONTENT_S(A)->NNZ = NNZ; + SMCU_CONTENT_S(A)->nblocks = 1; + SMCU_CONTENT_S(A)->blockrows = M; + SMCU_CONTENT_S(A)->blockcols = N; + SMCU_CONTENT_S(A)->blocknnz = NNZ; + SMCU_CONTENT_S(A)->own_data = SUNTRUE; + SMCU_CONTENT_S(A)->sparse_type = SUNMAT_CUSPARSE_CSR; + SMCU_CONTENT_S(A)->colind = d_colind; + SMCU_CONTENT_S(A)->rowptrs = d_rowptr; + SMCU_CONTENT_S(A)->data = d_values; + SMCU_CONTENT_S(A)->mat_descr = mat_descr; + SMCU_CONTENT_S(A)->cusp_handle = cusp; + SMCU_CONTENT_S(A)->fixed_pattern = SUNFALSE; + + return A; +} + + +SUNMatrix SUNMatrix_cuSparse_MakeCSR(cusparseMatDescr_t mat_descr, int M, int N, int NNZ, + int *rowptrs , int *colind , realtype *data, + cusparseHandle_t cusp) +{ + /* return with NULL matrix on illegal input */ + if ( (M <= 0) || (N <= 0) || (NNZ < 0) ) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatrix_MakeCSR_cuSparse: illegal value(s) for M, N, or NNZ\n"); + return NULL; + } + + if ( (rowptrs == NULL) || (colind == NULL) || (data == NULL) ) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatrix_MakeCSR_cuSparse: rowptrs, colind, or data is NULL\n"); + return NULL; + } + + if (cusparseGetMatIndexBase(mat_descr) != CUSPARSE_INDEX_BASE_ZERO) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatrix_MakeCSR_cuSparse: the cusparseMatDescr_t must have index base CUSPARSE_INDEX_BASE_ZERO\n"); + return NULL; + } + + SUNMatrix A = SUNMatrix_cuSparse_NewEmpty(); + if (A == NULL) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatrix_MakeCSR_cuSparse: SUNMatrix_cuSparse_NewEmpty returned NULL\n"); + return NULL; + } + + /* Fill content */ + SMCU_CONTENT_S(A)->M = M; + SMCU_CONTENT_S(A)->N = N; + SMCU_CONTENT_S(A)->NNZ = NNZ; + SMCU_CONTENT_S(A)->nblocks = 1; + SMCU_CONTENT_S(A)->blockrows = M; + SMCU_CONTENT_S(A)->blockcols = N; + SMCU_CONTENT_S(A)->blocknnz = NNZ; + SMCU_CONTENT_S(A)->own_data = SUNFALSE; + SMCU_CONTENT_S(A)->sparse_type = SUNMAT_CUSPARSE_CSR; + SMCU_CONTENT_S(A)->colind = colind; + SMCU_CONTENT_S(A)->rowptrs = rowptrs; + SMCU_CONTENT_S(A)->data = data; + SMCU_CONTENT_S(A)->mat_descr = mat_descr; + SMCU_CONTENT_S(A)->cusp_handle = cusp; + SMCU_CONTENT_S(A)->fixed_pattern = SUNFALSE; + + return A; +} + + +SUNMatrix SUNMatrix_cuSparse_NewBlockCSR(int nblocks, int blockrows, int blockcols, int blocknnz, cusparseHandle_t cusp) +{ + int M, N, NNZ; + + /* Return with NULL matrix on illegal input */ + if (blockrows != blockcols) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatrix_cuSparse_NewBlockCSR: matrix must be square for the BCSR format\n"); + return NULL; + } + + M = nblocks * blockrows; + N = M; + NNZ = nblocks * blocknnz; + + /* Return with NULL matrix on illegal input */ + if ( (M <= 0) || (N <= 0) || (NNZ < 0) ) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatrix_cuSparse_NewBlockCSR: illegal value(s) for M, N, or NNZ\n"); + return NULL; + } + + /* Allocate the SUNMatrix object */ + SUNMatrix A = SUNMatrix_cuSparse_NewEmpty(); + if (A == NULL) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatrix_cuSparse_NewBlockCSR: SUNMatrix_cuSparse_NewEmpty returned NULL\n"); + return NULL; + } + + /* Allocate device memory for the matrix */ + int *d_colind, *d_rowptr; + realtype *d_values; + + d_colind = NULL; + d_rowptr = NULL; + d_values = NULL; + + cudaError_t cuerr; + cuerr = cudaMalloc((void **) &d_colind, sizeof(*d_colind) * blocknnz); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) + { + SUNMatDestroy(A); + return NULL; + } + cuerr = cudaMalloc((void **) &d_rowptr, sizeof(*d_rowptr) * (blockrows + 1)); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) + { + SUNMatDestroy(A); + cudaFree(d_colind); + return NULL; + } + cuerr = cudaMalloc((void **) &d_values, sizeof(*d_values) * blocknnz * nblocks); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) + { + SUNMatDestroy(A); + cudaFree(d_colind); + cudaFree(d_rowptr); + return NULL; + } + + /* Choose sensible defaults */ + cusparseStatus_t cusparse_status = CUSPARSE_STATUS_SUCCESS; + cusparseMatDescr_t mat_descr; + cusparse_status = cusparseCreateMatDescr(&mat_descr); + if (!SUNDIALS_CUSPARSE_VERIFY(cusparse_status)) + { + cudaFree(d_rowptr); cudaFree(d_colind); + cudaFree(d_values); SUNMatDestroy(A); + return NULL; + } + + cusparse_status = cusparseSetMatType(mat_descr, CUSPARSE_MATRIX_TYPE_GENERAL); + if (!SUNDIALS_CUSPARSE_VERIFY(cusparse_status)) + { + cudaFree(d_rowptr); cudaFree(d_colind); + cudaFree(d_values); SUNMatDestroy(A); + cusparseDestroyMatDescr(mat_descr); + return NULL; + } + + cusparse_status = cusparseSetMatIndexBase(mat_descr, CUSPARSE_INDEX_BASE_ZERO); + if (!SUNDIALS_CUSPARSE_VERIFY(cusparse_status)) + { + cudaFree(d_rowptr); cudaFree(d_colind); + cudaFree(d_values); SUNMatDestroy(A); + cusparseDestroyMatDescr(mat_descr); + return NULL; + } + + /* Fill the content */ + SMCU_CONTENT_S(A)->M = M; + SMCU_CONTENT_S(A)->N = N; + SMCU_CONTENT_S(A)->NNZ = NNZ; + SMCU_CONTENT_S(A)->nblocks = nblocks; + SMCU_CONTENT_S(A)->blockrows = blockrows; + SMCU_CONTENT_S(A)->blockcols = blockrows; + SMCU_CONTENT_S(A)->blocknnz = blocknnz; + SMCU_CONTENT_S(A)->own_data = SUNTRUE; + SMCU_CONTENT_S(A)->sparse_type = SUNMAT_CUSPARSE_BCSR; + SMCU_CONTENT_S(A)->colind = d_colind; + SMCU_CONTENT_S(A)->rowptrs = d_rowptr; + SMCU_CONTENT_S(A)->data = d_values; + SMCU_CONTENT_S(A)->mat_descr = mat_descr; + SMCU_CONTENT_S(A)->cusp_handle = cusp; + SMCU_CONTENT_S(A)->fixed_pattern = SUNFALSE; + + return A; +} + +/* ------------------------------------------------------------------ + * Implementation specific routines. + * ------------------------------------------------------------------ */ + +int SUNMatrix_cuSparse_SparseType(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_CUSPARSE) + return SMCU_SPARSETYPE_S(A); + else + return SUNMAT_ILL_INPUT; +} + +int SUNMatrix_cuSparse_Rows(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_CUSPARSE) + return SMCU_ROWS_S(A); + else + return SUNMAT_ILL_INPUT; +} + +int SUNMatrix_cuSparse_Columns(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_CUSPARSE) + return SMCU_COLUMNS_S(A); + else + return SUNMAT_ILL_INPUT; +} + +int SUNMatrix_cuSparse_NNZ(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_CUSPARSE) + return SMCU_NNZ_S(A); + else + return SUNMAT_ILL_INPUT; +} + +int* SUNMatrix_cuSparse_IndexPointers(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_CUSPARSE) + return SMCU_INDEXPTRS_S(A); + else + return NULL; +} + +int* SUNMatrix_cuSparse_IndexValues(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_CUSPARSE) + return SMCU_INDEXVALS_S(A); + else + return NULL; +} + +realtype* SUNMatrix_cuSparse_Data(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_CUSPARSE) + return SMCU_DATA_S(A); + else + return NULL; +} + +int SUNMatrix_cuSparse_NumBlocks(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_CUSPARSE) + return SMCU_NBLOCKS_S(A); + else + return SUNMAT_ILL_INPUT; +} + +int SUNMatrix_cuSparse_BlockRows(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_CUSPARSE) + return SMCU_BLOCKROWS_S(A); + else + return SUNMAT_ILL_INPUT; +} + +int SUNMatrix_cuSparse_BlockColumns(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_CUSPARSE) + return SMCU_BLOCKCOLS_S(A); + else + return SUNMAT_ILL_INPUT; +} + +int SUNMatrix_cuSparse_BlockNNZ(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_CUSPARSE) + return SMCU_BLOCKNNZ_S(A); + else + return SUNMAT_ILL_INPUT; +} + +realtype* SUNMatrix_cuSparse_BlockData(SUNMatrix A, int blockidx) +{ + realtype *matdata; + int offset; + + if (SUNMatGetID(A) != SUNMATRIX_CUSPARSE) + return NULL; + + if (blockidx >= SMCU_NBLOCKS_S(A)) + return NULL; + + matdata = SMCU_DATA_S(A); + offset = SMCU_BLOCKNNZ_S(A)*blockidx; + + return (&matdata[offset]); +} + +cusparseMatDescr_t SUNMatrix_cuSparse_MatDescr(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_CUSPARSE) + return SMCU_MATDESCR_S(A); + else + return NULL; +} + +int SUNMatrix_cuSparse_SetFixedPattern(SUNMatrix A, booleantype yesno) +{ + if (SUNMatGetID(A) != SUNMATRIX_CUSPARSE) + return SUNMAT_ILL_INPUT; + + SMCU_FIXEDPATTERN_S(A) = yesno; + + return SUNMAT_SUCCESS; +} + + +int SUNMatrix_cuSparse_CopyToDevice(SUNMatrix dA, realtype* h_data, + int* h_idxptrs, int* h_idxvals) +{ + cudaError_t cuerr; + cudaStream_t stream; + cusparseStatus_t cusparse_status; + int nidxvals, nidxptrs; + + if (SUNMatGetID(dA) != SUNMATRIX_CUSPARSE) + return SUNMAT_ILL_INPUT; + + cusparse_status = cusparseGetStream(SMCU_CUSPHANDLE_S(dA), &stream); + if (!SUNDIALS_CUSPARSE_VERIFY(cusparse_status)) return SUNMAT_OPERATION_FAIL; + + if (h_data != NULL) + { + cuerr = cudaMemcpyAsync(SMCU_DATA_S(dA), h_data, + SMCU_NNZ_S(dA)*sizeof(realtype), + cudaMemcpyHostToDevice, stream); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) return SUNMAT_OPERATION_FAIL; + } + + switch(SMCU_SPARSETYPE_S(dA)) + { + case SUNMAT_CUSPARSE_CSR: + nidxptrs = SMCU_ROWS_S(dA)+1; + nidxvals = SMCU_NNZ_S(dA); + break; + case SUNMAT_CUSPARSE_BCSR: + nidxptrs = SMCU_BLOCKROWS_S(dA)+1; + nidxvals = SMCU_BLOCKNNZ_S(dA); + break; + default: + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatrix_cuSparse_CopyToDevice: unrecognized sparse type\n"); + return SUNMAT_ILL_INPUT; + } + + if (h_idxptrs != NULL) + { + cuerr = cudaMemcpyAsync(SMCU_INDEXPTRS_S(dA), h_idxptrs, + nidxptrs*sizeof(int), + cudaMemcpyHostToDevice, stream); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) return SUNMAT_OPERATION_FAIL; + } + + if (h_idxvals != NULL) + { + cuerr = cudaMemcpyAsync(SMCU_INDEXVALS_S(dA), h_idxvals, + nidxvals*sizeof(int), + cudaMemcpyHostToDevice, stream); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) return SUNMAT_OPERATION_FAIL; + } + + return SUNMAT_SUCCESS; +} + + +int SUNMatrix_cuSparse_CopyFromDevice(SUNMatrix dA, realtype* h_data, + int* h_idxptrs, int* h_idxvals) +{ + cudaError_t cuerr; + cudaStream_t stream; + cusparseStatus_t cusparse_status; + int nidxvals, nidxptrs; + + if (SUNMatGetID(dA) != SUNMATRIX_CUSPARSE) + return SUNMAT_ILL_INPUT; + + cusparse_status = cusparseGetStream(SMCU_CUSPHANDLE_S(dA), &stream); + if (!SUNDIALS_CUSPARSE_VERIFY(cusparse_status)) return SUNMAT_OPERATION_FAIL; + + if (h_data != NULL) + { + cuerr = cudaMemcpyAsync(h_data, SMCU_DATA_S(dA), + SMCU_NNZ_S(dA)*sizeof(realtype), + cudaMemcpyDeviceToHost, stream); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) return SUNMAT_OPERATION_FAIL; + } + + switch(SMCU_SPARSETYPE_S(dA)) + { + case SUNMAT_CUSPARSE_CSR: + nidxptrs = SMCU_ROWS_S(dA)+1; + nidxvals = SMCU_NNZ_S(dA); + case SUNMAT_CUSPARSE_BCSR: + nidxptrs = SMCU_BLOCKROWS_S(dA)+1; + nidxvals = SMCU_BLOCKNNZ_S(dA); + } + + if (h_idxptrs != NULL) + { + cuerr = cudaMemcpyAsync(h_idxptrs, SMCU_INDEXPTRS_S(dA), + nidxptrs*sizeof(int), + cudaMemcpyDeviceToHost, stream); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) return SUNMAT_OPERATION_FAIL; + } + + if (h_idxvals != NULL) + { + cuerr = cudaMemcpyAsync(h_idxvals, SMCU_INDEXVALS_S(dA), + nidxvals*sizeof(int), + cudaMemcpyDeviceToHost, stream); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) return SUNMAT_OPERATION_FAIL; + } + + return SUNMAT_SUCCESS; +} + +/* + * ----------------------------------------------------------------- + * implementation of matrix operations + * ----------------------------------------------------------------- + */ + + +SUNMatrix_ID SUNMatGetID_cuSparse(SUNMatrix A) +{ + return SUNMATRIX_CUSPARSE; +} + +/* Returns a new matrix allocated to have the same structure as A, + but it does not copy any nonzeros, column vals, or row pointers. */ +SUNMatrix SUNMatClone_cuSparse(SUNMatrix A) +{ + SUNMatrix B; + + switch (SMCU_SPARSETYPE_S(A)) + { + case SUNMAT_CUSPARSE_CSR: + B = SUNMatrix_cuSparse_NewCSR(SMCU_ROWS_S(A), SMCU_COLUMNS_S(A), SMCU_NNZ_S(A), + SMCU_CUSPHANDLE_S(A)); + break; + case SUNMAT_CUSPARSE_BCSR: + B = SUNMatrix_cuSparse_NewBlockCSR(SMCU_NBLOCKS_S(A), SMCU_BLOCKROWS_S(A), SMCU_BLOCKCOLS_S(A), + SMCU_BLOCKNNZ_S(A), SMCU_CUSPHANDLE_S(A)); + break; + default: + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatClone_cuSparse: sparse type not recognized\n"); + B = NULL; + } + + SMCU_FIXEDPATTERN_S(B) = SMCU_FIXEDPATTERN_S(A); + + return B; +} + + +/* Deallocates the SUNMatrix object and all data it owns */ +void SUNMatDestroy_cuSparse(SUNMatrix A) +{ + if (A == NULL) return; + + /* free content */ + if (A->content != NULL) + { + if (SMCU_OWNDATA_S(A)) + { + /* free data array */ + if (SMCU_DATA_S(A)) + { + cudaFree(SMCU_DATA_S(A)); + SMCU_DATA_S(A) = NULL; + } + + /* free index values array */ + if (SMCU_INDEXVALS_S(A)) + { + cudaFree(SMCU_INDEXVALS_S(A)); + SMCU_INDEXVALS_S(A) = NULL; + } + + /* free index pointers array */ + if (SMCU_INDEXPTRS_S(A)) + { + cudaFree(SMCU_INDEXPTRS_S(A)); + SMCU_INDEXPTRS_S(A) = NULL; + } + + /* free cusparseMatDescr_t */ + cusparseDestroyMatDescr(SMCU_MATDESCR_S(A)); + } + + /* free content struct */ + free(A->content); + A->content = NULL; + } + + /* free ops and matrix */ + if (A->ops) { free(A->ops); A->ops = NULL; } + free(A); A = NULL; + + return; +} + + +/* Performs A_ij = 0 */ +int SUNMatZero_cuSparse(SUNMatrix A) +{ + cudaError_t cuerr; + cudaStream_t stream; + + cusparseGetStream(SMCU_CUSPHANDLE_S(A), &stream); + + /* set all data to zero */ + cuerr = cudaMemsetAsync(SMCU_DATA_S(A), 0, SMCU_NNZ_S(A)*sizeof(realtype), stream); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) return SUNMAT_OPERATION_FAIL; + + /* set all rowptrs to zero unless the sparsity pattern is fixed */ + if (!SMCU_FIXEDPATTERN_S(A)) + { + cuerr = cudaMemsetAsync(SMCU_INDEXPTRS_S(A), 0, + (SMCU_BLOCKROWS_S(A)+1)*sizeof(int), + stream); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) return SUNMAT_OPERATION_FAIL; + + /* set all colind to zero */ + cuerr = cudaMemsetAsync(SMCU_INDEXVALS_S(A), 0, + SMCU_BLOCKNNZ_S(A)*sizeof(int), + stream); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) return SUNMAT_OPERATION_FAIL; + } + + return SUNMAT_SUCCESS; +} + + +/* Copies the nonzeros, column vals, and row pointers into dst */ +int SUNMatCopy_cuSparse(SUNMatrix src, SUNMatrix dst) +{ + cudaError_t cuerr; + cudaStream_t stream; + + /* Verify that src and dst are compatible */ + if (!SMCompatible_cuSparse(src, dst)) + return SUNMAT_ILL_INPUT; + + cusparseGetStream(SMCU_CUSPHANDLE_S(src), &stream); + + /* Ensure that dst is allocated with at least as + much memory as we have nonzeros in src */ + if (SMCU_NNZ_S(dst) < SMCU_NNZ_S(src)) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatCopy_cuSparse: the destination matrix has less nonzeros than the source\n"); + return SUNMAT_ILL_INPUT; + } + + /* Zero out dst so that copy works correctly */ + if (SUNMatZero_cuSparse(dst) != SUNMAT_SUCCESS) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatCopy_cuSparse: SUNMatZero_cuSparse failed\n"); + return SUNMAT_OPERATION_FAIL; + } + + /* Copy the data over */ + cuerr = cudaMemcpyAsync(SMCU_DATA_S(dst), SMCU_DATA_S(src), + SMCU_NNZ_S(src)*sizeof(*SMCU_DATA_S(src)), + cudaMemcpyDeviceToDevice, stream); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) return SUNMAT_OPERATION_FAIL; + + /* Copy the row pointers over */ + cuerr = cudaMemcpyAsync(SMCU_INDEXPTRS_S(dst), SMCU_INDEXPTRS_S(src), + (SMCU_BLOCKROWS_S(src)+1)*sizeof(*SMCU_INDEXPTRS_S(src)), + cudaMemcpyDeviceToDevice, stream); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) return SUNMAT_OPERATION_FAIL; + + /* Copy the column indices over */ + cuerr = cudaMemcpyAsync(SMCU_INDEXVALS_S(dst), SMCU_INDEXVALS_S(src), + SMCU_BLOCKNNZ_S(src)*sizeof(*SMCU_INDEXVALS_S(src)), + cudaMemcpyDeviceToDevice, stream); + if (!SUNDIALS_CUDA_VERIFY(cuerr)) return SUNMAT_OPERATION_FAIL; + + return SUNMAT_SUCCESS; +} + + +/* Performs A = cA + I. Requires the diagonal to be allocated already. */ +int SUNMatScaleAddI_cuSparse(realtype c, SUNMatrix A) +{ + cudaStream_t stream; + cusparseStatus_t cusparse_status; + + cusparse_status = cusparseGetStream(SMCU_CUSPHANDLE_S(A), &stream); + if (!SUNDIALS_CUSPARSE_VERIFY(cusparse_status)) return SUNMAT_OPERATION_FAIL; + + unsigned threadsPerBlock, gridSize; + switch (SMCU_SPARSETYPE_S(A)) + { + case SUNMAT_CUSPARSE_CSR: + /* Choose the grid size to be the number of rows in the matrix, + and then choose threadsPerBlock to be a multiple of the warp size + that results in enough threads to have one per 2 columns. */ + threadsPerBlock = MAX_THREAD_PER_BLOCK(CUDA_WARP_SIZE*(SMCU_COLUMNS_S(A)/2 + CUDA_WARP_SIZE - 1)/CUDA_WARP_SIZE); + gridSize = SMCU_ROWS_S(A); + + { +#ifdef SUNDIALS_CUDA_KERNEL_TIMING + cudaEvent_t start, stop; + float milliseconds = 0; + cudaEventCreate(&start); + cudaEventCreate(&stop); + cudaEventRecord(start); +#endif + + scaleAddIKernelCSR + <<>>(SMCU_ROWS_S(A), + c, + SMCU_DATA_S(A), + SMCU_INDEXPTRS_S(A), + SMCU_INDEXVALS_S(A)); + +#ifdef SUNDIALS_CUDA_KERNEL_TIMING + cudaEventRecord(stop); + cudaEventSynchronize(stop); + cudaEventElapsedTime(&milliseconds, start, stop); + fprintf(stdout, + "[performance] scaleAddIKernelCSR runtime (s): %22.15e\n", + milliseconds/1000.0); + /* scaleAddIKernelCSR reads 1 real, writes 1 real, reads 3 ints */ + fprintf(stdout, + "[performance] scaleAddIKernelCSR effective bandwidth (GB/s): %f\n", + (SMCU_NNZ_S(A)*(2*sizeof(realtype) + sizeof(int)) + 2*SMCU_ROWS_S(A)*sizeof(int))/milliseconds/1e6); +#endif + } + + break; + case SUNMAT_CUSPARSE_BCSR: + /* Choose the grid size to be the number of blocks in the matrix, + and then choose threadsPerBlock to be a multiple of the warp size + that results in enough threads to have one per row of the block. */ + threadsPerBlock = MAX_THREAD_PER_BLOCK(CUDA_WARP_SIZE*(SMCU_BLOCKROWS_S(A) + CUDA_WARP_SIZE - 1)/CUDA_WARP_SIZE); + gridSize = SMCU_NBLOCKS_S(A); + + { +#ifdef SUNDIALS_CUDA_KERNEL_TIMING + cudaEvent_t start, stop; + float milliseconds = 0; + cudaEventCreate(&start); + cudaEventCreate(&stop); + cudaEventRecord(start); +#endif + + scaleAddIKernelBCSR + <<>>(SMCU_BLOCKROWS_S(A), + SMCU_NBLOCKS_S(A), + SMCU_BLOCKNNZ_S(A), + c, + SMCU_DATA_S(A), + SMCU_INDEXPTRS_S(A), + SMCU_INDEXVALS_S(A)); + +#ifdef SUNDIALS_CUDA_KERNEL_TIMING + cudaEventRecord(stop); + cudaEventSynchronize(stop); + cudaEventElapsedTime(&milliseconds, start, stop); + fprintf(stdout, + "[performance] scaleAddIKernelBCSR runtime (s): %22.15e\n", + milliseconds/1000.0); + /* scaleAddIKernelBCSR reads 1 real, writes 1 real, reads 3 ints */ + fprintf(stdout, + "[performance] scaleAddIKernelBCSR effective bandwidth (GB/s): %f\n", + (SMCU_NNZ_S(A)*(2*sizeof(realtype) + sizeof(int)) + 2*SMCU_ROWS_S(A)*sizeof(int))/milliseconds/1e6); +#endif + } + break; + default: + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatScaleAddI_cuSparse: sparse type not recognized\n"); + return SUNMAT_ILL_INPUT; + } + +#ifdef SUNDIALS_DEBUG_CUDA_LASTERROR + cudaDeviceSynchronize(); + if (!SUNDIALS_CUDA_VERIFY(cudaGetLastError())) return SUNMAT_OPERATION_FAIL; +#endif + + return SUNMAT_SUCCESS; +} + + +/* Performs A = cA + B */ +int SUNMatScaleAdd_cuSparse(realtype c, SUNMatrix A, SUNMatrix B) +{ + cudaStream_t stream; + cusparseStatus_t cusparse_status; + + if (!SMCompatible_cuSparse(A, B)) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatScaleAdd_cuSparse: SUNMatScaleAdd_cuSparse failed\n"); + return SUNMAT_ILL_INPUT; + } + + cusparse_status = cusparseGetStream(SMCU_CUSPHANDLE_S(A), &stream); + if (!SUNDIALS_CUSPARSE_VERIFY(cusparse_status)) return SUNMAT_OPERATION_FAIL; + + unsigned threadsPerBlock, gridSize; + switch (SMCU_SPARSETYPE_S(A)) + { + case SUNMAT_CUSPARSE_CSR: + /* Choose the grid size to be the number of rows in the matrix, + and then choose threadsPerBlock to be a multiple of the warp size + that results in enough threads to have one per 2 columns. */ + threadsPerBlock = MAX_THREAD_PER_BLOCK(CUDA_WARP_SIZE*(SMCU_COLUMNS_S(A)/2 + CUDA_WARP_SIZE - 1)/CUDA_WARP_SIZE); + gridSize = SMCU_ROWS_S(A); + + { +#ifdef SUNDIALS_CUDA_KERNEL_TIMING + cudaEvent_t start, stop; + float milliseconds = 0; + cudaEventCreate(&start); + cudaEventCreate(&stop); + cudaEventRecord(start); +#endif + + scaleAddKernelCSR + <<>>(SMCU_NNZ_S(A), + c, + SMCU_DATA_S(A), + SMCU_DATA_S(B)); + +#ifdef SUNDIALS_CUDA_KERNEL_TIMING + cudaEventRecord(stop); + cudaEventSynchronize(stop); + cudaEventElapsedTime(&milliseconds, start, stop); + fprintf(stdout, + "[performance] scaleAddKernelCSR runtime (s): %22.15e\n", + milliseconds/1000.0); + /* scaleAddKernelCSR reads 2 realtype, and writes 1 realtype */ + fprintf(stdout, + "[performance] scaleAddKernelCSR effective bandwidth (GB/s): %f\n", + SMCU_NNZ_S(A)*sizeof(realtype)*3/milliseconds/1e6); +#endif + } + + break; + case SUNMAT_CUSPARSE_BCSR: + /* Choose the grid size to be the number of blocks in the matrix, + and then choose threadsPerBlock to be a multiple of the warp size + that results in enough threads to have one per row of the block. */ + threadsPerBlock = MAX_THREAD_PER_BLOCK(CUDA_WARP_SIZE*(SMCU_BLOCKROWS_S(A) + CUDA_WARP_SIZE - 1)/CUDA_WARP_SIZE); + gridSize = SMCU_NBLOCKS_S(A); + + { +#ifdef SUNDIALS_CUDA_KERNEL_TIMING + cudaEvent_t start, stop; + float milliseconds = 0; + cudaEventCreate(&start); + cudaEventCreate(&stop); + cudaEventRecord(start); +#endif + + scaleAddKernelCSR + <<>>(SMCU_NNZ_S(A), + c, + SMCU_DATA_S(A), + SMCU_DATA_S(B)); + +#ifdef SUNDIALS_CUDA_KERNEL_TIMING + cudaEventRecord(stop); + cudaEventSynchronize(stop); + cudaEventElapsedTime(&milliseconds, start, stop); + fprintf(stdout, + "[performance] scaleAddKernelCSR (BCSR format) runtime (s): %22.15e\n", + milliseconds/1000.0); + /* scaleAddKernelCSR reads 2 realtype, and writes 1 realtype */ + fprintf(stdout, + "[performance] scaleAddKernelCSR (BCSR format) effective bandwidth (GB/s): %f\n", + SMCU_NNZ_S(A)*sizeof(realtype)*3/milliseconds/1e6); +#endif + } + + break; + default: + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatScaleAdd_cuSparse: sparse type not recognized\n"); + return SUNMAT_ILL_INPUT; + } + +#ifdef SUNDIALS_DEBUG_CUDA_LASTERROR + cudaDeviceSynchronize(); + if (!SUNDIALS_CUDA_VERIFY(cudaGetLastError())) return SUNMAT_OPERATION_FAIL; +#endif + + return SUNMAT_SUCCESS; +} + + +/* Perform y = Ax */ +int SUNMatMatvec_cuSparse(SUNMatrix A, N_Vector x, N_Vector y) +{ + /* Verify that the dimensions of A, x, and y agree */ + if ( (SMCU_COLUMNS_S(A) != N_VGetLength(x)) || + (SMCU_ROWS_S(A) != N_VGetLength(y)) ) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatMatvec_cuSparse: dimensions do not agree\n"); + return SUNMAT_ILL_INPUT; + } + + realtype *d_xdata = N_VGetDeviceArrayPointer_Cuda(x); + realtype *d_ydata = N_VGetDeviceArrayPointer_Cuda(y); + + if (SMCU_SPARSETYPE_S(A) == SUNMAT_CUSPARSE_CSR) + { + const realtype one = ONE; + cusparseStatus_t cusparse_status; + + /* Zero result vector */ + N_VConst(ZERO, y); + + { +#ifdef SUNDIALS_CUDA_KERNEL_TIMING + cudaEvent_t start, stop; + float milliseconds = 0; + cudaEventCreate(&start); + cudaEventCreate(&stop); + cudaEventRecord(start); +#endif + + cusparse_status = cusparseXcsrmv(SMCU_CUSPHANDLE_S(A), + CUSPARSE_OPERATION_NON_TRANSPOSE, + SMCU_ROWS_S(A), + SMCU_COLUMNS_S(A), + SMCU_NNZ_S(A), + &one, + SMCU_MATDESCR_S(A), + SMCU_DATA_S(A), + SMCU_INDEXPTRS_S(A), + SMCU_INDEXVALS_S(A), + d_xdata, + &one, + d_ydata); + +#ifdef SUNDIALS_CUDA_KERNEL_TIMING + cudaEventRecord(stop); + cudaEventSynchronize(stop); + cudaEventElapsedTime(&milliseconds, start, stop); + fprintf(stdout, + "[performance] cusparseXcsrmv untime (s): %22.15e\n", + milliseconds/1000.0); +#endif + } + + if (!SUNDIALS_CUSPARSE_VERIFY(cusparse_status)) return SUNMAT_OPERATION_FAIL; + } + else if (SMCU_SPARSETYPE_S(A) == SUNMAT_CUSPARSE_BCSR) + { + cudaStream_t stream; + cusparseStatus_t cusparse_status; + unsigned gridSize, threadsPerBlock; + + cusparse_status = cusparseGetStream(SMCU_CUSPHANDLE_S(A), &stream); + if (!SUNDIALS_CUSPARSE_VERIFY(cusparse_status)) return SUNMAT_OPERATION_FAIL; + + /* Choose the grid size to be the number of blocks in the matrix, + and then choose threadsPerBlock to be a multiple of the warp size + that results in enough threads to have one per row of the block. */ + threadsPerBlock = MAX_THREAD_PER_BLOCK(CUDA_WARP_SIZE*(SMCU_BLOCKROWS_S(A) + CUDA_WARP_SIZE - 1)/CUDA_WARP_SIZE); + gridSize = SMCU_NBLOCKS_S(A); + + { +#ifdef SUNDIALS_CUDA_KERNEL_TIMING + cudaEvent_t start, stop; + float milliseconds = 0; + cudaEventCreate(&start); + cudaEventCreate(&stop); + cudaEventRecord(start); +#endif + + matvecBCSR + <<>>(SMCU_BLOCKROWS_S(A), + SMCU_NBLOCKS_S(A), + SMCU_BLOCKNNZ_S(A), + SMCU_DATA_S(A), + SMCU_INDEXPTRS_S(A), + SMCU_INDEXVALS_S(A), + d_xdata, + d_ydata); + +#ifdef SUNDIALS_CUDA_KERNEL_TIMING + cudaEventRecord(stop); + cudaEventSynchronize(stop); + cudaEventElapsedTime(&milliseconds, start, stop); + fprintf(stdout, + "[performance] matvecBCSR runtime (s): %22.15e\n", + milliseconds/1000.0); + fprintf(stdout, + "[performance] matvecBCSR effective bandwidth (GB/s): %f\n", + (SMCU_NNZ_S(A)*(sizeof(realtype)*4 + sizeof(int)) + 2*SMCU_ROWS_S(A)*sizeof(int))/milliseconds/1e6); +#endif + + } + +#ifdef SUNDIALS_DEBUG_CUDA_LASTERROR + cudaDeviceSynchronize(); + if (!SUNDIALS_CUDA_VERIFY(cudaGetLastError())) return SUNMAT_OPERATION_FAIL; +#endif + } + else + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatMatvec_cuSparse: sparse type not recognized\n"); + return SUNMAT_ILL_INPUT; + } + + return SUNMAT_SUCCESS; +} + + +/* + * ================================================================= + * private functions + * ================================================================= + */ + + +/* ----------------------------------------------------------------- + * Function to check compatibility of two sparse SUNMatrix objects + */ +static booleantype SMCompatible_cuSparse(SUNMatrix A, SUNMatrix B) +{ + /* both matrices must be sparse */ + if ( (SUNMatGetID(A) != SUNMATRIX_CUSPARSE) || + (SUNMatGetID(B) != SUNMATRIX_CUSPARSE) ) + return SUNFALSE; + + /* both matrices must have the same shape and sparsity type */ + if (SMCU_ROWS_S(A) != SMCU_ROWS_S(B)) + return SUNFALSE; + if (SMCU_COLUMNS_S(A) != SMCU_COLUMNS_S(B)) + return SUNFALSE; + if (SMCU_SPARSETYPE_S(A) != SMCU_SPARSETYPE_S(B)) + return SUNFALSE; + + return SUNTRUE; +} + +/* ----------------------------------------------------------------- + * Function to create empty SUNMatrix with ops attached and + * the content structure allocated. + */ +SUNMatrix SUNMatrix_cuSparse_NewEmpty() +{ + /* Create an empty matrix object */ + SUNMatrix A = NULL; + A = SUNMatNewEmpty(); + if (A == NULL) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatrix_cuSparse_NewEmpty: SUNMatNewEmpty failed\n"); + return NULL; + } + + /* Attach operations */ + A->ops->getid = SUNMatGetID_cuSparse; + A->ops->clone = SUNMatClone_cuSparse; + A->ops->destroy = SUNMatDestroy_cuSparse; + A->ops->zero = SUNMatZero_cuSparse; + A->ops->copy = SUNMatCopy_cuSparse; + A->ops->scaleadd = SUNMatScaleAdd_cuSparse; + A->ops->scaleaddi = SUNMatScaleAddI_cuSparse; + A->ops->matvec = SUNMatMatvec_cuSparse; + + /* Create content */ + SUNMatrix_Content_cuSparse content = NULL; + content = (SUNMatrix_Content_cuSparse) malloc(sizeof *content); + if (content == NULL) + { + SUNDIALS_DEBUG_PRINT("ERROR in SUNMatrix_cuSparse_NewEmpty: failed to malloc content\n"); + SUNMatDestroy(A); + return NULL; + } + + /* Attach content */ + A->content = content; + + return A; +} diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/CMakeLists.txt index aecf7d928..db135e7c1 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/CMakeLists.txt @@ -1,9 +1,9 @@ # --------------------------------------------------------------- -# Programmer: Daniel R. Reynolds @ SMU -# Cody J. Balos @ LLNL +# Programmer(s): Daniel R. Reynolds @ SMU +# Cody J. Balos @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -13,94 +13,95 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the dense SUNMatrix library +# --------------------------------------------------------------- -INSTALL(CODE "MESSAGE(\"\nInstall SUNMATRIX_DENSE\n\")") +install(CODE "MESSAGE(\"\nInstall SUNMATRIX_DENSE\n\")") # Add F90 module if F2003 interface is enabled -IF(F90_FOUND AND F2003_INTERFACE_ENABLE) - ADD_SUBDIRECTORY(F90) -ENDIF(F90_FOUND AND F2003_INTERFACE_ENABLE) +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) # Add variable sunmatrixdense_SOURCES with the sources for the SUNMATRIXDENSE lib -SET(sunmatrixdense_SOURCES sunmatrix_dense.c) +set(sunmatrixdense_SOURCES sunmatrix_dense.c) # Add variable shared_SOURCES with the common SUNDIALS sources which will # also be included in the SUNMATRIXDENSE library -SET(shared_SOURCES +set(shared_SOURCES ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c ${sundials_SOURCE_DIR}/src/sundials/sundials_matrix.c ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c ) # Add variable sunmatrixdense_HEADERS with the exported SUNMATRIXDENSE header files -SET(sunmatrixdense_HEADERS +set(sunmatrixdense_HEADERS ${sundials_SOURCE_DIR}/include/sunmatrix/sunmatrix_dense.h ) # Add source directory to include directories -INCLUDE_DIRECTORIES(.) +include_directories(.) # Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY -ADD_DEFINITIONS(-DBUILD_SUNDIALS_LIBRARY) +add_definitions(-DBUILD_SUNDIALS_LIBRARY) # Rules for building and installing the static library: # - Add the build target for the SUNMATRIXDENSE library # - Set the library name and make sure it is not deleted # - Install the SUNMATRIXDENSE library -IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_sunmatrixdense_static STATIC ${sunmatrixdense_SOURCES} ${shared_SOURCES}) - SET_TARGET_PROPERTIES(sundials_sunmatrixdense_static +if(BUILD_STATIC_LIBS) + add_library(sundials_sunmatrixdense_static STATIC ${sunmatrixdense_SOURCES} ${shared_SOURCES}) + set_target_properties(sundials_sunmatrixdense_static PROPERTIES OUTPUT_NAME sundials_sunmatrixdense CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_sunmatrixdense_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_STATIC_LIBS) + install(TARGETS sundials_sunmatrixdense_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_STATIC_LIBS) # Rules for building and installing the shared library: # - Add the build target for the SUNMATRIXDENSE library # - Set the library name and make sure it is not deleted # - Set VERSION and SOVERSION for shared libraries # - Install the SUNMATRIXDENSE library -IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_sunmatrixdense_shared SHARED ${sunmatrixdense_SOURCES} ${shared_SOURCES}) +if(BUILD_SHARED_LIBS) + add_library(sundials_sunmatrixdense_shared SHARED ${sunmatrixdense_SOURCES} ${shared_SOURCES}) - IF(UNIX) - TARGET_LINK_LIBRARIES(sundials_sunmatrixdense_shared m) - ENDIF() + if(UNIX) + target_link_libraries(sundials_sunmatrixdense_shared m) + endif() - SET_TARGET_PROPERTIES(sundials_sunmatrixdense_shared + set_target_properties(sundials_sunmatrixdense_shared PROPERTIES OUTPUT_NAME sundials_sunmatrixdense CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_sunmatrixdense_shared + set_target_properties(sundials_sunmatrixdense_shared PROPERTIES VERSION ${sunmatrixlib_VERSION} SOVERSION ${sunmatrixlib_SOVERSION}) - INSTALL(TARGETS sundials_sunmatrixdense_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) -ENDIF(BUILD_SHARED_LIBS) + install(TARGETS sundials_sunmatrixdense_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(BUILD_SHARED_LIBS) # Install the SUNMATRIXDENSE header files -INSTALL(FILES ${sunmatrixdense_HEADERS} DESTINATION include/sunmatrix) +install(FILES ${sunmatrixdense_HEADERS} DESTINATION include/sunmatrix) # If FCMIX is enabled, build and install the FSUNMATRIXDENSE library -IF(F77_INTERFACE_ENABLE AND F77_FOUND) - SET(fsunmatrixdense_SOURCES fsunmatrix_dense.c) +if(F77_INTERFACE_ENABLE AND F77_FOUND) + set(fsunmatrixdense_SOURCES fsunmatrix_dense.c) - IF(BUILD_STATIC_LIBS) - ADD_LIBRARY(sundials_fsunmatrixdense_static STATIC ${fsunmatrixdense_SOURCES}) - SET_TARGET_PROPERTIES(sundials_fsunmatrixdense_static + if(BUILD_STATIC_LIBS) + add_library(sundials_fsunmatrixdense_static STATIC ${fsunmatrixdense_SOURCES}) + set_target_properties(sundials_fsunmatrixdense_static PROPERTIES OUTPUT_NAME sundials_fsunmatrixdense CLEAN_DIRECT_OUTPUT 1) - INSTALL(TARGETS sundials_fsunmatrixdense_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_STATIC_LIBS) + install(TARGETS sundials_fsunmatrixdense_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_STATIC_LIBS) - IF(BUILD_SHARED_LIBS) - ADD_LIBRARY(sundials_fsunmatrixdense_shared ${fsunmatrixdense_SOURCES}) + if(BUILD_SHARED_LIBS) + add_library(sundials_fsunmatrixdense_shared ${fsunmatrixdense_SOURCES}) # fsunmatrixdense depends on sunmatrixdense - TARGET_LINK_LIBRARIES(sundials_fsunmatrixdense_shared sundials_sunmatrixdense_shared) + target_link_libraries(sundials_fsunmatrixdense_shared sundials_sunmatrixdense_shared) - SET_TARGET_PROPERTIES(sundials_fsunmatrixdense_shared + set_target_properties(sundials_fsunmatrixdense_shared PROPERTIES OUTPUT_NAME sundials_fsunmatrixdense CLEAN_DIRECT_OUTPUT 1) - SET_TARGET_PROPERTIES(sundials_fsunmatrixdense_shared + set_target_properties(sundials_fsunmatrixdense_shared PROPERTIES VERSION ${sunmatrixlib_VERSION} SOVERSION ${sunmatrixlib_SOVERSION}) - INSTALL(TARGETS sundials_fsunmatrixdense_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) - ENDIF(BUILD_SHARED_LIBS) + install(TARGETS sundials_fsunmatrixdense_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(BUILD_SHARED_LIBS) -ENDIF(F77_INTERFACE_ENABLE AND F77_FOUND) +endif(F77_INTERFACE_ENABLE AND F77_FOUND) # -MESSAGE(STATUS "Added SUNMATRIX_DENSE module") +message(STATUS "Added SUNMATRIX_DENSE module") diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/F90/fsunmatrix_dense.f90 b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/F90/fsunmatrix_dense.f90 deleted file mode 100644 index eb9b59382..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/F90/fsunmatrix_dense.f90 +++ /dev/null @@ -1,200 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): David J. Gardner @ LLNL -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS dense matrix using the ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fsunmatrix_dense_mod - - !======= Interfaces ========= - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - type(c_ptr) function FSUNDenseMatrix(M, N) & - bind(C,name='SUNDenseMatrix') - use, intrinsic :: iso_c_binding - implicit none - integer(c_long), value :: M - integer(c_long), value :: N - end function FSUNDenseMatrix - - ! ================================================================= - ! Destructors - ! ================================================================= - - subroutine FSUNMatDestroy_Dense(A) & - bind(C,name='SUNMatDestroy_Dense') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end subroutine FSUNMatDestroy_Dense - - ! ================================================================= - ! Other routines - ! ================================================================= - - ! ----------------------------------------------------------------- - ! NOT INTERFACED SUNDenseMatrix_Print - ! ----------------------------------------------------------------- - - integer(c_long) function FSUNDenseMatrix_Rows(A) & - bind(C,name='SUNDenseMatrix_Rows') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNDenseMatrix_Rows - - integer(c_long) function FSUNDenseMatrix_Columns(A) & - bind(C,name='SUNDenseMatrix_Columns') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNDenseMatrix_Columns - - integer(c_long) function FSUNDenseMatrix_LData(A) & - bind(C,name='SUNDenseMatrix_LData') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNDenseMatrix_LData - - type(c_ptr) function FSUNDenseMatrix_Data(A) & - bind(C,name='SUNDenseMatrix_Data') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNDenseMatrix_Data - - ! ----------------------------------------------------------------- - ! NOT INTERFACED SUNDenseMatrix_Cols - ! ----------------------------------------------------------------- - - type(c_ptr) function FSUNDenseMatrix_Column(A, j) & - bind(C,name='SUNDenseMatrix_Column') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - integer(c_long), value :: j - end function FSUNDenseMatrix_Column - - ! ================================================================= - ! Operations - ! ================================================================= - - integer(c_int) function FSUNMatGetID_Dense(A) & - bind(C,name='SUNMatGetID_Dense') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNMatGetID_Dense - - type(c_ptr) function FSUNMatClone_Dense(A) & - bind(C,name='SUNMatClone_Dense') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: A - end function FSUNMatClone_Dense - - integer(c_int) function FSUNMatZero_Dense(A) & - bind(C,name='SUNMatZero_Dense') - use, intrinsic :: iso_c_binding - type(c_ptr), value :: A - end function FSUNMatZero_Dense - - integer(c_int) function FSUNMatCopy_Dense(A, B) & - bind(C,name='SUNMatCopy_Dense') - use, intrinsic :: iso_c_binding - type(c_ptr), value :: A - type(c_ptr), value :: B - end function FSUNMatCopy_Dense - - integer(c_int) function FSUNMatScaleAdd_Dense(c, A, B) & - bind(C,name='SUNMatScaleAdd_Dense') - use, intrinsic :: iso_c_binding - real(c_double), value :: c - type(c_ptr), value :: A - type(c_ptr), value :: B - end function FSUNMatScaleAdd_Dense - - integer(c_int) function FSUNMatScaleAddI_Dense(c, A) & - bind(C,name='SUNMatScaleAddI_Dense') - use, intrinsic :: iso_c_binding - real(c_double), value :: c - type(c_ptr), value :: A - end function FSUNMatScaleAddI_Dense - - integer(c_int) function FSUNMatMatvec_Dense(A, x, y) & - bind(C,name='SUNMatMatvec_Dense') - use, intrinsic :: iso_c_binding - type(c_ptr), value :: A - type(c_ptr), value :: x - type(c_ptr), value :: y - end function FSUNMatMatvec_Dense - - integer(c_int) function FSUNMatSpace_Dense(A, lenrw, leniw) & - bind(C,name='SUNMatSpace_Dense') - use, intrinsic :: iso_c_binding - type(c_ptr), value :: A - integer(c_long) :: lenrw - integer(c_long) :: leniw - end function FSUNMatSpace_Dense - - end interface - -contains - - ! ================================================================ - ! Helpful routines - ! ================================================================ - - ! ---------------------------------------------------------------- - ! FSUNMatGetData_Dense - ! - ! Extracts data array from a SUNDIALS Dense Matrix - ! ---------------------------------------------------------------- - - subroutine FSUNMatGetData_Dense(A, f_array) - - !======= Inclusions =========== - use, intrinsic :: iso_c_binding - - !======= Declarations ========= - implicit none - - ! calling variables - type(c_ptr) :: A - real(c_double), pointer :: f_array(:,:) - - ! internal variables - type(c_ptr) :: c_array - integer(c_long) :: M, N - - !======= Internals ============ - - ! get data pointer from N_Vector - c_array = FSUNDenseMatrix_Data(A) - - ! get matrix size - M = FSUNDenseMatrix_Rows(A) - N = FSUNDenseMatrix_Columns(A) - - ! convert and reshape 1D data array - call c_f_pointer(c_array, f_array, (/M,N/)) - - end subroutine FSUNMatGetData_Dense - -end module fsunmatrix_dense_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fmod/CMakeLists.txt similarity index 75% rename from deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/F90/CMakeLists.txt rename to deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fmod/CMakeLists.txt index d405e77a6..5bce2e97c 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/F90/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fmod/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Cody J. Balos @ LLNL +# Programmer(s): Cody J. Balos @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -12,22 +12,25 @@ # SUNDIALS Copyright End # --------------------------------------------------------------- # CMakeLists.txt file for the F2003 dense SUNMatrix object library +# --------------------------------------------------------------- -set(sunmatrixdense_SOURCES fsunmatrix_dense.f90) +set(sunmatrixdense_SOURCES fsunmatrix_dense_mod.f90 fsunmatrix_dense_mod.c) if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fsunmatrixdense_mod_static STATIC + sundials_add_f2003_interface_library(sundials_fsunmatrixdense_mod_static STATIC_OBJECT ${sunmatrixdense_SOURCES} ) + add_dependencies(sundials_fsunmatrixdense_mod_static_obj sundials_fgeneric_static_obj) set_target_properties(sundials_fsunmatrixdense_mod_static PROPERTIES OUTPUT_NAME sundials_fsunmatrixdense_mod CLEAN_DIRECT_OUTPUT 1) install(TARGETS sundials_fsunmatrixdense_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif(BUILD_STATIC_LIBS) if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fsunmatrixdense_mod_shared SHARED + sundials_add_f2003_interface_library(sundials_fsunmatrixdense_mod_shared SHARED_OBJECT ${sunmatrixdense_SOURCES} ) + add_dependencies(sundials_fsunmatrixdense_mod_shared_obj sundials_fgeneric_shared_obj) set_target_properties(sundials_fsunmatrixdense_mod_shared PROPERTIES OUTPUT_NAME sundials_fsunmatrixdense_mod CLEAN_DIRECT_OUTPUT 1) set_target_properties(sundials_fsunmatrixdense_mod_shared diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fmod/fsunmatrix_dense_mod.c b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fmod/fsunmatrix_dense_mod.c new file mode 100644 index 000000000..dee5c7cf6 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fmod/fsunmatrix_dense_mod.c @@ -0,0 +1,429 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_matrix.h" + + +#include "sunmatrix/sunmatrix_dense.h" + +SWIGEXPORT SUNMatrix _wrap_FSUNDenseMatrix(int64_t const *farg1, int64_t const *farg2) { + SUNMatrix fresult ; + sunindextype arg1 ; + sunindextype arg2 ; + SUNMatrix result; + + arg1 = (sunindextype)(*farg1); + arg2 = (sunindextype)(*farg2); + result = (SUNMatrix)SUNDenseMatrix(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FSUNDenseMatrix_Print(SUNMatrix farg1, void *farg2) { + SUNMatrix arg1 = (SUNMatrix) 0 ; + FILE *arg2 = (FILE *) 0 ; + + arg1 = (SUNMatrix)(farg1); + arg2 = (FILE *)(farg2); + SUNDenseMatrix_Print(arg1,arg2); +} + + +SWIGEXPORT int64_t _wrap_FSUNDenseMatrix_Rows(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNDenseMatrix_Rows(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNDenseMatrix_Columns(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNDenseMatrix_Columns(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNDenseMatrix_LData(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNDenseMatrix_LData(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT double * _wrap_FSUNDenseMatrix_Data(SUNMatrix farg1) { + double * fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + realtype *result = 0 ; + + arg1 = (SUNMatrix)(farg1); + result = (realtype *)SUNDenseMatrix_Data(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void * _wrap_FSUNDenseMatrix_Cols(SUNMatrix farg1) { + void * fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + realtype **result = 0 ; + + arg1 = (SUNMatrix)(farg1); + result = (realtype **)SUNDenseMatrix_Cols(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT double * _wrap_FSUNDenseMatrix_Column(SUNMatrix farg1, int64_t const *farg2) { + double * fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype arg2 ; + realtype *result = 0 ; + + arg1 = (SUNMatrix)(farg1); + arg2 = (sunindextype)(*farg2); + result = (realtype *)SUNDenseMatrix_Column(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatGetID_Dense(SUNMatrix farg1) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix_ID result; + + arg1 = (SUNMatrix)(farg1); + result = (SUNMatrix_ID)SUNMatGetID_Dense(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SUNMatrix _wrap_FSUNMatClone_Dense(SUNMatrix farg1) { + SUNMatrix fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix result; + + arg1 = (SUNMatrix)(farg1); + result = (SUNMatrix)SUNMatClone_Dense(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FSUNMatDestroy_Dense(SUNMatrix farg1) { + SUNMatrix arg1 = (SUNMatrix) 0 ; + + arg1 = (SUNMatrix)(farg1); + SUNMatDestroy_Dense(arg1); +} + + +SWIGEXPORT int _wrap_FSUNMatZero_Dense(SUNMatrix farg1) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + result = (int)SUNMatZero_Dense(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatCopy_Dense(SUNMatrix farg1, SUNMatrix farg2) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNMatCopy_Dense(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatScaleAdd_Dense(double const *farg1, SUNMatrix farg2, SUNMatrix farg3) { + int fresult ; + realtype arg1 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + SUNMatrix arg3 = (SUNMatrix) 0 ; + int result; + + arg1 = (realtype)(*farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (SUNMatrix)(farg3); + result = (int)SUNMatScaleAdd_Dense(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatScaleAddI_Dense(double const *farg1, SUNMatrix farg2) { + int fresult ; + realtype arg1 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (realtype)(*farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNMatScaleAddI_Dense(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatMatvec_Dense(SUNMatrix farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)SUNMatMatvec_Dense(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatSpace_Dense(SUNMatrix farg1, long *farg2, long *farg3) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNMatSpace_Dense(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fmod/fsunmatrix_dense_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fmod/fsunmatrix_dense_mod.f90 new file mode 100644 index 000000000..c604962f5 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fmod/fsunmatrix_dense_mod.f90 @@ -0,0 +1,446 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunmatrix_dense_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_matrix_mod + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FSUNDenseMatrix + public :: FSUNDenseMatrix_Print + public :: FSUNDenseMatrix_Rows + public :: FSUNDenseMatrix_Columns + public :: FSUNDenseMatrix_LData + public :: FSUNDenseMatrix_Data + public :: FSUNDenseMatrix_Cols + public :: FSUNDenseMatrix_Column + public :: FSUNMatGetID_Dense + public :: FSUNMatClone_Dense + public :: FSUNMatDestroy_Dense + public :: FSUNMatZero_Dense + public :: FSUNMatCopy_Dense + public :: FSUNMatScaleAdd_Dense + public :: FSUNMatScaleAddI_Dense + public :: FSUNMatMatvec_Dense + public :: FSUNMatSpace_Dense + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNDenseMatrix(farg1, farg2) & +bind(C, name="_wrap_FSUNDenseMatrix") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +subroutine swigc_FSUNDenseMatrix_Print(farg1, farg2) & +bind(C, name="_wrap_FSUNDenseMatrix_Print") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_FSUNDenseMatrix_Rows(farg1) & +bind(C, name="_wrap_FSUNDenseMatrix_Rows") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNDenseMatrix_Columns(farg1) & +bind(C, name="_wrap_FSUNDenseMatrix_Columns") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNDenseMatrix_LData(farg1) & +bind(C, name="_wrap_FSUNDenseMatrix_LData") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNDenseMatrix_Data(farg1) & +bind(C, name="_wrap_FSUNDenseMatrix_Data") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNDenseMatrix_Cols(farg1) & +bind(C, name="_wrap_FSUNDenseMatrix_Cols") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNDenseMatrix_Column(farg1, farg2) & +bind(C, name="_wrap_FSUNDenseMatrix_Column") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FSUNMatGetID_Dense(farg1) & +bind(C, name="_wrap_FSUNMatGetID_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatClone_Dense(farg1) & +bind(C, name="_wrap_FSUNMatClone_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FSUNMatDestroy_Dense(farg1) & +bind(C, name="_wrap_FSUNMatDestroy_Dense") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FSUNMatZero_Dense(farg1) & +bind(C, name="_wrap_FSUNMatZero_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatCopy_Dense(farg1, farg2) & +bind(C, name="_wrap_FSUNMatCopy_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatScaleAdd_Dense(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNMatScaleAdd_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatScaleAddI_Dense(farg1, farg2) & +bind(C, name="_wrap_FSUNMatScaleAddI_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatMatvec_Dense(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNMatMatvec_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatSpace_Dense(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNMatSpace_Dense") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNDenseMatrix(m, n) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), pointer :: swig_result +integer(C_INT64_T), intent(in) :: m +integer(C_INT64_T), intent(in) :: n +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +integer(C_INT64_T) :: farg2 + +farg1 = m +farg2 = n +fresult = swigc_FSUNDenseMatrix(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FSUNDenseMatrix_Print(a, outfile) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: outfile +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(a) +farg2 = outfile +call swigc_FSUNDenseMatrix_Print(farg1, farg2) +end subroutine + +function FSUNDenseMatrix_Rows(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNDenseMatrix_Rows(farg1) +swig_result = fresult +end function + +function FSUNDenseMatrix_Columns(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNDenseMatrix_Columns(farg1) +swig_result = fresult +end function + +function FSUNDenseMatrix_LData(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNDenseMatrix_LData(farg1) +swig_result = fresult +end function + +function FSUNDenseMatrix_Data(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNDenseMatrix_Data(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +function FSUNDenseMatrix_Cols(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNDenseMatrix_Cols(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNDenseMatrix_Column(a, j) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T), intent(in) :: j +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 + +farg1 = c_loc(a) +farg2 = j +fresult = swigc_FSUNDenseMatrix_Column(farg1, farg2) +call c_f_pointer(fresult, swig_result, [1]) +end function + +function FSUNMatGetID_Dense(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNMatrix_ID) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatGetID_Dense(farg1) +swig_result = fresult +end function + +function FSUNMatClone_Dense(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatClone_Dense(farg1) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FSUNMatDestroy_Dense(a) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +call swigc_FSUNMatDestroy_Dense(farg1) +end subroutine + +function FSUNMatZero_Dense(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatZero_Dense(farg1) +swig_result = fresult +end function + +function FSUNMatCopy_Dense(a, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(SUNMatrix), target, intent(inout) :: b +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(a) +farg2 = c_loc(b) +fresult = swigc_FSUNMatCopy_Dense(farg1, farg2) +swig_result = fresult +end function + +function FSUNMatScaleAdd_Dense(c, a, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +real(C_DOUBLE), intent(in) :: c +type(SUNMatrix), target, intent(inout) :: a +type(SUNMatrix), target, intent(inout) :: b +integer(C_INT) :: fresult +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(a) +farg3 = c_loc(b) +fresult = swigc_FSUNMatScaleAdd_Dense(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNMatScaleAddI_Dense(c, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +real(C_DOUBLE), intent(in) :: c +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c +farg2 = c_loc(a) +fresult = swigc_FSUNMatScaleAddI_Dense(farg1, farg2) +swig_result = fresult +end function + +function FSUNMatMatvec_Dense(a, x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(a) +farg2 = c_loc(x) +farg3 = c_loc(y) +fresult = swigc_FSUNMatMatvec_Dense(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNMatSpace_Dense(a, lenrw, leniw) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_LONG), dimension(*), target, intent(inout) :: lenrw +integer(C_LONG), dimension(*), target, intent(inout) :: leniw +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(a) +farg2 = c_loc(lenrw(1)) +farg3 = c_loc(leniw(1)) +fresult = swigc_FSUNMatSpace_Dense(farg1, farg2, farg3) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.c b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.c index 219fb5c20..b33bf738a 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -41,25 +41,29 @@ void FSUNDENSEMAT_INIT(int *code, long int *M, long int *N, int *ier) case FCMIX_CVODE: if (F2C_CVODE_matrix) SUNMatDestroy(F2C_CVODE_matrix); F2C_CVODE_matrix = NULL; - F2C_CVODE_matrix = SUNDenseMatrix(*M, *N); + F2C_CVODE_matrix = SUNDenseMatrix((sunindextype)(*M), + (sunindextype)(*N)); if (F2C_CVODE_matrix == NULL) *ier = -1; break; case FCMIX_IDA: if (F2C_IDA_matrix) SUNMatDestroy(F2C_IDA_matrix); F2C_IDA_matrix = NULL; - F2C_IDA_matrix = SUNDenseMatrix(*M, *N); + F2C_IDA_matrix = SUNDenseMatrix((sunindextype)(*M), + (sunindextype)(*N)); if (F2C_IDA_matrix == NULL) *ier = -1; break; case FCMIX_KINSOL: if (F2C_KINSOL_matrix) SUNMatDestroy(F2C_KINSOL_matrix); F2C_KINSOL_matrix = NULL; - F2C_KINSOL_matrix = SUNDenseMatrix(*M, *N); + F2C_KINSOL_matrix = SUNDenseMatrix((sunindextype)(*M), + (sunindextype)(*N)); if (F2C_KINSOL_matrix == NULL) *ier = -1; break; case FCMIX_ARKODE: if (F2C_ARKODE_matrix) SUNMatDestroy(F2C_ARKODE_matrix); F2C_ARKODE_matrix = NULL; - F2C_ARKODE_matrix = SUNDenseMatrix(*M, *N); + F2C_ARKODE_matrix = SUNDenseMatrix((sunindextype)(*M), + (sunindextype)(*N)); if (F2C_ARKODE_matrix == NULL) *ier = -1; break; default: @@ -73,6 +77,7 @@ void FSUNDENSEMASSMAT_INIT(long int *M, long int *N, int *ier) *ier = 0; if (F2C_ARKODE_mass_matrix) SUNMatDestroy(F2C_ARKODE_mass_matrix); F2C_ARKODE_mass_matrix = NULL; - F2C_ARKODE_mass_matrix = SUNDenseMatrix(*M, *N); + F2C_ARKODE_mass_matrix = SUNDenseMatrix((sunindextype)(*M), + (sunindextype)(*N)); if (F2C_ARKODE_mass_matrix == NULL) *ier = -1; } diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.h b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.h index cf952b4c4..a218acb88 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/sunmatrix_dense.c b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/sunmatrix_dense.c index 6494e01c9..970ab0e87 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/sunmatrix_dense.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/dense/sunmatrix_dense.c @@ -1,12 +1,11 @@ -/* - * ----------------------------------------------------------------- +/* ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU * David Gardner @ LLNL - * Based on code sundials_dense.c by: Scott D. Cohen, + * Based on code sundials_dense.c by: Scott D. Cohen, * Alan C. Hindmarsh and Radu Serban @ LLNL * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -15,10 +14,9 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the dense implementation of + * This is the implementation file for the dense implementation of * the SUNMATRIX package. - * ----------------------------------------------------------------- - */ + * -----------------------------------------------------------------*/ #include #include @@ -48,58 +46,50 @@ static booleantype SMCompatible2_Dense(SUNMatrix A, N_Vector x, N_Vector y); SUNMatrix SUNDenseMatrix(sunindextype M, sunindextype N) { SUNMatrix A; - SUNMatrix_Ops ops; SUNMatrixContent_Dense content; sunindextype j; /* return with NULL matrix on illegal dimension input */ if ( (M <= 0) || (N <= 0) ) return(NULL); - /* Create matrix */ + /* Create an empty matrix object */ A = NULL; - A = (SUNMatrix) malloc(sizeof *A); + A = SUNMatNewEmpty(); if (A == NULL) return(NULL); - - /* Create matrix operation structure */ - ops = NULL; - ops = (SUNMatrix_Ops) malloc(sizeof(struct _generic_SUNMatrix_Ops)); - if (ops == NULL) { free(A); return(NULL); } /* Attach operations */ - ops->getid = SUNMatGetID_Dense; - ops->clone = SUNMatClone_Dense; - ops->destroy = SUNMatDestroy_Dense; - ops->zero = SUNMatZero_Dense; - ops->copy = SUNMatCopy_Dense; - ops->scaleadd = SUNMatScaleAdd_Dense; - ops->scaleaddi = SUNMatScaleAddI_Dense; - ops->matvec = SUNMatMatvec_Dense; - ops->space = SUNMatSpace_Dense; + A->ops->getid = SUNMatGetID_Dense; + A->ops->clone = SUNMatClone_Dense; + A->ops->destroy = SUNMatDestroy_Dense; + A->ops->zero = SUNMatZero_Dense; + A->ops->copy = SUNMatCopy_Dense; + A->ops->scaleadd = SUNMatScaleAdd_Dense; + A->ops->scaleaddi = SUNMatScaleAddI_Dense; + A->ops->matvec = SUNMatMatvec_Dense; + A->ops->space = SUNMatSpace_Dense; /* Create content */ content = NULL; - content = (SUNMatrixContent_Dense) malloc(sizeof(struct _SUNMatrixContent_Dense)); - if (content == NULL) { free(ops); free(A); return(NULL); } + content = (SUNMatrixContent_Dense) malloc(sizeof *content); + if (content == NULL) { SUNMatDestroy(A); return(NULL); } + + /* Attach content */ + A->content = content; /* Fill content */ - content->M = M; - content->N = N; + content->M = M; + content->N = N; content->ldata = M*N; - content->data = NULL; + content->data = NULL; + content->cols = NULL; + + /* Allocate content */ content->data = (realtype *) calloc(M * N, sizeof(realtype)); - if (content->data == NULL) { - free(content); free(ops); free(A); return(NULL); - } - content->cols = NULL; + if (content->data == NULL) { SUNMatDestroy(A); return(NULL); } + content->cols = (realtype **) malloc(N * sizeof(realtype *)); - if (content->cols == NULL) { - free(content->data); free(content); free(ops); free(A); return(NULL); - } + if (content->cols == NULL) { SUNMatDestroy(A); return(NULL); } for (j=0; jcols[j] = content->data + j * M; - - /* Attach content and ops */ - A->content = content; - A->ops = ops; return(A); } @@ -146,7 +136,7 @@ sunindextype SUNDenseMatrix_Rows(SUNMatrix A) if (SUNMatGetID(A) == SUNMATRIX_DENSE) return SM_ROWS_D(A); else - return -1; + return SUNMAT_ILL_INPUT; } sunindextype SUNDenseMatrix_Columns(SUNMatrix A) @@ -154,7 +144,7 @@ sunindextype SUNDenseMatrix_Columns(SUNMatrix A) if (SUNMatGetID(A) == SUNMATRIX_DENSE) return SM_COLUMNS_D(A); else - return -1; + return SUNMAT_ILL_INPUT; } sunindextype SUNDenseMatrix_LData(SUNMatrix A) @@ -162,7 +152,7 @@ sunindextype SUNDenseMatrix_LData(SUNMatrix A) if (SUNMatGetID(A) == SUNMATRIX_DENSE) return SM_LDATA_D(A); else - return -1; + return SUNMAT_ILL_INPUT; } realtype* SUNDenseMatrix_Data(SUNMatrix A) @@ -209,12 +199,29 @@ SUNMatrix SUNMatClone_Dense(SUNMatrix A) void SUNMatDestroy_Dense(SUNMatrix A) { - /* perform operation */ - free(SM_DATA_D(A)); SM_DATA_D(A) = NULL; - free(SM_CONTENT_D(A)->cols); SM_CONTENT_D(A)->cols = NULL; - free(A->content); A->content = NULL; - free(A->ops); A->ops = NULL; + if (A == NULL) return; + + /* free content */ + if (A->content != NULL) { + /* free data array */ + if (SM_DATA_D(A) != NULL) { + free(SM_DATA_D(A)); + SM_DATA_D(A) = NULL; + } + /* free column pointers */ + if (SM_CONTENT_D(A)->cols != NULL) { + free(SM_CONTENT_D(A)->cols); + SM_CONTENT_D(A)->cols = NULL; + } + /* free content struct */ + free(A->content); + A->content = NULL; + } + + /* free ops and matrix */ + if (A->ops) { free(A->ops); A->ops = NULL; } free(A); A = NULL; + return; } @@ -227,7 +234,7 @@ int SUNMatZero_Dense(SUNMatrix A) Adata = SM_DATA_D(A); for (i=0; i +#include +#include +#include +#include +#include +#include + +/* + * ---------------------------------------------------------------------------- + * Macros for accessing the SUNMatrix_SLUNRloc content structure members + * and useful values stored in nested SuperLU structures. + * ---------------------------------------------------------------------------- + */ + +#define SM_CONTENT_SLUNRLOC(A) ( (SUNMatrixContent_SLUNRloc)(A->content) ) + +#define SM_SUPERMATRIX_SLUNRLOC(A) ( SM_CONTENT_SLUNRLOC(A)->A_super ) + +#define SM_GRID_SLUNRLOC(A) ( SM_CONTENT_SLUNRLOC(A)->grid ) + +#define SM_COMMPATTERN_SLUNRLOC(A) ( SM_CONTENT_SLUNRLOC(A)->gsmv_comm ) + +#define SM_ROWTOPROC_SLUNRLOC(A) ( SM_CONTENT_SLUNRLOC(A)->row_to_proc ) + +#define SM_OWNDATA_SLUNRLOC(A) ( SM_CONTENT_SLUNRLOC(A)->own_data ) + +#define SM_COLSORTED_SLUNRLOC(A) ( SM_CONTENT_SLUNRLOC(A)->ACS_super ) + +#define SM_SUPERSTORE_SLUNRLOC(A) ( (NRformat_loc*)(SM_SUPERMATRIX_SLUNRLOC(A)->Store) ) + +#define SM_GLOBALROWS_SLUNRLOC(A) ( SM_SUPERMATRIX_SLUNRLOC(A)->nrow ) + +#define SM_GLOBALCOLS_SLUNRLOC(A) ( SM_SUPERMATRIX_SLUNRLOC(A)->ncol ) + +#define SM_LOCALROWS_SLUNRLOC(A) ( SM_SUPERSTORE_SLUNRLOC(A)->m_loc ) + +#define SM_LOCALNNZ_SLUNRLOC(A) ( SM_SUPERSTORE_SLUNRLOC(A)->nnz_loc ) + +#define SM_FSTROW_SLUNRLOC(A) ( SM_SUPERSTORE_SLUNRLOC(A)->fst_row ) + +#define SM_DATA_SLUNRLOC(A) ( (realtype*)SM_SUPERSTORE_SLUNRLOC(A)->nzval ) + +#define SM_COLIND_SLUNRLOC(A) ( SM_SUPERSTORE_SLUNRLOC(A)->colind ) + +#define SM_ROWPTRS_SLUNRLOC(A) ( SM_SUPERSTORE_SLUNRLOC(A)->rowptr ) + +/* constants */ +#define ZERO RCONST(0.0) + +/* Private function prototypes */ +static booleantype SMCompatible_SLUNRloc(SUNMatrix A, SUNMatrix B); + +/* + * ---------------------------------------------------------------------------- + * Exported functions + * ---------------------------------------------------------------------------- + */ + +SUNMatrix SUNMatrix_SLUNRloc(SuperMatrix *A_super, gridinfo_t *grid) +{ + SUNMatrix A; + SUNMatrix_Ops ops; + SUNMatrixContent_SLUNRloc content; + + /* Check for valid intputs */ + if (A_super == NULL || grid == NULL) + return(NULL); + + if (A_super->Stype != SLU_NR_loc || + A_super->Dtype != SLU_D || + A_super->Mtype != SLU_GE) + return(NULL); + + /* Create the matrix */ + A = NULL; + A = (SUNMatrix) malloc(sizeof(*A)); + if (A == NULL) return(NULL); + + /* Create the matrix operations structure */ + ops = NULL; + ops = (SUNMatrix_Ops) malloc(sizeof(struct _generic_SUNMatrix_Ops)); + if (ops == NULL) { free(A); return(NULL); } + + /* Attach operations */ + ops->getid = SUNMatGetID_SLUNRloc; + ops->clone = SUNMatClone_SLUNRloc; + ops->destroy = SUNMatDestroy_SLUNRloc; + ops->zero = SUNMatZero_SLUNRloc; + ops->copy = SUNMatCopy_SLUNRloc; + ops->scaleadd = SUNMatScaleAdd_SLUNRloc; + ops->scaleaddi = SUNMatScaleAddI_SLUNRloc; + ops->matvecsetup = SUNMatMatvecSetup_SLUNRloc; + ops->matvec = SUNMatMatvec_SLUNRloc; + ops->space = SUNMatSpace_SLUNRloc; + + /* Create content */ + content = NULL; + content = (SUNMatrixContent_SLUNRloc) + malloc(sizeof(struct _SUNMatrixContent_SLUNRloc)); + if (content == NULL) { free(ops); free(A); return(NULL); } + + /* Attach content to SuperMatrix */ + content->A_super = A_super; + content->own_data = SUNFALSE; + content->grid = grid; + content->row_to_proc = NULL; + content->gsmv_comm = NULL; + content->ACS_super = NULL; + + /* Attach content and ops to SUNMatrix */ + A->content = content; + A->ops = ops; + + return(A); +} + +void SUNMatrix_SLUNRloc_Print(SUNMatrix A, FILE *fp) +{ + fprintf(fp, "====== START SUNMatrix_SLUNRloc_Print %p ======\n", (void*) A); + fprintf(fp, "A->content->A_super = %p\n", (void*) SM_SUPERMATRIX_SLUNRLOC(A)); + + /* Call SuperLU_DIST print routine */ + file_dPrint_CompRowLoc_Matrix_dist(fp, SM_SUPERMATRIX_SLUNRLOC(A)); + + fprintf(fp, "======= END SUNMatrix_SLUNRloc_Print %p =======\n", (void*) A); +} + + +/* + * ---------------------------------------------------------------------------- + * Implementation of accessor functions + * ---------------------------------------------------------------------------- + */ + +SuperMatrix* SUNMatrix_SLUNRloc_SuperMatrix(SUNMatrix A) +{ + return(SM_SUPERMATRIX_SLUNRLOC(A)); +} + +gridinfo_t* SUNMatrix_SLUNRloc_ProcessGrid(SUNMatrix A) +{ + return(SM_GRID_SLUNRLOC(A)); +} + +booleantype SUNMatrix_SLUNRloc_OwnData(SUNMatrix A) +{ + return(SM_OWNDATA_SLUNRLOC(A)); +} + +/* + * ---------------------------------------------------------------------------- + * Implementation of matrix operations + * ---------------------------------------------------------------------------- + */ + +SUNMatrix_ID SUNMatGetID_SLUNRloc(SUNMatrix A) +{ + return(SUNMATRIX_SLUNRLOC); +} + +SUNMatrix SUNMatClone_SLUNRloc(SUNMatrix A) +{ + SUNMatrix B; + SuperMatrix *B_super; + + /* allocate new SuperMatrix */ + B_super = NULL; + B_super = malloc(sizeof(SuperMatrix)); + if (B_super == NULL) return(NULL); + + /* call the SuperLU-DIST clone function */ + dClone_CompRowLoc_Matrix_dist(SM_SUPERMATRIX_SLUNRLOC(A), B_super); + + /* create the new SUNMatrix */ + B = NULL; + B = SUNMatrix_SLUNRloc(B_super, SM_GRID_SLUNRLOC(A)); + if (B == NULL) { + /* call SuperLU-DIST destroy function */ + Destroy_CompRowLoc_Matrix_dist(B_super); + free(B_super); + return(NULL); + } + + /* Allocated the SuperMatrix ourselves, so SUNMatrix now owns the data */ + SM_OWNDATA_SLUNRLOC(B) = SUNTRUE; + + return(B); +} + +void SUNMatDestroy_SLUNRloc(SUNMatrix A) +{ + if (SM_OWNDATA_SLUNRLOC(A)) { + /* call SuperLU-DIST destroy function */ + Destroy_CompRowLoc_Matrix_dist(SM_SUPERMATRIX_SLUNRLOC(A)); + free(SM_SUPERMATRIX_SLUNRLOC(A)); + } + if (SM_COLSORTED_SLUNRLOC(A)) { + /* if CS exists, then the Matvec has been initialized and we must finalize + it by calling the SuperLU DIST pdgsmv_finalize routine to free up memory + allocated */ + + pdgsmv_finalize(SM_COMMPATTERN_SLUNRLOC(A)); + Destroy_CompRowLoc_Matrix_dist(SM_COLSORTED_SLUNRLOC(A)); + free(SM_COLSORTED_SLUNRLOC(A)); + SM_COLSORTED_SLUNRLOC(A) = NULL; + } + if (SM_ROWTOPROC_SLUNRLOC(A)) { + free(SM_ROWTOPROC_SLUNRLOC(A)); + SM_ROWTOPROC_SLUNRLOC(A) = NULL; + } + if (SM_COMMPATTERN_SLUNRLOC(A)) { + free(SM_COMMPATTERN_SLUNRLOC(A)); + SM_COMMPATTERN_SLUNRLOC(A) = NULL; + } + free(A->content); A->content = NULL; + free(A->ops); A->ops = NULL; + free(A); A = NULL; + return; +} + +int SUNMatZero_SLUNRloc(SUNMatrix A) +{ + /* call SuperLU-DIST clone function */ + dZero_CompRowLoc_Matrix_dist(SM_SUPERMATRIX_SLUNRLOC(A)); + return(SUNMAT_SUCCESS); +} + +int SUNMatCopy_SLUNRloc(SUNMatrix A, SUNMatrix B) +{ + /* call SuperLU-DIST copy function */ + dCopy_CompRowLoc_Matrix_dist(SM_SUPERMATRIX_SLUNRLOC(A), + SM_SUPERMATRIX_SLUNRLOC(B)); + return(SUNMAT_SUCCESS); +} + +int SUNMatScaleAdd_SLUNRloc(realtype c, SUNMatrix A, SUNMatrix B) +{ + /* check that B can be added into A */ + if (!SMCompatible_SLUNRloc(A, B)) return(SUNMAT_ILL_INPUT); + + /* call SuperLU-DIST ScaleAdd function */ + dScaleAdd_CompRowLoc_Matrix_dist(SM_SUPERMATRIX_SLUNRLOC(A), + SM_SUPERMATRIX_SLUNRLOC(B), c); + return(SUNMAT_SUCCESS); +} + +int SUNMatScaleAddI_SLUNRloc(realtype c, SUNMatrix A) +{ + /* call SuperLU-DIST ScaleAddI function */ + dScaleAddId_CompRowLoc_Matrix_dist(SM_SUPERMATRIX_SLUNRLOC(A), c); + return(SUNMAT_SUCCESS); +} + +int SUNMatMatvec_SLUNRloc(SUNMatrix A, N_Vector x, N_Vector y) +{ + SuperMatrix *ACS; + realtype *xdata, *ydata; + + /* Extract the column-sorted A */ + ACS = SM_COLSORTED_SLUNRLOC(A); + + /* The column-sorted matrix ACS and the communication pattern must be + established by calling SUNMatMatvecSetup prior to calling SUNMatMatvec. */ + if (ACS == NULL || SM_ROWTOPROC_SLUNRLOC(A) == NULL || + SM_COMMPATTERN_SLUNRLOC(A) == NULL) + return(SUNMAT_MATVEC_SETUP_REQUIRED); + + xdata = N_VGetArrayPointer(x); + ydata = N_VGetArrayPointer(y); + if (xdata == NULL || ydata == NULL) + return(SUNMAT_MEM_FAIL); + + /* Call SuperLU-DIST Matvec routine to perform the actual Matvec. */ + pdgsmv(0, ACS, SM_GRID_SLUNRLOC(A), SM_COMMPATTERN_SLUNRLOC(A), xdata, ydata); + + return(SUNMAT_SUCCESS); +} + +int SUNMatMatvecSetup_SLUNRloc(SUNMatrix A) +{ + sunindextype *temp; + sunindextype nprocs; + sunindextype i, j; + + SuperMatrix *ACS = SM_COLSORTED_SLUNRLOC(A); + + /* If ACS is NULL, then this is the first setup call and things must be + allocated */ + if (ACS == NULL) { + ACS = (SuperMatrix *) malloc(sizeof(SuperMatrix)); + + /* Clone and copy A to create ACS which will be A but with column-sorted + column indices to [internal, external]. ACS is used with the Matvec + routine. */ + dClone_CompRowLoc_Matrix_dist(SM_SUPERMATRIX_SLUNRLOC(A), ACS); + dCopy_CompRowLoc_Matrix_dist(SM_SUPERMATRIX_SLUNRLOC(A), ACS); + + SM_ROWTOPROC_SLUNRLOC(A) = (sunindextype *) + malloc(SM_GLOBALROWS_SLUNRLOC(A)*sizeof(sunindextype)); + if (SM_ROWTOPROC_SLUNRLOC(A) == NULL) { + Destroy_CompRowLoc_Matrix_dist(ACS); free(ACS); + return(SUNMAT_MEM_FAIL); + } + + SM_COMMPATTERN_SLUNRLOC(A) = (pdgsmv_comm_t *) malloc(sizeof(pdgsmv_comm_t)); + if (SM_COMMPATTERN_SLUNRLOC(A) == NULL) { + free(SM_ROWTOPROC_SLUNRLOC(A)); + Destroy_CompRowLoc_Matrix_dist(ACS); free(ACS); + return(SUNMAT_MEM_FAIL); + } + + SM_COLSORTED_SLUNRLOC(A) = ACS; + } else { + /* if ACS has already been created, we can reuse it to save allocations, + but we must finalize the last matvec to avoid leaking memory.*/ + pdgsmv_finalize(SM_COMMPATTERN_SLUNRLOC(A)); + } + + /* calculate the number of processes the matrix is spread across */ + nprocs = SM_GRID_SLUNRLOC(A)->nprow*SM_GRID_SLUNRLOC(A)->npcol; + + /* establish a row number to process mapping */ + temp = (sunindextype*) malloc((nprocs+1)*sizeof(sunindextype)); + if (temp == NULL) { SUNMatDestroy(A); return(SUNMAT_MEM_FAIL); } + + MPI_Allgather(&SM_FSTROW_SLUNRLOC(A), 1, MPI_SUNINDEXTYPE, + temp, 1, MPI_SUNINDEXTYPE, SM_GRID_SLUNRLOC(A)->comm); + + temp[nprocs] = SM_GLOBALROWS_SLUNRLOC(A); + for (i=0; i 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_matrix.h" + + +#include "sunmatrix/sunmatrix_sparse.h" + +SWIGEXPORT SUNMatrix _wrap_FSUNSparseMatrix(int64_t const *farg1, int64_t const *farg2, int64_t const *farg3, int const *farg4) { + SUNMatrix fresult ; + sunindextype arg1 ; + sunindextype arg2 ; + sunindextype arg3 ; + int arg4 ; + SUNMatrix result; + + arg1 = (sunindextype)(*farg1); + arg2 = (sunindextype)(*farg2); + arg3 = (sunindextype)(*farg3); + arg4 = (int)(*farg4); + result = (SUNMatrix)SUNSparseMatrix(arg1,arg2,arg3,arg4); + fresult = result; + return fresult; +} + + +SWIGEXPORT SUNMatrix _wrap_FSUNSparseFromDenseMatrix(SUNMatrix farg1, double const *farg2, int const *farg3) { + SUNMatrix fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + realtype arg2 ; + int arg3 ; + SUNMatrix result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + result = (SUNMatrix)SUNSparseFromDenseMatrix(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT SUNMatrix _wrap_FSUNSparseFromBandMatrix(SUNMatrix farg1, double const *farg2, int const *farg3) { + SUNMatrix fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + realtype arg2 ; + int arg3 ; + SUNMatrix result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (realtype)(*farg2); + arg3 = (int)(*farg3); + result = (SUNMatrix)SUNSparseFromBandMatrix(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSparseMatrix_ToCSR(SUNMatrix farg1, void *farg2) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) (SUNMatrix)0 ; + SUNMatrix *arg2 = (SUNMatrix *) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (SUNMatrix *)(farg2); + result = (int)SUNSparseMatrix_ToCSR(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSparseMatrix_ToCSC(SUNMatrix farg1, void *farg2) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) (SUNMatrix)0 ; + SUNMatrix *arg2 = (SUNMatrix *) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (SUNMatrix *)(farg2); + result = (int)SUNSparseMatrix_ToCSC(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSparseMatrix_Realloc(SUNMatrix farg1) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + result = (int)SUNSparseMatrix_Realloc(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSparseMatrix_Reallocate(SUNMatrix farg1, int64_t const *farg2) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype arg2 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (sunindextype)(*farg2); + result = (int)SUNSparseMatrix_Reallocate(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT void _wrap_FSUNSparseMatrix_Print(SUNMatrix farg1, void *farg2) { + SUNMatrix arg1 = (SUNMatrix) 0 ; + FILE *arg2 = (FILE *) 0 ; + + arg1 = (SUNMatrix)(farg1); + arg2 = (FILE *)(farg2); + SUNSparseMatrix_Print(arg1,arg2); +} + + +SWIGEXPORT int64_t _wrap_FSUNSparseMatrix_Rows(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNSparseMatrix_Rows(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNSparseMatrix_Columns(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNSparseMatrix_Columns(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNSparseMatrix_NNZ(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNSparseMatrix_NNZ(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int64_t _wrap_FSUNSparseMatrix_NP(SUNMatrix farg1) { + int64_t fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype result; + + arg1 = (SUNMatrix)(farg1); + result = SUNSparseMatrix_NP(arg1); + fresult = (sunindextype)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNSparseMatrix_SparseType(SUNMatrix farg1) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + result = (int)SUNSparseMatrix_SparseType(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT double * _wrap_FSUNSparseMatrix_Data(SUNMatrix farg1) { + double * fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + realtype *result = 0 ; + + arg1 = (SUNMatrix)(farg1); + result = (realtype *)SUNSparseMatrix_Data(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int64_t * _wrap_FSUNSparseMatrix_IndexValues(SUNMatrix farg1) { + int64_t * fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype *result = 0 ; + + arg1 = (SUNMatrix)(farg1); + result = (sunindextype *)SUNSparseMatrix_IndexValues(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int64_t * _wrap_FSUNSparseMatrix_IndexPointers(SUNMatrix farg1) { + int64_t * fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + sunindextype *result = 0 ; + + arg1 = (SUNMatrix)(farg1); + result = (sunindextype *)SUNSparseMatrix_IndexPointers(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatGetID_Sparse(SUNMatrix farg1) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix_ID result; + + arg1 = (SUNMatrix)(farg1); + result = (SUNMatrix_ID)SUNMatGetID_Sparse(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT SUNMatrix _wrap_FSUNMatClone_Sparse(SUNMatrix farg1) { + SUNMatrix fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix result; + + arg1 = (SUNMatrix)(farg1); + result = (SUNMatrix)SUNMatClone_Sparse(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT void _wrap_FSUNMatDestroy_Sparse(SUNMatrix farg1) { + SUNMatrix arg1 = (SUNMatrix) 0 ; + + arg1 = (SUNMatrix)(farg1); + SUNMatDestroy_Sparse(arg1); +} + + +SWIGEXPORT int _wrap_FSUNMatZero_Sparse(SUNMatrix farg1) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + result = (int)SUNMatZero_Sparse(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatCopy_Sparse(SUNMatrix farg1, SUNMatrix farg2) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNMatCopy_Sparse(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatScaleAdd_Sparse(double const *farg1, SUNMatrix farg2, SUNMatrix farg3) { + int fresult ; + realtype arg1 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + SUNMatrix arg3 = (SUNMatrix) 0 ; + int result; + + arg1 = (realtype)(*farg1); + arg2 = (SUNMatrix)(farg2); + arg3 = (SUNMatrix)(farg3); + result = (int)SUNMatScaleAdd_Sparse(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatScaleAddI_Sparse(double const *farg1, SUNMatrix farg2) { + int fresult ; + realtype arg1 ; + SUNMatrix arg2 = (SUNMatrix) 0 ; + int result; + + arg1 = (realtype)(*farg1); + arg2 = (SUNMatrix)(farg2); + result = (int)SUNMatScaleAddI_Sparse(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatMatvec_Sparse(SUNMatrix farg1, N_Vector farg2, N_Vector farg3) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + result = (int)SUNMatMatvec_Sparse(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNMatSpace_Sparse(SUNMatrix farg1, long *farg2, long *farg3) { + int fresult ; + SUNMatrix arg1 = (SUNMatrix) 0 ; + long *arg2 = (long *) 0 ; + long *arg3 = (long *) 0 ; + int result; + + arg1 = (SUNMatrix)(farg1); + arg2 = (long *)(farg2); + arg3 = (long *)(farg3); + result = (int)SUNMatSpace_Sparse(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/fmod/fsunmatrix_sparse_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/fmod/fsunmatrix_sparse_mod.f90 new file mode 100644 index 000000000..2e263af07 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/fmod/fsunmatrix_sparse_mod.f90 @@ -0,0 +1,656 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunmatrix_sparse_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_matrix_mod + use fsundials_types_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + integer(C_INT), parameter, public :: CSC_MAT = 0_C_INT + integer(C_INT), parameter, public :: CSR_MAT = 1_C_INT + public :: FSUNSparseMatrix + public :: FSUNSparseFromDenseMatrix + public :: FSUNSparseFromBandMatrix + public :: FSUNSparseMatrix_ToCSR + public :: FSUNSparseMatrix_ToCSC + public :: FSUNSparseMatrix_Realloc + public :: FSUNSparseMatrix_Reallocate + public :: FSUNSparseMatrix_Print + public :: FSUNSparseMatrix_Rows + public :: FSUNSparseMatrix_Columns + public :: FSUNSparseMatrix_NNZ + public :: FSUNSparseMatrix_NP + public :: FSUNSparseMatrix_SparseType + public :: FSUNSparseMatrix_Data + public :: FSUNSparseMatrix_IndexValues + public :: FSUNSparseMatrix_IndexPointers + public :: FSUNMatGetID_Sparse + public :: FSUNMatClone_Sparse + public :: FSUNMatDestroy_Sparse + public :: FSUNMatZero_Sparse + public :: FSUNMatCopy_Sparse + public :: FSUNMatScaleAdd_Sparse + public :: FSUNMatScaleAddI_Sparse + public :: FSUNMatMatvec_Sparse + public :: FSUNMatSpace_Sparse + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNSparseMatrix(farg1, farg2, farg3, farg4) & +bind(C, name="_wrap_FSUNSparseMatrix") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), intent(in) :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT64_T), intent(in) :: farg3 +integer(C_INT), intent(in) :: farg4 +type(C_PTR) :: fresult +end function + +function swigc_FSUNSparseFromDenseMatrix(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNSparseFromDenseMatrix") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNSparseFromBandMatrix(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNSparseFromBandMatrix") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNSparseMatrix_ToCSR(farg1, farg2) & +bind(C, name="_wrap_FSUNSparseMatrix_ToCSR") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSparseMatrix_ToCSC(farg1, farg2) & +bind(C, name="_wrap_FSUNSparseMatrix_ToCSC") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSparseMatrix_Realloc(farg1) & +bind(C, name="_wrap_FSUNSparseMatrix_Realloc") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSparseMatrix_Reallocate(farg1, farg2) & +bind(C, name="_wrap_FSUNSparseMatrix_Reallocate") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +subroutine swigc_FSUNSparseMatrix_Print(farg1, farg2) & +bind(C, name="_wrap_FSUNSparseMatrix_Print") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +end subroutine + +function swigc_FSUNSparseMatrix_Rows(farg1) & +bind(C, name="_wrap_FSUNSparseMatrix_Rows") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNSparseMatrix_Columns(farg1) & +bind(C, name="_wrap_FSUNSparseMatrix_Columns") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNSparseMatrix_NNZ(farg1) & +bind(C, name="_wrap_FSUNSparseMatrix_NNZ") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNSparseMatrix_NP(farg1) & +bind(C, name="_wrap_FSUNSparseMatrix_NP") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT64_T) :: fresult +end function + +function swigc_FSUNSparseMatrix_SparseType(farg1) & +bind(C, name="_wrap_FSUNSparseMatrix_SparseType") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNSparseMatrix_Data(farg1) & +bind(C, name="_wrap_FSUNSparseMatrix_Data") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNSparseMatrix_IndexValues(farg1) & +bind(C, name="_wrap_FSUNSparseMatrix_IndexValues") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNSparseMatrix_IndexPointers(farg1) & +bind(C, name="_wrap_FSUNSparseMatrix_IndexPointers") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNMatGetID_Sparse(farg1) & +bind(C, name="_wrap_FSUNMatGetID_Sparse") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatClone_Sparse(farg1) & +bind(C, name="_wrap_FSUNMatClone_Sparse") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +subroutine swigc_FSUNMatDestroy_Sparse(farg1) & +bind(C, name="_wrap_FSUNMatDestroy_Sparse") +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +end subroutine + +function swigc_FSUNMatZero_Sparse(farg1) & +bind(C, name="_wrap_FSUNMatZero_Sparse") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatCopy_Sparse(farg1, farg2) & +bind(C, name="_wrap_FSUNMatCopy_Sparse") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatScaleAdd_Sparse(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNMatScaleAdd_Sparse") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatScaleAddI_Sparse(farg1, farg2) & +bind(C, name="_wrap_FSUNMatScaleAddI_Sparse") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), intent(in) :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatMatvec_Sparse(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNMatMatvec_Sparse") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNMatSpace_Sparse(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNMatSpace_Sparse") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNSparseMatrix(m, n, nnz, sparsetype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), pointer :: swig_result +integer(C_INT64_T), intent(in) :: m +integer(C_INT64_T), intent(in) :: n +integer(C_INT64_T), intent(in) :: nnz +integer(C_INT), intent(in) :: sparsetype +type(C_PTR) :: fresult +integer(C_INT64_T) :: farg1 +integer(C_INT64_T) :: farg2 +integer(C_INT64_T) :: farg3 +integer(C_INT) :: farg4 + +farg1 = m +farg2 = n +farg3 = nnz +farg4 = sparsetype +fresult = swigc_FSUNSparseMatrix(farg1, farg2, farg3, farg4) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNSparseFromDenseMatrix(a, droptol, sparsetype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +real(C_DOUBLE), intent(in) :: droptol +integer(C_INT), intent(in) :: sparsetype +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 + +farg1 = c_loc(a) +farg2 = droptol +farg3 = sparsetype +fresult = swigc_FSUNSparseFromDenseMatrix(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNSparseFromBandMatrix(a, droptol, sparsetype) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +real(C_DOUBLE), intent(in) :: droptol +integer(C_INT), intent(in) :: sparsetype +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 +integer(C_INT) :: farg3 + +farg1 = c_loc(a) +farg2 = droptol +farg3 = sparsetype +fresult = swigc_FSUNSparseFromBandMatrix(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNSparseMatrix_ToCSR(a, bout) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR), target, intent(inout) :: bout +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(a) +farg2 = c_loc(bout) +fresult = swigc_FSUNSparseMatrix_ToCSR(farg1, farg2) +swig_result = fresult +end function + +function FSUNSparseMatrix_ToCSC(a, bout) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR), target, intent(inout) :: bout +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(a) +farg2 = c_loc(bout) +fresult = swigc_FSUNSparseMatrix_ToCSC(farg1, farg2) +swig_result = fresult +end function + +function FSUNSparseMatrix_Realloc(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNSparseMatrix_Realloc(farg1) +swig_result = fresult +end function + +function FSUNSparseMatrix_Reallocate(a, nnz) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T), intent(in) :: nnz +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT64_T) :: farg2 + +farg1 = c_loc(a) +farg2 = nnz +fresult = swigc_FSUNSparseMatrix_Reallocate(farg1, farg2) +swig_result = fresult +end function + +subroutine FSUNSparseMatrix_Print(a, outfile) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: outfile +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(a) +farg2 = outfile +call swigc_FSUNSparseMatrix_Print(farg1, farg2) +end subroutine + +function FSUNSparseMatrix_Rows(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNSparseMatrix_Rows(farg1) +swig_result = fresult +end function + +function FSUNSparseMatrix_Columns(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNSparseMatrix_Columns(farg1) +swig_result = fresult +end function + +function FSUNSparseMatrix_NNZ(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNSparseMatrix_NNZ(farg1) +swig_result = fresult +end function + +function FSUNSparseMatrix_NP(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT64_T) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNSparseMatrix_NP(farg1) +swig_result = fresult +end function + +function FSUNSparseMatrix_SparseType(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNSparseMatrix_SparseType(farg1) +swig_result = fresult +end function + +function FSUNSparseMatrix_Data(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +real(C_DOUBLE), dimension(:), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNSparseMatrix_Data(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +function FSUNSparseMatrix_IndexValues(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), dimension(:), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNSparseMatrix_IndexValues(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +function FSUNSparseMatrix_IndexPointers(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT64_T), dimension(:), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNSparseMatrix_IndexPointers(farg1) +call c_f_pointer(fresult, swig_result, [1]) +end function + +function FSUNMatGetID_Sparse(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNMatrix_ID) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatGetID_Sparse(farg1) +swig_result = fresult +end function + +function FSUNMatClone_Sparse(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), pointer :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatClone_Sparse(farg1) +call c_f_pointer(fresult, swig_result) +end function + +subroutine FSUNMatDestroy_Sparse(a) +use, intrinsic :: ISO_C_BINDING +type(SUNMatrix), target, intent(inout) :: a +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +call swigc_FSUNMatDestroy_Sparse(farg1) +end subroutine + +function FSUNMatZero_Sparse(a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(a) +fresult = swigc_FSUNMatZero_Sparse(farg1) +swig_result = fresult +end function + +function FSUNMatCopy_Sparse(a, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(SUNMatrix), target, intent(inout) :: b +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(a) +farg2 = c_loc(b) +fresult = swigc_FSUNMatCopy_Sparse(farg1, farg2) +swig_result = fresult +end function + +function FSUNMatScaleAdd_Sparse(c, a, b) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +real(C_DOUBLE), intent(in) :: c +type(SUNMatrix), target, intent(inout) :: a +type(SUNMatrix), target, intent(inout) :: b +integer(C_INT) :: fresult +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c +farg2 = c_loc(a) +farg3 = c_loc(b) +fresult = swigc_FSUNMatScaleAdd_Sparse(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNMatScaleAddI_Sparse(c, a) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +real(C_DOUBLE), intent(in) :: c +type(SUNMatrix), target, intent(inout) :: a +integer(C_INT) :: fresult +real(C_DOUBLE) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c +farg2 = c_loc(a) +fresult = swigc_FSUNMatScaleAddI_Sparse(farg1, farg2) +swig_result = fresult +end function + +function FSUNMatMatvec_Sparse(a, x, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +type(N_Vector), target, intent(inout) :: x +type(N_Vector), target, intent(inout) :: y +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(a) +farg2 = c_loc(x) +farg3 = c_loc(y) +fresult = swigc_FSUNMatMatvec_Sparse(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNMatSpace_Sparse(a, lenrw, leniw) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNMatrix), target, intent(inout) :: a +integer(C_LONG), dimension(*), target, intent(inout) :: lenrw +integer(C_LONG), dimension(*), target, intent(inout) :: leniw +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(a) +farg2 = c_loc(lenrw(1)) +farg3 = c_loc(leniw(1)) +fresult = swigc_FSUNMatSpace_Sparse(farg1, farg2, farg3) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.c b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.c index c9cb09218..5e2825f3d 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.c @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -42,25 +42,37 @@ void FSUNSPARSEMAT_INIT(int *code, long int *M, long int *N, case FCMIX_CVODE: if (F2C_CVODE_matrix) SUNMatDestroy(F2C_CVODE_matrix); F2C_CVODE_matrix = NULL; - F2C_CVODE_matrix = SUNSparseMatrix(*M, *N, *NNZ, *sparsetype); + F2C_CVODE_matrix = SUNSparseMatrix((sunindextype)(*M), + (sunindextype)(*N), + (sunindextype)(*NNZ), + *sparsetype); if (F2C_CVODE_matrix == NULL) *ier = -1; break; case FCMIX_IDA: if (F2C_IDA_matrix) SUNMatDestroy(F2C_IDA_matrix); F2C_IDA_matrix = NULL; - F2C_IDA_matrix = SUNSparseMatrix(*M, *N, *NNZ, *sparsetype); + F2C_IDA_matrix = SUNSparseMatrix((sunindextype)(*M), + (sunindextype)(*N), + (sunindextype)(*NNZ), + *sparsetype); if (F2C_IDA_matrix == NULL) *ier = -1; break; case FCMIX_KINSOL: if (F2C_KINSOL_matrix) SUNMatDestroy(F2C_KINSOL_matrix); F2C_KINSOL_matrix = NULL; - F2C_KINSOL_matrix = SUNSparseMatrix(*M, *N, *NNZ, *sparsetype); + F2C_KINSOL_matrix = SUNSparseMatrix((sunindextype)(*M), + (sunindextype)(*N), + (sunindextype)(*NNZ), + *sparsetype); if (F2C_KINSOL_matrix == NULL) *ier = -1; break; case FCMIX_ARKODE: if (F2C_ARKODE_matrix) SUNMatDestroy(F2C_ARKODE_matrix); F2C_ARKODE_matrix = NULL; - F2C_ARKODE_matrix = SUNSparseMatrix(*M, *N, *NNZ, *sparsetype); + F2C_ARKODE_matrix = SUNSparseMatrix((sunindextype)(*M), + (sunindextype)(*N), + (sunindextype)(*NNZ), + *sparsetype); if (F2C_ARKODE_matrix == NULL) *ier = -1; break; default: @@ -68,12 +80,15 @@ void FSUNSPARSEMAT_INIT(int *code, long int *M, long int *N, } } -void FSUNSPARSEMASSMAT_INIT(long int *M, long int *N, long int *NNZ, +void FSUNSPARSEMASSMAT_INIT(long int *M, long int *N, long int *NNZ, int *sparsetype, int *ier) { *ier = 0; if (F2C_ARKODE_mass_matrix) SUNMatDestroy(F2C_ARKODE_mass_matrix); F2C_ARKODE_mass_matrix = NULL; - F2C_ARKODE_mass_matrix = SUNSparseMatrix(*M, *N, *NNZ, *sparsetype); + F2C_ARKODE_mass_matrix = SUNSparseMatrix((sunindextype)(*M), + (sunindextype)(*N), + (sunindextype)(*NNZ), + *sparsetype); if (F2C_ARKODE_mass_matrix == NULL) *ier = -1; } diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.h b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.h index 1fbcde6b9..79bde1220 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.h @@ -3,7 +3,7 @@ * Programmer(s): Daniel Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/sunmatrix_sparse.c b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/sunmatrix_sparse.c index ee34771c5..4d5eb9d0f 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/sunmatrix_sparse.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunmatrix/sparse/sunmatrix_sparse.c @@ -2,11 +2,11 @@ * ----------------------------------------------------------------- * Programmer(s): Daniel Reynolds @ SMU * David Gardner @ LLNL - * Based on code sundials_sparse.c by: Carol Woodward and + * Based on code sundials_sparse.c by: Carol Woodward and * Slaven Peles @ LLNL, and Daniel R. Reynolds @ SMU * ----------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -15,10 +15,10 @@ * SPDX-License-Identifier: BSD-3-Clause * SUNDIALS Copyright End * ----------------------------------------------------------------- - * This is the implementation file for the sparse implementation of + * This is the implementation file for the sparse implementation of * the SUNMATRIX package. * ----------------------------------------------------------------- - */ + */ #include #include @@ -33,8 +33,9 @@ /* Private function prototypes */ static booleantype SMCompatible_Sparse(SUNMatrix A, SUNMatrix B); static booleantype SMCompatible2_Sparse(SUNMatrix A, N_Vector x, N_Vector y); -int Matvec_SparseCSC(SUNMatrix A, N_Vector x, N_Vector y); -int Matvec_SparseCSR(SUNMatrix A, N_Vector x, N_Vector y); +static int Matvec_SparseCSC(SUNMatrix A, N_Vector x, N_Vector y); +static int Matvec_SparseCSR(SUNMatrix A, N_Vector x, N_Vector y); +static int format_convert(const SUNMatrix A, SUNMatrix B); /* * ----------------------------------------------------------------- @@ -56,38 +57,35 @@ SUNMatrix SUNSparseMatrix(sunindextype M, sunindextype N, sunindextype NNZ, int sparsetype) { SUNMatrix A; - SUNMatrix_Ops ops; SUNMatrixContent_Sparse content; /* return with NULL matrix on illegal input */ if ( (M <= 0) || (N <= 0) || (NNZ < 0) ) return(NULL); if ( (sparsetype != CSC_MAT) && (sparsetype != CSR_MAT) ) return(NULL); - /* Create matrix */ + /* Create an empty matrix object */ A = NULL; - A = (SUNMatrix) malloc(sizeof *A); + A = SUNMatNewEmpty(); if (A == NULL) return(NULL); - - /* Create matrix operation structure */ - ops = NULL; - ops = (SUNMatrix_Ops) malloc(sizeof(struct _generic_SUNMatrix_Ops)); - if (ops == NULL) { free(A); return(NULL); } /* Attach operations */ - ops->getid = SUNMatGetID_Sparse; - ops->clone = SUNMatClone_Sparse; - ops->destroy = SUNMatDestroy_Sparse; - ops->zero = SUNMatZero_Sparse; - ops->copy = SUNMatCopy_Sparse; - ops->scaleadd = SUNMatScaleAdd_Sparse; - ops->scaleaddi = SUNMatScaleAddI_Sparse; - ops->matvec = SUNMatMatvec_Sparse; - ops->space = SUNMatSpace_Sparse; + A->ops->getid = SUNMatGetID_Sparse; + A->ops->clone = SUNMatClone_Sparse; + A->ops->destroy = SUNMatDestroy_Sparse; + A->ops->zero = SUNMatZero_Sparse; + A->ops->copy = SUNMatCopy_Sparse; + A->ops->scaleadd = SUNMatScaleAdd_Sparse; + A->ops->scaleaddi = SUNMatScaleAddI_Sparse; + A->ops->matvec = SUNMatMatvec_Sparse; + A->ops->space = SUNMatSpace_Sparse; /* Create content */ content = NULL; - content = (SUNMatrixContent_Sparse) malloc(sizeof(struct _SUNMatrixContent_Sparse)); - if (content == NULL) { free(ops); free(A); return(NULL); } + content = (SUNMatrixContent_Sparse) malloc(sizeof *content); + if (content == NULL) { SUNMatDestroy(A); return(NULL); } + + /* Attach content */ + A->content = content; /* Fill content */ content->sparsetype = sparsetype; @@ -111,37 +109,30 @@ SUNMatrix SUNSparseMatrix(sunindextype M, sunindextype N, content->rowvals = NULL; content->colptrs = NULL; } + content->data = NULL; + content->indexvals = NULL; + content->indexptrs = NULL; + + /* Allocate content */ content->data = (realtype *) calloc(NNZ, sizeof(realtype)); - if (content->data == NULL) { - free(content); free(ops); free(A); return(NULL); - } + if (content->data == NULL) { SUNMatDestroy(A); return(NULL); } + content->indexvals = (sunindextype *) calloc(NNZ, sizeof(sunindextype)); - if (content->indexvals == NULL) { - free(content->data); free(content); free(ops); free(A); return(NULL); - } + if (content->indexvals == NULL) { SUNMatDestroy(A); return(NULL); } + content->indexptrs = (sunindextype *) calloc((content->NP + 1), sizeof(sunindextype)); - if (content->indexptrs == NULL) { - free(content->indexvals); - free(content->data); - free(content); - free(ops); - free(A); - return(NULL); - } + if (content->indexptrs == NULL) { SUNMatDestroy(A); return(NULL); } content->indexptrs[content->NP] = 0; - /* Attach content and ops */ - A->content = content; - A->ops = ops; - return(A); } + /* ---------------------------------------------------------------------------- - * Function to create a new sparse matrix from an existing dense matrix - * by copying all nonzero values into the sparse matrix structure. Returns NULL + * Function to create a new sparse matrix from an existing dense matrix + * by copying all nonzero values into the sparse matrix structure. Returns NULL * if the request for matrix storage cannot be satisfied. */ @@ -158,7 +149,7 @@ SUNMatrix SUNSparseFromDenseMatrix(SUNMatrix Ad, realtype droptol, int sparsetyp return NULL; if (SUNMatGetID(Ad) != SUNMATRIX_DENSE) return NULL; - + /* set size of new matrix */ M = SM_ROWS_D(Ad); N = SM_COLUMNS_D(Ad); @@ -168,18 +159,18 @@ SUNMatrix SUNSparseFromDenseMatrix(SUNMatrix Ad, realtype droptol, int sparsetyp for (j=0; j droptol); - + /* allocate sparse matrix */ As = SUNSparseMatrix(M, N, nnz, sparsetype); if (As == NULL) return NULL; - + /* copy nonzeros from Ad into As, based on CSR/CSC type */ nnz = 0; if (sparsetype == CSC_MAT) { for (j=0; j droptol ) { + if ( SUNRabs(SM_ELEMENT_D(Ad,i,j)) > droptol ) { (SM_INDEXVALS_S(As))[nnz] = i; (SM_DATA_S(As))[nnz++] = SM_ELEMENT_D(Ad,i,j); } @@ -190,7 +181,7 @@ SUNMatrix SUNSparseFromDenseMatrix(SUNMatrix Ad, realtype droptol, int sparsetyp for (i=0; i droptol ) { + if ( SUNRabs(SM_ELEMENT_D(Ad,i,j)) > droptol ) { (SM_INDEXVALS_S(As))[nnz] = j; (SM_DATA_S(As))[nnz++] = SM_ELEMENT_D(Ad,i,j); } @@ -198,14 +189,14 @@ SUNMatrix SUNSparseFromDenseMatrix(SUNMatrix Ad, realtype droptol, int sparsetyp } (SM_INDEXPTRS_S(As))[M] = nnz; } - + return(As); } /* ---------------------------------------------------------------------------- - * Function to create a new sparse matrix from an existing band matrix - * by copying all nonzero values into the sparse matrix structure. Returns NULL + * Function to create a new sparse matrix from an existing band matrix + * by copying all nonzero values into the sparse matrix structure. Returns NULL * if the request for matrix storage cannot be satisfied. */ @@ -222,7 +213,7 @@ SUNMatrix SUNSparseFromBandMatrix(SUNMatrix Ad, realtype droptol, int sparsetype return NULL; if (SUNMatGetID(Ad) != SUNMATRIX_BAND) return NULL; - + /* set size of new matrix */ M = SM_ROWS_B(Ad); N = SM_COLUMNS_B(Ad); @@ -243,7 +234,7 @@ SUNMatrix SUNSparseFromBandMatrix(SUNMatrix Ad, realtype droptol, int sparsetype for (j=0; j droptol ) { + if ( SUNRabs(SM_ELEMENT_B(Ad,i,j)) > droptol ) { (SM_INDEXVALS_S(As))[nnz] = i; (SM_DATA_S(As))[nnz++] = SM_ELEMENT_B(Ad,i,j); } @@ -254,7 +245,7 @@ SUNMatrix SUNSparseFromBandMatrix(SUNMatrix Ad, realtype droptol, int sparsetype for (i=0; i droptol ) { + if ( SUNRabs(SM_ELEMENT_B(Ad,i,j)) > droptol ) { (SM_INDEXVALS_S(As))[nnz] = j; (SM_DATA_S(As))[nnz++] = SM_ELEMENT_B(Ad,i,j); } @@ -267,6 +258,36 @@ SUNMatrix SUNSparseFromBandMatrix(SUNMatrix Ad, realtype droptol, int sparsetype } +/* ---------------------------------------------------------------------------- + * Function to create a new CSR matrix from a CSC matrix. + */ +int SUNSparseMatrix_ToCSR(const SUNMatrix A, SUNMatrix* Bout) +{ + if (A == NULL) return(SUNMAT_ILL_INPUT); + if (SM_SPARSETYPE_S(A) != CSC_MAT) return(SUNMAT_ILL_INPUT); + + *Bout = SUNSparseMatrix(SM_ROWS_S(A), SM_COLUMNS_S(A), SM_NNZ_S(A), CSR_MAT); + if (*Bout == NULL) return(SUNMAT_MEM_FAIL); + + return format_convert(A, *Bout); +} + + +/* ---------------------------------------------------------------------------- + * Function to create a new CSC matrix from a CSR matrix. + */ +int SUNSparseMatrix_ToCSC(const SUNMatrix A, SUNMatrix* Bout) +{ + if (A == NULL) return(SUNMAT_ILL_INPUT); + if (SM_SPARSETYPE_S(A) != CSR_MAT) return(SUNMAT_ILL_INPUT); + + *Bout = SUNSparseMatrix(SM_ROWS_S(A), SM_COLUMNS_S(A), SM_NNZ_S(A), CSC_MAT); + if (*Bout == NULL) return(SUNMAT_MEM_FAIL); + + return format_convert(A, *Bout); +} + + /* ---------------------------------------------------------------------------- * Function to reallocate internal sparse matrix storage arrays so that the * resulting sparse matrix holds indexptrs[NP] nonzeros. Returns 0 on success @@ -279,57 +300,56 @@ int SUNSparseMatrix_Realloc(SUNMatrix A) /* check for valid matrix type */ if (SUNMatGetID(A) != SUNMATRIX_SPARSE) - return 1; + return SUNMAT_ILL_INPUT; /* get total number of nonzeros (return with failure if illegal) */ nzmax = (SM_INDEXPTRS_S(A))[SM_NP_S(A)]; - if (nzmax < 0) - return 1; + if (nzmax < 0) return SUNMAT_ILL_INPUT; /* perform reallocation */ SM_INDEXVALS_S(A) = (sunindextype *) realloc(SM_INDEXVALS_S(A), nzmax*sizeof(sunindextype)); SM_DATA_S(A) = (realtype *) realloc(SM_DATA_S(A), nzmax*sizeof(realtype)); SM_NNZ_S(A) = nzmax; - return 0; + return SUNMAT_SUCCESS; } /* ---------------------------------------------------------------------------- * Function to reallocate internal sparse matrix storage arrays so that the - * resulting sparse matrix has storage for a specified number of nonzeros. - * Returns 0 on success and 1 on failure (e.g. if A does not have sparse type, + * resulting sparse matrix has storage for a specified number of nonzeros. + * Returns 0 on success and 1 on failure (e.g. if A does not have sparse type, * or if nnz is negative) */ int SUNSparseMatrix_Reallocate(SUNMatrix A, sunindextype NNZ) { /* check for valid matrix type */ - if (SUNMatGetID(A) != SUNMATRIX_SPARSE) return 1; + if (SUNMatGetID(A) != SUNMATRIX_SPARSE) return SUNMAT_ILL_INPUT; /* check for valid nnz */ - if (NNZ < 0) return 1; + if (NNZ < 0) return SUNMAT_ILL_INPUT; /* perform reallocation */ SM_INDEXVALS_S(A) = (sunindextype *) realloc(SM_INDEXVALS_S(A), NNZ*sizeof(sunindextype)); SM_DATA_S(A) = (realtype *) realloc(SM_DATA_S(A), NNZ*sizeof(realtype)); SM_NNZ_S(A) = NNZ; - return 0; + return SUNMAT_SUCCESS; } /* ---------------------------------------------------------------------------- - * Function to print the sparse matrix + * Function to print the sparse matrix */ - + void SUNSparseMatrix_Print(SUNMatrix A, FILE* outfile) { sunindextype i, j; char *matrixtype; char *indexname; - /* should not be called unless A is a sparse matrix; + /* should not be called unless A is a sparse matrix; otherwise return immediately */ if (SUNMatGetID(A) != SUNMATRIX_SPARSE) return; @@ -344,7 +364,7 @@ void SUNSparseMatrix_Print(SUNMatrix A, FILE* outfile) } fprintf(outfile, "\n"); fprintf(outfile, "%ld by %ld %s matrix, NNZ: %ld \n", - (long int) SM_ROWS_S(A), (long int) SM_COLUMNS_S(A), + (long int) SM_ROWS_S(A), (long int) SM_COLUMNS_S(A), matrixtype, (long int) SM_NNZ_S(A)); for (j=0; jrowvals = NULL; - SM_CONTENT_S(A)->colvals = NULL; - } - if (SM_INDEXPTRS_S(A)) { - free(SM_INDEXPTRS_S(A)); - SM_INDEXPTRS_S(A) = NULL; - SM_CONTENT_S(A)->colptrs = NULL; - SM_CONTENT_S(A)->rowptrs = NULL; + if (A == NULL) return; + + /* free content */ + if (A->content != NULL) { + /* free data array */ + if (SM_DATA_S(A)) { + free(SM_DATA_S(A)); + SM_DATA_S(A) = NULL; + } + /* free index values array */ + if (SM_INDEXVALS_S(A)) { + free(SM_INDEXVALS_S(A)); + SM_INDEXVALS_S(A) = NULL; + SM_CONTENT_S(A)->rowvals = NULL; + SM_CONTENT_S(A)->colvals = NULL; + } + /* free index pointers array */ + if (SM_INDEXPTRS_S(A)) { + free(SM_INDEXPTRS_S(A)); + SM_INDEXPTRS_S(A) = NULL; + SM_CONTENT_S(A)->colptrs = NULL; + SM_CONTENT_S(A)->rowptrs = NULL; + } + /* free content struct */ + free(A->content); + A->content = NULL; } - free(A->content); A->content = NULL; - free(A->ops); A->ops = NULL; + + /* free ops and matrix */ + if (A->ops) { free(A->ops); A->ops = NULL; } free(A); A = NULL; + return; } - + int SUNMatZero_Sparse(SUNMatrix A) { sunindextype i; @@ -490,10 +523,10 @@ int SUNMatZero_Sparse(SUNMatrix A) (SM_DATA_S(A))[i] = ZERO; (SM_INDEXVALS_S(A))[i] = 0; } - for (i=0; i (SM_NNZ_S(A) - Ap[N])) newmat = SUNTRUE; - + /* perform operation based on existing/necessary structure */ /* case 1: A already contains a diagonal */ @@ -599,11 +633,11 @@ int SUNMatScaleAddI_Sparse(realtype c, SUNMatrix A) Ax[i] = c*Ax[i]; } - + /* case 2: A has sufficient storage, but does not already contain a diagonal */ } else if (!newmat) { - + /* create work arrays for nonzero indices and values in a single column (row) */ w = (sunindextype *) malloc(M * sizeof(sunindextype)); x = (realtype *) malloc(M * sizeof(realtype)); @@ -611,11 +645,11 @@ int SUNMatScaleAddI_Sparse(realtype c, SUNMatrix A) /* determine storage location where last column (row) should end */ nz = Ap[N] + newvals; - /* store pointer past last column (row) from original A, - and store updated value in revised A */ + /* store pointer past last column (row) from original A, + and store updated value in revised A */ cend = Ap[N]; Ap[N] = nz; - + /* iterate through columns (rows) backwards */ for (j=N-1; j>=0; j--) { @@ -639,8 +673,8 @@ int SUNMatScaleAddI_Sparse(realtype c, SUNMatrix A) /* fill entries of A with this column's (row's) data */ for (i=M-1; i>=0; i--) { - if ( w[i] > 0 ) { - Ai[--nz] = i; + if ( w[i] > 0 ) { + Ai[--nz] = i; Ax[nz] = x[i]; } } @@ -648,14 +682,14 @@ int SUNMatScaleAddI_Sparse(realtype c, SUNMatrix A) /* store ptr past this col (row) from orig A, update value for new A */ cend = Ap[j]; Ap[j] = nz; - + } /* clean up */ free(w); free(x); - + /* case 3: A must be reallocated with sufficient storage */ } else { @@ -672,11 +706,11 @@ int SUNMatScaleAddI_Sparse(realtype c, SUNMatrix A) Cp = Ci = NULL; Cx = NULL; if (SM_INDEXPTRS_S(C)) Cp = SM_INDEXPTRS_S(C); - else return (-1); + else return (SUNMAT_MEM_FAIL); if (SM_INDEXVALS_S(C)) Ci = SM_INDEXVALS_S(C); - else return (-1); + else return (SUNMAT_MEM_FAIL); if (SM_DATA_S(C)) Cx = SM_DATA_S(C); - else return (-1); + else return (SUNMAT_MEM_FAIL); /* initialize total nonzero count */ nz = 0; @@ -707,8 +741,8 @@ int SUNMatScaleAddI_Sparse(realtype c, SUNMatrix A) /* fill entries of C with this column's (row's) data */ for (i=0; i 0 ) { - Ci[nz] = i; + if ( w[i] > 0 ) { + Ci[nz] = i; Cx[nz++] = x[i]; } } @@ -721,7 +755,7 @@ int SUNMatScaleAddI_Sparse(realtype c, SUNMatrix A) SM_NNZ_S(A) = SM_NNZ_S(C); if (SM_DATA_S(A)) - free(SM_DATA_S(A)); + free(SM_DATA_S(A)); SM_DATA_S(A) = SM_DATA_S(C); SM_DATA_S(C) = NULL; @@ -736,12 +770,12 @@ int SUNMatScaleAddI_Sparse(realtype c, SUNMatrix A) SM_INDEXPTRS_S(C) = NULL; /* clean up */ - SUNMatDestroy_Sparse(C); + SUNMatDestroy_Sparse(C); free(w); free(x); } - return 0; + return SUNMAT_SUCCESS; } @@ -755,7 +789,7 @@ int SUNMatScaleAdd_Sparse(realtype c, SUNMatrix A, SUNMatrix B) /* Verify that A and B are compatible */ if (!SMCompatible_Sparse(A, B)) - return 1; + return SUNMAT_ILL_INPUT; /* store shortcuts to matrix dimensions (M is inner dimension, N is outer) */ if (SM_SPARSETYPE_S(A) == CSC_MAT) { @@ -771,17 +805,17 @@ int SUNMatScaleAdd_Sparse(realtype c, SUNMatrix A, SUNMatrix B) Ap = Ai = Bp = Bi = NULL; Ax = Bx = NULL; if (SM_INDEXPTRS_S(A)) Ap = SM_INDEXPTRS_S(A); - else return(-1); + else return(SUNMAT_MEM_FAIL); if (SM_INDEXVALS_S(A)) Ai = SM_INDEXVALS_S(A); - else return(-1); + else return(SUNMAT_MEM_FAIL); if (SM_DATA_S(A)) Ax = SM_DATA_S(A); - else return(-1); + else return(SUNMAT_MEM_FAIL); if (SM_INDEXPTRS_S(B)) Bp = SM_INDEXPTRS_S(B); - else return(-1); + else return(SUNMAT_MEM_FAIL); if (SM_INDEXVALS_S(B)) Bi = SM_INDEXVALS_S(B); - else return(-1); + else return(SUNMAT_MEM_FAIL); if (SM_DATA_S(B)) Bx = SM_DATA_S(B); - else return(-1); + else return(SUNMAT_MEM_FAIL); /* create work arrays for row indices and nonzero column values */ w = (sunindextype *) malloc(M * sizeof(sunindextype)); @@ -802,18 +836,18 @@ int SUNMatScaleAdd_Sparse(realtype c, SUNMatrix A, SUNMatrix B) for (i=Bp[j]; i (SM_NNZ_S(A) - Ap[N])) newmat = SUNTRUE; - + /* perform operation based on existing/necessary structure */ /* case 1: A already contains sparsity pattern of B */ @@ -836,23 +870,21 @@ int SUNMatScaleAdd_Sparse(realtype c, SUNMatrix A, SUNMatrix B) } - + /* case 2: A has sufficient storage, but does not already contain B's sparsity */ } else if (!newmat) { - /* determine storage location where last column (row) should end */ nz = Ap[N] + newvals; - /* store pointer past last column (row) from original A, - and store updated value in revised A */ + /* store pointer past last column (row) from original A, + and store updated value in revised A */ cend = Ap[N]; Ap[N] = nz; - + /* iterate through columns (rows) backwards */ for (j=N-1; j>=0; j--) { - /* clear out temporary arrays for this column (row) */ for (i=0; i=0; i--) { - if ( w[i] > 0 ) { - Ai[--nz] = i; + if ( w[i] > 0 ) { + Ai[--nz] = i; Ax[nz] = x[i]; } } @@ -882,14 +914,14 @@ int SUNMatScaleAdd_Sparse(realtype c, SUNMatrix A, SUNMatrix B) /* store ptr past this col (row) from orig A, update value for new A */ cend = Ap[j]; Ap[j] = nz; - + } - - + + /* case 3: A must be reallocated with sufficient storage */ } else { - + /* create new matrix for sum */ C = SUNSparseMatrix(SM_ROWS_S(A), SM_COLUMNS_S(A), Ap[N] + newvals, SM_SPARSETYPE_S(A)); @@ -898,11 +930,11 @@ int SUNMatScaleAdd_Sparse(realtype c, SUNMatrix A, SUNMatrix B) Cp = Ci = NULL; Cx = NULL; if (SM_INDEXPTRS_S(C)) Cp = SM_INDEXPTRS_S(C); - else return(-1); + else return(SUNMAT_MEM_FAIL); if (SM_INDEXVALS_S(C)) Ci = SM_INDEXVALS_S(C); - else return(-1); + else return(SUNMAT_MEM_FAIL); if (SM_DATA_S(C)) Cx = SM_DATA_S(C); - else return(-1); + else return(SUNMAT_MEM_FAIL); /* initialize total nonzero count */ nz = 0; @@ -933,8 +965,8 @@ int SUNMatScaleAdd_Sparse(realtype c, SUNMatrix A, SUNMatrix B) /* fill entries of C with this column's data */ for (i=0; i 0 ) { - Ci[nz] = i; + if ( w[i] > 0 ) { + Ci[nz] = i; Cx[nz++] = x[i]; } } @@ -946,7 +978,7 @@ int SUNMatScaleAdd_Sparse(realtype c, SUNMatrix A, SUNMatrix B) /* update A's structure with C's values; nullify C's pointers */ SM_NNZ_S(A) = SM_NNZ_S(C); - free(SM_DATA_S(A)); + free(SM_DATA_S(A)); SM_DATA_S(A) = SM_DATA_S(C); SM_DATA_S(C) = NULL; @@ -959,7 +991,7 @@ int SUNMatScaleAdd_Sparse(realtype c, SUNMatrix A, SUNMatrix B) SM_INDEXPTRS_S(C) = NULL; /* clean up */ - SUNMatDestroy_Sparse(C); + SUNMatDestroy_Sparse(C); } @@ -976,12 +1008,12 @@ int SUNMatMatvec_Sparse(SUNMatrix A, N_Vector x, N_Vector y) { /* Verify that A, x and y are compatible */ if (!SMCompatible2_Sparse(A, x, y)) - return 1; + return SUNMAT_ILL_INPUT; /* Perform operation */ if(SM_SPARSETYPE_S(A) == CSC_MAT) return Matvec_SparseCSC(A, x, y); - else + else return Matvec_SparseCSR(A, x, y); } @@ -989,7 +1021,7 @@ int SUNMatSpace_Sparse(SUNMatrix A, long int *lenrw, long int *leniw) { *lenrw = SM_NNZ_S(A); *leniw = 10 + SM_NP_S(A) + SM_NNZ_S(A); - return 0; + return SUNMAT_SUCCESS; } @@ -1029,26 +1061,26 @@ static booleantype SMCompatible_Sparse(SUNMatrix A, SUNMatrix B) static booleantype SMCompatible2_Sparse(SUNMatrix A, N_Vector x, N_Vector y) { - - /* vectors must be one of {SERIAL, OPENMP, PTHREADS} */ - if ( (N_VGetVectorID(x) != SUNDIALS_NVEC_SERIAL) && - (N_VGetVectorID(x) != SUNDIALS_NVEC_OPENMP) && - (N_VGetVectorID(x) != SUNDIALS_NVEC_PTHREADS) ) + /* vectors must implement N_VGetArrayPointer */ + if ( (x->ops->nvgetarraypointer == NULL) || + (y->ops->nvgetarraypointer == NULL) ) return SUNFALSE; - /* Optimally we would verify that the dimensions of A, x and y agree, - but since there is no generic 'length' routine for N_Vectors we cannot */ + /* Verify that the dimensions of A, x, and y agree */ + if ( (SUNSparseMatrix_Columns(A) != N_VGetLength(x)) || + (SUNSparseMatrix_Rows(A) != N_VGetLength(y)) ) + return SUNFALSE; return SUNTRUE; } /* ----------------------------------------------------------------- - * Computes y=A*x, where A is a CSC SUNMatrix_Sparse of dimension MxN, x is a - * compatible N_Vector object of length N, and y is a compatible + * Computes y=A*x, where A is a CSC SUNMatrix_Sparse of dimension MxN, x is a + * compatible N_Vector object of length N, and y is a compatible * N_Vector object of length M. - * - * Returns 0 if successful, 1 if unsuccessful (failed memory access, or both + * + * Returns 0 if successful, 1 if unsuccessful (failed memory access, or both * x and y are the same vector). */ int Matvec_SparseCSC(SUNMatrix A, N_Vector x, N_Vector y) @@ -1062,13 +1094,13 @@ int Matvec_SparseCSC(SUNMatrix A, N_Vector x, N_Vector y) Ai = SM_INDEXVALS_S(A); Ax = SM_DATA_S(A); if ((Ap == NULL) || (Ai == NULL) || (Ax == NULL)) - return 1; + return SUNMAT_MEM_FAIL; /* access vector data (return if failure) */ xd = N_VGetArrayPointer(x); yd = N_VGetArrayPointer(y); if ((xd == NULL) || (yd == NULL) || (xd == yd) ) - return 1; + return SUNMAT_MEM_FAIL; /* initialize result */ for (i=0; i 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_nonlinearsolver.h" + + +#include "sunnonlinsol/sunnonlinsol_fixedpoint.h" + +SWIGEXPORT SUNNonlinearSolver _wrap_FSUNNonlinSol_FixedPoint(N_Vector farg1, int const *farg2) { + SUNNonlinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + int arg2 ; + SUNNonlinearSolver result; + + arg1 = (N_Vector)(farg1); + arg2 = (int)(*farg2); + result = (SUNNonlinearSolver)SUNNonlinSol_FixedPoint(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT SUNNonlinearSolver _wrap_FSUNNonlinSol_FixedPointSens(int const *farg1, N_Vector farg2, int const *farg3) { + SUNNonlinearSolver fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + int arg3 ; + SUNNonlinearSolver result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + arg3 = (int)(*farg3); + result = (SUNNonlinearSolver)SUNNonlinSol_FixedPointSens(arg1,arg2,arg3); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetType_FixedPoint(SUNNonlinearSolver farg1) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinearSolver_Type result; + + arg1 = (SUNNonlinearSolver)(farg1); + result = (SUNNonlinearSolver_Type)SUNNonlinSolGetType_FixedPoint(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolInitialize_FixedPoint(SUNNonlinearSolver farg1) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + result = (int)SUNNonlinSolInitialize_FixedPoint(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSolve_FixedPoint(SUNNonlinearSolver farg1, N_Vector farg2, N_Vector farg3, N_Vector farg4, double const *farg5, int const *farg6, void *farg7) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype arg5 ; + int arg6 ; + void *arg7 = (void *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype)(*farg5); + arg6 = (int)(*farg6); + arg7 = (void *)(farg7); + result = (int)SUNNonlinSolSolve_FixedPoint(arg1,arg2,arg3,arg4,arg5,arg6,arg7); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolFree_FixedPoint(SUNNonlinearSolver farg1) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + result = (int)SUNNonlinSolFree_FixedPoint(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetSysFn_FixedPoint(SUNNonlinearSolver farg1, SUNNonlinSolSysFn farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinSolSysFn arg2 = (SUNNonlinSolSysFn) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (SUNNonlinSolSysFn)(farg2); + result = (int)SUNNonlinSolSetSysFn_FixedPoint(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetConvTestFn_FixedPoint(SUNNonlinearSolver farg1, SUNNonlinSolConvTestFn farg2, void *farg3) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinSolConvTestFn arg2 = (SUNNonlinSolConvTestFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (SUNNonlinSolConvTestFn)(farg2); + arg3 = (void *)(farg3); + result = (int)SUNNonlinSolSetConvTestFn_FixedPoint(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetMaxIters_FixedPoint(SUNNonlinearSolver farg1, int const *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNNonlinSolSetMaxIters_FixedPoint(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetDamping_FixedPoint(SUNNonlinearSolver farg1, double const *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + realtype arg2 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (realtype)(*farg2); + result = (int)SUNNonlinSolSetDamping_FixedPoint(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetNumIters_FixedPoint(SUNNonlinearSolver farg1, long *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (long *)(farg2); + result = (int)SUNNonlinSolGetNumIters_FixedPoint(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetCurIter_FixedPoint(SUNNonlinearSolver farg1, int *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (int *)(farg2); + result = (int)SUNNonlinSolGetCurIter_FixedPoint(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetNumConvFails_FixedPoint(SUNNonlinearSolver farg1, long *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (long *)(farg2); + result = (int)SUNNonlinSolGetNumConvFails_FixedPoint(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetSysFn_FixedPoint(SUNNonlinearSolver farg1, void *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinSolSysFn *arg2 = (SUNNonlinSolSysFn *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (SUNNonlinSolSysFn *)(farg2); + result = (int)SUNNonlinSolGetSysFn_FixedPoint(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fmod/fsunnonlinsol_fixedpoint_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fmod/fsunnonlinsol_fixedpoint_mod.f90 new file mode 100644 index 000000000..cdb2c88d1 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fmod/fsunnonlinsol_fixedpoint_mod.f90 @@ -0,0 +1,421 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunnonlinsol_fixedpoint_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_nonlinearsolver_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FSUNNonlinSol_FixedPoint + public :: FSUNNonlinSol_FixedPointSens + public :: FSUNNonlinSolGetType_FixedPoint + public :: FSUNNonlinSolInitialize_FixedPoint + public :: FSUNNonlinSolSolve_FixedPoint + public :: FSUNNonlinSolFree_FixedPoint + public :: FSUNNonlinSolSetSysFn_FixedPoint + public :: FSUNNonlinSolSetConvTestFn_FixedPoint + public :: FSUNNonlinSolSetMaxIters_FixedPoint + public :: FSUNNonlinSolSetDamping_FixedPoint + public :: FSUNNonlinSolGetNumIters_FixedPoint + public :: FSUNNonlinSolGetCurIter_FixedPoint + public :: FSUNNonlinSolGetNumConvFails_FixedPoint + public :: FSUNNonlinSolGetSysFn_FixedPoint + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNNonlinSol_FixedPoint(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSol_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FSUNNonlinSol_FixedPointSens(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNNonlinSol_FixedPointSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT), intent(in) :: farg3 +type(C_PTR) :: fresult +end function + +function swigc_FSUNNonlinSolGetType_FixedPoint(farg1) & +bind(C, name="_wrap_FSUNNonlinSolGetType_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolInitialize_FixedPoint(farg1) & +bind(C, name="_wrap_FSUNNonlinSolInitialize_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSolve_FixedPoint(farg1, farg2, farg3, farg4, farg5, farg6, farg7) & +bind(C, name="_wrap_FSUNNonlinSolSolve_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT), intent(in) :: farg6 +type(C_PTR), value :: farg7 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolFree_FixedPoint(farg1) & +bind(C, name="_wrap_FSUNNonlinSolFree_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetSysFn_FixedPoint(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolSetSysFn_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetConvTestFn_FixedPoint(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNNonlinSolSetConvTestFn_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetMaxIters_FixedPoint(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolSetMaxIters_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetDamping_FixedPoint(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolSetDamping_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +real(C_DOUBLE), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolGetNumIters_FixedPoint(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolGetNumIters_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolGetCurIter_FixedPoint(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolGetCurIter_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolGetNumConvFails_FixedPoint(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolGetNumConvFails_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolGetSysFn_FixedPoint(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolGetSysFn_FixedPoint") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNNonlinSol_FixedPoint(y, m) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNNonlinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +integer(C_INT), intent(in) :: m +type(C_PTR) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(y) +farg2 = m +fresult = swigc_FSUNNonlinSol_FixedPoint(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNNonlinSol_FixedPointSens(count, y, m) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNNonlinearSolver), pointer :: swig_result +integer(C_INT), intent(in) :: count +type(N_Vector), target, intent(inout) :: y +integer(C_INT), intent(in) :: m +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 +integer(C_INT) :: farg3 + +farg1 = count +farg2 = c_loc(y) +farg3 = m +fresult = swigc_FSUNNonlinSol_FixedPointSens(farg1, farg2, farg3) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNNonlinSolGetType_FixedPoint(nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNNonlinearSolver_Type) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(nls) +fresult = swigc_FSUNNonlinSolGetType_FixedPoint(farg1) +swig_result = fresult +end function + +function FSUNNonlinSolInitialize_FixedPoint(nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(nls) +fresult = swigc_FSUNNonlinSolInitialize_FixedPoint(farg1) +swig_result = fresult +end function + +function FSUNNonlinSolSolve_FixedPoint(nls, y0, y, w, tol, callsetup, mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(N_Vector), target, intent(inout) :: y0 +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE), intent(in) :: tol +integer(C_INT), intent(in) :: callsetup +type(C_PTR) :: mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +real(C_DOUBLE) :: farg5 +integer(C_INT) :: farg6 +type(C_PTR) :: farg7 + +farg1 = c_loc(nls) +farg2 = c_loc(y0) +farg3 = c_loc(y) +farg4 = c_loc(w) +farg5 = tol +farg6 = callsetup +farg7 = mem +fresult = swigc_FSUNNonlinSolSolve_FixedPoint(farg1, farg2, farg3, farg4, farg5, farg6, farg7) +swig_result = fresult +end function + +function FSUNNonlinSolFree_FixedPoint(nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(nls) +fresult = swigc_FSUNNonlinSolFree_FixedPoint(farg1) +swig_result = fresult +end function + +function FSUNNonlinSolSetSysFn_FixedPoint(nls, sysfn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_FUNPTR), intent(in), value :: sysfn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = sysfn +fresult = swigc_FSUNNonlinSolSetSysFn_FixedPoint(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolSetConvTestFn_FixedPoint(nls, ctestfn, ctest_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_FUNPTR), intent(in), value :: ctestfn +type(C_PTR) :: ctest_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(nls) +farg2 = ctestfn +farg3 = ctest_data +fresult = swigc_FSUNNonlinSolSetConvTestFn_FixedPoint(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNNonlinSolSetMaxIters_FixedPoint(nls, maxiters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT), intent(in) :: maxiters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(nls) +farg2 = maxiters +fresult = swigc_FSUNNonlinSolSetMaxIters_FixedPoint(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolSetDamping_FixedPoint(nls, beta) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +real(C_DOUBLE), intent(in) :: beta +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +real(C_DOUBLE) :: farg2 + +farg1 = c_loc(nls) +farg2 = beta +fresult = swigc_FSUNNonlinSolSetDamping_FixedPoint(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolGetNumIters_FixedPoint(nls, niters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_LONG), dimension(*), target, intent(inout) :: niters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = c_loc(niters(1)) +fresult = swigc_FSUNNonlinSolGetNumIters_FixedPoint(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolGetCurIter_FixedPoint(nls, iter) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT), dimension(*), target, intent(inout) :: iter +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = c_loc(iter(1)) +fresult = swigc_FSUNNonlinSolGetCurIter_FixedPoint(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolGetNumConvFails_FixedPoint(nls, nconvfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_LONG), dimension(*), target, intent(inout) :: nconvfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = c_loc(nconvfails(1)) +fresult = swigc_FSUNNonlinSolGetNumConvFails_FixedPoint(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolGetSysFn_FixedPoint(nls, sysfn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_FUNPTR), target, intent(inout) :: sysfn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = c_loc(sysfn) +fresult = swigc_FSUNNonlinSolGetSysFn_FixedPoint(farg1, farg2) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.c b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.c index baecfe157..77314bde9 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.h b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.h index 8373f000e..e84e96201 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.h @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU *----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c index a27719e5e..0c299dca9 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c @@ -2,7 +2,7 @@ * Programmer(s): Daniel R. Reynolds @ SMU * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -44,7 +44,6 @@ static void FreeContent(SUNNonlinearSolver NLS); SUNNonlinearSolver SUNNonlinSol_FixedPoint(N_Vector y, int m) { SUNNonlinearSolver NLS; - SUNNonlinearSolver_Ops ops; SUNNonlinearSolverContent_FixedPoint content; int retval; @@ -61,61 +60,47 @@ SUNNonlinearSolver SUNNonlinSol_FixedPoint(N_Vector y, int m) /* Create nonlinear linear solver */ NLS = NULL; - NLS = (SUNNonlinearSolver) malloc(sizeof *NLS); + NLS = SUNNonlinSolNewEmpty(); if (NLS == NULL) return(NULL); - /* Create nonlinear solver operations structure */ - ops = NULL; - ops = (SUNNonlinearSolver_Ops) malloc(sizeof *ops); - if (ops == NULL) { free(NLS); return(NULL); } + /* Attach operations */ + NLS->ops->gettype = SUNNonlinSolGetType_FixedPoint; + NLS->ops->initialize = SUNNonlinSolInitialize_FixedPoint; + NLS->ops->solve = SUNNonlinSolSolve_FixedPoint; + NLS->ops->free = SUNNonlinSolFree_FixedPoint; + NLS->ops->setsysfn = SUNNonlinSolSetSysFn_FixedPoint; + NLS->ops->setctestfn = SUNNonlinSolSetConvTestFn_FixedPoint; + NLS->ops->setmaxiters = SUNNonlinSolSetMaxIters_FixedPoint; + NLS->ops->getnumiters = SUNNonlinSolGetNumIters_FixedPoint; + NLS->ops->getcuriter = SUNNonlinSolGetCurIter_FixedPoint; + NLS->ops->getnumconvfails = SUNNonlinSolGetNumConvFails_FixedPoint; /* Create nonlinear solver content structure */ content = NULL; content = (SUNNonlinearSolverContent_FixedPoint) malloc(sizeof *content); - if (content == NULL) { free(ops); free(NLS); return(NULL); } - - /* Attach content and ops */ - NLS->content = content; - NLS->ops = ops; - - /* Attach operations */ - ops->gettype = SUNNonlinSolGetType_FixedPoint; - ops->initialize = SUNNonlinSolInitialize_FixedPoint; - ops->setup = NULL; /* no setup needed */ - ops->solve = SUNNonlinSolSolve_FixedPoint; - ops->free = SUNNonlinSolFree_FixedPoint; - ops->setsysfn = SUNNonlinSolSetSysFn_FixedPoint; - ops->setlsetupfn = NULL; /* no lsetup needed */ - ops->setlsolvefn = NULL; /* no lsolve needed */ - ops->setctestfn = SUNNonlinSolSetConvTestFn_FixedPoint; - ops->setmaxiters = SUNNonlinSolSetMaxIters_FixedPoint; - ops->getnumiters = SUNNonlinSolGetNumIters_FixedPoint; - ops->getcuriter = SUNNonlinSolGetCurIter_FixedPoint; - ops->getnumconvfails = SUNNonlinSolGetNumConvFails_FixedPoint; + if (content == NULL) { SUNNonlinSolFree(NLS); return(NULL); } /* Initialize all components of content to 0/NULL */ memset(content, 0, sizeof(struct _SUNNonlinearSolverContent_FixedPoint)); + /* Attach content */ + NLS->content = content; + /* Fill general content */ content->Sys = NULL; content->CTest = NULL; content->m = m; + content->damping = SUNFALSE; + content->beta = ONE; content->curiter = 0; content->maxiters = 3; content->niters = 0; content->nconvfails = 0; + content->ctest_data = NULL; /* Fill allocatable content */ retval = AllocateContent(NLS, y); - - if (retval != SUN_NLS_SUCCESS) { - NLS->content = NULL; - NLS->ops = NULL; - free(content); - free(ops); - free(NLS); - return(NULL); - } + if (retval != SUN_NLS_SUCCESS) { SUNNonlinSolFree(NLS); return(NULL); } return(NLS); } @@ -189,7 +174,7 @@ int SUNNonlinSolInitialize_FixedPoint(SUNNonlinearSolver NLS) by the Sys function provided to the nonlinear solver. ---------------------------------------------------------------------------*/ int SUNNonlinSolSolve_FixedPoint(SUNNonlinearSolver NLS, N_Vector y0, - N_Vector y, N_Vector w, realtype tol, + N_Vector ycor, N_Vector w, realtype tol, booleantype callSetup, void* mem) { /* local variables */ @@ -197,7 +182,19 @@ int SUNNonlinSolSolve_FixedPoint(SUNNonlinearSolver NLS, N_Vector y0, N_Vector yprev, gy, delta; /* check that the inputs are non-null */ - if ( (NLS == NULL) || (y0 == NULL) || (y == NULL) || (w == NULL) || (mem == NULL) ) + if ( (NLS == NULL) || + (y0 == NULL) || + (ycor == NULL) || + (w == NULL) || + (mem == NULL) ) + return(SUN_NLS_MEM_NULL); + + /* check that all required function pointers have been set */ + if ( (FP_CONTENT(NLS)->Sys == NULL) || (FP_CONTENT(NLS)->CTest == NULL) ) + return(SUN_NLS_MEM_NULL); + + /* check that all required function pointers have been set */ + if ( (FP_CONTENT(NLS)->Sys == NULL) || (FP_CONTENT(NLS)->CTest == NULL) ) return(SUN_NLS_MEM_NULL); /* set local shortcut variables */ @@ -205,9 +202,6 @@ int SUNNonlinSolSolve_FixedPoint(SUNNonlinearSolver NLS, N_Vector y0, gy = FP_CONTENT(NLS)->gy; delta = FP_CONTENT(NLS)->delta; - /* load prediction into y */ - N_VScale(ONE, y0, y); - /* Looping point for attempts at solution of the nonlinear system: Evaluate fixed-point function (store in gy). Performs the accelerated fixed-point iteration. @@ -217,27 +211,28 @@ int SUNNonlinSolSolve_FixedPoint(SUNNonlinearSolver NLS, N_Vector y0, FP_CONTENT(NLS)->curiter++ ) { /* update previous solution guess */ - N_VScale(ONE, y, yprev); + N_VScale(ONE, ycor, yprev); /* compute fixed-point iteration function, store in gy */ - retval = FP_CONTENT(NLS)->Sys(y, gy, mem); + retval = FP_CONTENT(NLS)->Sys(ycor, gy, mem); if (retval != SUN_NLS_SUCCESS) break; /* perform fixed point update, based on choice of acceleration or not */ if (FP_CONTENT(NLS)->m == 0) { /* basic fixed-point solver */ - N_VScale(ONE, gy, y); + N_VScale(ONE, gy, ycor); } else { /* Anderson-accelerated solver */ - retval = AndersonAccelerate(NLS, gy, y, yprev, FP_CONTENT(NLS)->curiter); + retval = AndersonAccelerate(NLS, gy, ycor, yprev, FP_CONTENT(NLS)->curiter); } /* increment nonlinear solver iteration counter */ FP_CONTENT(NLS)->niters++; /* compute change in solution, and call the convergence test function */ - N_VLinearSum(ONE, y, -ONE, yprev, delta); + N_VLinearSum(ONE, ycor, -ONE, yprev, delta); /* test for convergence */ - retval = FP_CONTENT(NLS)->CTest(NLS, y, delta, tol, w, mem); + retval = FP_CONTENT(NLS)->CTest(NLS, ycor, delta, tol, w, + FP_CONTENT(NLS)->ctest_data); /* return if successful */ if (retval == SUN_NLS_SUCCESS) return(SUN_NLS_SUCCESS); @@ -301,7 +296,9 @@ int SUNNonlinSolSetSysFn_FixedPoint(SUNNonlinearSolver NLS, SUNNonlinSolSysFn Sy return(SUN_NLS_SUCCESS); } -int SUNNonlinSolSetConvTestFn_FixedPoint(SUNNonlinearSolver NLS, SUNNonlinSolConvTestFn CTestFn) +int SUNNonlinSolSetConvTestFn_FixedPoint(SUNNonlinearSolver NLS, + SUNNonlinSolConvTestFn CTestFn, + void* ctest_data) { /* check that the nonlinear solver is non-null */ if (NLS == NULL) @@ -312,6 +309,10 @@ int SUNNonlinSolSetConvTestFn_FixedPoint(SUNNonlinearSolver NLS, SUNNonlinSolCon return(SUN_NLS_ILL_INPUT); FP_CONTENT(NLS)->CTest = CTestFn; + + /* attach convergence test data */ + FP_CONTENT(NLS)->ctest_data = ctest_data; + return(SUN_NLS_SUCCESS); } @@ -329,6 +330,29 @@ int SUNNonlinSolSetMaxIters_FixedPoint(SUNNonlinearSolver NLS, int maxiters) return(SUN_NLS_SUCCESS); } +int SUNNonlinSolSetDamping_FixedPoint(SUNNonlinearSolver NLS, realtype beta) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + /* check that beta is a vaild */ + if (beta <= ZERO) + return(SUN_NLS_ILL_INPUT); + + if (beta < ONE) { + /* enable damping */ + FP_CONTENT(NLS)->beta = beta; + FP_CONTENT(NLS)->damping = SUNTRUE; + } else { + /* disable damping */ + FP_CONTENT(NLS)->beta = ONE; + FP_CONTENT(NLS)->damping = SUNFALSE; + } + + return(SUN_NLS_SUCCESS); +} + /*============================================================================== Get functions @@ -403,9 +427,10 @@ static int AndersonAccelerate(SUNNonlinearSolver NLS, N_Vector gval, N_Vector x, N_Vector xold, int iter) { /* local variables */ - int nvec, retval, i_pt, i, j, lAA, maa, *ipt_map; - realtype a, b, rtemp, c, s, *cvals, *R, *gamma; - N_Vector fv, vtemp, gold, fold, *df, *dg, *Q, *Xvecs; + int nvec, retval, i_pt, i, j, lAA, maa, *ipt_map; + realtype a, b, rtemp, c, s, beta, onembeta, *cvals, *R, *gamma; + N_Vector fv, vtemp, gold, fold, *df, *dg, *Q, *Xvecs; + booleantype damping; /* local shortcut variables */ vtemp = x; /* use result as temporary vector */ @@ -421,6 +446,8 @@ static int AndersonAccelerate(SUNNonlinearSolver NLS, N_Vector gval, R = FP_CONTENT(NLS)->R; gamma = FP_CONTENT(NLS)->gamma; fv = FP_CONTENT(NLS)->delta; + damping = FP_CONTENT(NLS)->damping; + beta = FP_CONTENT(NLS)->beta; /* reset ipt_map, i_pt */ for (i = 0; i < maa; i++) ipt_map[i]=0; @@ -475,7 +502,7 @@ static int AndersonAccelerate(SUNNonlinearSolver NLS, N_Vector gval, c = a / rtemp; s = b / rtemp; R[(i+1)*maa + i] = rtemp; - R[(i+1)*maa + i+1] = 0.0; + R[(i+1)*maa + i+1] = ZERO; if (i < maa-1) { for (j = i+2; j < maa; j++) { a = R[j*maa + i]; @@ -535,6 +562,19 @@ static int AndersonAccelerate(SUNNonlinearSolver NLS, N_Vector gval, nvec += 1; } + /* if enabled, apply damping */ + if (damping) { + onembeta = (ONE - beta); + cvals[nvec] = -onembeta; + Xvecs[nvec] = fv; + nvec += 1; + for (i = lAA - 1; i > -1; i--) { + cvals[nvec] = onembeta * gamma[i]; + Xvecs[nvec] = df[ipt_map[i]]; + nvec += 1; + } + } + /* update solution */ retval = N_VLinearCombination(nvec, cvals, Xvecs, x); if (retval != 0) return(SUN_NLS_VECTOROP_ERR); @@ -578,7 +618,7 @@ static int AllocateContent(SUNNonlinearSolver NLS, N_Vector y) if (FP_CONTENT(NLS)->gamma == NULL) { FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } - FP_CONTENT(NLS)->cvals = (realtype *) malloc((m+1) * sizeof(realtype)); + FP_CONTENT(NLS)->cvals = (realtype *) malloc(2*(m+1) * sizeof(realtype)); if (FP_CONTENT(NLS)->cvals == NULL) { FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } @@ -594,7 +634,7 @@ static int AllocateContent(SUNNonlinearSolver NLS, N_Vector y) if (FP_CONTENT(NLS)->q == NULL) { FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } - FP_CONTENT(NLS)->Xvecs = (N_Vector *) malloc((m+1) * sizeof(N_Vector)); + FP_CONTENT(NLS)->Xvecs = (N_Vector *) malloc(2*(m+1) * sizeof(N_Vector)); if (FP_CONTENT(NLS)->Xvecs == NULL) { FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } } diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/CMakeLists.txt index 7f942b91d..aa27199b0 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/CMakeLists.txt @@ -2,7 +2,7 @@ # Programmer(s): David J. Gardner @ LLNL # ------------------------------------------------------------------------------ # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -17,9 +17,9 @@ install(CODE "MESSAGE(\"\nInstall SUNNONLINSOL_NEWTON\n\")") # Add F90 module if F2003 interface is enabled -if(F90_FOUND AND F2003_INTERFACE_ENABLE) - add_subdirectory(F90) -endif(F90_FOUND AND F2003_INTERFACE_ENABLE) +if(F2003_FOUND AND F2003_INTERFACE_ENABLE) + add_subdirectory(fmod) +endif(F2003_FOUND AND F2003_INTERFACE_ENABLE) # Add variable with the sources for the library set(lib_SOURCES sunnonlinsol_newton.c) @@ -74,7 +74,7 @@ if(BUILD_SHARED_LIBS) endif() # Install the header files -INSTALL(FILES ${lib_HEADERS} DESTINATION include/sunnonlinsol) +install(FILES ${lib_HEADERS} DESTINATION include/sunnonlinsol) # If FCMIX is enabled, build and install the F library if(F77_INTERFACE_ENABLE AND F77_FOUND) diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/F90/fsunnonlinsol_newton.f90 b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/F90/fsunnonlinsol_newton.f90 deleted file mode 100644 index 4c32e3cfa..000000000 --- a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/F90/fsunnonlinsol_newton.f90 +++ /dev/null @@ -1,160 +0,0 @@ -! ----------------------------------------------------------------- -! Programmer(s): Cody J. Balos @ LLNL -! ----------------------------------------------------------------- -! SUNDIALS Copyright Start -! Copyright (c) 2002-2019, Lawrence Livermore National Security -! and Southern Methodist University. -! All rights reserved. -! -! See the top-level LICENSE and NOTICE files for details. -! -! SPDX-License-Identifier: BSD-3-Clause -! SUNDIALS Copyright End -! ----------------------------------------------------------------- -! This file contains a Fortran module for interfacing directly with -! the SUNDIALS Newton iteration nonlinear solver using the -! ISO_C_BINDING module. -! ----------------------------------------------------------------- - -module fsunnonlinsol_newton_mod - - !======= Interfaces ========= - interface - - ! ================================================================= - ! Constructors - ! ================================================================= - - type(c_ptr) function FSUNNonlinSol_Newton(y) & - bind(C,name='SUNNonlinSol_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: y - end function FSUNNonlinSol_Newton - - type(c_ptr) function FSUNNonlinSol_NewtonSens(cnt, y) & - bind(C,name='SUNNonlinSol_NewtonSens') - use, intrinsic :: iso_c_binding - implicit none - integer(c_int), value :: cnt - type(c_ptr), value :: y - end function FSUNNonlinSol_NewtonSens - - ! ================================================================= - ! Destructors - ! ================================================================= - - integer(c_int) function FSUNNonlinSolFree_Newton(NLS) & - bind(C,name='SUNNonlinSolFree_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: NLS - end function FSUNNonlinSolFree_Newton - - ! ================================================================= - ! Operations - ! ================================================================= - - integer(c_int) function FSUNNonlinSolGetType_Newton(NLS) & - bind(C,name='SUNNonlinSolGetType_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: NLS - end function FSUNNonlinSolGetType_Newton - - integer(c_int) function FSUNNonlinSolInitialize_Newton(NLS) & - bind(C,name='SUNNonlinSolInitialize_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: NLS - end function FSUNNonlinSolInitialize_Newton - - integer(c_int) function FSUNNonlinSolSolve_Newton(NLS, y0, y, w, tol, & - callSetup, mem) & - bind(C,name='SUNNonlinSolSolve_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: NLS - type(c_ptr), value :: y0 - type(c_ptr), value :: y - type(c_ptr), value :: w - real(c_double), value :: tol - integer(c_int), value :: callSetup - type(c_ptr), value :: mem - end function FSUNNonlinSolSolve_Newton - - ! ================================================================= - ! Set functions - ! ================================================================= - - integer(c_int) function FSUNNonlinSolSetSysFn_Newton(NLS, SysFn) & - bind(C,name='SUNNonlinSolSetSysFn_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: NLS - type(c_funptr), value :: SysFn - end function FSUNNonlinSolSetSysFn_Newton - - integer(c_int) function FSUNNonlinSolSetLSetupFn_Newton(NLS, LSetupFn) & - bind(C,name='SUNNonlinSolSetLSetupFn_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: NLS - type(c_funptr), value :: LSetupFn - end function FSUNNonlinSolSetLSetupFn_Newton - - integer(c_int) function FSUNNonlinSolSetLSolveFn_Newton(NLS, LSolveFn) & - bind(C,name='SUNNonlinSolSetLSolveFn_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: NLS - type(c_funptr), value :: LSolveFn - end function FSUNNonlinSolSetLSolveFn_Newton - - integer(c_int) function FSUNNonlinSolSetConvTestFn_Newton(NLS, CTestFN) & - bind(C,name='SUNNonlinSolSetConvTestFn_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: NLS - type(c_funptr), value :: CTestFN - end function FSUNNonlinSolSetConvTestFn_Newton - - integer(c_int) function FSUNNonlinSolSetMaxIters_Newton(NLS, maxiters) & - bind(C,name='SUNNonlinSolSetMaxIters_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: NLS - integer(c_int), value :: maxiters - end function FSUNNonlinSolSetMaxIters_Newton - - ! ================================================================= - ! Get functions - ! ================================================================= - - integer(c_int) function FSUNNonlinSolGetNumIters_Newton(NLS, niters) & - bind(C,name='SUNNonlinSolGetNumIters_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: NLS - integer(c_long) :: niters - end function FSUNNonlinSolGetNumIters_Newton - - integer(c_int) function FSUNNonlinSolGetCurIter_Newton(NLS, iter) & - bind(C,name='SUNNonlinSolGetCurIter_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: NLS - integer(c_int) :: iter - end function FSUNNonlinSolGetCurIter_Newton - - integer(c_int) function FSUNNonlinSolGetSysFn_Newton(NLS, SysFn) & - bind(C,name='SUNNonlinSolGetSysFn_Newton') - use, intrinsic :: iso_c_binding - implicit none - type(c_ptr), value :: NLS - type(c_funptr) :: SysFn - end function FSUNNonlinSolGetSysFn_Newton - - end interface - -end module fsunnonlinsol_newton_mod diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/F90/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fmod/CMakeLists.txt similarity index 78% rename from deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/F90/CMakeLists.txt rename to deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fmod/CMakeLists.txt index e7471f3ae..92d1fedd2 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/F90/CMakeLists.txt +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fmod/CMakeLists.txt @@ -1,8 +1,8 @@ # --------------------------------------------------------------- -# Programmer: Cody J. Balos @ LLNL +# Programmer(s): Cody J. Balos @ LLNL # --------------------------------------------------------------- # SUNDIALS Copyright Start -# Copyright (c) 2002-2019, Lawrence Livermore National Security +# Copyright (c) 2002-2020, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # @@ -15,21 +15,23 @@ # object library # --------------------------------------------------------------- -set(sunnonlinsolnewton_SOURCES fsunnonlinsol_newton.f90) +set(sunnonlinsolnewton_SOURCES fsunnonlinsol_newton_mod.f90 fsunnonlinsol_newton_mod.c) if(BUILD_STATIC_LIBS) - sundials_add_f2003_interface_library(sundials_fsunnonlinsolnewton_mod_static STATIC + sundials_add_f2003_interface_library(sundials_fsunnonlinsolnewton_mod_static STATIC_OBJECT ${sunnonlinsolnewton_SOURCES} ) + add_dependencies(sundials_fsunnonlinsolnewton_mod_static_obj sundials_fgeneric_static_obj) set_target_properties(sundials_fsunnonlinsolnewton_mod_static PROPERTIES OUTPUT_NAME sundials_fsunnonlinsolnewton_mod CLEAN_DIRECT_OUTPUT 1) install(TARGETS sundials_fsunnonlinsolnewton_mod_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif(BUILD_STATIC_LIBS) if(BUILD_SHARED_LIBS) - sundials_add_f2003_interface_library(sundials_fsunnonlinsolnewton_mod_shared SHARED + sundials_add_f2003_interface_library(sundials_fsunnonlinsolnewton_mod_shared SHARED_OBJECT ${sunnonlinsolnewton_SOURCES} ) + add_dependencies(sundials_fsunnonlinsolnewton_mod_shared_obj sundials_fgeneric_shared_obj) set_target_properties(sundials_fsunnonlinsolnewton_mod_shared PROPERTIES OUTPUT_NAME sundials_fsunnonlinsolnewton_mod CLEAN_DIRECT_OUTPUT 1) set_target_properties(sundials_fsunnonlinsolnewton_mod_shared diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fmod/fsunnonlinsol_newton_mod.c b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fmod/fsunnonlinsol_newton_mod.c new file mode 100644 index 000000000..6b295a425 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fmod/fsunnonlinsol_newton_mod.c @@ -0,0 +1,425 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.0 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------- + * Programmer(s): Auto-generated by swig. + * --------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- + * 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 + +/* qualifier for exported *const* global data variables*/ +#ifndef SWIGEXTERN +# ifdef __cplusplus +# define SWIGEXTERN extern +# else +# define SWIGEXTERN +# endif +#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 + +/* Errors in SWIG */ +#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 + + + + +#include +#define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ + { printf("In " DECL ": " MSG); assert(0); RETURNNULL; } + + +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + + +/* 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 SWIGVERSION 0x040000 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "sundials/sundials_nonlinearsolver.h" + + +#include "sunnonlinsol/sunnonlinsol_newton.h" + +SWIGEXPORT SUNNonlinearSolver _wrap_FSUNNonlinSol_Newton(N_Vector farg1) { + SUNNonlinearSolver fresult ; + N_Vector arg1 = (N_Vector) 0 ; + SUNNonlinearSolver result; + + arg1 = (N_Vector)(farg1); + result = (SUNNonlinearSolver)SUNNonlinSol_Newton(arg1); + fresult = result; + return fresult; +} + + +SWIGEXPORT SUNNonlinearSolver _wrap_FSUNNonlinSol_NewtonSens(int const *farg1, N_Vector farg2) { + SUNNonlinearSolver fresult ; + int arg1 ; + N_Vector arg2 = (N_Vector) 0 ; + SUNNonlinearSolver result; + + arg1 = (int)(*farg1); + arg2 = (N_Vector)(farg2); + result = (SUNNonlinearSolver)SUNNonlinSol_NewtonSens(arg1,arg2); + fresult = result; + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetType_Newton(SUNNonlinearSolver farg1) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinearSolver_Type result; + + arg1 = (SUNNonlinearSolver)(farg1); + result = (SUNNonlinearSolver_Type)SUNNonlinSolGetType_Newton(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolInitialize_Newton(SUNNonlinearSolver farg1) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + result = (int)SUNNonlinSolInitialize_Newton(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSolve_Newton(SUNNonlinearSolver farg1, N_Vector farg2, N_Vector farg3, N_Vector farg4, double const *farg5, int const *farg6, void *farg7) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + N_Vector arg2 = (N_Vector) 0 ; + N_Vector arg3 = (N_Vector) 0 ; + N_Vector arg4 = (N_Vector) 0 ; + realtype arg5 ; + int arg6 ; + void *arg7 = (void *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (N_Vector)(farg2); + arg3 = (N_Vector)(farg3); + arg4 = (N_Vector)(farg4); + arg5 = (realtype)(*farg5); + arg6 = (int)(*farg6); + arg7 = (void *)(farg7); + result = (int)SUNNonlinSolSolve_Newton(arg1,arg2,arg3,arg4,arg5,arg6,arg7); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolFree_Newton(SUNNonlinearSolver farg1) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + result = (int)SUNNonlinSolFree_Newton(arg1); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetSysFn_Newton(SUNNonlinearSolver farg1, SUNNonlinSolSysFn farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinSolSysFn arg2 = (SUNNonlinSolSysFn) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (SUNNonlinSolSysFn)(farg2); + result = (int)SUNNonlinSolSetSysFn_Newton(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetLSetupFn_Newton(SUNNonlinearSolver farg1, SUNNonlinSolLSetupFn farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinSolLSetupFn arg2 = (SUNNonlinSolLSetupFn) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (SUNNonlinSolLSetupFn)(farg2); + result = (int)SUNNonlinSolSetLSetupFn_Newton(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetLSolveFn_Newton(SUNNonlinearSolver farg1, SUNNonlinSolLSolveFn farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinSolLSolveFn arg2 = (SUNNonlinSolLSolveFn) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (SUNNonlinSolLSolveFn)(farg2); + result = (int)SUNNonlinSolSetLSolveFn_Newton(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetConvTestFn_Newton(SUNNonlinearSolver farg1, SUNNonlinSolConvTestFn farg2, void *farg3) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinSolConvTestFn arg2 = (SUNNonlinSolConvTestFn) 0 ; + void *arg3 = (void *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (SUNNonlinSolConvTestFn)(farg2); + arg3 = (void *)(farg3); + result = (int)SUNNonlinSolSetConvTestFn_Newton(arg1,arg2,arg3); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolSetMaxIters_Newton(SUNNonlinearSolver farg1, int const *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + int arg2 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (int)(*farg2); + result = (int)SUNNonlinSolSetMaxIters_Newton(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetNumIters_Newton(SUNNonlinearSolver farg1, long *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (long *)(farg2); + result = (int)SUNNonlinSolGetNumIters_Newton(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetCurIter_Newton(SUNNonlinearSolver farg1, int *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + int *arg2 = (int *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (int *)(farg2); + result = (int)SUNNonlinSolGetCurIter_Newton(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetNumConvFails_Newton(SUNNonlinearSolver farg1, long *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + long *arg2 = (long *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (long *)(farg2); + result = (int)SUNNonlinSolGetNumConvFails_Newton(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + +SWIGEXPORT int _wrap_FSUNNonlinSolGetSysFn_Newton(SUNNonlinearSolver farg1, void *farg2) { + int fresult ; + SUNNonlinearSolver arg1 = (SUNNonlinearSolver) 0 ; + SUNNonlinSolSysFn *arg2 = (SUNNonlinSolSysFn *) 0 ; + int result; + + arg1 = (SUNNonlinearSolver)(farg1); + arg2 = (SUNNonlinSolSysFn *)(farg2); + result = (int)SUNNonlinSolGetSysFn_Newton(arg1,arg2); + fresult = (int)(result); + return fresult; +} + + + diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fmod/fsunnonlinsol_newton_mod.f90 b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fmod/fsunnonlinsol_newton_mod.f90 new file mode 100644 index 000000000..a65f329e1 --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fmod/fsunnonlinsol_newton_mod.f90 @@ -0,0 +1,439 @@ +! This file was automatically generated by SWIG (http://www.swig.org). +! Version 4.0.0 +! +! Do not make changes to this file unless you know what you are doing--modify +! the SWIG interface file instead. + +! --------------------------------------------------------------- +! Programmer(s): Auto-generated by swig. +! --------------------------------------------------------------- +! SUNDIALS Copyright Start +! Copyright (c) 2002-2020, Lawrence Livermore National Security +! and Southern Methodist University. +! All rights reserved. +! +! See the top-level LICENSE and NOTICE files for details. +! +! SPDX-License-Identifier: BSD-3-Clause +! SUNDIALS Copyright End +! --------------------------------------------------------------- + +module fsunnonlinsol_newton_mod + use, intrinsic :: ISO_C_BINDING + use fsundials_nvector_mod + use fsundials_types_mod + use fsundials_nonlinearsolver_mod + use fsundials_nvector_mod + use fsundials_types_mod + implicit none + private + + ! DECLARATION CONSTRUCTS + public :: FSUNNonlinSol_Newton + public :: FSUNNonlinSol_NewtonSens + public :: FSUNNonlinSolGetType_Newton + public :: FSUNNonlinSolInitialize_Newton + public :: FSUNNonlinSolSolve_Newton + public :: FSUNNonlinSolFree_Newton + public :: FSUNNonlinSolSetSysFn_Newton + public :: FSUNNonlinSolSetLSetupFn_Newton + public :: FSUNNonlinSolSetLSolveFn_Newton + public :: FSUNNonlinSolSetConvTestFn_Newton + public :: FSUNNonlinSolSetMaxIters_Newton + public :: FSUNNonlinSolGetNumIters_Newton + public :: FSUNNonlinSolGetCurIter_Newton + public :: FSUNNonlinSolGetNumConvFails_Newton + public :: FSUNNonlinSolGetSysFn_Newton + +! WRAPPER DECLARATIONS +interface +function swigc_FSUNNonlinSol_Newton(farg1) & +bind(C, name="_wrap_FSUNNonlinSol_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR) :: fresult +end function + +function swigc_FSUNNonlinSol_NewtonSens(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSol_NewtonSens") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +integer(C_INT), intent(in) :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR) :: fresult +end function + +function swigc_FSUNNonlinSolGetType_Newton(farg1) & +bind(C, name="_wrap_FSUNNonlinSolGetType_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolInitialize_Newton(farg1) & +bind(C, name="_wrap_FSUNNonlinSolInitialize_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSolve_Newton(farg1, farg2, farg3, farg4, farg5, farg6, farg7) & +bind(C, name="_wrap_FSUNNonlinSolSolve_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +type(C_PTR), value :: farg3 +type(C_PTR), value :: farg4 +real(C_DOUBLE), intent(in) :: farg5 +integer(C_INT), intent(in) :: farg6 +type(C_PTR), value :: farg7 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolFree_Newton(farg1) & +bind(C, name="_wrap_FSUNNonlinSolFree_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetSysFn_Newton(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolSetSysFn_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetLSetupFn_Newton(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolSetLSetupFn_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetLSolveFn_Newton(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolSetLSolveFn_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetConvTestFn_Newton(farg1, farg2, farg3) & +bind(C, name="_wrap_FSUNNonlinSolSetConvTestFn_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_FUNPTR), value :: farg2 +type(C_PTR), value :: farg3 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolSetMaxIters_Newton(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolSetMaxIters_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +integer(C_INT), intent(in) :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolGetNumIters_Newton(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolGetNumIters_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolGetCurIter_Newton(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolGetCurIter_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolGetNumConvFails_Newton(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolGetNumConvFails_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +function swigc_FSUNNonlinSolGetSysFn_Newton(farg1, farg2) & +bind(C, name="_wrap_FSUNNonlinSolGetSysFn_Newton") & +result(fresult) +use, intrinsic :: ISO_C_BINDING +type(C_PTR), value :: farg1 +type(C_PTR), value :: farg2 +integer(C_INT) :: fresult +end function + +end interface + + +contains + ! MODULE SUBPROGRAMS +function FSUNNonlinSol_Newton(y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNNonlinearSolver), pointer :: swig_result +type(N_Vector), target, intent(inout) :: y +type(C_PTR) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(y) +fresult = swigc_FSUNNonlinSol_Newton(farg1) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNNonlinSol_NewtonSens(count, y) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +type(SUNNonlinearSolver), pointer :: swig_result +integer(C_INT), intent(in) :: count +type(N_Vector), target, intent(inout) :: y +type(C_PTR) :: fresult +integer(C_INT) :: farg1 +type(C_PTR) :: farg2 + +farg1 = count +farg2 = c_loc(y) +fresult = swigc_FSUNNonlinSol_NewtonSens(farg1, farg2) +call c_f_pointer(fresult, swig_result) +end function + +function FSUNNonlinSolGetType_Newton(nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(SUNNonlinearSolver_Type) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(nls) +fresult = swigc_FSUNNonlinSolGetType_Newton(farg1) +swig_result = fresult +end function + +function FSUNNonlinSolInitialize_Newton(nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(nls) +fresult = swigc_FSUNNonlinSolInitialize_Newton(farg1) +swig_result = fresult +end function + +function FSUNNonlinSolSolve_Newton(nls, y0, y, w, tol, calllsetup, mem) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(N_Vector), target, intent(inout) :: y0 +type(N_Vector), target, intent(inout) :: y +type(N_Vector), target, intent(inout) :: w +real(C_DOUBLE), intent(in) :: tol +integer(C_INT), intent(in) :: calllsetup +type(C_PTR) :: mem +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 +type(C_PTR) :: farg3 +type(C_PTR) :: farg4 +real(C_DOUBLE) :: farg5 +integer(C_INT) :: farg6 +type(C_PTR) :: farg7 + +farg1 = c_loc(nls) +farg2 = c_loc(y0) +farg3 = c_loc(y) +farg4 = c_loc(w) +farg5 = tol +farg6 = calllsetup +farg7 = mem +fresult = swigc_FSUNNonlinSolSolve_Newton(farg1, farg2, farg3, farg4, farg5, farg6, farg7) +swig_result = fresult +end function + +function FSUNNonlinSolFree_Newton(nls) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT) :: fresult +type(C_PTR) :: farg1 + +farg1 = c_loc(nls) +fresult = swigc_FSUNNonlinSolFree_Newton(farg1) +swig_result = fresult +end function + +function FSUNNonlinSolSetSysFn_Newton(nls, sysfn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_FUNPTR), intent(in), value :: sysfn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = sysfn +fresult = swigc_FSUNNonlinSolSetSysFn_Newton(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolSetLSetupFn_Newton(nls, lsetupfn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_FUNPTR), intent(in), value :: lsetupfn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = lsetupfn +fresult = swigc_FSUNNonlinSolSetLSetupFn_Newton(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolSetLSolveFn_Newton(nls, lsolvefn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_FUNPTR), intent(in), value :: lsolvefn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = lsolvefn +fresult = swigc_FSUNNonlinSolSetLSolveFn_Newton(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolSetConvTestFn_Newton(nls, ctestfn, ctest_data) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_FUNPTR), intent(in), value :: ctestfn +type(C_PTR) :: ctest_data +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_FUNPTR) :: farg2 +type(C_PTR) :: farg3 + +farg1 = c_loc(nls) +farg2 = ctestfn +farg3 = ctest_data +fresult = swigc_FSUNNonlinSolSetConvTestFn_Newton(farg1, farg2, farg3) +swig_result = fresult +end function + +function FSUNNonlinSolSetMaxIters_Newton(nls, maxiters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT), intent(in) :: maxiters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +integer(C_INT) :: farg2 + +farg1 = c_loc(nls) +farg2 = maxiters +fresult = swigc_FSUNNonlinSolSetMaxIters_Newton(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolGetNumIters_Newton(nls, niters) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_LONG), dimension(*), target, intent(inout) :: niters +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = c_loc(niters(1)) +fresult = swigc_FSUNNonlinSolGetNumIters_Newton(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolGetCurIter_Newton(nls, iter) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_INT), dimension(*), target, intent(inout) :: iter +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = c_loc(iter(1)) +fresult = swigc_FSUNNonlinSolGetCurIter_Newton(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolGetNumConvFails_Newton(nls, nconvfails) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +integer(C_LONG), dimension(*), target, intent(inout) :: nconvfails +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = c_loc(nconvfails(1)) +fresult = swigc_FSUNNonlinSolGetNumConvFails_Newton(farg1, farg2) +swig_result = fresult +end function + +function FSUNNonlinSolGetSysFn_Newton(nls, sysfn) & +result(swig_result) +use, intrinsic :: ISO_C_BINDING +integer(C_INT) :: swig_result +type(SUNNonlinearSolver), target, intent(inout) :: nls +type(C_FUNPTR), target, intent(inout) :: sysfn +integer(C_INT) :: fresult +type(C_PTR) :: farg1 +type(C_PTR) :: farg2 + +farg1 = c_loc(nls) +farg2 = c_loc(sysfn) +fresult = swigc_FSUNNonlinSolGetSysFn_Newton(farg1, farg2) +swig_result = fresult +end function + + +end module diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.c b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.c index dfa990931..b1028f136 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.h b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.h index 289a525fb..ffc844337 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.h +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.h @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/sunnonlinsol_newton.c b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/sunnonlinsol_newton.c index 677f6ede1..a7cdca427 100644 --- a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/sunnonlinsol_newton.c +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/newton/sunnonlinsol_newton.c @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2019, Lawrence Livermore National Security + * Copyright (c) 2002-2020, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -27,6 +27,7 @@ #define NEWTON_CONTENT(S) ( (SUNNonlinearSolverContent_Newton)(S->content) ) /* Constant macros */ +#define ZERO RCONST(0.0) /* real 0.0 */ #define ONE RCONST(1.0) /* real 1.0 */ /*============================================================================== @@ -36,7 +37,6 @@ SUNNonlinearSolver SUNNonlinSol_Newton(N_Vector y) { SUNNonlinearSolver NLS; - SUNNonlinearSolver_Ops ops; SUNNonlinearSolverContent_Newton content; /* Check that the supplied N_Vector is non-NULL */ @@ -49,57 +49,51 @@ SUNNonlinearSolver SUNNonlinSol_Newton(N_Vector y) (y->ops->nvlinearsum == NULL) ) return(NULL); - /* Create nonlinear linear solver */ + /* Create an empty nonlinear linear solver object */ NLS = NULL; - NLS = (SUNNonlinearSolver) malloc(sizeof *NLS); + NLS = SUNNonlinSolNewEmpty(); if (NLS == NULL) return(NULL); - /* Create linear solver operation structure */ - ops = NULL; - ops = (SUNNonlinearSolver_Ops) malloc(sizeof *ops); - if (ops == NULL) { free(NLS); return(NULL); } - /* Attach operations */ - ops->gettype = SUNNonlinSolGetType_Newton; - ops->initialize = SUNNonlinSolInitialize_Newton; - ops->setup = NULL; /* no setup needed */ - ops->solve = SUNNonlinSolSolve_Newton; - ops->free = SUNNonlinSolFree_Newton; - ops->setsysfn = SUNNonlinSolSetSysFn_Newton; - ops->setlsetupfn = SUNNonlinSolSetLSetupFn_Newton; - ops->setlsolvefn = SUNNonlinSolSetLSolveFn_Newton; - ops->setctestfn = SUNNonlinSolSetConvTestFn_Newton; - ops->setmaxiters = SUNNonlinSolSetMaxIters_Newton; - ops->getnumiters = SUNNonlinSolGetNumIters_Newton; - ops->getcuriter = SUNNonlinSolGetCurIter_Newton; - ops->getnumconvfails = SUNNonlinSolGetNumConvFails_Newton; + NLS->ops->gettype = SUNNonlinSolGetType_Newton; + NLS->ops->initialize = SUNNonlinSolInitialize_Newton; + NLS->ops->solve = SUNNonlinSolSolve_Newton; + NLS->ops->free = SUNNonlinSolFree_Newton; + NLS->ops->setsysfn = SUNNonlinSolSetSysFn_Newton; + NLS->ops->setlsetupfn = SUNNonlinSolSetLSetupFn_Newton; + NLS->ops->setlsolvefn = SUNNonlinSolSetLSolveFn_Newton; + NLS->ops->setctestfn = SUNNonlinSolSetConvTestFn_Newton; + NLS->ops->setmaxiters = SUNNonlinSolSetMaxIters_Newton; + NLS->ops->getnumiters = SUNNonlinSolGetNumIters_Newton; + NLS->ops->getcuriter = SUNNonlinSolGetCurIter_Newton; + NLS->ops->getnumconvfails = SUNNonlinSolGetNumConvFails_Newton; /* Create content */ content = NULL; content = (SUNNonlinearSolverContent_Newton) malloc(sizeof *content); - if (content == NULL) { free(ops); free(NLS); return(NULL); } + if (content == NULL) { SUNNonlinSolFree(NLS); return(NULL); } /* Initialize all components of content to 0/NULL */ memset(content, 0, sizeof(struct _SUNNonlinearSolverContent_Newton)); - /* Fill content */ + /* Attach content */ + NLS->content = content; + + /* Fill general content */ content->Sys = NULL; content->LSetup = NULL; content->LSolve = NULL; content->CTest = NULL; - content->delta = N_VClone(y); content->jcur = SUNFALSE; content->curiter = 0; content->maxiters = 3; content->niters = 0; content->nconvfails = 0; + content->ctest_data = NULL; - /* check if clone was successful */ - if (content->delta == NULL) { free(ops); free(NLS); return(NULL); } - - /* Attach content and ops */ - NLS->content = content; - NLS->ops = ops; + /* Fill allocatable content */ + content->delta = N_VClone(y); + if (content->delta == NULL) { SUNNonlinSolFree(NLS); return(NULL); } return(NLS); } @@ -183,7 +177,7 @@ int SUNNonlinSolInitialize_Newton(SUNNonlinearSolver NLS) the Sys, LSetup, and LSolve functions provided to the nonlinear solver. ----------------------------------------------------------------------------*/ int SUNNonlinSolSolve_Newton(SUNNonlinearSolver NLS, - N_Vector y0, N_Vector y, + N_Vector y0, N_Vector ycor, N_Vector w, realtype tol, booleantype callLSetup, void* mem) { @@ -193,13 +187,21 @@ int SUNNonlinSolSolve_Newton(SUNNonlinearSolver NLS, N_Vector delta; /* check that the inputs are non-null */ - if ( (NLS == NULL) || - (y0 == NULL) || - (y == NULL) || - (w == NULL) || - (mem == NULL) ) + if ( (NLS == NULL) || + (y0 == NULL) || + (ycor == NULL) || + (w == NULL) || + (mem == NULL) ) return(SUN_NLS_MEM_NULL); + /* check that all required function pointers have been set */ + if ( (NEWTON_CONTENT(NLS)->Sys == NULL) || + (NEWTON_CONTENT(NLS)->LSolve == NULL) || + (callLSetup && (NEWTON_CONTENT(NLS)->LSetup == NULL)) || + (NEWTON_CONTENT(NLS)->CTest == NULL) ) { + return(SUN_NLS_MEM_NULL); + } + /* set local shortcut variables */ delta = NEWTON_CONTENT(NLS)->delta; @@ -213,12 +215,12 @@ int SUNNonlinSolSolve_Newton(SUNNonlinearSolver NLS, for(;;) { /* compute the nonlinear residual, store in delta */ - retval = NEWTON_CONTENT(NLS)->Sys(y0, delta, mem); + retval = NEWTON_CONTENT(NLS)->Sys(ycor, delta, mem); if (retval != SUN_NLS_SUCCESS) break; /* if indicated, setup the linear system */ if (callLSetup) { - retval = NEWTON_CONTENT(NLS)->LSetup(y0, delta, jbad, + retval = NEWTON_CONTENT(NLS)->LSetup(jbad, &(NEWTON_CONTENT(NLS)->jcur), mem); if (retval != SUN_NLS_SUCCESS) break; @@ -227,9 +229,6 @@ int SUNNonlinSolSolve_Newton(SUNNonlinearSolver NLS, /* initialize counter curiter */ NEWTON_CONTENT(NLS)->curiter = 0; - /* load prediction into y */ - N_VScale(ONE, y0, y); - /* looping point for Newton iteration. Break out on any error. */ for(;;) { @@ -240,14 +239,15 @@ int SUNNonlinSolSolve_Newton(SUNNonlinearSolver NLS, N_VScale(-ONE, delta, delta); /* solve the linear system to get Newton update delta */ - retval = NEWTON_CONTENT(NLS)->LSolve(y, delta, mem); + retval = NEWTON_CONTENT(NLS)->LSolve(delta, mem); if (retval != SUN_NLS_SUCCESS) break; /* update the Newton iterate */ - N_VLinearSum(ONE, y, ONE, delta, y); + N_VLinearSum(ONE, ycor, ONE, delta, ycor); /* test for convergence */ - retval = NEWTON_CONTENT(NLS)->CTest(NLS, y, delta, tol, w, mem); + retval = NEWTON_CONTENT(NLS)->CTest(NLS, ycor, delta, tol, w, + NEWTON_CONTENT(NLS)->ctest_data); /* if successful update Jacobian status and return */ if (retval == SUN_NLS_SUCCESS) { @@ -266,7 +266,7 @@ int SUNNonlinSolSolve_Newton(SUNNonlinearSolver NLS, } /* compute the nonlinear residual, store in delta */ - retval = NEWTON_CONTENT(NLS)->Sys(y, delta, mem); + retval = NEWTON_CONTENT(NLS)->Sys(ycor, delta, mem); if (retval != SUN_NLS_SUCCESS) break; } /* end of Newton iteration loop */ @@ -274,13 +274,14 @@ int SUNNonlinSolSolve_Newton(SUNNonlinearSolver NLS, /* all errors go here */ /* If there is a recoverable convergence failure and the Jacobian-related - data appears not to be current, increment the convergence failure count - and loop again with a call to lsetup in which jbad is TRUE. Otherwise - break out and return. */ + data appears not to be current, increment the convergence failure count, + reset the initial correction to zero, and loop again with a call to + lsetup in which jbad is TRUE. Otherwise break out and return. */ if ((retval > 0) && !(NEWTON_CONTENT(NLS)->jcur) && (NEWTON_CONTENT(NLS)->LSetup)) { NEWTON_CONTENT(NLS)->nconvfails++; callLSetup = SUNTRUE; jbad = SUNTRUE; + N_VConst(ZERO, ycor); continue; } else { break; @@ -371,7 +372,9 @@ int SUNNonlinSolSetLSolveFn_Newton(SUNNonlinearSolver NLS, SUNNonlinSolLSolveFn } -int SUNNonlinSolSetConvTestFn_Newton(SUNNonlinearSolver NLS, SUNNonlinSolConvTestFn CTestFn) +int SUNNonlinSolSetConvTestFn_Newton(SUNNonlinearSolver NLS, + SUNNonlinSolConvTestFn CTestFn, + void* ctest_data) { /* check that the nonlinear solver is non-null */ if (NLS == NULL) @@ -382,6 +385,10 @@ int SUNNonlinSolSetConvTestFn_Newton(SUNNonlinearSolver NLS, SUNNonlinSolConvTes return(SUN_NLS_ILL_INPUT); NEWTON_CONTENT(NLS)->CTest = CTestFn; + + /* attach convergence test data */ + NEWTON_CONTENT(NLS)->ctest_data = ctest_data; + return(SUN_NLS_SUCCESS); } diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/petscsnes/CMakeLists.txt b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/petscsnes/CMakeLists.txt new file mode 100644 index 000000000..da2d23b1f --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/petscsnes/CMakeLists.txt @@ -0,0 +1,79 @@ +# ------------------------------------------------------------------------------ +# Programmer(s): Cody J. Balos @ LLNL +# ------------------------------------------------------------------------------ +# SUNDIALS Copyright Start +# Copyright (c) 2002-2020, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# ------------------------------------------------------------------------------ +# CMakeLists.txt file for the PETSc SUNNonlinearSolver library +# ------------------------------------------------------------------------------ +install(CODE "MESSAGE(\"\nInstall SUNNONLINSOL_PETSCSNES\n\")") + +if(MPI_C_COMPILER) + # use MPI wrapper as the compiler + set(CMAKE_C_COMPILER ${MPI_C_COMPILER}) +else() + # add MPI_INCLUDE_PATH to include directories + include_directories(${MPI_INCLUDE_PATH}) +endif() + +# Add variable with the sources for the library +set(lib_SOURCES sunnonlinsol_petscsnes.c) + +# Add variable with the common SUNDIALS sources to be included in the library +set(shared_SOURCES + ${sundials_SOURCE_DIR}/src/sundials/sundials_math.c + ${sundials_SOURCE_DIR}/src/sundials/sundials_nvector.c + ${sundials_SOURCE_DIR}/src/sundials/sundials_nonlinearsolver.c + ) + +# Add variable with the exported header files +set(lib_HEADERS + ${sundials_SOURCE_DIR}/include/sunnonlinsol/sunnonlinsol_petscsnes.h + ) + +# Define C preprocessor flag -DBUILD_SUNDIALS_LIBRARY +add_definitions(-DBUILD_SUNDIALS_LIBRARY) + +if(BUILD_STATIC_LIBS) + add_library(sundials_sunnonlinsolpetscsnes_static STATIC ${lib_SOURCES} ${shared_SOURCES}) + + target_link_libraries(sundials_sunnonlinsolpetscsnes_static + PUBLIC sundials_nvecpetsc_static PETSC::SNES) + + set_target_properties(sundials_sunnonlinsolpetscsnes_static PROPERTIES + OUTPUT_NAME sundials_sunnonlinsolpetscsnes + CLEAN_DIRECT_OUTPUT 1) + + install(TARGETS sundials_sunnonlinsolpetscsnes_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() + +if(BUILD_SHARED_LIBS) + add_library(sundials_sunnonlinsolpetscsnes_shared SHARED ${lib_SOURCES} ${shared_SOURCES}) + + target_link_libraries(sundials_sunnonlinsolpetscsnes_shared + PUBLIC sundials_nvecpetsc_shared PETSC::SNES) + + if(UNIX) + target_link_libraries(sundials_sunnonlinsolpetscsnes_shared PRIVATE m) + endif() + + set_target_properties(sundials_sunnonlinsolpetscsnes_shared PROPERTIES + OUTPUT_NAME sundials_sunnonlinsolpetscsnes + CLEAN_DIRECT_OUTPUT 1 + VERSION ${sunnonlinsollib_VERSION} + SOVERSION ${sunnonlinsollib_SOVERSION}) + + install(TARGETS sundials_sunnonlinsolpetscsnes_shared DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() + +# Install the header files +install(FILES ${lib_HEADERS} DESTINATION include/sunnonlinsol) + +message(STATUS "Added SUNNONLINSOL_PETSCSNES module") diff --git a/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/petscsnes/sunnonlinsol_petscsnes.c b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/petscsnes/sunnonlinsol_petscsnes.c new file mode 100644 index 000000000..7a3436dfb --- /dev/null +++ b/deps/AMICI/ThirdParty/sundials/src/sunnonlinsol/petscsnes/sunnonlinsol_petscsnes.c @@ -0,0 +1,371 @@ +/* ----------------------------------------------------------------------------- + * Programmer(s): Cody J. Balos @ LLNL + * ----------------------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2020, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ----------------------------------------------------------------------------- + * This is the implementation file for the SUNNonlinearSolver module + * implementation that interfaces to the PETSc SNES nonlinear solvers. + * ---------------------------------------------------------------------------*/ + +#include +#include +#include + +#include + +#include +#include +#include + +#define SUNNLS_SNES_CONTENT(NLS) ( (SUNNonlinearSolverContent_PetscSNES)(NLS->content) ) +#define SUNNLS_SNESOBJ(NLS) ( SUNNLS_SNES_CONTENT(NLS)->snes ) + +/* private function which translates the SNESFunction form to the SUNNonlinSolSysFn form */ +static PetscErrorCode PetscSysFn(SNES snes, Vec x, Vec f, void *ctx); + +/*============================================================================== + Constructor + ============================================================================*/ + +/* create a SUNNonlinearSolver wrapper for the PETSc SNES context */ +SUNNonlinearSolver SUNNonlinSol_PetscSNES(N_Vector y, SNES snes) +{ + int ierr; + SUNNonlinearSolver NLS; + SUNNonlinearSolverContent_PetscSNES content; + + /* check that the supplied SNES is non-NULL */ + if (snes == NULL || y == NULL) return NULL; + + /* check that the vector is the right type */ + if (N_VGetVectorID(y) != SUNDIALS_NVEC_PETSC) return NULL; + + /* + * Create an empty nonlinear linear solver object + */ + + NLS = SUNNonlinSolNewEmpty(); + if (NLS == NULL) return NULL; + + /* Attach operations */ + NLS->ops->gettype = SUNNonlinSolGetType_PetscSNES; + NLS->ops->initialize = SUNNonlinSolInitialize_PetscSNES; + NLS->ops->solve = SUNNonlinSolSolve_PetscSNES; + NLS->ops->free = SUNNonlinSolFree_PetscSNES; + NLS->ops->setsysfn = SUNNonlinSolSetSysFn_PetscSNES; + NLS->ops->getnumiters = SUNNonlinSolGetNumIters_PetscSNES; + NLS->ops->getnumconvfails = SUNNonlinSolGetNumConvFails_PetscSNES; + + /* + * Create content + */ + + content = NULL; + content = (SUNNonlinearSolverContent_PetscSNES) malloc(sizeof *content); + if (content == NULL) { + SUNNonlinSolFree(NLS); + return NULL; + } + + /* Initialize all components of content to 0/NULL */ + memset(content, 0, sizeof(struct _SUNNonlinearSolverContent_PetscSNES)); + + /* Attach content */ + NLS->content = content; + + /* + * Fill content + */ + + content->snes = snes; + + /* Create all internal vectors */ + content->y = N_VCloneEmpty(y); + if (content->y == NULL) { + SUNNonlinSolFree(NLS); + return NULL; + } + + content->f = N_VCloneEmpty(y); + if (content->f == NULL) { + SUNNonlinSolFree(NLS); + return NULL; + } + + ierr = VecDuplicate(N_VGetVector_Petsc(y), &content->r); + if (ierr != 0) { + SUNNonlinSolFree(NLS); + return NULL; + } + + /* tell SNES about the sys function */ + ierr = SNESSetFunction(SUNNLS_SNESOBJ(NLS), SUNNLS_SNES_CONTENT(NLS)->r, PetscSysFn, NLS); + if (ierr != 0) { + SUNNonlinSolFree(NLS); + return NULL; + } + + return(NLS); +} + + +/*============================================================================== + GetType, Initialize, Setup, Solve, and Free operations + ============================================================================*/ + +/* get the type of SUNNonlinearSolver */ +SUNNonlinearSolver_Type SUNNonlinSolGetType_PetscSNES(SUNNonlinearSolver NLS) +{ + return(SUNNONLINEARSOLVER_ROOTFIND); +} + +/* performs any initialization needed */ +int SUNNonlinSolInitialize_PetscSNES(SUNNonlinearSolver NLS) +{ + PetscErrorCode ptcerr; + + /* set the system function again to ensure it is the wrapper */ + ptcerr = SNESSetFunction(SUNNLS_SNESOBJ(NLS), SUNNLS_SNES_CONTENT(NLS)->r, PetscSysFn, NLS); + if (ptcerr != 0) { + SUNNLS_SNES_CONTENT(NLS)->petsc_last_err = ptcerr; + return SUN_NLS_EXT_FAIL; + } + + return SUN_NLS_SUCCESS; +} + +/*------------------------------------------------------------------------------ + SUNNonlinSolSolve_PetscSNES: Performs the nonlinear solve F(y) = 0 or G(y) = y + + Successful solve return code: + SUN_NLS_SUCCESS = 0 + + Recoverable failure return codes (positive): + SUN_NLS_CONV_RECVR + *_RHSFUNC_RECVR (ODEs) or *_RES_RECVR (DAEs) + + Unrecoverable failure return codes (negative): + *_MEM_NULL + *_RHSFUNC_FAIL (ODEs) or *_RES_FAIL (DAEs) + + Note return values beginning with * are package specific values returned by + the Sys function provided to the nonlinear solver. + ----------------------------------------------------------------------------*/ +int SUNNonlinSolSolve_PetscSNES(SUNNonlinearSolver NLS, + N_Vector y0, N_Vector y, + N_Vector w, realtype tol, + booleantype callLSetup, void* mem) +{ + /* local variables */ + PetscErrorCode ierr; + SNESConvergedReason reason; + int retval; + sunindextype nni; + + /* check that the inputs are non-null */ + if ( (NLS == NULL) || + (y0 == NULL) || + (y == NULL) || + (w == NULL) ) + return SUN_NLS_MEM_NULL; + + /* store a pointer to the integrator memory so it can be + * accessed in the system function */ + SUNNLS_SNES_CONTENT(NLS)->imem = mem; + + /* call petsc SNES solve */ + ierr = SNESSolve(SUNNLS_SNESOBJ(NLS), NULL, N_VGetVector_Petsc(y)); + + /* check if the call to the system function failed */ + if (SUNNLS_SNES_CONTENT(NLS)->sysfn_last_err != SUN_NLS_SUCCESS) + return SUNNLS_SNES_CONTENT(NLS)->sysfn_last_err; + + /* check if the SNESSolve had a failure elsewhere */ + if (ierr != 0) { + SUNNLS_SNES_CONTENT(NLS)->petsc_last_err = ierr; + return SUN_NLS_EXT_FAIL; /* ierr != 0 is not recoverable with PETSc */ + } + + /* + * determine if and why the system converged/diverged so we can determine + * if it is a recoverable failure or success + */ + + ierr = SNESGetConvergedReason(SUNNLS_SNESOBJ(NLS), &reason); + if (ierr != 0) { + SUNNLS_SNES_CONTENT(NLS)->petsc_last_err = ierr; + return SUN_NLS_EXT_FAIL; /* ierr != 0 is not recoverable with PETSc */ + } + + if ( (reason == SNES_CONVERGED_ITERATING) || + (reason == SNES_CONVERGED_FNORM_ABS) || + (reason == SNES_CONVERGED_FNORM_RELATIVE) || + (reason == SNES_CONVERGED_SNORM_RELATIVE) ) { + /* success */ + retval = SUN_NLS_SUCCESS; + } else { + /* recoverable failure */ + retval = SUN_NLS_CONV_RECVR; + /* update convergence failure count */ + SUNNLS_SNES_CONTENT(NLS)->nconvfails++; + } + + /* update iteration count */ + ierr = SNESGetIterationNumber(SUNNLS_SNESOBJ(NLS), &nni); + if (ierr != 0) { + SUNNLS_SNES_CONTENT(NLS)->petsc_last_err = ierr; + return SUN_NLS_EXT_FAIL; /* ierr != 0 is not recoverable with PETSc */ + } + SUNNLS_SNES_CONTENT(NLS)->nni += nni; + + return retval; +} + +/* free the SUNNonlinearSolver */ +int SUNNonlinSolFree_PetscSNES(SUNNonlinearSolver NLS) +{ + /* return if NLS is already free */ + if (NLS == NULL) + return SUN_NLS_SUCCESS; + + /* free items from contents, then the generic structure */ + if (NLS->content) { + if (SUNNLS_SNES_CONTENT(NLS)->r) VecDestroy(&SUNNLS_SNES_CONTENT(NLS)->r); + if (SUNNLS_SNES_CONTENT(NLS)->y) N_VDestroy_Petsc(SUNNLS_SNES_CONTENT(NLS)->y); + if (SUNNLS_SNES_CONTENT(NLS)->f) N_VDestroy_Petsc(SUNNLS_SNES_CONTENT(NLS)->f); + free(NLS->content); + NLS->content = NULL; + } + + /* free the ops structure */ + if (NLS->ops) { + free(NLS->ops); + NLS->ops = NULL; + } + + /* free the nonlinear solver */ + free(NLS); + + return SUN_NLS_SUCCESS; +} + + +/*============================================================================== + Set functions + ============================================================================*/ + +/* set the system residual function */ +int SUNNonlinSolSetSysFn_PetscSNES(SUNNonlinearSolver NLS, SUNNonlinSolSysFn SysFn) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return SUN_NLS_MEM_NULL; + + /* check that the nonlinear system function is non-null */ + if (SysFn == NULL) + return(SUN_NLS_ILL_INPUT); + + SUNNLS_SNES_CONTENT(NLS)->Sys = SysFn; + return SUN_NLS_SUCCESS; +} + +/*============================================================================== + Get functions + ============================================================================*/ + + +/* get the PETSc SNES context underneath the SUNNonlinearSolver object */ +int SUNNonlinSolGetSNES_PetscSNES(SUNNonlinearSolver NLS, SNES *snes) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return SUN_NLS_MEM_NULL; + + /* return the SNES context */ + *snes = SUNNLS_SNESOBJ(NLS); + return SUN_NLS_SUCCESS; +} + +/* get the last error return by SNES */ +int SUNNonlinSolGetPetscError_PetscSNES(SUNNonlinearSolver NLS, PetscErrorCode* err) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return SUN_NLS_MEM_NULL; + + /* return the last PETSc error code returned by SNES */ + *err = SUNNLS_SNES_CONTENT(NLS)->petsc_last_err; + return SUN_NLS_SUCCESS; +} + +/* get a pointer to the SUNDIALS integrator-provided system function F(y) */ +int SUNNonlinSolGetSysFn_PetscSNES(SUNNonlinearSolver NLS, SUNNonlinSolSysFn* SysFn) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return SUN_NLS_MEM_NULL; + + /* return the nonlinear system defining function */ + *SysFn = SUNNLS_SNES_CONTENT(NLS)->Sys; + return SUN_NLS_SUCCESS; +} + +/* get the total number of iterations performed in the lifetime + of this SUNNonlinearSolver object */ +int SUNNonlinSolGetNumIters_PetscSNES(SUNNonlinearSolver NLS, long int* nni) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return SUN_NLS_MEM_NULL; + + *nni = SUNNLS_SNES_CONTENT(NLS)->nni; + return SUN_NLS_SUCCESS; +} + +/* get the total number of nonlinear convergence failures in the + lifetime of this SUNNonlinearSolver object */ +int SUNNonlinSolGetNumConvFails_PetscSNES(SUNNonlinearSolver NLS, + long int* nconvfails) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return SUN_NLS_MEM_NULL; + + *nconvfails = SUNNLS_SNES_CONTENT(NLS)->nconvfails; + + return SUN_NLS_SUCCESS; +} + +/*============================================================================== + Private functions + ============================================================================*/ + +static PetscErrorCode PetscSysFn(SNES snes, Vec x, Vec f, void *ctx) +{ + int retval; + SUNNonlinearSolver NLS = (SUNNonlinearSolver) ctx; + + /* wrap up the petsc vectors in nvectors */ + N_VSetVector_Petsc(SUNNLS_SNES_CONTENT(NLS)->y, x); + N_VSetVector_Petsc(SUNNLS_SNES_CONTENT(NLS)->f, f); + + /* now call the SUNDIALS format system function to evaluate F(y) */ + retval = SUNNLS_SNES_CONTENT(NLS)->Sys(SUNNLS_SNES_CONTENT(NLS)->y, + SUNNLS_SNES_CONTENT(NLS)->f, + SUNNLS_SNES_CONTENT(NLS)->imem); + /* store the return value */ + SUNNLS_SNES_CONTENT(NLS)->sysfn_last_err = retval; + + /* if there was some sort of failure in the system function, return -1 to + * indicate an error instead of retval so that we don't overlap with one of + * the standard PETSc error codes */ + return (retval != 0) ? -1 : 0; +} diff --git a/deps/AMICI/documentation/_templates/autosummary/class.rst b/deps/AMICI/documentation/_templates/autosummary/class.rst index 66670d3f4..030e2a4c1 100644 --- a/deps/AMICI/documentation/_templates/autosummary/class.rst +++ b/deps/AMICI/documentation/_templates/autosummary/class.rst @@ -7,6 +7,7 @@ {% block methods %} {% if '__init__' in methods %} .. automethod:: __init__ + :noindex: {% endif %} {% if methods %} .. rubric:: Methods Summary diff --git a/deps/AMICI/documentation/conf.py b/deps/AMICI/documentation/conf.py index 56af2bea0..a3b8b005b 100644 --- a/deps/AMICI/documentation/conf.py +++ b/deps/AMICI/documentation/conf.py @@ -3,6 +3,19 @@ import re import subprocess import mock + +from sphinx.transforms.post_transforms import ReferencesResolver + +import amici + +# The short X.Y version +version = amici.__version__ +# The full version, including alpha/beta/rc tags +release = version + +del amici + + # -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. @@ -38,8 +51,6 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. # -from sphinx.transforms.post_transforms import ReferencesResolver - sys.path.insert(0, os.path.abspath('../python/sdist')) sys.path.insert(0, os.path.abspath('../')) @@ -48,24 +59,14 @@ # Note that for sub-modules, all parent modules must be listed explicitly. autodoc_mock_imports = ['_amici', 'amici._amici'] for mod_name in autodoc_mock_imports: - sys.modules[mod_name] = mock.Mock() + sys.modules[mod_name] = mock.MagicMock() # -- Project information ----------------------------------------------------- project = 'AMICI' copyright = '2020, The AMICI developers' author = 'The AMICI developers' - -import amici - -# The short X.Y version -version = amici.__version__ -# The full version, including alpha/beta/rc tags -release = version - -del amici - - +title = 'AMICI Documentation' # -- General configuration --------------------------------------------------- @@ -188,8 +189,8 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'AMICI.tex', 'AMICI Documentation', - 'The AMICI developers', 'manual'), + (master_doc, 'AMICI.tex', title, + author, 'manual'), ] @@ -198,7 +199,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'amici', 'AMICI Documentation', + (master_doc, 'amici', title, [author], 1) ] @@ -209,7 +210,7 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'AMICI', 'AMICI Documentation', + (master_doc, 'AMICI', title, author, 'AMICI', 'Advanced Multilanguage Interface for CVODES and IDAS.', 'Miscellaneous'), ] @@ -346,13 +347,6 @@ def fix_typehints(sig: str) -> str: sig = sig.replace('sunindextype', 'int') sig = sig.replace('H5::H5File', 'object') - # enum classes - for ec in ['SteadyStateSensitivityMode', 'InternalSensitivityMethod', - 'InterpolationType', 'LinearMultistepMethod', 'LinearSolver', - 'NewtonDampingFactorMode', 'NonlinearSolverIteration', - 'SensitivityMethod', 'SensitivityOrder']: - sig = sig.replace(ec, 'int') - # remove const sig = sig.replace(' const ', r' ') sig = re.sub(r' const$', r'', sig) @@ -403,14 +397,14 @@ def process_missing_ref(app, env, node, contnode): for old, new in doclinks.items(): node['reftarget'] = node['reftarget'].replace(old, new) - contnode = node[0] - if 'refuri' in contnode: + cnode = node[0] + if 'refuri' in cnode: for old, new in doclinks.items(): - contnode['refuri'] = contnode['refuri'].replace(old, new) + cnode['refuri'] = cnode['refuri'].replace(old, new) refdoc = node.get('refdoc', env.docname) resolver = ReferencesResolver(env.get_doctree(refdoc)) - result = resolver.resolve_anyref(refdoc, node, contnode) + result = resolver.resolve_anyref(refdoc, node, cnode) return result diff --git a/deps/AMICI/documentation/gfx/steadystate_solver_workflow.png b/deps/AMICI/documentation/gfx/steadystate_solver_workflow.png new file mode 100644 index 000000000..10bd172ab Binary files /dev/null and b/deps/AMICI/documentation/gfx/steadystate_solver_workflow.png differ diff --git a/deps/AMICI/include/amici/abstract_model.h b/deps/AMICI/include/amici/abstract_model.h index 33614cfb1..ef787aef7 100644 --- a/deps/AMICI/include/amici/abstract_model.h +++ b/deps/AMICI/include/amici/abstract_model.h @@ -68,6 +68,39 @@ class AbstractModel { const AmiVector &dx, int ip, const AmiVector &sx, const AmiVector &sdx, AmiVector &sxdot) = 0; + /** + * @brief Residual function backward when running in steady state mode + * @param t time + * @param xB adjoint state + * @param dxB time derivative of state (DAE only) + * @param xBdot array to which values of the residual function will be + * written + */ + virtual void fxBdot_ss(const realtype t, const AmiVector &xB, + const AmiVector &dxB, AmiVector &xBdot) = 0; + + /** + * @brief Sparse Jacobian function backward, steady state case + * @param JB sparse matrix to which values of the Jacobian will be written + */ + virtual void fJSparseB_ss(SUNMatrix JB) = 0; + + /** + * @brief Computes the sparse backward Jacobian for steadystate integration + * and writes it to the model member + * @param t timepoint + * @param cj scalar in Jacobian + * @param x Vector with the states + * @param dx Vector with the derivative states + * @param xB Vector with the adjoint states + * @param dxB Vector with the adjoint derivative states + * @param xBdot Vector with the adjoint state right hand side + */ + virtual void writeSteadystateJB(const realtype t, realtype cj, + const AmiVector &x, const AmiVector &dx, + const AmiVector &xB, const AmiVector &dxB, + const AmiVector &xBdot) = 0; + /** * @brief Dense Jacobian function * @param t time @@ -81,6 +114,22 @@ class AbstractModel { const AmiVector &dx, const AmiVector &xdot, SUNMatrix J) = 0; + /** + * @brief Dense Jacobian function + * @param t time + * @param cj scaling factor (inverse of timestep, DAE only) + * @param x state + * @param dx time derivative of state (DAE only) + * @param xB Vector with the adjoint states + * @param dxB Vector with the adjoint derivative states + * @param xBdot Vector with the adjoint right hand side (unused) + * @param JB dense matrix to which values of the jacobian will be written + */ + virtual void fJB(const realtype t, realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xB, + const AmiVector &dxB, const AmiVector &xBdot, + SUNMatrix JB) = 0; + /** * @brief Sparse Jacobian function * @param t time @@ -94,6 +143,22 @@ class AbstractModel { const AmiVector &dx, const AmiVector &xdot, SUNMatrix J) = 0; + /** + * @brief Sparse Jacobian function + * @param t time + * @param cj scaling factor (inverse of timestep, DAE only) + * @param x state + * @param dx time derivative of state (DAE only) + * @param xB Vector with the adjoint states + * @param dxB Vector with the adjoint derivative states + * @param xBdot Vector with the adjoint right hand side (unused) + * @param JB dense matrix to which values of the jacobian will be written + */ + virtual void fJSparseB(const realtype t, realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xB, + const AmiVector &dxB, const AmiVector &xBdot, + SUNMatrix JB) = 0; + /** * @brief Diagonal Jacobian function * @param t time diff --git a/deps/AMICI/include/amici/amici.h b/deps/AMICI/include/amici/amici.h index e246d5323..be98a65ff 100644 --- a/deps/AMICI/include/amici/amici.h +++ b/deps/AMICI/include/amici/amici.h @@ -87,7 +87,7 @@ class AmiciApplication { * @param format string with warning message printf-style format * @param ... arguments to be formatted */ - void warningF(const char *identifier, const char *format, ...); + void warningF(const char *identifier, const char *format, ...) const; /** * @brief printf interface to error() @@ -95,7 +95,7 @@ class AmiciApplication { * @param format string with error message printf-style format * @param ... arguments to be formatted */ - void errorF(const char *identifier, const char *format, ...); + void errorF(const char *identifier, const char *format, ...) const; /** * @brief Checks the values in an array for NaNs and Infs diff --git a/deps/AMICI/include/amici/backwardproblem.h b/deps/AMICI/include/amici/backwardproblem.h index fcf4a3663..17f48e324 100644 --- a/deps/AMICI/include/amici/backwardproblem.h +++ b/deps/AMICI/include/amici/backwardproblem.h @@ -8,11 +8,11 @@ namespace amici { -class ReturnData; class ExpData; class Solver; class Model; class ForwardProblem; +class SteadystateProblem; //! class to solve backwards problems. /*! @@ -25,8 +25,10 @@ class BackwardProblem { /** * @brief Construct backward problem from forward problem * @param fwd pointer to corresponding forward problem + * @param posteq pointer to postequilibration problem, can be nullptr */ - explicit BackwardProblem(const ForwardProblem *fwd); + explicit BackwardProblem(const ForwardProblem &fwd, + const SteadystateProblem *posteq); /** * @brief Solve the backward problem. @@ -68,15 +70,29 @@ class BackwardProblem { std::vector const& getdJydx() const { return dJydx; } + + /** + * @brief Accessor for xB + * @return xB + */ + AmiVector const& getAdjointState() const { + return xB; + } + + /** + * @brief Accessor for xQB + * @return xQB + */ + AmiVector const& getAdjointQuadrature() const { + return xQB; + } private: /** * @brief Execute everything necessary for the handling of events * for the backward problem - * - * @param iroot index of event @type int */ - void handleEventB(int iroot); + void handleEventB(); /** * @brief Execute everything necessary for the handling of data @@ -93,22 +109,14 @@ class BackwardProblem { * This is the maximum of tdata and troot but also takes into account if * it<0 or iroot<0 where these expressions do not necessarily make sense. * - * @param troot timepoint of next event @type realtype - * @param iroot index of next event @type int * @param it index of next data point @type int - * @param model pointer to model specification object @type Model * @return tnext next timepoint @type realtype */ - realtype getTnext(std::vector const& troot, int iroot, int it); - - /** - * @brief Compute likelihood sensitivities. - */ - void computeLikelihoodSensitivities(); + realtype getTnext(int it); Model *model; - ReturnData *rdata; Solver *solver; + const ExpData *edata; /** current time */ realtype t; @@ -121,29 +129,24 @@ class BackwardProblem { /** quadrature state vector */ AmiVector xQB; /** array of state vectors at discontinuities*/ - const AmiVectorArray x_disc; + std::vector x_disc; /** array of differential state vectors at discontinuities*/ - const AmiVectorArray xdot_disc; + std::vector xdot_disc; /** array of old differential state vectors at discontinuities*/ - const AmiVectorArray xdot_old_disc; + std::vector xdot_old_disc; /** sensitivity state vector array */ AmiVectorArray sx0; /** array of number of found roots for a certain event type */ std::vector nroots; /** array containing the time-points of discontinuities*/ - const std::vector discs; - /** array containing the index of discontinuities */ - const std::vector irdiscs; + std::vector discs; /** index of the backward problem */ int which = 0; - /** current root index, will be increased during the forward solve and - * decreased during backward solve */ - int iroot = 0; /** array of index which root has been found */ - const std::vector rootidx; + std::vector> rootidx; /** state derivative of data likelihood */ - const std::vector dJydx; + std::vector dJydx; /** state derivative of event likelihood */ const std::vector dJzdx; }; diff --git a/deps/AMICI/include/amici/defines.h b/deps/AMICI/include/amici/defines.h index 780b4a62d..a88baad64 100644 --- a/deps/AMICI/include/amici/defines.h +++ b/deps/AMICI/include/amici/defines.h @@ -18,39 +18,34 @@ constexpr double pi = 3.14159265358979323846; // clang-format off -#define AMICI_ONEOUTPUT 5 +constexpr int AMICI_ONEOUTPUT= 5; /* Return codes */ -#define AMICI_RECOVERABLE_ERROR 1 -#define AMICI_UNRECOVERABLE_ERROR -10 -#define AMICI_TOO_MUCH_WORK -1 -#define AMICI_TOO_MUCH_ACC -2 -#define AMICI_ERR_FAILURE -3 -#define AMICI_CONV_FAILURE -4 -#define AMICI_ILL_INPUT -22 -#define AMICI_ERROR -99 -#define AMICI_NOT_IMPLEMENTED -999 -#define AMICI_SUCCESS 0 -#define AMICI_DATA_RETURN 1 -#define AMICI_ROOT_RETURN 2 - -#define AMICI_NORMAL 1 -#define AMICI_ONE_STEP 2 - -#define AMICI_PREEQUILIBRATE -1 +constexpr int AMICI_RECOVERABLE_ERROR= 1; +constexpr int AMICI_UNRECOVERABLE_ERROR= -10; +constexpr int AMICI_TOO_MUCH_WORK= -1; +constexpr int AMICI_TOO_MUCH_ACC= -2; +constexpr int AMICI_ERR_FAILURE= -3; +constexpr int AMICI_CONV_FAILURE= -4; +constexpr int AMICI_ILL_INPUT= -22; +constexpr int AMICI_ERROR= -99; +constexpr int AMICI_NO_STEADY_STATE= -81; +constexpr int AMICI_DAMPING_FACTOR_ERROR= -86; +constexpr int AMICI_SINGULAR_JACOBIAN= -807; +constexpr int AMICI_NOT_IMPLEMENTED= -999; +constexpr int AMICI_SUCCESS= 0; +constexpr int AMICI_DATA_RETURN= 1; +constexpr int AMICI_ROOT_RETURN= 2; + +constexpr int AMICI_NORMAL= 1; +constexpr int AMICI_ONE_STEP= 2; + +constexpr int AMICI_PREEQUILIBRATE= -1; #ifndef booleantype #define booleantype int #endif -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - /** defines variable type for simulation variables * (determines numerical accuracy) */ using realtype = double; @@ -143,11 +138,21 @@ enum class SteadyStateSensitivityMode { }; /** State in which the steady state computation finished */ -enum class NewtonStatus { - failed=-1, - newt=1, - newt_sim=2, - newt_sim_newt=3, +enum class SteadyStateStatus { + failed_too_long_simulation = -5, + failed_damping = -4, + failed_factorization = -3, + failed_convergence = -2, + failed = -1, + not_run = 0, + success = 1 +}; + +/** Context for which the sensitivity flag should be computed */ +enum class SteadyStateContext { + newtonSensi = 0, + sensiStorage = 1, + solverCreation = 2 }; /** Damping factor flag for the Newton method */ @@ -156,6 +161,19 @@ enum class NewtonDampingFactorMode { on = 1 }; +/** fixedParameter to be used in condition context */ +enum class FixedParameterContext { + simulation = 0, + preequilibration = 1, + presimulation = 2, +}; + +enum class RDataReporting { + full, + residuals, + likelihood, +}; + /** * Type for function to process warnings or error messages. */ diff --git a/deps/AMICI/include/amici/edata.h b/deps/AMICI/include/amici/edata.h index 5bdeb68d8..ba2d1dc9b 100644 --- a/deps/AMICI/include/amici/edata.h +++ b/deps/AMICI/include/amici/edata.h @@ -3,6 +3,7 @@ #include "amici/defines.h" #include "amici/vector.h" +#include "amici/misc.h" #include @@ -520,7 +521,7 @@ void checkSigmaPositivity(realtype sigma, const char *sigmaName); * @brief The ConditionContext class applies condition-specific amici::Model * settings and restores them when going out of scope */ -class ConditionContext { +class ConditionContext : public ContextManager { public: /** * @brief Apply condition-specific settings from edata to model while @@ -528,8 +529,13 @@ class ConditionContext { * * @param model * @param edata + * @param fpc flag indicating which fixedParmeter from edata to apply */ - explicit ConditionContext(Model *model, const ExpData *edata = nullptr); + explicit ConditionContext( + Model *model, const ExpData *edata = nullptr, + FixedParameterContext fpc = FixedParameterContext::simulation); + + ConditionContext &operator=(const ConditionContext &other) = delete; ~ConditionContext(); @@ -539,8 +545,10 @@ class ConditionContext { * backed-up in the constructor call. * * @param edata + * @param fpc flag indicating which fixedParmeter from edata to apply */ - void applyCondition(const ExpData *edata); + void applyCondition(const ExpData *edata, + FixedParameterContext fpc); /** * @brief Restore original settings on constructor-supplied amici::Model. diff --git a/deps/AMICI/include/amici/exception.h b/deps/AMICI/include/amici/exception.h index 541730469..3e1c9bb80 100644 --- a/deps/AMICI/include/amici/exception.h +++ b/deps/AMICI/include/amici/exception.h @@ -4,6 +4,7 @@ #include "amici/defines.h" // necessary for realtype #include +#include namespace amici { @@ -19,13 +20,13 @@ class AmiException : public std::exception { * @param fmt error message with printf format * @param ... printf formating variables */ - AmiException(char const* fmt, ...); + explicit AmiException(char const* fmt, ...); /** - * @brief Copy constructor - * @param old object to copy from + * @brief Move constructor + * @param old object to move from */ - AmiException(const AmiException& old); + AmiException(AmiException&& old) noexcept; /** * @brief Override of default error message function @@ -46,8 +47,8 @@ class AmiException : public std::exception { void storeBacktrace(int nMaxFrames); private: - char msg[500]{}; - char trace[500]{}; + std::array msg; + std::array trace; }; diff --git a/deps/AMICI/include/amici/forwardproblem.h b/deps/AMICI/include/amici/forwardproblem.h index 123514140..f08c721b1 100644 --- a/deps/AMICI/include/amici/forwardproblem.h +++ b/deps/AMICI/include/amici/forwardproblem.h @@ -3,6 +3,8 @@ #include "amici/defines.h" #include "amici/vector.h" +#include "amici/model.h" +#include "amici/misc.h" #include "amici/sundials_matrix_wrapper.h" #include @@ -11,10 +13,28 @@ namespace amici { -class ReturnData; class ExpData; class Solver; -class Model; +class SteadystateProblem; +class FinalStateStorer; + +/** + * @brief implements an exchange format to store and transfer the state of a simulation at a + * specific timepoint. + */ +struct SimulationState{ + /** timepoint */ + realtype t; + /** state variables */ + AmiVector x; + /** state variables */ + AmiVector dx; + /** state variable sensitivity */ + AmiVectorArray sx; + /** state of the model that was used for simulation */ + ModelState state; +}; + /** * @brief The ForwardProblem class groups all functions for solving the @@ -23,17 +43,21 @@ class Model; class ForwardProblem { public: /** - * @brief Constructor - * @param rdata pointer to ReturnData instance - * @param edata pointer to ExpData instance - * @param model pointer to Model instance - * @param solver pointer to Solver instance - */ - ForwardProblem(ReturnData *rdata, const ExpData *edata, - Model *model, Solver *solver); + * @brief Constructor + * @param edata pointer to ExpData instance + * @param model pointer to Model instance + * @param solver pointer to Solver instance + * @param preeq preequilibration with which to initialize the forward problem, + * pass nullptr for no initialization + */ + ForwardProblem(const ExpData *edata, Model *model, Solver *solver, + const SteadystateProblem *preeq); ~ForwardProblem() = default; + /** allow FinalStateStorer to access private members and functions */ + friend FinalStateStorer; + /** * @brief Solve the forward problem. * @@ -41,6 +65,13 @@ class ForwardProblem { */ void workForwardProblem(); + /** + * @brief computes adjoint updates dJydx according to provided model and expdata + * @param model Model instance + * @param edata experimental data + */ + void getAdjointUpdates(Model &model, const ExpData &edata); + /** * @brief Accessor for t * @return t @@ -49,6 +80,22 @@ class ForwardProblem { return t; } + /** + * @brief Accessor for x + * @return x + */ + AmiVector const& getState() const { + return x; + } + + /** + * @brief Accessor for dx + * @return dx + */ + AmiVector const& getStateDerivative() const { + return dx; + } + /** * @brief Accessor for sx * @return sx @@ -61,7 +108,7 @@ class ForwardProblem { * @brief Accessor for x_disc * @return x_disc */ - AmiVectorArray const& getStatesAtDiscontinuities() const { + std::vector const& getStatesAtDiscontinuities() const { return x_disc; } @@ -69,7 +116,7 @@ class ForwardProblem { * @brief Accessor for xdot_disc * @return xdot_disc */ - AmiVectorArray const& getRHSAtDiscontinuities() const { + std::vector const& getRHSAtDiscontinuities() const { return xdot_disc; } @@ -77,7 +124,7 @@ class ForwardProblem { * @brief Accessor for xdot_old_disc * @return xdot_old_disc */ - AmiVectorArray const& getRHSBeforeDiscontinuities() const { + std::vector const& getRHSBeforeDiscontinuities() const { return xdot_old_disc; } @@ -101,7 +148,7 @@ class ForwardProblem { * @brief Accessor for rootidx * @return rootidx */ - std::vector const& getRootIndexes() const { + std::vector> const& getRootIndexes() const { return rootidx; } @@ -121,14 +168,6 @@ class ForwardProblem { return dJzdx; } - /** - * @brief Accessor for iroot - * @return iroot - */ - int getRootCounter() const { - return iroot; - } - /** * @brief Accessor for pointer to x * @return &x @@ -161,25 +200,87 @@ class ForwardProblem { return &sdx; } + /** + * @brief Accessor for it + * @return it + */ + int getCurrentTimeIteration() const { + return it; + } + + /** + * @brief Returns final time point for which simulations are available + * @return time point + */ + realtype getFinalTime() const { + return final_state.t; + } + + /** + * @brief Returns maximal event index for which simulations are available + * @return index + */ + int getEventCounter() const { + return static_cast(event_states.size() - 1); + } + + /** + * @brief Returns maximal event index for which the timepoint is available + * @return index + */ + int getRootCounter() const { + return static_cast(discs.size() - 1); + } + + /** + * @brief Retrieves the carbon copy of the simulation state variables at + * the specified timepoint index + * @param it timpoint index + * @return state + */ + const SimulationState &getSimulationStateTimepoint(int it) const { + if (model->getTimepoint(it) == initial_state.t) + return getInitialSimulationState(); + return timepoint_states.find(model->getTimepoint(it))->second; + }; + + /** + * @brief Retrieves the carbon copy of the simulation state variables at + * the specified event index + * @param iroot event index + * @return SimulationState + */ + const SimulationState &getSimulationStateEvent(int iroot) const { + return event_states.at(iroot); + }; + + /** + * @brief Retrieves the carbon copy of the simulation state variables at the + * initial timepoint + * @return SimulationState + */ + const SimulationState &getInitialSimulationState() const { + return initial_state; + }; + + /** + * @brief Retrieves the carbon copy of the simulation state variables at the + * final timepoint (or when simulation failed) + * @return SimulationState + */ + const SimulationState &getFinalSimulationState() const { + return final_state; + }; + /** pointer to model instance */ Model *model; - /** pointer to return data instance */ - ReturnData *rdata; - /** pointer to solver instance */ Solver *solver; /** pointer to experimental data instance */ const ExpData *edata; - private: - /** - * @brief Perform preequilibration - */ - void handlePreequilibration(); - - void updateAndReinitStatesAndSensitivities(bool isSteadystate); void handlePresimulation(); @@ -191,23 +292,10 @@ class ForwardProblem { void handleEvent(realtype *tlastroot,bool seflag); - /** - * @brief Evaluates the Jacobian and differential equation right hand side, - * stores it in RetunData - */ - void storeJacobianAndDerivativeInReturnData(); - /** * @brief Extract output information for events */ - void getEventOutput(); - - /** - * @brief Extracts event information for forward sensitivity analysis - * - * @param ie index of event type - */ - void getEventSensisFSA(int ie); + void storeEvent(); /** * @brief Execute everything necessary for the handling of data points @@ -217,34 +305,51 @@ class ForwardProblem { void handleDataPoint(int it); /** - * @brief Extracts output information for data-points + * @brief Applies the event bolus to the current state * - * @param it index of current timepoint + * @param model pointer to model specification object */ - void getDataOutput(int it); + void applyEventBolus(); /** - * @brief Extracts data information for forward sensitivity analysis + * @brief Applies the event bolus to the current sensitivities + */ + void applyEventSensiBolusFSA(); + + /** + * @brief checks whether there are any events to fill * - * @param it index of current timepoint + * @param nmaxevent maximal number of events */ - void getDataSensisFSA(int it); + bool checkEventsToFill(int nmaxevent) const { + return std::any_of(nroots.cbegin(), nroots.cend(), + [nmaxevent](int curNRoots) { + return curNRoots < nmaxevent; + }); + }; /** - * @brief Applies the event bolus to the current state + * @brief fills events at final timepoint if necessary * - * @param model pointer to model specification object + * @param nmaxevent maximal number of events */ - void applyEventBolus(); + void fillEvents(int nmaxevent) { + if (checkEventsToFill(nmaxevent)) { + discs.push_back(t); + storeEvent(); + } + } /** - * @brief Applies the event bolus to the current sensitivities + * @brief Creates a carbon copy of the current simulation state variables + * @return state */ - void applyEventSensiBolusFSA(); + SimulationState getSimulationState() const; - /** array of index which root has been found - * (dimension: ne * ne * nmaxevent, ordering = ?) */ - std::vector rootidx; + /** array of index vectors (dimension ne) indicating whether the respective + * root has been detected for all so far encountered discontinuities, + * extended as needed (dimension: dynamic) */ + std::vector> rootidx; /** array of number of found roots for a certain event type * (dimension: ne) */ @@ -265,21 +370,17 @@ class ForwardProblem { * (dimension: nmaxevent x ne, ordering = ?) */ std::vector irdiscs; - /** current root index, will be increased during the forward solve and - * decreased during backward solve */ - int iroot = 0; + /** array of state vectors (dimension nx) for all so far encountered + * discontinuities, extended as needed (dimension dynamic) */ + std::vector x_disc; - /** array of state vectors at discontinuities - * (dimension nx x nMaxEvent * ne, ordering =?) */ - AmiVectorArray x_disc; + /** array of differential state vectors (dimension nx) for all so far + * encountered discontinuities, extended as needed (dimension dynamic) */ + std::vector xdot_disc; - /** array of differential state vectors at discontinuities - * (dimension nx x nMaxEvent * ne, ordering =?) */ - AmiVectorArray xdot_disc; - - /** array of old differential state vectors at discontinuities - * (dimension nx x nMaxEvent * ne, ordering =?) */ - AmiVectorArray xdot_old_disc; + /** array of old differential state vectors (dimension nx) for all so far + * encountered discontinuities, extended as needed (dimension dynamic) */ + std::vector xdot_old_disc; /** state derivative of data likelihood * (dimension nJ x nx x nt, ordering =?) */ @@ -300,17 +401,21 @@ class ForwardProblem { */ std::vector rootsfound; - /** temporary storage of Jacobian, kept here to avoid reallocation - * (dimension: nx x nx, col-major) */ - SUNMatrixWrapper Jtmp; + /** simulation states history at timepoints */ + std::map timepoint_states; + + /** simulation state history at events*/ + std::vector event_states; + + /** simulation state after initialization*/ + SimulationState initial_state; + + /** simulation state after simulation*/ + SimulationState final_state; /** state vector (dimension: nx_solver) */ AmiVector x; - /** state vector, including states eliminated from conservation laws - * (dimension: nx) */ - AmiVector x_rdata; - /** old state vector (dimension: nx_solver) */ AmiVector x_old; @@ -329,22 +434,48 @@ class ForwardProblem { /** sensitivity state vector array (dimension: nx_cl x nplist, row-major) */ AmiVectorArray sx; - /** full sensitivity state vector array, including states eliminated from - * conservation laws (dimension: nx x nplist, row-major) */ - AmiVectorArray sx_rdata; - /** differential sensitivity state vector array * (dimension: nx_cl x nplist, row-major) */ AmiVectorArray sdx; - + /** sensitivity of the event timepoint (dimension: nplist) */ std::vector stau; /** storage for last found root */ realtype tlastroot = 0.0; + /** flag to indicate wheter solver was preeinitialized via preequilibration */ + bool preequilibrated = false; + + /** current iteration number for time index */ + int it; + }; +/** + * @brief stores the stimulation state when it goes out of scope + */ +class FinalStateStorer : public ContextManager { + public: + /** + * @brief constructor, attaches problem pointer + * @param fwd problem from which the simulation state is to be stored + */ + explicit FinalStateStorer(ForwardProblem *fwd) : fwd(fwd) { + } + + FinalStateStorer &operator=(const FinalStateStorer &other) = delete; + + /** + * @brief destructor, stores simulation state + */ + ~FinalStateStorer() { + if(fwd) + fwd->final_state = fwd->getSimulationState(); + } + private: + ForwardProblem *fwd; +}; } // namespace amici diff --git a/deps/AMICI/include/amici/hdf5.h b/deps/AMICI/include/amici/hdf5.h index 9136ed823..d326a2bcd 100644 --- a/deps/AMICI/include/amici/hdf5.h +++ b/deps/AMICI/include/amici/hdf5.h @@ -9,7 +9,6 @@ #include -#undef AMI_HDF5_H_DEBUG /* Macros for enabling/disabling HDF5 error auto-printing * AMICI_H5_SAVE_ERROR_HANDLER and AMICI_H5_RESTORE_ERROR_HANDLER must be called diff --git a/deps/AMICI/include/amici/interface_matlab.h b/deps/AMICI/include/amici/interface_matlab.h index edb6b7825..cea3d3a1f 100644 --- a/deps/AMICI/include/amici/interface_matlab.h +++ b/deps/AMICI/include/amici/interface_matlab.h @@ -6,11 +6,14 @@ #include #include -class Model; -extern std::unique_ptr getModel(); -namespace amici { +namespace amici { + +namespace generic_model { +extern std::unique_ptr getModel(); +} // namespace generic_model +class Model; class ReturnDataMatlab; @@ -39,7 +42,7 @@ void setSolverOptions(const mxArray *prhs[], int nrhs, Solver& solver); */ ReturnDataMatlab *setupReturnData(mxArray *plhs[], int nlhs); - + /*! * @brief expDataFromMatlabCall parses the experimental data from the matlab * call and writes it to an ExpData class object diff --git a/deps/AMICI/include/amici/misc.h b/deps/AMICI/include/amici/misc.h index b13534ad4..06862e9c8 100644 --- a/deps/AMICI/include/amici/misc.h +++ b/deps/AMICI/include/amici/misc.h @@ -2,6 +2,8 @@ #define AMICI_MISC_H #include "amici/defines.h" +#include "amici/exception.h" +#include "amici/vector.h" #include // SUNMatrixContent_Sparse #include @@ -22,9 +24,91 @@ namespace amici { * @return span of the slice */ - gsl::span slice(std::vector &data, int index, - unsigned size); +template +gsl::span slice(std::vector &data, int index, unsigned size) { + if ((index + 1) * size > data.size()) + throw std::out_of_range("requested slice is out of data range"); + if (size > 0) + return gsl::make_span(&data.at(index*size), size); + return gsl::make_span(static_cast(nullptr), 0); +} + +/** + * @brief creates a constant slice from existing constant data + * + * @param data to be sliced + * @param index slice index + * @param size slice size + * @return span of the slice + */ + +template +const gsl::span slice(const std::vector &data, + int index, unsigned size) { + if ((index + 1) * size > data.size()) + throw std::out_of_range("requested slice is out of data range"); + if (size > 0) + return gsl::make_span(&data.at(index*size), size); + + return gsl::make_span(static_cast(nullptr), 0); +} + +/** + * @brief local helper to check whether the provided buffer has the expected + * size + * @param buffer buffer to which values are to be written + * @param expected_size expected size of the buffer + */ +template +void checkBufferSize(gsl::span buffer, + typename gsl::span::index_type expected_size) { + if (buffer.size() != expected_size) + throw AmiException("Incorrect buffer size! Was %u, expected %u.", + buffer.size(), expected_size); +} + +/* TODO: templating writeSlice breaks implicit conversion between vector & span + not sure whether this is fixable */ + +/** + * @brief local helper function to write computed slice to provided buffer (span) + * @param slice computed value + * @param buffer buffer to which values are to be written + */ +template +void writeSlice(const gsl::span slice, gsl::span buffer) { + checkBufferSize(buffer, slice.size()); + std::copy(slice.begin(), slice.end(), buffer.data()); +}; + +/** + * @brief local helper function to write computed slice to provided buffer (vector) + * @param slice computed value + * @param buffer buffer to which values are to be written + */ +template +void writeSlice(const std::vector &s, std::vector &b) { + writeSlice(gsl::make_span(s.data(), s.size()), + gsl::make_span(b.data(), b.size())); +}; + +/** + * @brief local helper function to write computed slice to provided buffer (vector/span) + * @param slice computed value + * @param buffer buffer to which values are to be written + */ +template +void writeSlice(const std::vector &s, gsl::span b) { + writeSlice(gsl::make_span(s.data(), s.size()), b); +}; + +/** + * @brief local helper function to write computed slice to provided buffer (AmiVector/span) + * @param slice computed value + * @param buffer buffer to which values are to be written + */ +void writeSlice(const AmiVector &s, gsl::span b); /** @@ -92,6 +176,16 @@ std::string regexErrorToString(std::regex_constants::error_type err_type); */ std::string printfToString(const char *fmt, va_list ap); +/** + * @brief Generic implementation for a context manager, explicitely deletes copy and move operators for + * derived classes + */ +class ContextManager{ + public: + ContextManager() = default; + ContextManager(ContextManager &other) = delete; + ContextManager(ContextManager &&other) = delete; +}; } // namespace amici diff --git a/deps/AMICI/include/amici/model.h b/deps/AMICI/include/amici/model.h index 715652f3d..05e8b430d 100644 --- a/deps/AMICI/include/amici/model.h +++ b/deps/AMICI/include/amici/model.h @@ -32,13 +32,45 @@ void serialize(Archive &ar, amici::Model &u, unsigned int version); namespace amici { /** - * @brief The Model class represents an AMICI ODE model. The model can compute + * @brief implements an exchange format to store and transfer the state of the model at a + * specific timepoint. This is designed to only encompass the minimal number of attributes that need to be + * transferred. + */ +struct ModelState { + /** flag indicating whether a certain heaviside function should be active or + not (dimension: ne) */ + std::vector h; + + /** total abundances for conservation laws + (dimension: nx_rdata-nx_solver) */ + std::vector total_cl; + + /** sensitivities of total abundances for conservation laws + (dimension: (nx_rdata-nx_solver) x np, row-major) */ + std::vector stotal_cl; + + /** unscaled parameters (dimension: np) */ + std::vector unscaledParameters; + + /** constants (dimension: nk) */ + std::vector fixedParameters; + + /** indexes of parameters wrt to which sensitivities are computed + * (dimension: nplist) + */ + std::vector plist; +}; + + + +/** + * @brief The Model class represents an AMICI ODE/DAE model. The model can compute * various model related quantities based on symbolically generated code. */ class Model : public AbstractModel { public: /** default constructor */ - Model(); + Model() = default; /** * @brief Constructor with model dimensions @@ -47,6 +79,8 @@ class Model : public AbstractModel { * @param nx_solver number of state variables with conservation laws applied * @param nxtrue_solver number of state variables of the non-augmented model * with conservation laws applied + * @param nx_solver_reinit number of state variables with conservation laws + * subject to reinitialization * @param ny number of observables * @param nytrue number of observables of the non-augmented model * @param nz number of event observables @@ -75,9 +109,10 @@ class Model : public AbstractModel { * @param ndxdotdp_implicit number of nonzero elements dxdotdp_implicit */ Model(int nx_rdata, int nxtrue_rdata, int nx_solver, int nxtrue_solver, - int ny, int nytrue, int nz, int nztrue, int ne, int nJ, int nw, - int ndwdx, int ndwdp, int ndxdotdw, std::vector ndJydy, int nnz, - int ubw, int lbw, amici::SecondOrderMode o2mode, + int nx_solver_reinit, int ny, int nytrue, int nz, int nztrue, int ne, + int nJ, int nw, int ndwdx, int ndwdp, int ndxdotdw, + std::vector ndJydy, int nnz, int ubw, int lbw, + amici::SecondOrderMode o2mode, const std::vector &p, std::vector k, const std::vector &plist, std::vector idlist, std::vector z2event, bool pythonGenerated = false, @@ -176,8 +211,10 @@ class Model : public AbstractModel { * @param xB adjoint state variables * @param dxB time derivative of adjoint states (DAE only) * @param xQB adjoint quadratures + * @param posteq flag indicating whether postequilibration was performed */ - void initializeB(AmiVector &xB, AmiVector &dxB, AmiVector &xQB); + void initializeB(AmiVector &xB, AmiVector &dxB, AmiVector &xQB, + bool posteq) const; /** * @brief Initialization of initial states @@ -224,6 +261,12 @@ class Model : public AbstractModel { */ int ncl() const; + /** + * @brief Number of solver states subject to reinitialization + * @return model member nx_solver_reinit + */ + int nx_reinit() const; + /** * @brief Fixed parameters * @return pointer to constants array @@ -577,6 +620,32 @@ class Model : public AbstractModel { */ void setAllStatesNonNegative(); + /** + * @brief retrieves the current model state + * @return current model state + */ + ModelState const &getModelState() const { + return state; + }; + + /** + * @brief sets the current model state + * @param state model state + */ + void setModelState(ModelState const &state) { + if (static_cast(state.unscaledParameters.size()) != np()) + throw AmiException("Mismatch in parameter size"); + if (static_cast(state.fixedParameters.size()) != nk()) + throw AmiException("Mismatch in fixed parameter size"); + if (static_cast(state.h.size()) != ne) + throw AmiException("Mismatch in heaviside size"); + if (static_cast(state.total_cl.size()) != ncl()) + throw AmiException("Mismatch in conservation law size"); + if (static_cast(state.stotal_cl.size()) != ncl() * np() ) + throw AmiException("Mismatch in conservation law sensitivity size"); + this->state = state; + }; + /** * @brief Get the list of parameters for which sensitivities are computed * @return list of parameter indices @@ -1117,6 +1186,9 @@ class Model : public AbstractModel { */ int nxtrue_solver{0}; + /** number of solver states subject to reinitialization */ + int nx_solver_reinit{0}; + /** number of observables */ int ny{0}; @@ -1192,7 +1264,7 @@ class Model : public AbstractModel { * temporary storage of dxdotdp data across functions, Matlab only * (dimension: nplist x nx_solver, row-major) */ - AmiVectorArray dxdotdp; + AmiVectorArray dxdotdp {0, 0}; /** AMICI context */ AmiciApplication *app = &defaultContext; @@ -1233,8 +1305,8 @@ class Model : public AbstractModel { * @param sllh first order buffer * @param s2llh second order buffer */ - void checkLLHBufferSize(std::vector &sllh, - std::vector &s2llh); + void checkLLHBufferSize(const std::vector &sllh, + const std::vector &s2llh) const; /** * @brief Set the nplist-dependent vectors to their proper sizes @@ -1590,6 +1662,9 @@ class Model : public AbstractModel { */ N_Vector computeX_pos(const_N_Vector x); + /** all variables necessary for function evaluation */ + ModelState state; + /** Sparse Jacobian (dimension: nnz)*/ mutable SUNMatrixWrapper J; @@ -1750,40 +1825,17 @@ class Model : public AbstractModel { */ mutable std::vector deltaqB; - /** flag indicating whether a certain heaviside function should be active or - not (dimension: ne) */ - mutable std::vector h; - - /** total abundances for conservation laws - (dimension: nx_rdata-nx_solver) */ - mutable std::vector total_cl; - - /** sensitivities of total abundances for conservation laws - (dimension: (nx_rdata-nx_solver) x np, row-major) */ - mutable std::vector stotal_cl; - /** temporary storage of positified state variables according to * stateIsNonNegative (dimension: nx_solver) */ - mutable AmiVector x_pos_tmp; - - /** unscaled parameters (dimension: np) */ - std::vector unscaledParameters; + mutable AmiVector x_pos_tmp {0}; /** orignal user-provided, possibly scaled parameter array (dimension: np) */ std::vector originalParameters; - /** constants (dimension: nk) */ - std::vector fixedParameters; - /** index indicating to which event an event output belongs */ std::vector z2event; - /** indexes of parameters wrt to which sensitivities are computed - * (dimension: nplist) - */ - std::vector plist_; - /** state initialisation (size nx_solver) */ std::vector x0data; diff --git a/deps/AMICI/include/amici/model_dae.h b/deps/AMICI/include/amici/model_dae.h index c0be1e2ea..7446765c4 100644 --- a/deps/AMICI/include/amici/model_dae.h +++ b/deps/AMICI/include/amici/model_dae.h @@ -36,6 +36,8 @@ class Model_DAE : public Model { * @param nx_solver number of state variables with conservation laws applied * @param nxtrue_solver number of state variables of the non-augmented model with conservation laws applied + * @param nx_solver_reinit number of state variables with conservation laws + * subject to reinitialization * @param ny number of observables * @param nytrue number of observables of the non-augmented model * @param nz number of event observables @@ -63,7 +65,7 @@ class Model_DAE : public Model { * @param ndxdotdp_implicit number of nonzero elements dxdotdp_implicit */ Model_DAE(const int nx_rdata, const int nxtrue_rdata, const int nx_solver, - const int nxtrue_solver, const int ny, const int nytrue, + const int nxtrue_solver, const int nx_solver_reinit, const int ny, const int nytrue, const int nz, const int nztrue, const int ne, const int nJ, const int nw, const int ndwdx, const int ndwdp, const int ndxdotdw, std::vector ndJydy, const int nnz, const int ubw, @@ -72,10 +74,12 @@ class Model_DAE : public Model { std::vector const &plist, std::vector const &idlist, std::vector const &z2event, const bool pythonGenerated=false, const int ndxdotdp_explicit=0, const int ndxdotdp_implicit=0) - : Model(nx_rdata, nxtrue_rdata, nx_solver, nxtrue_solver, ny, nytrue, + : Model(nx_rdata, nxtrue_rdata, nx_solver, nxtrue_solver, nx_solver_reinit, ny, nytrue, nz, nztrue, ne, nJ, nw, ndwdx, ndwdp, ndxdotdw, std::move(ndJydy), nnz, ubw, lbw, o2mode, p, k, plist, idlist, z2event, - pythonGenerated, ndxdotdp_explicit, ndxdotdp_implicit) {} + pythonGenerated, ndxdotdp_explicit, ndxdotdp_implicit) { + M = SUNMatrixWrapper(nx_solver, nx_solver); + } void fJ(realtype t, realtype cj, const AmiVector &x, const AmiVector &dx, const AmiVector &xdot, SUNMatrix J) override; @@ -92,6 +96,10 @@ class Model_DAE : public Model { void fJ(realtype t, realtype cj, N_Vector x, N_Vector dx, N_Vector xdot, SUNMatrix J); + void fJB(const realtype t, realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xB, const AmiVector &dxB, + const AmiVector &xBdot, SUNMatrix JB) override; + /** * @brief Jacobian of xBdot with respect to adjoint state xB * @param t timepoint @@ -102,7 +110,6 @@ class Model_DAE : public Model { * @param dxB Vector with the adjoint derivative states * @param JB Matrix to which the Jacobian will be written **/ - void fJB(realtype t, realtype cj, N_Vector x, N_Vector dx, N_Vector xB, N_Vector dxB, SUNMatrix JB); @@ -121,7 +128,13 @@ class Model_DAE : public Model { void fJSparse(realtype t, realtype cj, N_Vector x, N_Vector dx, SUNMatrix J); - /** JB in sparse form (for sparse solvers from the SuiteSparse Package) + void fJSparseB(const realtype t, realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xB, + const AmiVector &dxB, const AmiVector &xBdot, + SUNMatrix JB) override; + + /** + * @brief JB in sparse form (for sparse solvers from the SuiteSparse Package) * @param t timepoint * @param cj scalar in Jacobian * @param x Vector with the states @@ -133,7 +146,8 @@ class Model_DAE : public Model { void fJSparseB(realtype t, realtype cj, N_Vector x, N_Vector dx, N_Vector xB, N_Vector dxB, SUNMatrix JB); - /** diagonalized Jacobian (for preconditioning) + /** + * @brief Diagonal of the Jacobian (for preconditioning) * @param t timepoint * @param JDiag Vector to which the Jacobian diagonal will be written * @param cj scaling factor, inverse of the step size @@ -148,7 +162,8 @@ class Model_DAE : public Model { const AmiVector &xdot, const AmiVector &v, AmiVector &nJv, realtype cj) override; - /** Matrix vector product of J with a vector v (for iterative solvers) + /** + * @brief Matrix vector product of J with a vector v (for iterative solvers) * @param t timepoint * @param cj scaling factor, inverse of the step size * @param x Vector with the states @@ -160,7 +175,8 @@ class Model_DAE : public Model { void fJv(realtype t, N_Vector x, N_Vector dx, N_Vector v, N_Vector Jv, realtype cj); - /** Matrix vector product of JB with a vector v (for iterative solvers) + /** + * @brief Matrix vector product of JB with a vector v (for iterative solvers) * @param t timepoint * @param x Vector with the states * @param dx Vector with the derivative states @@ -178,7 +194,8 @@ class Model_DAE : public Model { void froot(realtype t, const AmiVector &x, const AmiVector &dx, gsl::span root) override; - /** Event trigger function for events + /** + * @brief Event trigger function for events * @param t timepoint * @param x Vector with the states * @param dx Vector with the derivative states @@ -198,7 +215,8 @@ class Model_DAE : public Model { */ void fxdot(realtype t, N_Vector x, N_Vector dx, N_Vector xdot); - /** Right hand side of differential equation for adjoint state xB + /** + * @brief Right hand side of differential equation for adjoint state xB * @param t timepoint * @param x Vector with the states * @param dx Vector with the derivative states @@ -209,7 +227,8 @@ class Model_DAE : public Model { void fxBdot(realtype t, N_Vector x, N_Vector dx, N_Vector xB, N_Vector dxB, N_Vector xBdot); - /** Right hand side of integral equation for quadrature states qB + /** + * @brief Right hand side of integral equation for quadrature states qB * @param t timepoint * @param x Vector with the states * @param dx Vector with the derivative states @@ -220,7 +239,51 @@ class Model_DAE : public Model { void fqBdot(realtype t, N_Vector x, N_Vector dx, N_Vector xB, N_Vector dxB, N_Vector qBdot); - /** Sensitivity of dx/dt wrt model parameters p + void fxBdot_ss(const realtype t, const AmiVector &xB, + const AmiVector &dxB, AmiVector &xBdot) override; + + /** + * @brief Implementation of fxBdot for steady state case at the N_Vector level + * @param t timepoint + * @param xB Vector with the adjoint state + * @param dxB Vector with the adjoint derivative states + * @param xBdot Vector with the adjoint right hand side + */ + void fxBdot_ss(realtype t, N_Vector xB, N_Vector dxB, N_Vector xBdot) const; + + /** + * @brief Implementation of fqBdot for steady state at the N_Vector level + * @param t timepoint + * @param xB Vector with the adjoint states + * @param dxB Vector with the adjoint derivative states + * @param qBdot Vector with the adjoint quadrature right hand side + */ + void fqBdot_ss(realtype t, N_Vector xB, N_Vector dxB, N_Vector qBdot) const; + + /** + * @brief Sparse Jacobian function backward, steady state case + * @param JB sparse matrix to which values of the Jacobian will be written + */ + void fJSparseB_ss(SUNMatrix JB) override; + + /** + * @brief Computes the sparse backward Jacobian for steadystate integration + * and writes it to the model member + * @param t timepoint + * @param cj scalar in Jacobian + * @param x Vector with the states + * @param dx Vector with the derivative states + * @param xB Vector with the adjoint states + * @param dxB Vector with the adjoint derivative states + * @param xBdot Vector with the adjoint state right hand side + */ + void writeSteadystateJB(const realtype t, realtype cj, + const AmiVector &x, const AmiVector &dx, + const AmiVector &xB, const AmiVector &dxB, + const AmiVector &xBdot) override; + + /** + * @brief Sensitivity of dx/dt wrt model parameters p * @param t timepoint * @param x Vector with the states * @param dx Vector with the derivative states @@ -234,7 +297,8 @@ class Model_DAE : public Model { void fsxdot(realtype t, const AmiVector &x, const AmiVector &dx, int ip, const AmiVector &sx, const AmiVector &sdx, AmiVector &sxdot) override; - /** Right hand side of differential equation for state sensitivities sx + /** + * @brief Right hand side of differential equation for state sensitivities sx * @param t timepoint * @param x Vector with the states * @param dx Vector with the derivative states @@ -275,7 +339,7 @@ class Model_DAE : public Model { const realtype *dwdx) = 0; /** - * @brief model specific implementation for fJB + * @brief Model specific implementation for fJB * @param JB Matrix to which the Jacobian will be written * @param t timepoint * @param x Vector with the states @@ -296,7 +360,7 @@ class Model_DAE : public Model { const realtype *dwdx); /** - * @brief model specific implementation for fJSparse + * @brief Model specific implementation for fJSparse * @param JSparse Matrix to which the Jacobian will be written * @param t timepoint * @param x Vector with the states @@ -354,7 +418,7 @@ class Model_DAE : public Model { const realtype *dwdx); /** - * Model specific implementation for fJvB + * @brief Model specific implementation for fJvB * @param JvB Matrix vector product of JB with a vector v * @param t timepoint * @param x Vector with the states @@ -405,7 +469,7 @@ class Model_DAE : public Model { const realtype *dx, const realtype *w) = 0; /** - * @brief model specific implementation of fdxdotdp + * @brief Model specific implementation of fdxdotdp * @param dxdotdp partial derivative xdot wrt p * @param t timepoint * @param x Vector with the states @@ -423,7 +487,7 @@ class Model_DAE : public Model { const realtype *w, const realtype *dwdp); /** - * @brief model specific implementation of fM + * @brief Model specific implementation of fM * @param M mass matrix * @param t timepoint * @param x Vector with the states diff --git a/deps/AMICI/include/amici/model_ode.h b/deps/AMICI/include/amici/model_ode.h index c18db306f..038e5967d 100644 --- a/deps/AMICI/include/amici/model_ode.h +++ b/deps/AMICI/include/amici/model_ode.h @@ -36,6 +36,8 @@ class Model_ODE : public Model { * @param nx_solver number of state variables with conservation laws applied * @param nxtrue_solver number of state variables of the non-augmented model with conservation laws applied + * @param nx_solver_reinit number of state variables with conservation laws + * subject to reinitialization * @param ny number of observables * @param nytrue number of observables of the non-augmented model * @param nz number of event observables @@ -63,7 +65,7 @@ class Model_ODE : public Model { * @param ndxdotdp_implicit number of nonzero elements dxdotdp_implicit */ Model_ODE(const int nx_rdata, const int nxtrue_rdata, const int nx_solver, - const int nxtrue_solver, const int ny, const int nytrue, + const int nxtrue_solver, const int nx_solver_reinit, const int ny, const int nytrue, const int nz, const int nztrue, const int ne, const int nJ, const int nw, const int ndwdx, const int ndwdp, const int ndxdotdw, std::vector ndJydy, @@ -73,7 +75,7 @@ class Model_ODE : public Model { std::vector const &idlist, std::vector const &z2event, const bool pythonGenerated=false, const int ndxdotdp_explicit=0, const int ndxdotdp_implicit=0) - : Model(nx_rdata, nxtrue_rdata, nx_solver, nxtrue_solver, ny, nytrue, + : Model(nx_rdata, nxtrue_rdata, nx_solver, nxtrue_solver, nx_solver_reinit, ny, nytrue, nz, nztrue, ne, nJ, nw, ndwdx, ndwdp, ndxdotdw, std::move(ndJydy), nnz, ubw, lbw, o2mode, p, k, plist, idlist, z2event, pythonGenerated, ndxdotdp_explicit, ndxdotdp_implicit) {} @@ -94,8 +96,13 @@ class Model_ODE : public Model { **/ void fJ(realtype t, N_Vector x, N_Vector xdot, SUNMatrix J); - /** implementation of fJB at the N_Vector level, this function provides an - *interface to the model specific routines for the solver implementation + void fJB(const realtype t, realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xB, const AmiVector &dxB, + const AmiVector &xBdot, SUNMatrix JB) override; + + /** + * @brief Implementation of fJB at the N_Vector level, this function provides + * an interface to the model specific routines for the solver implementation * @param t timepoint * @param x Vector with the states * @param xB Vector with the adjoint states @@ -109,17 +116,22 @@ class Model_ODE : public Model { SUNMatrix J) override; /** - * Implementation of fJSparse at the N_Vector level, this function - * provides - * an interface to the model specific routines for the solver implementation - * aswell as the AmiVector level implementation + * @brief Implementation of fJSparse at the N_Vector level, this function + * provides an interface to the model specific routines for the solver + * implementation aswell as the AmiVector level implementation * @param t timepoint * @param x Vector with the states * @param J Matrix to which the Jacobian will be written */ void fJSparse(realtype t, N_Vector x, SUNMatrix J); - /** implementation of fJSparseB at the N_Vector level, this function + void fJSparseB(const realtype t, realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xB, + const AmiVector &dxB, const AmiVector &xBdot, + SUNMatrix JB) override; + + /** + * @brief Implementation of fJSparseB at the N_Vector level, this function * provides an interface to the model specific routines for the solver * implementation * @param t timepoint @@ -131,8 +143,9 @@ class Model_ODE : public Model { void fJSparseB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, SUNMatrix JB); - /** implementation of fJDiag at the N_Vector level, this function provides - *an interface to the model specific routines for the solver implementation + /** + * @brief Implementation of fJDiag at the N_Vector level, this function provides + * an interface to the model specific routines for the solver implementation * @param t timepoint * @param JDiag Vector to which the Jacobian diagonal will be written * @param x Vector with the states @@ -140,7 +153,7 @@ class Model_ODE : public Model { void fJDiag(realtype t, N_Vector JDiag, N_Vector x); /** - * @brief diagonalized Jacobian (for preconditioning) + * @brief Diagonal of the Jacobian (for preconditioning) * @param t timepoint * @param JDiag Vector to which the Jacobian diagonal will be written * @param cj scaling factor, inverse of the step size @@ -154,7 +167,8 @@ class Model_ODE : public Model { const AmiVector &xdot, const AmiVector &v, AmiVector &nJv, realtype cj) override; - /** implementation of fJv at the N_Vector level. + /** + * @brief Implementation of fJv at the N_Vector level. * @param t timepoint * @param x Vector with the states * @param v Vector with which the Jacobian is multiplied @@ -164,7 +178,7 @@ class Model_ODE : public Model { void fJv(N_Vector v, N_Vector Jv, realtype t, N_Vector x); /** - * @brief implementation of fJvB at the N_Vector level + * @brief Implementation of fJvB at the N_Vector level * @param t timepoint * @param x Vector with the states * @param xB Vector with the adjoint states @@ -177,8 +191,7 @@ class Model_ODE : public Model { gsl::span root) override; /** - * @brief implementation of froot at the N_Vector level - * + * @brief Implementation of froot at the N_Vector level * This function provides an interface to the model specific routines for * the solver implementation aswell as the AmiVector level implementation * @param t timepoint @@ -190,16 +203,18 @@ class Model_ODE : public Model { void fxdot(realtype t, const AmiVector &x, const AmiVector &dx, AmiVector &xdot) override; - /** implementation of fxdot at the N_Vector level, this function provides an - * interface to the model specific routines for the solver implementation - * aswell as the AmiVector level implementation + /** + * @brief Implementation of fxdot at the N_Vector level, this function + * provides an interface to the model specific routines for the solver + * implementation aswell as the AmiVector level implementation * @param t timepoint * @param x Vector with the states * @param xdot Vector with the right hand side */ void fxdot(realtype t, N_Vector x, N_Vector xdot); - /** implementation of fxBdot at the N_Vector level + /** + * @brief Implementation of fxBdot at the N_Vector level * @param t timepoint * @param x Vector with the states * @param xB Vector with the adjoint states @@ -207,7 +222,8 @@ class Model_ODE : public Model { */ void fxBdot(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot); - /** implementation of fqBdot at the N_Vector level + /** + * @brief Implementation of fqBdot at the N_Vector level * @param t timepoint * @param x Vector with the states * @param xB Vector with the adjoint states @@ -215,17 +231,57 @@ class Model_ODE : public Model { */ void fqBdot(realtype t, N_Vector x, N_Vector xB, N_Vector qBdot); - /** Sensitivity of dx/dt wrt model parameters w + void fxBdot_ss(const realtype t, const AmiVector &xB, + const AmiVector & /*dxB*/, AmiVector &xBdot) override; + + /** + * @brief Implementation of fxBdot for steady state at the N_Vector level + * @param t timepoint + * @param xB Vector with the states + * @param xBdot Vector with the adjoint right hand side + */ + void fxBdot_ss(realtype t, N_Vector xB, N_Vector xBdot) const; + + /** + * @brief Implementation of fqBdot for steady state case at the N_Vector level + * @param t timepoint + * @param xB Vector with the adjoint states + * @param qBdot Vector with the adjoint quadrature right hand side + */ + void fqBdot_ss(realtype t, N_Vector xB, N_Vector qBdot) const; + + /** + * @brief Sparse Jacobian function backward, steady state case + * @param JB sparse matrix to which values of the Jacobian will be written + */ + void fJSparseB_ss(SUNMatrix JB) override; + + /** + * @brief Computes the sparse backward Jacobian for steadystate integration + * and writes it to the model member + * @param t timepoint + * @param cj scalar in Jacobian + * @param x Vector with the states + * @param dx Vector with the derivative states + * @param xB Vector with the adjoint states + * @param dxB Vector with the adjoint derivative states + * @param xBdot Vector with the adjoint state right hand side + */ + void writeSteadystateJB(const realtype t, realtype cj, + const AmiVector &x, const AmiVector &dx, + const AmiVector &xB, const AmiVector &dxB, + const AmiVector &xBdot) override; + + /** + * @brief Sensitivity of dx/dt wrt model parameters w * @param t timepoint * @param x Vector with the states - * @return status flag indicating successful execution */ void fdxdotdw(realtype t, const N_Vector x); /** Explicit sensitivity of dx/dt wrt model parameters p * @param t timepoint * @param x Vector with the states - * @return status flag indicating successful execution */ void fdxdotdp(realtype t, const N_Vector x); @@ -236,7 +292,7 @@ class Model_ODE : public Model { AmiVector &sxdot) override; /** - * @brief implementation of fsxdot at the N_Vector level + * @brief Implementation of fsxdot at the N_Vector level * @param t timepoint * @param x Vector with the states * @param ip parameter index @@ -248,7 +304,8 @@ class Model_ODE : public Model { std::unique_ptr getSolver() override; protected: - /** model specific implementation for fJ + /** + * @brief Model specific implementation for fJ * @param J Matrix to which the Jacobian will be written * @param t timepoint * @param x Vector with the states @@ -262,7 +319,8 @@ class Model_ODE : public Model { const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) = 0; - /** model specific implementation for fJB + /** + * @brief Model specific implementation for fJB * @param JB Matrix to which the Jacobian will be written * @param t timepoint * @param x Vector with the states @@ -278,7 +336,8 @@ class Model_ODE : public Model { const realtype *xB, const realtype *w, const realtype *dwdx); - /** model specific implementation for fJSparse + /** + * @brief Model specific implementation for fJSparse * @param JSparse Matrix to which the Jacobian will be written * @param t timepoint * @param x Vector with the states @@ -293,7 +352,8 @@ class Model_ODE : public Model { const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx); - /** model specific implementation for fJSparse, data only + /** + * @brief Model specific implementation for fJSparse, data only * @param JSparse Matrix to which the Jacobian will be written * @param t timepoint * @param x Vector with the states @@ -309,7 +369,7 @@ class Model_ODE : public Model { const realtype *dwdx); /** - * @brief model specific implementation for fJSparse, column pointers + * @brief Model specific implementation for fJSparse, column pointers * @param indexptrs column pointers **/ virtual void fJSparse_colptrs(sunindextype *indexptrs); @@ -338,7 +398,8 @@ class Model_ODE : public Model { const realtype *xB, const realtype *w, const realtype *dwdx); - /** model specific implementation for fJSparseB + /** + * @brief Model specific implementation for fJSparseB * @param JSparseB data array * @param t timepoint * @param x Vector with the states @@ -382,7 +443,7 @@ class Model_ODE : public Model { const realtype *w, const realtype *dwdx); /** - * @brief model specific implementation for froot + * @brief Model specific implementation for froot * @param root values of the trigger function * @param t timepoint * @param x Vector with the states @@ -393,7 +454,8 @@ class Model_ODE : public Model { virtual void froot(realtype *root, realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h); - /** model specific implementation for fxdot + /** + * @brief Model specific implementation for fxdot * @param xdot residual function * @param t timepoint * @param x Vector with the states @@ -406,7 +468,8 @@ class Model_ODE : public Model { const realtype *p, const realtype *k, const realtype *h, const realtype *w) = 0; - /** model specific implementation of fdxdotdp, with w chainrule (Matlab) + /** + * @brief Model specific implementation of fdxdotdp, with w chainrule (Matlab) * @param dxdotdp partial derivative xdot wrt p * @param t timepoint * @param x Vector with the states @@ -422,7 +485,8 @@ class Model_ODE : public Model { const realtype *h, int ip, const realtype *w, const realtype *dwdp); - /** model specific implementation of fdxdotdp_explicit, no w chainrule (Py) + /** + * @brief Model specific implementation of fdxdotdp_explicit, no w chainrule (Py) * @param dxdotdp_explicit partial derivative xdot wrt p * @param t timepoint * @param x Vector with the states @@ -436,27 +500,32 @@ class Model_ODE : public Model { const realtype *k, const realtype *h, const realtype *w); - /** model specific implementation of fdxdotdp_explicit, colptrs part + /** + * @brief Model specific implementation of fdxdotdp_explicit, colptrs part * @param indexptrs column pointers */ virtual void fdxdotdp_explicit_colptrs(sunindextype *indexptrs); - /** model specific implementation of fdxdotdp_explicit, rowvals part + /** + * @brief Model specific implementation of fdxdotdp_explicit, rowvals part * @param indexvals row values */ virtual void fdxdotdp_explicit_rowvals(sunindextype *indexvals); - /** model specific implementation of fdxdotdp_implicit, colptrs part + /** + * @brief Model specific implementation of fdxdotdp_implicit, colptrs part * @param indexptrs column pointers */ virtual void fdxdotdp_implicit_colptrs(sunindextype *indexptrs); - /** model specific implementation of fdxdotdp_implicit, rowvals part + /** + * @brief Model specific implementation of fdxdotdp_implicit, rowvals part * @param indexvals row values */ virtual void fdxdotdp_implicit_rowvals(sunindextype *indexvals); - /** model specific implementation of fdxdotdw, data part + /** + * @brief Model specific implementation of fdxdotdw, data part * @param dxdotdw partial derivative xdot wrt w * @param t timepoint * @param x Vector with the states @@ -469,12 +538,14 @@ class Model_ODE : public Model { const realtype *p, const realtype *k, const realtype *h, const realtype *w); - /** model specific implementation of fdxdotdw, colptrs part + /** + * @brief Model specific implementation of fdxdotdw, colptrs part * @param indexptrs column pointers */ virtual void fdxdotdw_colptrs(sunindextype *indexptrs); - /** model specific implementation of fdxdotdw, rowvals part + /** + * @brief Model specific implementation of fdxdotdw, rowvals part * @param indexvals row values */ virtual void fdxdotdw_rowvals(sunindextype *indexvals); diff --git a/deps/AMICI/include/amici/newton_solver.h b/deps/AMICI/include/amici/newton_solver.h index 5482e0a20..7ce6a2a73 100644 --- a/deps/AMICI/include/amici/newton_solver.h +++ b/deps/AMICI/include/amici/newton_solver.h @@ -8,12 +8,10 @@ #include - - namespace amici { -class ReturnData; class Model; +class Solver; class AmiVector; /** @@ -25,43 +23,28 @@ class NewtonSolver { public: /** - * Initializes all members with the provided objects + * @brief Initializes all members with the provided objects * * @param t pointer to time variable * @param x pointer to state variables - * @param model pointer to the AMICI model object - * @param rdata pointer to the return data object + * @param model pointer to the model object */ - NewtonSolver(realtype *t, AmiVector *x, Model *model, ReturnData *rdata); + NewtonSolver(realtype *t, AmiVector *x, Model *model); /** - * Factory method to create a NewtonSolver based on linsolType + * @brief Factory method to create a NewtonSolver based on linsolType * * @param t pointer to time variable * @param x pointer to state variables - * @param linsolType integer indicating which linear solver to use - * @param model pointer to the AMICI model object - * @param rdata pointer to the return data object - * @param maxlinsteps maximum number of allowed linear steps per Newton step for steady state computation - * @param maxsteps maximum number of allowed Newton steps for steady state computation - * @param atol absolute tolerance - * @param rtol relative tolerance - * @param dampingFactorMode to switch on/off a use of a damping factor - * @param dampingFactorLowerBound a lower bound for the damping factor + * @param simulationSolver solver with settings + * @param model pointer to the model object * @return solver NewtonSolver according to the specified linsolType */ - static std::unique_ptr getSolver(realtype *t, AmiVector *x, - LinearSolver linsolType, - Model *model, - ReturnData *rdata, - int maxlinsteps, - int maxsteps, - double atol, double rtol, - NewtonDampingFactorMode dampingFactorMode, - double dampingFactorLowerBound); + static std::unique_ptr getSolver( + realtype *t, AmiVector *x, Solver &simulationSolver, Model *model); /** - * Computes the solution of one Newton iteration + * @brief Computes the solution of one Newton iteration * * @param ntry integer newton_try integer start number of Newton solver * (1 or 2) @@ -72,15 +55,24 @@ class NewtonSolver { void getStep(int ntry, int nnewt, AmiVector &delta); /** - * Computes steady state sensitivities + * @brief Computes steady state sensitivities * * @param sx pointer to state variable sensitivities */ void computeNewtonSensis(AmiVectorArray &sx); + + /** + * @brief Accessor for numlinsteps + * + * @return numlinsteps + */ + const std::vector &getNumLinSteps() const { + return numlinsteps; + } /** - * Writes the Jacobian for the Newton iteration and passes it to the linear - * solver + * @brief Writes the Jacobian for the Newton iteration and passes it to the + * linear solver * * @param ntry integer newton_try integer start number of Newton solver * (1 or 2) @@ -89,7 +81,17 @@ class NewtonSolver { virtual void prepareLinearSystem(int ntry, int nnewt) = 0; /** - * Solves the linear system for the Newton step + * Writes the Jacobian (JB) for the Newton iteration and passes it to the linear + * solver + * + * @param ntry integer newton_try integer start number of Newton solver + * (1 or 2) + * @param nnewt integer number of current Newton step + */ + virtual void prepareLinearSystemB(int ntry, int nnewt) = 0; + + /** + * @brief Solves the linear system for the Newton step * * @param rhs containing the RHS of the linear system, will be * overwritten by solution to the linear system @@ -115,17 +117,20 @@ class NewtonSolver { protected: /** time variable */ realtype *t; - /** pointer to the AMICI model object */ + /** pointer to the model object */ Model *model; - /** pointer to the return data object */ - ReturnData *rdata; /** right hand side AmiVector */ AmiVector xdot; /** current state */ AmiVector *x; /** current state time derivative (DAE) */ AmiVector dx; - + /** history of number of linear steps */ + std::vector numlinsteps; + /** current adjoint state */ + AmiVector xB; + /** current adjoint state time derivative (DAE) */ + AmiVector dxB; }; /** @@ -137,20 +142,19 @@ class NewtonSolverDense : public NewtonSolver { public: /** - * Constructor, initializes all members with the provided objects + * @brief Constructor, initializes all members with the provided objects * and initializes temporary storage objects * * @param t pointer to time variable * @param x pointer to state variables - * @param model pointer to the AMICI model object - * @param rdata pointer to the return data object + * @param model pointer to the model object */ - NewtonSolverDense(realtype *t, AmiVector *x, Model *model, ReturnData *rdata); + NewtonSolverDense(realtype *t, AmiVector *x, Model *model); ~NewtonSolverDense() override; /** - * Solves the linear system for the Newton step + * @brief Solves the linear system for the Newton step * * @param rhs containing the RHS of the linear system, will be * overwritten by solution to the linear system @@ -158,8 +162,8 @@ class NewtonSolverDense : public NewtonSolver { void solveLinearSystem(AmiVector &rhs) override; /** - * Writes the Jacobian for the Newton iteration and passes it to the linear - * solver + * @brief Writes the Jacobian for the Newton iteration and passes it to the + * linear solver * * @param ntry integer newton_try integer start number of Newton solver * (1 or 2) @@ -167,6 +171,16 @@ class NewtonSolverDense : public NewtonSolver { */ void prepareLinearSystem(int ntry, int nnewt) override; + /** + * Writes the Jacobian (JB) for the Newton iteration and passes it to the linear + * solver + * + * @param ntry integer newton_try integer start number of Newton solver + * (1 or 2) + * @param nnewt integer number of current Newton step + */ + void prepareLinearSystemB(int ntry, int nnewt) override; + private: /** temporary storage of Jacobian */ SUNMatrixWrapper Jtmp; @@ -184,19 +198,18 @@ class NewtonSolverSparse : public NewtonSolver { public: /** - * Constructor, initializes all members with the provided objects, + * @brief Constructor, initializes all members with the provided objects, * initializes temporary storage objects and the klu solver * * @param t pointer to time variable * @param x pointer to state variables - * @param model pointer to the AMICI model object - * @param rdata pointer to the return data object + * @param model pointer to the model object */ - NewtonSolverSparse(realtype *t, AmiVector *x, Model *model, ReturnData *rdata); + NewtonSolverSparse(realtype *t, AmiVector *x, Model *model); ~NewtonSolverSparse() override; /** - * Solves the linear system for the Newton step + * @brief Solves the linear system for the Newton step * * @param rhs containing the RHS of the linear system, will be * overwritten by solution to the linear system @@ -204,8 +217,8 @@ class NewtonSolverSparse : public NewtonSolver { void solveLinearSystem(AmiVector &rhs) override; /** - * Writes the Jacobian for the Newton iteration and passes it to the linear - * solver + * @brief Writes the Jacobian for the Newton iteration and passes it to the + * linear solver * * @param ntry integer newton_try integer start number of Newton solver * (1 or 2) @@ -213,6 +226,16 @@ class NewtonSolverSparse : public NewtonSolver { */ void prepareLinearSystem(int ntry, int nnewt) override; + /** + * Writes the Jacobian (JB) for the Newton iteration and passes it to the linear + * solver + * + * @param ntry integer newton_try integer start number of Newton solver + * (1 or 2) + * @param nnewt integer number of current Newton step + */ + void prepareLinearSystemB(int ntry, int nnewt) override; + private: /** temporary storage of Jacobian */ SUNMatrixWrapper Jtmp; @@ -230,17 +253,16 @@ class NewtonSolverIterative : public NewtonSolver { public: /** - * Constructor, initializes all members with the provided objects + * @brief Constructor, initializes all members with the provided objects * @param t pointer to time variable * @param x pointer to state variables - * @param model pointer to the AMICI model object - * @param rdata pointer to the return data object + * @param model pointer to the model object */ - NewtonSolverIterative(realtype *t, AmiVector *x, Model *model, ReturnData *rdata); + NewtonSolverIterative(realtype *t, AmiVector *x, Model *model); ~NewtonSolverIterative() override = default; /** - * Solves the linear system for the Newton step by passing it to + * @brief Solves the linear system for the Newton step by passing it to * linsolveSPBCG * * @param rhs containing the RHS of the linear system, will be @@ -249,7 +271,7 @@ class NewtonSolverIterative : public NewtonSolver { void solveLinearSystem(AmiVector &rhs) override; /** - * Writes the Jacobian for the Newton iteration and passes it to the linear + * Writes the Jacobian (J) for the Newton iteration and passes it to the linear * solver. * Also wraps around getSensis for iterative linear solver. * @@ -259,6 +281,17 @@ class NewtonSolverIterative : public NewtonSolver { */ void prepareLinearSystem(int ntry, int nnewt) override; + /** + * Writes the Jacobian (JB) for the Newton iteration and passes it to the linear + * solver. + * Also wraps around getSensis for iterative linear solver. + * + * @param ntry integer newton_try integer start number of Newton solver + * (1 or 2) + * @param nnewt integer number of current Newton step + */ + void prepareLinearSystemB(int ntry, int nnewt) override; + /** * Iterative linear solver created from SPILS BiCG-Stab. * Solves the linear system within each Newton step if iterative solver is @@ -296,6 +329,8 @@ class NewtonSolverIterative : public NewtonSolver { AmiVector ns_tmp; /** ??? */ AmiVector ns_Jdiag; + /** temporary storage of Jacobian */ + SUNMatrixWrapper ns_J; }; diff --git a/deps/AMICI/include/amici/rdata.h b/deps/AMICI/include/amici/rdata.h index 8f159e0c5..414db1029 100644 --- a/deps/AMICI/include/amici/rdata.h +++ b/deps/AMICI/include/amici/rdata.h @@ -2,14 +2,20 @@ #define AMICI_RDATA_H #include "amici/defines.h" +#include "amici/vector.h" +#include "amici/model.h" +#include "amici/misc.h" +#include "amici/forwardproblem.h" #include namespace amici { -class Model; class ReturnData; class Solver; class ExpData; +class ForwardProblem; +class BackwardProblem; +class SteadystateProblem; } // namespace amici namespace boost { @@ -42,6 +48,7 @@ class ReturnData { * @param nx see amici::Model::nx_rdata * @param nx_solver see amici::Model::nx_solver * @param nxtrue see amici::Model::nxtrue_rdata + * @param nx_solver_reinit see amici::Model::nx_solver_reinit * @param ny see amici::Model::ny * @param nytrue see amici::Model::nytrue * @param nz see amici::Model::nz @@ -57,13 +64,15 @@ class ReturnData { * @param o2mode see amici::Model::o2mode * @param sensi see amici::Solver::sensi * @param sensi_meth see amici::Solver::sensi_meth + * @param rdrm see amici::Solver::rdata_reporting */ ReturnData(std::vector ts, int np, int nk, int nx, int nx_solver, - int nxtrue, int ny, int nytrue, int nz, int nztrue, int ne, + int nxtrue, int nx_solver_reinit, int ny, int nytrue, int nz, int nztrue, int ne, int nJ, int nplist, int nmaxevent, int nt, int newton_maxsteps, int nw, std::vector pscale, SecondOrderMode o2mode, - SensitivityOrder sensi, SensitivityMethod sensi_meth); + SensitivityOrder sensi, SensitivityMethod sensi_meth, + RDataReporting rdrm); /** * @brief constructor that uses information from model and solver to @@ -76,61 +85,23 @@ class ReturnData { ~ReturnData() = default; /** - * @brief initializeObjectiveFunction - */ - void initializeObjectiveFunction(); - - /** - * @brief Set likelihood, state variables, outputs and respective - * sensitivities to NaN (typically after integration failure) - * @param t time of integration failure - */ - void invalidate(realtype t); - - /** - * @brief Set likelihood and chi2 to NaN - * (typically after integration failure) - */ - void invalidateLLH(); - - /** - * @brief Set likelihood sensitivities to NaN - * (typically after integration failure) - */ - void invalidateSLLH(); - - /** - * @brief applies the chain rule to account for parameter transformation in - * the sensitivities of simulation results - * @param model Model from which the ReturnData was obtained - */ - void applyChainRuleFactorToSimulationResults(const Model *model); - - /** - * @brief Residual function - * @param it time index - * @param edata ExpData instance containing observable data - */ - void fres(int it, const ExpData &edata); - - /** - * @brief Chi-squared function - * @param it time index - */ - void fchi2(int it); - - /** - * @brief Residual sensitivity function - * @param it time index - * @param edata ExpData instance containing observable data - */ - void fsres(int it, const ExpData &edata); - - /** - * @brief Fisher information matrix function - * @param it time index + * @brief constructor that uses information from model and solver to + * appropriately initialize fields + * @param preeq simulated preequilibration problem, pass nullptr to ignore + * @param fwd simulated forward problem, pass nullptr to ignore + * @param bwd simulat + * ed backward problem, pass nullptr to ignore + * @param posteq simulated postequilibration problem, pass nullptr to ignore + * @param model matching model instance + * @param solver matching solver instance + * @param edata matching experimental data */ - void fFIM(int it); + void processSimulationObjects(SteadystateProblem const *preeq, + ForwardProblem const *fwd, + BackwardProblem const *bwd, + SteadystateProblem const *posteq, + Model &model, Solver const &solver, + ExpData const *edata); /** timepoints (dimension: nt) */ std::vector ts; @@ -261,40 +232,85 @@ class ReturnData { /** computation time of backward solve [ms] */ double cpu_timeB = 0.0; - /** flag indicating success of Newton solver */ - int newton_status = 0; + /** flags indicating success of steady state solver (preequilibration) */ + std::vector preeq_status; + + /** computation time of the steady state solver [ms] (preequilibration) */ + double preeq_cpu_time = 0.0; - /** computation time of the Newton solver [ms] */ - double newton_cpu_time = 0.0; + /** computation time of the steady state solver of the backward problem [ms] + * (preequilibration) */ + double preeq_cpu_timeB = 0.0; + + /** flags indicating success of steady state solver (postequilibration) */ + std::vector posteq_status; + + /** computation time of the steady state solver [ms] (postequilibration) */ + double posteq_cpu_time = 0.0; + + /** computation time of the steady state solver of the backward problem [ms] + * (postequilibration) */ + double posteq_cpu_timeB = 0.0; /** - * number of Newton steps for steady state problem + * number of Newton steps for steady state problem (preequilibration) * [newton, simulation, newton] (length = 3) */ - std::vector newton_numsteps; + std::vector preeq_numsteps; + + /** + * number of linear steps by Newton step for steady state problem. this + * will only be filled for iterative solvers (preequilibration) + * (length = newton_maxsteps * 2) + */ + std::vector preeq_numlinsteps; + + /** + * number of simulation steps for adjoint steady state problem + * (preequilibration) [== 0 if analytical solution worked, > 0 otherwise] + */ + int preeq_numstepsB = 0; + + /** + * number of Newton steps for steady state problem (preequilibration) + * [newton, simulation, newton] (length = 3) (postequilibration) + */ + std::vector posteq_numsteps; /** * number of linear steps by Newton step for steady state problem. this - * will only be filled for iterative solvers (length = newton_maxsteps * 2) + * will only be filled for iterative solvers (postequilibration) + * (length = newton_maxsteps * 2) */ - std::vector newton_numlinsteps; + std::vector posteq_numlinsteps; /** - * time at which steadystate was reached in the simulation based approach + * number of simulation steps for adjoint steady state problem + * (postequilibration) [== 0 if analytical solution worked, > 0 otherwise] */ - realtype t_steadystate = NAN; + int posteq_numstepsB = 0; + + /** + * time when steadystate was reached via simulation (preequilibration) + */ + realtype preeq_t = NAN; /** * weighted root-mean-square of the rhs when steadystate - * was reached + * was reached (preequilibration) + */ + realtype preeq_wrms = NAN; + + /** + * time when steadystate was reached via simulation (postequilibration) */ - realtype wrms_steadystate = NAN; + realtype posteq_t = NAN; /** * weighted root-mean-square of the rhs when steadystate - * was reached + * was reached (postequilibration) */ - realtype wrms_sensi_steadystate = NAN; + realtype posteq_wrms = NAN; /** initial state (dimension: nx) */ std::vector x0; @@ -344,6 +360,9 @@ class ReturnData { /** number of states in the unaugmented system */ int nxtrue{0}; + /** number of solver states to be reinitilized after preequilibration */ + int nx_solver_reinit{0}; + /** number of observables */ int ny{0}; @@ -389,6 +408,9 @@ class ReturnData { /** sensitivity method */ SensitivityMethod sensi_meth{SensitivityMethod::none}; + /** reporting mode */ + RDataReporting rdata_reporting{RDataReporting::full}; + /** * @brief Serialize ReturnData (see boost::serialization::serialize) * @param ar Archive to serialize to @@ -398,8 +420,296 @@ class ReturnData { template friend void boost::serialization::serialize(Archive &ar, ReturnData &r, unsigned int version); + + protected: + + /** timepoint for model evaluation*/ + realtype t; + + /** partial state vector, excluding states eliminated from conservation laws */ + AmiVector x_solver; + + /** partial time derivative of state vector, excluding states eliminated from conservation laws */ + AmiVector dx_solver; + + /** partial sensitivity state vector array, excluding states eliminated from + * conservation laws */ + AmiVectorArray sx_solver; + + /** full state vector, including states eliminated from conservation laws */ + AmiVector x_rdata; + + /** full sensitivity state vector array, including states eliminated from + * conservation laws */ + AmiVectorArray sx_rdata; + + /** array of number of found roots for a certain event type + * (dimension: ne) */ + std::vector nroots; + + /** + * @brief initializes storage for likelihood reporting mode + */ + void initializeLikelihoodReporting(); + + /** + * @brief initializes storage for residual reporting mode + */ + void initializeResidualReporting(); + + /** + * @brief initializes storage for full reporting mode + */ + void initializeFullReporting(); + + + /** + * @brief initialize values for chi2 and llh and derivatives + */ + void initializeObjectiveFunction(); + + /** + * @brief extracts data from a preequilibration steadystateproblem + * @param preeq Steadystateproblem for preequilibration + * @param model Model instance to compute return values + */ + void processPreEquilibration(SteadystateProblem const &preeq, + Model &model); + + /** + * @brief extracts data from a preequilibration steadystateproblem + * @param posteq Steadystateproblem for postequilibration + * @param model Model instance to compute return values + * @param edata ExpData instance containing observable data + */ + void processPostEquilibration(SteadystateProblem const &posteq, + Model &model, + ExpData const *edata); + + /** + * @brief extracts results from forward problem + * @param fwd forward problem + * @param model model that was used for forward simulation + * @param edata ExpData instance containing observable data + */ + void processForwardProblem(ForwardProblem const &fwd, + Model &model, + ExpData const *edata); + + + /** + * @brief extracts results from backward problem + * @param fwd forward problem + * @param bwd backward problem + * @param preeq Steadystateproblem for preequilibration + * @param model model that was used for forward/backward simulation + */ + void processBackwardProblem(ForwardProblem const &fwd, + BackwardProblem const &bwd, + SteadystateProblem const *preeq, + Model &model); + + /** + * @brief extracts results from solver + * @param solver solver that was used for forward/backward simulation + */ + void processSolver(Solver const &solver); + + /** + * @brief Evaluates and stores the Jacobian and right hand side at final timepoint + * @param problem forward problem or steadystate problem + * @param model model that was used for forward/backward simulation + */ + template + void storeJacobianAndDerivativeInReturnData(T const &problem, Model &model) + { + readSimulationState(problem.getFinalSimulationState(), model); + + AmiVector xdot(nx_solver); + if (!this->xdot.empty() || !this->J.empty()) + model.fxdot(t, x_solver, dx_solver, xdot); + + if (!this->xdot.empty()) + writeSlice(xdot, this->xdot); + + if (!this->J.empty()) { + SUNMatrixWrapper J(nx_solver, nx_solver); + model.fJ(t, 0.0, x_solver, dx_solver, xdot, J.get()); + // CVODES uses colmajor, so we need to transform to rowmajor + for (int ix = 0; ix < model.nx_solver; ix++) + for (int jx = 0; jx < model.nx_solver; jx++) + this->J.at(ix * model.nx_solver + jx) = + J.data()[ix + model.nx_solver * jx]; + } + } + /** + * @brief sets member variables and model state according to provided simulation state + * @param state simulation state provided by Problem + * @param model model that was used for forward/backward simulation + */ + void readSimulationState(SimulationState const &state, Model &model); + + /** + * @brief Residual function + * @param it time index + * @param model model that was used for forward/backward simulation + * @param edata ExpData instance containing observable data + */ + void fres(int it, Model &model, const ExpData &edata); + + /** + * @brief Chi-squared function + * @param it time index + */ + void fchi2(int it); + + /** + * @brief Residual sensitivity function + * @param it time index + * @param model model that was used for forward/backward simulation + * @param edata ExpData instance containing observable data + */ + void fsres(int it, Model &model, const ExpData &edata); + + /** + * @brief Fisher information matrix function + * @param it time index + * @param model model that was used for forward/backward simulation + * @param edata ExpData instance containing observable data + */ + void fFIM(int it, Model &model, const ExpData &edata); + + /** + * @brief Set likelihood, state variables, outputs and respective + * sensitivities to NaN (typically after integration failure) + * @param it_start time index at which to start invalidating + */ + void invalidate(int it_start); + + /** + * @brief Set likelihood and chi2 to NaN + * (typically after integration failure) + */ + void invalidateLLH(); + + /** + * @brief Set likelihood sensitivities to NaN + * (typically after integration failure) + */ + void invalidateSLLH(); + + /** + * @brief applies the chain rule to account for parameter transformation in + * the sensitivities of simulation results + * @param model Model from which the ReturnData was obtained + */ + void applyChainRuleFactorToSimulationResults(const Model &model); + + + /** + * @brief Checks whether forward sensitivity analysis is performed + * @return boolean indicator + */ + bool computingFSA() const { + return (sensi_meth == SensitivityMethod::forward && + sensi >= SensitivityOrder::first); + } + + /** + * @brief Extracts output information for data-points, expects that x_solver and sx_solver were + * were set appropriately + * @param it timepoint index + * @param model model that was used in forward solve + * @param edata ExpData instance carrying experimental data + */ + void getDataOutput(int it, Model &model, ExpData const *edata); + + /** + * @brief Extracts data information for forward sensitivity analysis, expects that x_solver and + * sx_solver were were set appropriately + * @param it index of current timepoint + * @param model model that was used in forward solve + * @param edata ExpData instance carrying experimental data + */ + void getDataSensisFSA(int it, Model &model, ExpData const *edata); + + /** + * @brief Extracts output information for events, expects that x_solver and sx_solver were + * were set appropriately + * @param iroot event index + * @param t event timepoint + * @param rootidx information about which roots fired (1 indicating fired, 0/-1 for not) + * @param model model that was used in forward solve + * @param edata ExpData instance carrying experimental data + */ + void getEventOutput(int iroot, realtype t, const std::vector rootidx, + Model &model, ExpData const *edata); + + /** + * @brief Extracts event information for forward sensitivity analysis, expects that x_solver and + * sx_solver were set appropriately + * @param iroot event index + * @param ie index of event type + * @param t event timepoint + * @param model model that was used in forward solve + * @param edata ExpData instance carrying experimental data + */ + void getEventSensisFSA(int iroot, int ie, realtype t, Model &model, + ExpData const *edata); + + /** + * @brief Updates contribution to likelihood from quadratures (xQB), + * if preequilibration was run in adjoint mode + * @param model model that was used for forward/backward simulation + * @param preeq Steadystateproblem for preequilibration + * @param xQB vector with quadratures from adjoint computation + */ + void handleSx0Backward(const Model &model, SteadystateProblem const &preeq, + AmiVector &xQB) const; + + /** + * @brief Updates contribution to likelihood for inital state sensitivities + * (llhS0), if no preequilibration was run or if forward sensitivities were used + * @param model model that was used for forward/backward simulation + * @param llhS0 contribution to likelihood for initial state sensitivities + * @param xB vector with final adjoint state + * (exluding conservation laws) + */ + void handleSx0Forward(const Model &model, + std::vector &llhS0, + AmiVector &xB) const; +}; + +/** + * @brief The ModelContext temporarily stores amici::Model::state + * and restores it when going out of scope + */ +class ModelContext : public ContextManager { + public: + /** + * @brief initialize backup of the original values. + * + * @param model + */ + explicit ModelContext(Model *model); + + ModelContext &operator=(const ModelContext &other) = delete; + + ~ModelContext(); + + /** + * @brief Restore original state on constructor-supplied amici::Model. + * Will be called during destruction. Explicit call is generally not + * necessary. + */ + void restore(); + + private: + Model *model = nullptr; + ModelState original_state; }; + } // namespace amici #endif /* _MY_RDATA */ diff --git a/deps/AMICI/include/amici/serialization.h b/deps/AMICI/include/amici/serialization.h index 0392c2918..02e270aa9 100644 --- a/deps/AMICI/include/amici/serialization.h +++ b/deps/AMICI/include/amici/serialization.h @@ -69,6 +69,7 @@ void serialize(Archive &ar, amici::Solver &u, const unsigned int version) { ar &u.ordering; ar &u.cpu_time; ar &u.cpu_timeB; + ar &u.rdata_mode; } @@ -83,6 +84,7 @@ void serialize(Archive &ar, amici::Model &u, const unsigned int version) { ar &u.nxtrue_rdata; ar &u.nx_solver; ar &u.nxtrue_solver; + ar &u.nx_solver_reinit; ar &u.ny; ar &u.nytrue; ar &u.nz; @@ -99,12 +101,12 @@ void serialize(Archive &ar, amici::Model &u, const unsigned int version) { ar &u.o2mode; ar &u.z2event; ar &u.idlist; - ar &u.h; - ar &u.unscaledParameters; + ar &u.state.h; + ar &u.state.unscaledParameters; ar &u.originalParameters; - ar &u.fixedParameters; + ar &u.state.fixedParameters; ar &u.reinitializeFixedParameterInitialStates; - ar &u.plist_; + ar &u.state.plist; ar &u.x0data; ar &u.sx0data; ar &u.ts; @@ -165,15 +167,20 @@ void serialize(Archive &ar, amici::ReturnData &r, const unsigned int version) { ar &r.order; ar &r.cpu_time; ar &r.cpu_timeB; - ar &r.newton_cpu_time; - - ar &r.newton_status; - ar &r.newton_cpu_time; - ar &r.newton_numsteps; - ar &r.newton_numlinsteps; - ar &r.wrms_steadystate; - ar &r.wrms_sensi_steadystate; - ar &r.t_steadystate; + ar &r.preeq_cpu_time; + ar &r.preeq_cpu_timeB; + ar &r.preeq_status; + ar &r.preeq_numsteps; + ar &r.preeq_numlinsteps; + ar &r.preeq_wrms; + ar &r.preeq_t; + ar &r.posteq_cpu_time; + ar &r.posteq_cpu_timeB; + ar &r.posteq_status; + ar &r.posteq_numsteps; + ar &r.posteq_numlinsteps; + ar &r.posteq_wrms; + ar &r.posteq_t; ar &r.x0; ar &r.sx0; ar &r.llh; diff --git a/deps/AMICI/include/amici/solver.h b/deps/AMICI/include/amici/solver.h index 1c6e48adf..8f7c12958 100644 --- a/deps/AMICI/include/amici/solver.h +++ b/deps/AMICI/include/amici/solver.h @@ -7,6 +7,7 @@ #include "amici/symbolic_functions.h" #include "amici/vector.h" +#include #include #include @@ -119,23 +120,27 @@ class Solver { const AmiVector &dxB0, const AmiVector &xQB0) const; /** - * @brief Extracts diagnosis information from solver memory block and - * writes them into the return data object - * - * @param it time-point index - * @param rdata pointer to the return data object + * @brief Initialises the ami memory for quadrature computation + * @param t0 initial timepoint + * @param model pointer to the model instance + * @param x0 initial states + * @param dx0 initial derivative states + * @param xB0 initial adjoint states + * @param dxB0 initial derivative adjoint states + * @param xQ0 initial quadrature vector */ - void getDiagnosis(int it, ReturnData *rdata) const; + + void setupSteadystate(const realtype t0, Model *model, const AmiVector &x0, + const AmiVector &dx0, const AmiVector &xB0, + const AmiVector &dxB0, const AmiVector &xQ0) const; /** - * @brief Extracts diagnosis information from solver memory block and - * writes them into the return data object for the backward problem + * @brief Reinitializes state and respective sensitivities (if necessary) according + * to changes in fixedParameters * - * @param it time-point index - * @param rdata pointer to the return data object - * @param which identifier of the backwards problem + * @param model pointer to the model instance */ - void getDiagnosisB(int it, ReturnData *rdata, int which) const; + void updateAndReinitStatesAndSensitivities(Model *model); /** * getRootInfo extracts information which event occured @@ -188,6 +193,23 @@ class Solver { */ void setSensitivityMethod(SensitivityMethod sensi_meth); + /** + * @brief Return current sensitivity method during preequilibration + * @return method enum + */ + SensitivityMethod getSensitivityMethodPreequilibration() const; + + /** + * @brief Set sensitivity method for preequilibration + * @param sensi_meth_preeq + */ + void setSensitivityMethodPreequilibration(SensitivityMethod sensi_meth_preeq); + + /** + * @brief Disable forward sensitivity integration (used in steady state sim) + */ + void switchForwardSensisOff() const; + /** * @brief Get maximum number of allowed Newton steps for steady state * computation @@ -551,15 +573,28 @@ class Solver { */ void setInternalSensitivityMethod(InternalSensitivityMethod ism); + /** + * @brief returns the ReturnData reporting mode + * @return ReturnData reporting mode + */ + RDataReporting getReturnDataReportingMode() const; + + /** + * @brief sets the ReturnData reporting mode + * @param rdrm ReturnData reporting mode + */ + void setReturnDataReportingMode(RDataReporting rdrm); + /** * @brief write solution from forward simulation * @param t time * @param x state * @param dx derivative state * @param sx state sensitivity + * @param xQ quadrature */ void writeSolution(realtype *t, AmiVector &x, AmiVector &dx, - AmiVectorArray &sx) const; + AmiVectorArray &sx, AmiVector &xQ) const; /** * @brief write solution from forward simulation @@ -617,6 +652,13 @@ class Solver { */ const AmiVector &getAdjointQuadrature(int which, realtype t) const; + /** + * @brief Access quadrature solution at time t + * @param t time + * @return (interpolated) solution xQ + */ + const AmiVector &getQuadrature(realtype t) const; + /** * @brief Reinitializes the states in the solver after an event occurence * @@ -637,6 +679,12 @@ class Solver { virtual void sensReInit(const AmiVectorArray &yyS0, const AmiVectorArray &ypS0) const = 0; + /** + * @brief Switches off computation of state sensitivites without + * deallocating the memory for sensitivities + */ + virtual void sensToggleOff() const = 0; + /** * @brief Reinitializes the adjoint states after an event occurence * @@ -692,6 +740,113 @@ class Solver { */ int nquad() const; + /** + * @brief check if FSA is being computed + * @return flag + */ + bool computingFSA() const { + return getSensitivityOrder() >= SensitivityOrder::first && + getSensitivityMethod() == SensitivityMethod::forward; + } + + /** + * @brief check if ASA is being computed + * @return flag + */ + bool computingASA() const { + return getSensitivityOrder() >= SensitivityOrder::first && + getSensitivityMethod() == SensitivityMethod::adjoint; + } + + /** + * @brief Resets vectors containing diagnosis information + */ + void resetDiagnosis() const; + + /** + * @brief Stores diagnosis information from solver memory block for forward problem + */ + void storeDiagnosis() const; + + /** + * @brief Stores diagnosis information from solver memory block for backward problem + * + * @param which identifier of the backwards problem + */ + void storeDiagnosisB(int which) const; + + /** + * @brief Accessor ns + * @return ns + */ + std::vector const& getNumSteps() const { + return ns; + } + + /** + * @brief Accessor nsB + * @return nsB + */ + std::vector const& getNumStepsB() const { + return nsB; + } + + /** + * @brief Accessor nrhs + * @return nrhs + */ + std::vector const& getNumRhsEvals() const { + return nrhs; + } + + /** + * @brief Accessor nrhsB + * @return nrhsB + */ + std::vector const& getNumRhsEvalsB() const { + return nrhsB; + } + + /** + * @brief Accessor netf + * @return netf + */ + std::vector const& getNumErrTestFails() const { + return netf; + } + + /** + * @brief Accessor netfB + * @return netfB + */ + std::vector const& getNumErrTestFailsB() const { + return netfB; + } + + /** + * @brief Accessor nnlscf + * @return nnlscf + */ + std::vector const& getNumNonlinSolvConvFails() const { + return nnlscf; + } + + /** + * @brief Accessor nnlscfB + * @return nnlscfB + */ + std::vector const& getNumNonlinSolvConvFailsB() const { + return nnlscfB; + } + + /** + * @brief Accessor order + * @return order + */ + std::vector const& getLastOrder() const { + return order; + } + /** * @brief Serialize Solver (see boost::serialization::serialize) * @param ar Archive to serialize to @@ -776,6 +931,14 @@ class Solver { */ virtual void getQuadB(int which) const = 0; + /** + * @brief extracts the quadrature at the current timepoint from solver + * memory and writes it to the xQ member variable + * + * @param t timepoint for quadrature extraction + */ + virtual void getQuad(realtype &t) const = 0; + /** * @brief Initialises the states at the specified initial timepoint * @@ -786,6 +949,16 @@ class Solver { virtual void init(realtype t0, const AmiVector &x0, const AmiVector &dx0) const = 0; + /** + * @brief Initialises the states at the specified initial timepoint + * + * @param t0 initial timepoint + * @param x0 initial states + * @param dx0 initial derivative states + */ + virtual void initSteadystate(realtype t0, const AmiVector &x0, + const AmiVector &dx0) const = 0; + /** * @brief initialises the forward sensitivities * @param sx0 initial states semsitivities @@ -874,6 +1047,11 @@ class Solver { */ virtual void setJacTimesVecFnB(int which) const = 0; + /** + * @brief sets the sparse Jacobian function for backward steady state case + */ + virtual void setSparseJacFn_ss() const = 0; + /** * @brief Create specifies solver method and initializes solver memory for * the forward problem @@ -915,6 +1093,14 @@ class Solver { */ virtual void setQuadErrConB(int which, bool flag) const = 0; + /** + * @brief Specifies whether error control is also enforced for the + * forward quadrature problem + * + * @param flag activation flag + */ + virtual void setQuadErrCon(bool flag) const = 0; + /** * @brief Attaches the error handler function (errMsgIdAndTxt) * to the solver @@ -1039,11 +1225,25 @@ class Solver { virtual void getQuadDkyB(realtype t, int k, int which) const = 0; /** - * @brief initializes the adjoint problem + * @brief interpolates the (derivative of the) solution at the requested + * timepoint * + * @param t timepoint + * @param k derivative order + */ + virtual void getQuadDky(realtype t, int k) const = 0; + + /** + * @brief initializes the adjoint problem */ virtual void adjInit() const = 0; + /** + * @brief initializes the quadratures + * @param xQ0 vector with initial values for xQ + */ + virtual void quadInit(const AmiVector &xQ0) const = 0; + /** * @brief Specifies solver method and initializes solver memory for the * backward problem @@ -1074,6 +1274,15 @@ class Solver { virtual void quadSStolerancesB(int which, realtype reltolQB, realtype abstolQB) const = 0; + /** + * @brief sets relative and absolute tolerances for the quadrature problem + * + * @param reltolQB relative tolerances + * @param abstolQB absolute tolerances + */ + virtual void quadSStolerances(realtype reltolQB, + realtype abstolQB) const = 0; + /** * @brief reports the number of solver steps * @@ -1220,6 +1429,12 @@ class Solver { */ bool getQuadInitDoneB(int which) const; + /** + * @brief checks whether memory for quadratures has been allocated + * @return proxy for solverMemory->(cv|ida)_QuadMallocDone + */ + bool getQuadInitDone() const; + /** * @brief attaches a diagonal linear solver to the forward problem */ @@ -1279,6 +1494,12 @@ class Solver { */ void applyQuadTolerancesASA(int which) const; + /** + * @brief updates quadrature solver tolerances according to the + * currently specified member variables + */ + void applyQuadTolerances() const; + /** * @brief updates all senstivivity solver tolerances according to the * currently specified member variables @@ -1344,6 +1565,11 @@ class Solver { */ void setSensInitDone() const; + /** + * @brief sets that memory for forward sensitivities has not been allocated + */ + void setSensInitOff() const; + /** * @brief sets that memory for forward interpolation has been allocated */ @@ -1361,6 +1587,19 @@ class Solver { */ void setQuadInitDoneB(int which) const; + /** + * @brief sets that memory for quadratures has been allocated + */ + void setQuadInitDone() const; + + /** + * @brief Sets sensitivity method (for simulation or preequilibration) + * @param sensi_meth new value for sensi_meth[_preeq] + * @param preequilibration flag indicating preequilibration or simulation + */ + void checkSensitivityMethod(const SensitivityMethod sensi_meth, + bool preequilibration) const; + /** state (dimension: nx_solver) */ mutable AmiVector x = AmiVector(0); @@ -1386,8 +1625,11 @@ class Solver { /** adjoint quadrature interface variable (dimension: nJ x nplist) */ mutable AmiVector xQB = AmiVector(0); + /** forward quadrature interface variable (dimension: nx_solver) */ + mutable AmiVector xQ = AmiVector(0); + /** integration time of the forward problem */ - mutable realtype t; + mutable realtype t = std::nan(""); /** flag to force reInitPostProcessF before next call to solve */ mutable bool forceReInitPostProcessF = false; @@ -1399,6 +1641,9 @@ class Solver { /** method for sensitivity computation */ SensitivityMethod sensi_meth = SensitivityMethod::forward; + /** method for sensitivity computation in preequilibration */ + SensitivityMethod sensi_meth_preeq = SensitivityMethod::forward; + /** flag controlling stability limit detection */ booleantype stldet = true; @@ -1461,6 +1706,8 @@ class Solver { /** relative tolerances for steadystate computation */ realtype ss_rtol_sensi = NAN; + RDataReporting rdata_mode = RDataReporting::full; + /** CPU time, forward solve */ mutable realtype cpu_time = 0.0; @@ -1482,6 +1729,9 @@ class Solver { /** flag indicating whether adjInit was called */ mutable bool adjInitialized = false; + /** flag indicating whether (forward) quadInit was called */ + mutable bool quadInitialized = false; + /** vector of flags indicating whether binit was called for respective which */ mutable std::vector initializedB{false}; @@ -1492,6 +1742,37 @@ class Solver { /** number of checkpoints in the forward problem */ mutable int ncheckPtr = 0; + + /** number of integration steps forward problem (dimension: nt) */ + mutable std::vector ns; + + /** number of integration steps backward problem (dimension: nt) */ + mutable std::vector nsB; + + /** number of right hand side evaluations forward problem (dimension: nt) */ + mutable std::vector nrhs; + + /** number of right hand side evaluations backward problem (dimension: nt) */ + mutable std::vector nrhsB; + + /** number of error test failures forward problem (dimension: nt) */ + mutable std::vector netf; + + /** number of error test failures backward problem (dimension: nt) */ + mutable std::vector netfB; + + /** + * number of linear solver convergence failures forward problem (dimension: + * nt) */ + mutable std::vector nnlscf; + + /** + * number of linear solver convergence failures backward problem (dimension: + * nt) */ + mutable std::vector nnlscfB; + + /** employed order forward problem (dimension: nt) */ + mutable std::vector order; }; bool operator==(const Solver &a, const Solver &b); diff --git a/deps/AMICI/include/amici/solver_cvodes.h b/deps/AMICI/include/amici/solver_cvodes.h index 72e012aca..e17be1967 100644 --- a/deps/AMICI/include/amici/solver_cvodes.h +++ b/deps/AMICI/include/amici/solver_cvodes.h @@ -40,6 +40,8 @@ class CVodeSolver : public Solver { void sensReInit(const AmiVectorArray &yyS0, const AmiVectorArray &ypS0) const override; + void sensToggleOff() const override; + void reInitB(int which, realtype tB0, const AmiVector &yyB0, const AmiVector &ypB0) const override; @@ -95,6 +97,10 @@ class CVodeSolver : public Solver { void getQuadB(int which) const override; + void getQuad(realtype &t) const override; + + void getQuadDky(realtype t, int k) const override; + void reInitPostProcessF(realtype tnext) const override; void reInitPostProcessB(realtype tnext) const override; @@ -113,6 +119,8 @@ class CVodeSolver : public Solver { void setQuadErrConB(int which, bool flag) const override; + void setQuadErrCon(bool flag) const override; + void setErrHandlerFn() const override; void setUserData(Model *model) const override; @@ -136,6 +144,8 @@ class CVodeSolver : public Solver { void adjInit() const override; + void quadInit(const AmiVector &xQ0) const override; + void allocateSolverB(int *which) const override; void setSStolerancesB(int which, realtype relTolB, @@ -144,6 +154,8 @@ class CVodeSolver : public Solver { void quadSStolerancesB(int which, realtype reltolQB, realtype abstolQB) const override; + void quadSStolerances(realtype reltolQ, realtype abstolQ) const override; + void setMaxNumStepsB(int which, long int mxstepsB) const override; void diag() const override; @@ -172,8 +184,11 @@ class CVodeSolver : public Solver { friend bool operator==(const CVodeSolver &a, const CVodeSolver &b); - void init(realtype t0, const AmiVector &x0, const AmiVector &dx0) - const override; + void init(realtype t0, const AmiVector &x0, + const AmiVector &dx0) const override; + + void initSteadystate(const realtype t0, const AmiVector &x0, + const AmiVector &dx0) const override; void sensInit1(const AmiVectorArray &sx0, const AmiVectorArray &sdx0) const override; @@ -200,6 +215,8 @@ class CVodeSolver : public Solver { void setBandJacFnB(int which) const override; void setJacTimesVecFnB(int which) const override; + + void setSparseJacFn_ss() const override; }; } // namespace amici diff --git a/deps/AMICI/include/amici/solver_idas.h b/deps/AMICI/include/amici/solver_idas.h index 5a9bf100d..0d77708e8 100644 --- a/deps/AMICI/include/amici/solver_idas.h +++ b/deps/AMICI/include/amici/solver_idas.h @@ -42,6 +42,8 @@ class IDASolver : public Solver { void sensReInit(const AmiVectorArray &yyS0, const AmiVectorArray &ypS0) const override; + void sensToggleOff() const override; + void reInitB(int which, realtype tB0, const AmiVector &yyB0, const AmiVector &ypB0) const override; @@ -50,6 +52,8 @@ class IDASolver : public Solver { void quadSStolerancesB(int which, realtype reltolQB, realtype abstolQB) const override; + void quadSStolerances(realtype reltolQ, realtype abstolQ) const override; + int solve(realtype tout, int itask) const override; int solveF(realtype tout, int itask, @@ -73,6 +77,10 @@ class IDASolver : public Solver { void getQuadDkyB(realtype t, int k, int which) const override; + void getQuad(realtype &t) const override; + + void getQuadDky(realtype t, int k) const override; + void calcIC(realtype tout1) const override; void calcICB(int which, realtype tout1) const override; @@ -109,6 +117,8 @@ class IDASolver : public Solver { void setQuadErrConB(int which, bool flag) const override; + void setQuadErrCon(bool flag) const override; + void setErrHandlerFn() const override; void setUserData(Model *model) const override; @@ -133,6 +143,8 @@ class IDASolver : public Solver { void adjInit() const override; + void quadInit(const AmiVector &xQ0) const override; + void allocateSolverB(int *which) const override; void setMaxNumStepsB(int which, @@ -164,6 +176,9 @@ class IDASolver : public Solver { void init(realtype t0, const AmiVector &x0, const AmiVector &dx0) const override; + void initSteadystate(const realtype t0, const AmiVector &x0, + const AmiVector &dx0) const override; + void sensInit1(const AmiVectorArray &sx0, const AmiVectorArray &sdx0) const override; void binit(int which, realtype tf, @@ -188,6 +203,8 @@ class IDASolver : public Solver { void setBandJacFnB(int which) const override; void setJacTimesVecFnB(int which) const override; + + void setSparseJacFn_ss() const override; }; } // namespace amici diff --git a/deps/AMICI/include/amici/steadystateproblem.h b/deps/AMICI/include/amici/steadystateproblem.h index 0f6d36b9b..92bdc7b4d 100644 --- a/deps/AMICI/include/amici/steadystateproblem.h +++ b/deps/AMICI/include/amici/steadystateproblem.h @@ -4,6 +4,7 @@ #include "amici/defines.h" #include "amici/vector.h" #include "amici/solver_cvodes.h" +#include "amici/forwardproblem.h" #include #include @@ -13,7 +14,7 @@ namespace amici { -class ReturnData; +class ExpData; class Solver; class Model; @@ -21,109 +22,333 @@ class Model; * @brief The SteadystateProblem class solves a steady-state problem using * Newton's method and falls back to integration on failure. */ - class SteadystateProblem { public: - void workSteadyStateProblem(ReturnData *rdata, Solver *solver, - Model *model, int it); + /** + * @brief constructor + * @param solver Solver instance + * @param model Model instance + */ + explicit SteadystateProblem(const Solver &solver, + const Model &model); + + /** + * @brief Handles steady state computation in the forward case: + * tries to determine the steady state of the ODE system and computes + * steady state sensitivities if requested. + * @param solver pointer to the solver object + * @param model pointer to the model object + * @param it integer with the index of the current time step + */ + void workSteadyStateProblem(Solver *solver, Model *model, int it); + + + /** + * Integrates over the adjoint state backward in time by solving a linear + * system of equations, which gives the analytical solution. + * Computes the gradient via adjoint steady state sensitivities + * @param solver pointer to the solver object + * @param model pointer to the model object + * @param bwd backward problem + */ + void workSteadyStateBackwardProblem(Solver *solver, Model *model, + const BackwardProblem *bwd); + + /** + * @brief Handles the computation of the steady state, throws an + * AmiException, if no steady state was found + * @param solver pointer to the solver object + * @param newtonSolver pointer to the newtonSolver solver object + * @param model pointer to the model object + * @param it integer with the index of the current time step + */ + void findSteadyState(Solver *solver, + NewtonSolver *newtonSolver, + Model *model, int it); + + /** + * @brief Tries to determine the steady state by using Newton's method + * @param newtonSolver pointer to the newtonSolver solver object + * @param model pointer to the model object + * @param newton_retry bool flag indicating whether being relaunched + */ + void findSteadyStateByNewtonsMethod(NewtonSolver *newtonSolver, + Model *model, + bool newton_retry); + + /** + * @brief Tries to determine the steady state by using forward simulation + * @param solver pointer to the solver object + * @param model pointer to the model object + * @param it integer with the index of the current time step + */ + void findSteadyStateBySimulation(const Solver *solver, + Model *model, + int it); + + /** + * @brief Handles the computation of quadratures in adjoint mode + * @param newtonSolver pointer to the newtonSolver solver object + * @param solver pointer to the solver object + * @param model pointer to the model object + */ + void computeSteadyStateQuadrature(NewtonSolver *newtonSolver, + const Solver *solver, Model *model); + + /** + * @brief Computes the quadrature in steady state backward mode by + * solving the linear system defined by the backward Jacobian + * @param newtonSolver pointer to the newtonSolver solver object + * @param model pointer to the model object + */ + void getQuadratureByLinSolve(NewtonSolver *newtonSolver, Model *model); + + /** + * @brief Computes the quadrature in steady state backward mode by + * numerical integration of xB forward in time + * @param solver pointer to the solver object + * @param model pointer to the model object + */ + void getQuadratureBySimulation(const Solver *solver, Model *model); + + /** + * @brief Stores state and throws an exception if equilibration failed + * @param solver pointer to the solver object + * @param model pointer to the model object + */ + [[noreturn]] void handleSteadyStateFailure(const Solver *solver, + Model *model); + + /** + * @brief Assembles the error message to be thrown. + * @param errorString const pointer to string with error message + * @param status Entry of steady_state_staus to be processed + */ + void writeErrorString(std::string *errorString, SteadyStateStatus + status) const; + + /** + * @brief Checks depending on the status of the Newton solver, + * solver settings, and the model, whether state sensitivities + * still need to be computed via a linear system solve or stored + * @param model pointer to the model object + * @param solver pointer to the solver object + * @param it integer with the index of the current time step + * @param context SteadyStateContext giving the situation for the flag + * @return flag telling how to process state sensis + */ + bool getSensitivityFlag(const Model *model, const Solver *solver, int it, + SteadyStateContext context); /** - * Computes the weighted root mean square of xdot + * @brief Computes the weighted root mean square of xdot * the weights are computed according to x: * w_i = 1 / ( rtol * x_i + atol ) - * * @param x current state * @param xdot current rhs * @param atol absolute tolerance * @param rtol relative tolerance + * @param ewt error weight vector * @return root-mean-square norm */ realtype getWrmsNorm(AmiVector const &x, AmiVector const &xdot, realtype atol, - realtype rtol - ); + realtype rtol, + AmiVector &ewt) const; /** - * Checks convergence for state and respective sensitivities - * + * @brief Checks convergence for state and respective sensitivities * @param solver Solver instance * @param model instance + * @param checkSensitivities flag whether sensitivities should be checked * @return boolean indicating convergence */ - bool checkConvergence(const Solver *solver, - Model *model); + bool checkConvergence(const Solver *solver, Model *model, + SensitivityMethod checkSensitivities); /** - * Runs the Newton solver iterations and checks for convergence to steady - * state - * - * @param rdata pointer to the return data object - * @param model pointer to the AMICI model object + * @brief Runs the Newton solver iterations and checks for convergence + * to steady state + * @param model pointer to the model object * @param newtonSolver pointer to the NewtonSolver object @type * NewtonSolver - * @param steadystate_try start status of Newton solver + * @param newton_retry flag indicating if Newton solver is rerun */ - void applyNewtonsMethod(ReturnData *rdata, Model *model, - NewtonSolver *newtonSolver, - NewtonStatus steadystate_try); - /** - * Stores output of workSteadyStateProblem in return data - * - * @param newton_status integer flag indicating when a steady state was - * found - * @param run_time double coputation time of the solver in milliseconds - * @param rdata pointer to the return data instance - * @param model pointer to the model instance - * @param it current timepoint index, <0 indicates preequilibration - */ - void writeNewtonOutput(ReturnData *rdata, const Model *model, - NewtonStatus newton_status, double run_time, int it); + void applyNewtonsMethod(Model *model, NewtonSolver *newtonSolver, + bool newton_retry); /** - * Forward simulation is launched, if Newton solver fails in first try - * - * @param solver pointer to the AMICI solver object - * @param model pointer to the AMICI model object - * @param rdata pointer to the return data object + * @brief Simulation is launched, if Newton solver or linear system solve fails + * @param solver pointer to the solver object + * @param model pointer to the model object + * @param backward flag indicating adjoint mode (including quadrature) */ - void getSteadystateSimulation(ReturnData *rdata, Solver *solver, - Model *model); + void runSteadystateSimulation(const Solver *solver, Model *model, bool backward); /** - * initialize CVodeSolver instance for preequilibration simulation - * - * @param solver pointer to the AMICI solver object - * @param model pointer to the AMICI model object + * @brief Initialize CVodeSolver instance for preequilibration simulation + * @param solver pointer to the solver object + * @param model pointer to the model object + * @param forwardSensis flag switching on integration with FSA + * @param backward flag switching on quadratures computation * @return solver instance */ std::unique_ptr createSteadystateSimSolver(const Solver *solver, - Model *model) const; + Model *model, + bool forwardSensis, + bool backward) const; /** - * @brief constructor - * @param solver pointer to Solver instance - * @param x0 initial state + * @brief Initialize backward computation by setting state, time, adjoint + * state and checking for preequilibration mode + * @param solver pointer to the solver object + * @param model pointer to the model object + * @param bwd pointer to backward problem + * @return flag indicating whether backward computation to be carried out + */ + bool initializeBackwardProblem(Solver *solver, Model *model, + const BackwardProblem *bwd); + + /** + * @brief Compute the backward quadratures, which contribute to the + * gradient (xQB) from the quadrature over the backward state itself (xQ) + * @param model pointer to the model object + * @param yQ vector to be multiplied with dxdotdp + * @param yQB resulting vector after multiplication + */ + void computeQBfromQ(Model *model, const AmiVector &yQ, AmiVector &yQB) const; + + /** + * @brief Store carbon copy of current simulation state variables as SimulationState + * @param model model carrying the ModelState to be used + * @param storesensi flag to enable storage of sensitivities + */ + void storeSimulationState(Model *model, bool storesensi); + + /** + * @brief Returns the stored SimulationState + * @return stored SimulationState + */ + const SimulationState &getFinalSimulationState() const { + return state; + }; + + /** + * @brief Returns the quadratures from pre- or postequilibration + * @return xQB Vector with quadratures + */ + const AmiVector &getEquilibrationQuadratures() const { + return xQB; + } + /** + * @brief Returns state at steadystate + * @return x + */ + const AmiVector &getState() const { + return x; + }; + + + /** + * @brief Returns state sensitivity at steadystate + * @return sx + */ + const AmiVectorArray &getStateSensitivity() const { + return sx; + }; + + /** + * @brief Accessor for dJydx + * @return dJydx + */ + std::vector const& getDJydx() const { + return dJydx; + } + + /** + * @brief Accessor for run_time of the forward problem + * @return run_time + */ + double getCPUTime() const { return cpu_time; } + + /** + * @brief Accessor for run_time of the backward problem + * @return run_time + */ + double getCPUTimeB() const { return cpu_timeB; } + + /** + * @brief Accessor for steady_state_status + * @return steady_state_status + */ + std::vector const& getSteadyStateStatus() const + { return steady_state_status; } + + /** + * @brief Accessor for t + * @return t + */ + realtype getSteadyStateTime() const { return t; } + + /** + * @brief Accessor for wrms + * @return wrms + */ + realtype getResidualNorm() const { return wrms; } + + /** + * @brief Accessor for numsteps + * @return numsteps */ - explicit SteadystateProblem(const Solver *solver, const AmiVector &x0); - + const std::vector &getNumSteps() const { return numsteps; } + + /** + * @brief Accessor for numstepsB + * @return numstepsB + */ + const int getNumStepsB() const { return numstepsB; } + + /** + * @brief Accessor for numlinsteps + * @return numlinsteps + */ + const std::vector &getNumLinSteps() const { return numlinsteps; } + + /** + * @brief computes adjoint updates dJydx according to provided model and expdata + * @param model Model instance + * @param edata experimental data + */ + void getAdjointUpdates(Model &model, const ExpData &edata); + + /** + * @brief Accessor for xQB + * @return xQB + */ + AmiVector const& getAdjointQuadrature() const { return xQB; } + /** - * @brief routine that writes solutions of steadystate problem to target - vectors - * @param t final timepoint - * @param x steadystate state - * @param sx steadystate state sensitivity + * @brief Accessor for hasQuadrature_ + * @return hasQuadrature_ */ - void writeSolution(realtype *t, AmiVector &x, AmiVectorArray &sx) const; - + const bool hasQuadrature() const { return hasQuadrature_; } + + /** + * @brief computes adjoint updates dJydx according to provided model and expdata + * @return covergence of steady state solver + */ + bool checkSteadyStateSuccess() const; private: /** time variable for simulation steadystate finding */ realtype t; /** newton step */ AmiVector delta; - /** error weights */ - AmiVector ewt; + /** error weights for solver state, dimension nx_solver */ + AmiVector ewt_; + /** error weights for backward quadratures, dimension nplist() */ + AmiVector ewtQB_; /** container for relative error calcuation? */ AmiVector rel_x_newton; /** container for absolute error calcuation? */ @@ -142,10 +367,49 @@ class SteadystateProblem { AmiVectorArray sx; /** state differential sensitivities */ AmiVectorArray sdx; + /** adjoint state vector */ + AmiVector xB; + /** integral over adjoint state vector */ + AmiVector xQ; + /** quadrature state vector */ + AmiVector xQB; + /** quadrature state vector */ + AmiVector xQBdot; + + /** maximum number of steps for Newton solver for allocating numlinsteps */ + int maxSteps = 0; /** weighted root-mean-square error */ realtype wrms = NAN; + /** state derivative of data likelihood + * (dimension nJ x nx x nt, ordering =?) */ + std::vector dJydx; + + SimulationState state; + + /** stores diagnostic information about employed number of steps */ + std::vector numsteps = std::vector (3, 0); + + /** stores diagnostic information about employed number of linear steps */ + std::vector numlinsteps; + + /** stores information about employed number of backward steps */ + int numstepsB = 0; + + /** stores diagnostic information about runtime */ + double cpu_time = 0.0; + + /** stores diagnostic information about runtime backward */ + double cpu_timeB = 0.0; + + /** flag indicating whether backward mode was run */ + bool hasQuadrature_ = false; + + /** stores diagnostic information about execution success of the different + * approaches [newton, simulation, newton] (length = 3) + */ + std::vector steady_state_status; }; } // namespace amici diff --git a/deps/AMICI/include/amici/sundials_linsol_wrapper.h b/deps/AMICI/include/amici/sundials_linsol_wrapper.h index a80a8d79b..181cdafff 100644 --- a/deps/AMICI/include/amici/sundials_linsol_wrapper.h +++ b/deps/AMICI/include/amici/sundials_linsol_wrapper.h @@ -754,9 +754,10 @@ class SUNNonLinSolWrapper { /** * @brief Set function to test for convergence * @param CTestFn + * @param ctest_data * @return */ - int setConvTestFn(SUNNonlinSolConvTestFn CTestFn); + int setConvTestFn(SUNNonlinSolConvTestFn CTestFn, void* ctest_data); /** * @brief Set maximum number of non-linear iterations diff --git a/deps/AMICI/include/amici/sundials_matrix_wrapper.h b/deps/AMICI/include/amici/sundials_matrix_wrapper.h index 35fd16f63..3eceb4752 100644 --- a/deps/AMICI/include/amici/sundials_matrix_wrapper.h +++ b/deps/AMICI/include/amici/sundials_matrix_wrapper.h @@ -145,6 +145,12 @@ class SUNMatrixWrapper { */ void reset(); + /** + * @brief multiply with a scalar (in-place) + * @param a scalar value to multiply matrix + */ + void scale(realtype a); + /** * @brief N_Vector interface for multiply * @param c output vector, may already contain values @@ -198,14 +204,13 @@ class SUNMatrixWrapper { */ void zero(); + private: + void update_ptrs(); + /** * @brief CSC matrix to which all methods are applied */ SUNMatrix matrix = nullptr; - - private: - void update_ptrs(); - realtype *data_ptr = nullptr; sunindextype *indexptrs_ptr = nullptr; sunindextype *indexvals_ptr = nullptr; diff --git a/deps/AMICI/include/amici/vector.h b/deps/AMICI/include/amici/vector.h index 44a327f05..44a7b83ce 100644 --- a/deps/AMICI/include/amici/vector.h +++ b/deps/AMICI/include/amici/vector.h @@ -29,7 +29,7 @@ class AmiVector { * Using N_VMake_Serial ensures that the N_Vector * module does not try to deallocate the data vector * when calling N_VDestroy_Serial - * @brief emmpty constructor + * @brief empty constructor * @param length number of elements in vector */ explicit AmiVector(const long int length) @@ -45,6 +45,13 @@ class AmiVector { : vec(std::move(rvec)), nvec(N_VMake_Serial(static_cast(vec.size()), vec.data())) {} + /** Copy data from gsl::span and constructs a vector + * @brief constructor from gsl::span, + * @param rvec vector from which the data will be copied + */ + explicit AmiVector(gsl::span rvec) + : AmiVector(std::vector(rvec.begin(), rvec.end())) {} + /** * @brief copy constructor * @param vold vector from which the data will be copied @@ -89,7 +96,7 @@ class AmiVector { * @brief Vector accessor * @return Vector */ - std::vector const &getVector(); + std::vector const &getVector() const; /** * @brief returns the length of the vector diff --git a/deps/AMICI/matlab/@amidata/amidata.m b/deps/AMICI/matlab/@amidata/amidata.m index 3ccc65a30..b9be294d2 100644 --- a/deps/AMICI/matlab/@amidata/amidata.m +++ b/deps/AMICI/matlab/@amidata/amidata.m @@ -34,6 +34,8 @@ condition = double.empty(); % experimental condition for preequilibration conditionPreequilibration = double.empty(); + % reinitialize states based on fixed parameters after preeq.? + reinitializeStates = false; end methods @@ -121,6 +123,15 @@ assert(D.nk == numel(varargin{1}.conditionPreequilibration)); D.conditionPreequilibration = varargin{1}.conditionPreequilibration; end + if(isfield(varargin{1},'reinitializeStates')) + if islogical(varargin{1}.reinitializeStates) + D.reinitializeStates = varargin{1}.reinitializeStates; + elseif isnumeric(varargin{1}.reinitializeStates) + D.reinitializeStates = logical(varargin{1}.reinitializeStates); + else + error('Assignment error: Value for field reinitializeStates must be logical.'); + end + end elseif(nargin == 5) D.nt = varargin{1}; D.ny = varargin{2}; diff --git a/deps/AMICI/matlab/@amimodel/compileAndLinkModel.m b/deps/AMICI/matlab/@amimodel/compileAndLinkModel.m index 95c158a1b..6b84c4d8a 100644 --- a/deps/AMICI/matlab/@amimodel/compileAndLinkModel.m +++ b/deps/AMICI/matlab/@amimodel/compileAndLinkModel.m @@ -143,13 +143,24 @@ function compileAndLinkModel(modelname, modelSourceFolder, coptim, debug, funs, end end + % in case we compile python-generated code, there is a modelname.cpp + model_cpp = fullfile(modelSourceFolder, [modelname '.cpp']); + if(exist(model_cpp, 'file')) + model_cpp = ['"' model_cpp '" ']; + model_cpp_obj = [' "' fullfile(modelObjectFolder,[modelname objectFileSuffix]) '" ']; + else + model_cpp = ''; + model_cpp_obj = ''; + end + + % compile the wrapfunctions object fprintf('wrapfunctions | '); eval(['mex ' DEBUG COPT ... ' -c -outdir "' modelObjectFolder '" "' ... - fullfile(modelSourceFolder,'wrapfunctions.cpp') '" ' ... + fullfile(modelSourceFolder,'wrapfunctions.cpp') '" ' model_cpp ... includesstr]); - objectsstr = [objectsstr, ' "' fullfile(modelObjectFolder,['wrapfunctions' objectFileSuffix]) '"']; + objectsstr = [objectsstr, ' "' fullfile(modelObjectFolder,['wrapfunctions' objectFileSuffix]) '" ' model_cpp_obj]; % now we have compiled everything model-specific, so we can replace hashes.mat to prevent recompilation try diff --git a/deps/AMICI/matlab/@amimodel/generateC.m b/deps/AMICI/matlab/@amimodel/generateC.m index 3ef9cf1ce..38581515e 100644 --- a/deps/AMICI/matlab/@amimodel/generateC.m +++ b/deps/AMICI/matlab/@amimodel/generateC.m @@ -43,6 +43,8 @@ function generateC(this) fprintf(fid,'\n'); fprintf(fid,'using namespace amici;\n'); fprintf(fid,'\n'); + fprintf(fid,'namespace amici {\n\n'); + fprintf(fid,['namespace model_' this.modelname '{\n\n']); % function definition fprintf(fid,['void ' cppFunctionName '_' this.modelname '' this.fun.(ifun{1}).argstr ' {\n']); @@ -82,19 +84,28 @@ function generateC(this) end fprintf(fid,'}\n'); fprintf(fid,'\n'); + fprintf(fid,['} // namespace model_' this.modelname '\n\n']); + fprintf(fid,'} // namespace amici\n\n'); + fclose(fid); end end end +% wrapfunctions.h + fid = fopen(fullfile(this.wrap_path,'models',this.modelname,'wrapfunctions.h'),'w'); fprintf(fid,'#ifndef _amici_wrapfunctions_h\n'); fprintf(fid,'#define _amici_wrapfunctions_h\n'); fprintf(fid,'\n'); fprintf(fid,['#include "' this.modelname '.h"\n']); fprintf(fid,'\n'); +fprintf(fid,'namespace amici {\n\n'); +fprintf(fid,'namespace generic_model {\n\n'); fprintf(fid,'std::unique_ptr getModel();\n'); fprintf(fid,'\n'); +fprintf(fid,'} // namespace generic_model\n\n'); +fprintf(fid,'} // namespace amici \n\n'); fprintf(fid,'#endif /* _amici_wrapfunctions_h */\n'); fclose(fid); @@ -121,9 +132,9 @@ function generateC(this) fprintf(fid,'#include "amici/model_dae.h"\n'); end fprintf(fid,'\n'); -fprintf(fid,'namespace amici {\nclass Solver;\n}\n'); -fprintf(fid,'\n'); -fprintf(fid,'\n'); +fprintf(fid,'namespace amici {\n\n'); +fprintf(fid,'class Solver;\n\n'); +fprintf(fid,['namespace model_' this.modelname '{\n\n']); for ifun = this.funs if(~isfield(this.fun,ifun{1})) @@ -152,6 +163,7 @@ function generateC(this) fprintf(fid,[' ' num2str(this.nxtrue) ',\n']); fprintf(fid,[' ' num2str(this.nx) ',\n']); fprintf(fid,[' ' num2str(this.nxtrue) ',\n']); +fprintf(fid,[' 0,\n']); fprintf(fid,[' ' num2str(this.ny) ',\n']); fprintf(fid,[' ' num2str(this.nytrue) ',\n']); fprintf(fid,[' ' num2str(this.nz) ',\n']); @@ -194,17 +206,23 @@ function generateC(this) fprintf(fid,' }\n\n'); end fprintf(fid,'};\n\n'); - +fprintf(fid,['} // namespace model_' this.modelname '\n\n']); +fprintf(fid,'} // namespace amici \n\n'); fprintf(fid,['#endif /* _amici_' this.modelname '_h */\n']); fclose(fid); - +% wrapfunctions.cpp fid = fopen(fullfile(this.wrap_path,'models',this.modelname,'wrapfunctions.cpp'),'w'); fprintf(fid,'#include "amici/model.h"\n'); fprintf(fid,'#include "wrapfunctions.h"\n\n'); +fprintf(fid,'namespace amici {\n\n'); +fprintf(fid,'namespace generic_model {\n\n'); fprintf(fid,'std::unique_ptr getModel() {\n'); -fprintf(fid, [' return std::unique_ptr(new Model_' this.modelname '());\n']); +fprintf(fid,' return std::unique_ptr(\n'); +fprintf(fid,[' new amici::model_' this.modelname '::Model_' this.modelname '());\n']); fprintf(fid,'}\n\n'); +fprintf(fid,'} // namespace generic_model\n\n'); +fprintf(fid,'} // namespace amici \n\n'); fclose(fid); fprintf('CMakeLists | '); diff --git a/deps/AMICI/matlab/@amioption/amioption.m b/deps/AMICI/matlab/@amioption/amioption.m index 474ce265c..6945ba4ea 100644 --- a/deps/AMICI/matlab/@amioption/amioption.m +++ b/deps/AMICI/matlab/@amioption/amioption.m @@ -41,6 +41,8 @@ ism = 1; % sensitivity method sensi_meth = 1; + % sensitivity method for preequilibration + sensi_meth_preeq = 1; % sensitivity order sensi = 0; % number of reported events @@ -67,6 +69,8 @@ % unscaled parameters p. % Use [] for default as specified in the model (fallback: 'lin'). pscale = []; + % Mode for for computing sensitivities ({0: Newton}, 1: Simulation) + steadyStateSensitivityMode = 0; end methods diff --git a/deps/AMICI/matlab/auxiliary/compileAMICIDependencies.m b/deps/AMICI/matlab/auxiliary/compileAMICIDependencies.m index d20285ed0..1292336e1 100644 --- a/deps/AMICI/matlab/auxiliary/compileAMICIDependencies.m +++ b/deps/AMICI/matlab/auxiliary/compileAMICIDependencies.m @@ -2,10 +2,10 @@ %COMPILEAMICIDEPENDENCIES Compiles Sundials and SuiteSparse libraries required by AMICI sundials_path = fullfile(dependencyPath,'sundials'); - sundials_ver = '4.0.2'; + sundials_ver = '5.2.0'; ssparse_path = fullfile(dependencyPath,'SuiteSparse'); - ssparse_ver = '4.5.3'; + ssparse_ver = '5.4.0'; lapack_path = fullfile(dependencyPath,'lapack-3.5.0'); % currently not used, lapack implementation still needs to be done lapack_ver = '3.5.0'; @@ -135,19 +135,12 @@ fullfile('src', 'idas', 'idas_nls_sim.c'); fullfile('src', 'idas', 'idaa_io.c'); fullfile('src', 'sundials', 'sundials_math.c'); - fullfile('src', 'sundials', 'sundials_mpi.c'); - fullfile('src', 'sundials', 'sundials_sptfqmr.c'); fullfile('src', 'sundials', 'sundials_matrix.c'); - fullfile('src', 'sundials', 'sundials_pcg.c'); fullfile('src', 'sundials', 'sundials_direct.c'); - fullfile('src', 'sundials', 'sundials_spgmr.c'); - fullfile('src', 'sundials', 'sundials_spbcgs.c'); fullfile('src', 'sundials', 'sundials_nvector_senswrapper.c'); fullfile('src', 'sundials', 'sundials_dense.c'); fullfile('src', 'sundials', 'sundials_nvector.c'); fullfile('src', 'sundials', 'sundials_version.c'); - fullfile('src', 'sundials', 'sundials_spfgmr.c'); - fullfile('src', 'sundials', 'sundials_sparse.c'); fullfile('src', 'sundials', 'sundials_iterative.c'); fullfile('src', 'sundials', 'sundials_nonlinearsolver.c'); fullfile('src', 'sundials', 'sundials_linearsolver.c'); @@ -279,33 +272,26 @@ 'idas_nls_sim.o'; 'idaa_io.o'; 'sundials_math.o'; - 'sundials_mpi.o'; - 'sundials_sptfqmr.o'; 'sundials_matrix.o'; - 'sundials_pcg.o'; 'sundials_direct.o'; - 'sundials_spgmr.o'; - 'sundials_spbcgs.o'; 'sundials_nvector_senswrapper.o'; 'sundials_dense.o'; 'sundials_nvector.o'; 'sundials_version.o'; - 'sundials_spfgmr.o'; - 'sundials_sparse.o'; 'sundials_iterative.o'; 'sundials_nonlinearsolver.o'; 'sundials_linearsolver.o'; 'sundials_band.o'; - 'sunlinsol_dense.o'; 'sunmatrix_band.o'; - 'sunlinsol_spfgmr.o'; + 'sunmatrix_sparse.o'; 'sunnonlinsol_newton.o'; 'sunnonlinsol_fixedpoint.o'; - 'sunmatrix_sparse.o'; 'nvector_serial.o'; 'sunlinsol_pcg.o'; + 'sunlinsol_dense.o'; 'sunlinsol_spbcgs.o'; 'sunlinsol_band.o'; + 'sunlinsol_spfgmr.o'; 'cvodes_spils.o'; 'cvodes_nls_stg.o'; 'cvodes_ls.o'; diff --git a/deps/AMICI/matlab/examples/example_steadystate/example_steadystate.m b/deps/AMICI/matlab/examples/example_steadystate/example_steadystate.m index e0ce88b5a..118b1f5cf 100644 --- a/deps/AMICI/matlab/examples/example_steadystate/example_steadystate.m +++ b/deps/AMICI/matlab/examples/example_steadystate/example_steadystate.m @@ -219,7 +219,7 @@ subplot(1,3,3); hold on; - bar(sol_newton_fail.diagnosis.newton_numsteps([1, 3])); + bar(sol_newton_fail.diagnosis.posteq_numsteps([1, 3])); legend boxoff; title('Number of Newton steps'); xlabel('Solver run'); diff --git a/deps/AMICI/matlab/mtoc/config/customdoxygen.css b/deps/AMICI/matlab/mtoc/config/customdoxygen.css index 6a24a8c7d..685cdb5d0 100644 --- a/deps/AMICI/matlab/mtoc/config/customdoxygen.css +++ b/deps/AMICI/matlab/mtoc/config/customdoxygen.css @@ -158,7 +158,6 @@ pre.fragment { margin: 4px 8px 4px 2px; overflow: auto; word-wrap: break-word; - font-size: 9pt; line-height: 125%; font-family: monospace, fixed; font-size: 105%; @@ -234,7 +233,7 @@ div.ah, span.ah { -webkit-box-shadow: 2px 2px 3px #999; -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); - background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); + background-image: -moz-linear-gradient(top, #eee 0%, #444 40%, #000); } div.classindex ul { @@ -565,7 +564,6 @@ table.memberdecls { border-left: 1px solid #A8B8D9; border-right: 1px solid #A8B8D9; padding: 6px 10px 2px 10px; - background-color: #FBFCFD; border-top-width: 0; background-image:url('nav_g.png'); background-repeat:repeat-x; @@ -750,7 +748,7 @@ div.directory { } .icon { - font-family: Arial, Helvetica; + font-family: Arial, Helvetica, sans-serif; font-weight: bold; font-size: 12px; height: 14px; @@ -948,7 +946,6 @@ table.fieldtable { { height:32px; display:block; - text-decoration: none; outline: none; color: #283A5D; font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; @@ -1451,7 +1448,6 @@ tr.heading h2 { } div.header { - background-color: #343131; background-image: none; border-bottom: none; background-color: #FFFFFF; diff --git a/deps/AMICI/matlab/tests/testModels.m b/deps/AMICI/matlab/tests/testModels.m index 3c431b602..a0e3516a9 100644 --- a/deps/AMICI/matlab/tests/testModels.m +++ b/deps/AMICI/matlab/tests/testModels.m @@ -11,11 +11,13 @@ function testModels() '/model_jakstat_adjoint/sensiforwardemptysensind'}; cd(fileparts(mfilename('fullpath'))) - addpath(genpath('cpputest')); - wrapTestModels() + addpath(genpath('../../tests/cpputest')); + addpath(genpath('../examples')); + % wrapTestModels() cd(fileparts(mfilename('fullpath'))) - hdf5file = fullfile(fileparts(mfilename('fullpath')),'cpputest','expectedResults.h5'); + hdf5file = fullfile(fileparts(mfilename('fullpath')), ... + '../../tests/cpputest', 'expectedResults.h5'); info = h5info(hdf5file); for imodel = 1:length(info.Groups) @@ -48,6 +50,12 @@ function testModels() options = rmfield(options,'kappa'); t = options.ts; options = rmfield(options,'ts'); + if isempty(options.newton_preeq) + options.newton_preeq = false; + end + if(isfield(options, 'sx0')) + options.sx0 = transpose(options.sx0); + end ami_options = amioption(options); if(~isempty(data)) ami_data = amidata(data); @@ -66,7 +74,7 @@ function compareResults(sol,results) for ifield = transpose(fieldnames(sol)) if(strcmp(ifield{1},'diagnosis')) for jfield = transpose(fieldnames(sol.diagnosis)) - if(~ismember(jfield{1},{'newton_cpu_time'})) + if(ismember(jfield{1},{'xdot', 'J'})) checkAgreement(sol.diagnosis,results.diagnosis,jfield{1},0,1); end end @@ -94,7 +102,11 @@ function checkAgreement(sol,results,fieldname,atol,rtol) return end expected = results.(fieldname); - actual = sol.(fieldname); + if strcmp(fieldname, 'sx0') + actual = transpose(sol.(fieldname)); + else + actual = sol.(fieldname); + end if(nargin<4) atol = model_atol; end @@ -111,11 +123,15 @@ function checkAgreement(sol,results,fieldname,atol,rtol) assert(all(isinf(actual)==isinf(expected))); actual = actual(~isinf(actual)); expected = expected(~isinf(actual)); - assert(all(abs(expected - actual) <= atol) || all(abs((expected - actual) ./ (rtol + abs(expected))) <= rtol)); + try + assert(all(abs(expected - actual) <= atol) || all(abs((expected - actual) ./ (rtol + abs(expected))) <= rtol)); + catch + warning(['The assertion for field ' fieldname ' failed!']); + end end end - function [results,options,data,t,theta,kappa] = readDataFromHDF5(groups,hdf5file); + function [results,options,data,t,theta,kappa] = readDataFromHDF5(groups,hdf5file) data = []; t = []; theta = []; @@ -130,11 +146,11 @@ function checkAgreement(sol,results,fieldname,atol,rtol) options.sens_ind = options.sens_ind + 1; end if(~isempty(data)) - if(length(data.t)~=size(data.Y,1)) % no idea why this goes wrong only _sometimes_ + if(length(data.ts)~=size(data.Y,1)) % no idea why this goes wrong only _sometimes_ data.Y = transpose(data.Y); data.Sigma_Y = transpose(data.Sigma_Y); end - if(size(data.Z,2)>0) % don't ask ... + if(isfield(data, 'Z') && size(data.Z,2) > 0) % don't ask ... data.Z = transpose(data.Z); data.Sigma_Z = transpose(data.Sigma_Z); end diff --git a/deps/AMICI/models/model_calvetti/CMakeLists.txt b/deps/AMICI/models/model_calvetti/CMakeLists.txt index 20718b82e..e40f1e5ae 100644 --- a/deps/AMICI/models/model_calvetti/CMakeLists.txt +++ b/deps/AMICI/models/model_calvetti/CMakeLists.txt @@ -6,6 +6,10 @@ endif(POLICY CMP0060) if(POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif(POLICY CMP0065) +if(POLICY CMP0074) + # Use package_ROOT environment variables + cmake_policy(SET CMP0074 NEW) +endif(POLICY CMP0074) project(model_calvetti) @@ -52,6 +56,13 @@ ${MODEL_DIR}/wrapfunctions.cpp add_library(${PROJECT_NAME} ${SRC_LIST_LIB}) add_library(model ALIAS ${PROJECT_NAME}) +# This option can be helpful when using the Intel compiler and compilation of +# wrapfunctions.cpp fails due to insufficient memory. +option(ENABLE_WRAPFUNCTIONS_OPTIMIZATIONS "Enable compiler optimizations for wrapfunctions.cpp?" ON) +if(NOT ENABLE_WRAPFUNCTIONS_OPTIMIZATIONS) + set_source_files_properties(wrapfunctions.cpp PROPERTIES COMPILE_FLAGS -O0) +endif() + target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") target_link_libraries(${PROJECT_NAME} diff --git a/deps/AMICI/models/model_calvetti/main.cpp b/deps/AMICI/models/model_calvetti/main.cpp index 6d6caf54a..f957df9ad 100644 --- a/deps/AMICI/models/model_calvetti/main.cpp +++ b/deps/AMICI/models/model_calvetti/main.cpp @@ -10,8 +10,7 @@ #include "wrapfunctions.h" /* model-provided functions */ /* This is a scaffold for a stand-alone AMICI simulation executable - * demonstrating - * use of the AMICI C++ API. + * demonstrating the use of the AMICI C++ API. * * This program reads AMICI options from an HDF5 file, prints some results * and writes additional results to an HDF5 file. The name of the HDF5 file @@ -55,7 +54,7 @@ int main(int argc, char **argv) { hdffile = argv[1]; } - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); // Read AMICI settings and model parameters from HDF5 file diff --git a/deps/AMICI/models/model_calvetti/model_calvetti.h b/deps/AMICI/models/model_calvetti/model_calvetti.h index bffbd0ffd..17bc9d27c 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti.h +++ b/deps/AMICI/models/model_calvetti/model_calvetti.h @@ -1,6 +1,6 @@ #ifndef _amici_model_calvetti_h #define _amici_model_calvetti_h -/* Generated by amiwrap (R2017b) 5afd3fccf92ca20486e1bbaa4a50343b107e239c */ +/* Generated by amiwrap (R2017b) 667c9f20a05dd5266e9453b50081d7fb933f7389 */ #include #include #include "amici/defines.h" @@ -9,9 +9,10 @@ #include "amici/model_dae.h" namespace amici { + class Solver; -} +namespace model_model_calvetti{ extern void J_model_calvetti(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx); extern void JB_model_calvetti(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *xB, const realtype *dx, const realtype *dxB, const realtype *w, const realtype *dwdx); @@ -37,6 +38,7 @@ class Model_model_calvetti : public amici::Model_DAE { 6, 6, 6, + 0, 6, 6, 0, @@ -61,7 +63,7 @@ class Model_model_calvetti : public amici::Model_DAE { virtual amici::Model* clone() const override { return new Model_model_calvetti(*this); }; - const std::string getAmiciCommit() const override { return "5afd3fccf92ca20486e1bbaa4a50343b107e239c"; }; + const std::string getAmiciCommit() const override { return "667c9f20a05dd5266e9453b50081d7fb933f7389"; }; virtual void fJ(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) override { J_model_calvetti(J, t, x, p, k, h, cj, dx, w, dwdx); @@ -211,4 +213,8 @@ class Model_model_calvetti : public amici::Model_DAE { }; +} // namespace model_model_calvetti + +} // namespace amici + #endif /* _amici_model_calvetti_h */ diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_J.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_J.cpp index 0d3a72f80..4982911f3 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_J.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_J.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void J_model_calvetti(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) { J[0+0*6] = -cj-w[0]*(1.0E2/8.99E2)+dwdx[6]; J[0+1*6] = dwdx[16]; @@ -35,3 +39,7 @@ void J_model_calvetti(realtype *J, const realtype t, const realtype *x, const do J[5+5*6] = -dwdx[52]-1.0; } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_JB.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_JB.cpp index 5642bc792..21ce727f7 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_JB.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_JB.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void JB_model_calvetti(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *xB, const realtype *dx, const realtype *dxB, const realtype *w, const realtype *dwdx) { JB[0+0*6] = cj+w[0]*(1.0E2/8.99E2)-dwdx[6]; JB[0+3*6] = w[0]*(-1.0E2/8.99E2)+dwdx[6]-dwdx[7]*(w[23]*w[24]*2.0-w[20]*w[23]*w[24])+w[23]*w[24]*w[25]*dwdx[4]; @@ -35,3 +39,7 @@ void JB_model_calvetti(realtype *JB, const realtype t, const realtype *x, const JB[5+5*6] = dwdx[52]+1.0; } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_JDiag.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_JDiag.cpp index 6a1cf9cd5..126d11dd5 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_JDiag.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_JDiag.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void JDiag_model_calvetti(realtype *JDiag, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) { JDiag[0+0*6] = -cj-w[0]*(1.0E2/8.99E2)+dwdx[6]; JDiag[1+0*6] = -cj-w[6]*1.202935161794779E-2+dwdx[19]; @@ -15,3 +19,7 @@ void JDiag_model_calvetti(realtype *JDiag, const realtype t, const realtype *x, JDiag[5+0*6] = -dwdx[52]-1.0; } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_JSparse.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_JSparse.cpp index 053841de0..843a93ef3 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_JSparse.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_JSparse.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void JSparse_model_calvetti(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) { JSparse->indexvals[0] = 0; JSparse->indexvals[1] = 3; @@ -69,3 +73,7 @@ void JSparse_model_calvetti(SUNMatrixContent_Sparse JSparse, const realtype t, c JSparse->data[25] = -dwdx[52]-1.0; } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_JSparseB.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_JSparseB.cpp index 15769a394..446c49e82 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_JSparseB.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_JSparseB.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void JSparseB_model_calvetti(SUNMatrixContent_Sparse JSparseB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *xB, const realtype *dx, const realtype *dxB, const realtype *w, const realtype *dwdx) { JSparseB->indexvals[0] = 0; JSparseB->indexvals[1] = 1; @@ -69,3 +73,7 @@ void JSparseB_model_calvetti(SUNMatrixContent_Sparse JSparseB, const realtype t, JSparseB->data[25] = dwdx[52]+1.0; } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_Jy.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_Jy.cpp index 7a758ba5b..b4507d41e 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_Jy.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_Jy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void Jy_model_calvetti(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -29,3 +33,7 @@ switch(iy){ } } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_M.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_M.cpp index 314fa486b..32bfd132d 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_M.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_M.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void M_model_calvetti(realtype *M, const realtype t, const realtype *x, const realtype *p, const realtype *k) { M[0+0*6] = 1.0; M[1+1*6] = 1.0; M[2+2*6] = 1.0; } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_dJydsigma.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_dJydsigma.cpp index f69094f7e..08aa3f3ac 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_dJydsigma.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_dJydsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void dJydsigma_model_calvetti(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -29,3 +33,7 @@ switch(iy){ } } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_dJydy.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_dJydy.cpp index d69b3d988..16187c180 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_dJydy.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_dJydy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void dJydy_model_calvetti(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -29,3 +33,7 @@ switch(iy){ } } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_dwdx.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_dwdx.cpp index db1e8c82f..f52276f40 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_dwdx.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_dwdx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void dwdx_model_calvetti(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) { dwdx[0] = 1.0/(x[0]*x[0]*x[0])*-2.0; dwdx[1] = k[1]*w[15]*dwdx[0]; @@ -62,3 +66,7 @@ void dwdx_model_calvetti(realtype *dwdx, const realtype t, const realtype *x, co dwdx[52] = x[2]*w[11]*w[32]*w[33]*w[36]*dwdx[51]*(1.0/6.1E1); } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_dydx.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_dydx.cpp index 2918eff3d..d6872b7ad 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_dydx.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_dydx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void dydx_model_calvetti(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { dydx[0+0*6] = 1.0; dydx[1+1*6] = 1.0; @@ -20,3 +24,7 @@ void dydx_model_calvetti(double *dydx, const realtype t, const realtype *x, cons dydx[5+4*6] = 1.0; } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_root.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_root.cpp index d7db388c6..8fda25149 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_root.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_root.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void root_model_calvetti(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx) { root[0] = -t+1.0E1; root[1] = -t+1.2E1; @@ -13,3 +17,7 @@ void root_model_calvetti(realtype *root, const realtype t, const realtype *x, co root[3] = t-1.2E1; } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_sigmay.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_sigmay.cpp index dfd7cca3b..a970a9b28 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_sigmay.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_sigmay.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void sigmay_model_calvetti(double *sigmay, const realtype t, const realtype *p, const realtype *k) { sigmay[0] = 1.0; sigmay[1] = 1.0; @@ -15,3 +19,7 @@ void sigmay_model_calvetti(double *sigmay, const realtype t, const realtype *p, sigmay[5] = 1.0; } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_w.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_w.cpp index 9ecb4c3d4..771f36799 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_w.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_w.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void w_model_calvetti(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) { w[0] = 1.0/k[0]; w[1] = k[2]*k[2]; @@ -47,3 +51,7 @@ void w_model_calvetti(realtype *w, const realtype t, const realtype *x, const re w[37] = x[2]*w[11]*w[32]*w[33]*w[34]*w[36]*(1.0/6.1E1); } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_x0.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_x0.cpp index 1d405146b..b021d43f2 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_x0.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_x0.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void x0_model_calvetti(realtype *x0, const realtype t, const realtype *p, const realtype *k) { x0[0] = k[0]; x0[1] = k[2]; @@ -15,3 +19,7 @@ void x0_model_calvetti(realtype *x0, const realtype t, const realtype *p, const x0[5] = 1.0; } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_xdot.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_xdot.cpp index 5ced5c757..1ac7f42e9 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_xdot.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_xdot.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void xdot_model_calvetti(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx, const realtype *w) { xdot[0] = h[0]*(-1.0/3.1E1)+w[12]+w[22]-dx[0]-w[0]*x[0]*(1.0E2/8.99E2)+1.29E2/8.99E2; xdot[1] = w[30]-dx[1]-x[1]*w[6]*1.202935161794779E-2+1.816432094310117E-2; @@ -15,3 +19,7 @@ void xdot_model_calvetti(realtype *xdot, const realtype t, const realtype *x, co xdot[5] = x[4]-x[5]-w[37]+x[2]*w[31]*8.196729508204918E-9-8.196729508204918E-3; } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/model_calvetti_y.cpp b/deps/AMICI/models/model_calvetti/model_calvetti_y.cpp index b7dd0c135..af549ee25 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti_y.cpp +++ b/deps/AMICI/models/model_calvetti/model_calvetti_y.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_calvetti{ + void y_model_calvetti(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { y[0] = x[0]; y[1] = x[1]; @@ -15,3 +19,7 @@ void y_model_calvetti(double *y, const realtype t, const realtype *x, const real y[5] = x[4]; } +} // namespace model_model_calvetti + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/wrapfunctions.cpp b/deps/AMICI/models/model_calvetti/wrapfunctions.cpp index d78ca43b7..176465708 100644 --- a/deps/AMICI/models/model_calvetti/wrapfunctions.cpp +++ b/deps/AMICI/models/model_calvetti/wrapfunctions.cpp @@ -1,7 +1,16 @@ #include "amici/model.h" #include "wrapfunctions.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel() { - return std::unique_ptr(new Model_model_calvetti()); + return std::unique_ptr( + new amici::model_model_calvetti::Model_model_calvetti()); } +} // namespace generic_model + +} // namespace amici + diff --git a/deps/AMICI/models/model_calvetti/wrapfunctions.h b/deps/AMICI/models/model_calvetti/wrapfunctions.h index dbd0a7e78..c7bbb2504 100644 --- a/deps/AMICI/models/model_calvetti/wrapfunctions.h +++ b/deps/AMICI/models/model_calvetti/wrapfunctions.h @@ -3,6 +3,14 @@ #include "model_calvetti.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel(); +} // namespace generic_model + +} // namespace amici + #endif /* _amici_wrapfunctions_h */ diff --git a/deps/AMICI/models/model_dirac/CMakeLists.txt b/deps/AMICI/models/model_dirac/CMakeLists.txt index d0b6d8781..83ff4682d 100644 --- a/deps/AMICI/models/model_dirac/CMakeLists.txt +++ b/deps/AMICI/models/model_dirac/CMakeLists.txt @@ -6,6 +6,10 @@ endif(POLICY CMP0060) if(POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif(POLICY CMP0065) +if(POLICY CMP0074) + # Use package_ROOT environment variables + cmake_policy(SET CMP0074 NEW) +endif(POLICY CMP0074) project(model_dirac) diff --git a/deps/AMICI/models/model_dirac/main.cpp b/deps/AMICI/models/model_dirac/main.cpp index 07ff62a32..f957df9ad 100644 --- a/deps/AMICI/models/model_dirac/main.cpp +++ b/deps/AMICI/models/model_dirac/main.cpp @@ -54,7 +54,7 @@ int main(int argc, char **argv) { hdffile = argv[1]; } - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); // Read AMICI settings and model parameters from HDF5 file diff --git a/deps/AMICI/models/model_dirac/model_dirac.h b/deps/AMICI/models/model_dirac/model_dirac.h index 389dce41c..ba82dfd75 100644 --- a/deps/AMICI/models/model_dirac/model_dirac.h +++ b/deps/AMICI/models/model_dirac/model_dirac.h @@ -1,6 +1,6 @@ #ifndef _amici_model_dirac_h #define _amici_model_dirac_h -/* Generated by amiwrap (R2017b) 5193a397de39f5bd4b7d98718067dc71f02f916e */ +/* Generated by amiwrap (R2017b) 667c9f20a05dd5266e9453b50081d7fb933f7389 */ #include #include #include "amici/defines.h" @@ -9,9 +9,10 @@ #include "amici/model_ode.h" namespace amici { + class Solver; -} +namespace model_model_dirac{ extern void J_model_dirac(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void JB_model_dirac(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx); @@ -37,6 +38,7 @@ class Model_model_dirac : public amici::Model_ODE { 2, 2, 2, + 0, 1, 1, 0, @@ -61,7 +63,7 @@ class Model_model_dirac : public amici::Model_ODE { virtual amici::Model* clone() const override { return new Model_model_dirac(*this); }; - const std::string getAmiciCommit() const override { return "5193a397de39f5bd4b7d98718067dc71f02f916e"; }; + const std::string getAmiciCommit() const override { return "667c9f20a05dd5266e9453b50081d7fb933f7389"; }; virtual void fJ(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) override { J_model_dirac(J, t, x, p, k, h, w, dwdx); @@ -208,4 +210,8 @@ class Model_model_dirac : public amici::Model_ODE { }; +} // namespace model_model_dirac + +} // namespace amici + #endif /* _amici_model_dirac_h */ diff --git a/deps/AMICI/models/model_dirac/model_dirac_J.cpp b/deps/AMICI/models/model_dirac/model_dirac_J.cpp index d5bdab760..b304f9a16 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_J.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_J.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void J_model_dirac(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) { J[0+0*2] = -p[0]; J[1+0*2] = p[2]; J[1+1*2] = -p[3]; } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_JB.cpp b/deps/AMICI/models/model_dirac/model_dirac_JB.cpp index 5e31039c1..9eac55cf2 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_JB.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_JB.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void JB_model_dirac(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JB[0+0*2] = p[0]; JB[0+1*2] = -p[2]; JB[1+1*2] = p[3]; } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_JDiag.cpp b/deps/AMICI/models/model_dirac/model_dirac_JDiag.cpp index 6eec4676a..692dee0b3 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_JDiag.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_JDiag.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void JDiag_model_dirac(realtype *JDiag, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JDiag[0+0*2] = -p[0]; JDiag[1+0*2] = -p[3]; } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_JSparse.cpp b/deps/AMICI/models/model_dirac/model_dirac_JSparse.cpp index bd06c2f1e..7671ba143 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_JSparse.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_JSparse.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void JSparse_model_dirac(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JSparse->indexvals[0] = 0; JSparse->indexvals[1] = 1; @@ -19,3 +23,7 @@ void JSparse_model_dirac(SUNMatrixContent_Sparse JSparse, const realtype t, cons JSparse->data[2] = -p[3]; } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_JSparseB.cpp b/deps/AMICI/models/model_dirac/model_dirac_JSparseB.cpp index e5fa23083..3002e766f 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_JSparseB.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_JSparseB.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void JSparseB_model_dirac(SUNMatrixContent_Sparse JSparseB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JSparseB->indexvals[0] = 0; JSparseB->indexvals[1] = 0; @@ -19,3 +23,7 @@ void JSparseB_model_dirac(SUNMatrixContent_Sparse JSparseB, const realtype t, co JSparseB->data[2] = p[3]; } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_Jy.cpp b/deps/AMICI/models/model_dirac/model_dirac_Jy.cpp index a3a5d61e6..228ea6bb2 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_Jy.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_Jy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void Jy_model_dirac(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -14,3 +18,7 @@ switch(iy){ } } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_dJydsigma.cpp b/deps/AMICI/models/model_dirac/model_dirac_dJydsigma.cpp index 06bf85735..540bcc832 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_dJydsigma.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_dJydsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void dJydsigma_model_dirac(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -14,3 +18,7 @@ switch(iy){ } } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_dJydy.cpp b/deps/AMICI/models/model_dirac/model_dirac_dJydy.cpp index d01a4315a..86ab371f7 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_dJydy.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_dJydy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void dJydy_model_dirac(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -14,3 +18,7 @@ switch(iy){ } } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_deltasx.cpp b/deps/AMICI/models/model_dirac/model_dirac_deltasx.cpp index c4c2fd1ba..12b79f937 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_deltasx.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_deltasx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void deltasx_model_dirac(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) { switch (ip) { case 0: { @@ -83,3 +87,7 @@ switch (ip) { } } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_deltax.cpp b/deps/AMICI/models/model_dirac/model_dirac_deltax.cpp index 545280612..5deddc7e4 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_deltax.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_deltax.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void deltax_model_dirac(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) { switch(ie) { case 0: { @@ -21,3 +25,7 @@ void deltax_model_dirac(double *deltax, const realtype t, const realtype *x, con } } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_dxdotdp.cpp b/deps/AMICI/models/model_dirac/model_dirac_dxdotdp.cpp index 8254c3683..fb3a1380a 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_dxdotdp.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_dxdotdp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void dxdotdp_model_dirac(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) { switch (ip) { case 0: { @@ -26,3 +30,7 @@ switch (ip) { } } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_dydx.cpp b/deps/AMICI/models/model_dirac/model_dirac_dydx.cpp index 012dbfabd..18a73e367 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_dydx.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_dydx.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void dydx_model_dirac(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { dydx[0+1*1] = 1.0; } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_root.cpp b/deps/AMICI/models/model_dirac/model_dirac_root.cpp index b0bb89f93..a54473970 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_root.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_root.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void root_model_dirac(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { root[0] = -t+p[1]; root[1] = t-p[1]; } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_sigmay.cpp b/deps/AMICI/models/model_dirac/model_dirac_sigmay.cpp index d56a4717a..97538bff2 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_sigmay.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_sigmay.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void sigmay_model_dirac(double *sigmay, const realtype t, const realtype *p, const realtype *k) { sigmay[0] = 1.0; } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_stau.cpp b/deps/AMICI/models/model_dirac/model_dirac_stau.cpp index 27dd2eeb5..24fb6db81 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_stau.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_stau.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void stau_model_dirac(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) { switch (ip) { case 1: { @@ -27,3 +31,7 @@ switch (ip) { } } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_xdot.cpp b/deps/AMICI/models/model_dirac/model_dirac_xdot.cpp index d874bd04e..2a97a2d20 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_xdot.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_xdot.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void xdot_model_dirac(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { xdot[0] = -p[0]*x[0]; xdot[1] = p[2]*x[0]-p[3]*x[1]; } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/model_dirac_y.cpp b/deps/AMICI/models/model_dirac/model_dirac_y.cpp index 9e9ee50f2..c24eb7723 100644 --- a/deps/AMICI/models/model_dirac/model_dirac_y.cpp +++ b/deps/AMICI/models/model_dirac/model_dirac_y.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_dirac{ + void y_model_dirac(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { y[0] = x[1]; } +} // namespace model_model_dirac + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/wrapfunctions.cpp b/deps/AMICI/models/model_dirac/wrapfunctions.cpp index b5f6e7c56..b420ef18c 100644 --- a/deps/AMICI/models/model_dirac/wrapfunctions.cpp +++ b/deps/AMICI/models/model_dirac/wrapfunctions.cpp @@ -1,7 +1,16 @@ #include "amici/model.h" #include "wrapfunctions.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel() { - return std::unique_ptr(new Model_model_dirac()); + return std::unique_ptr( + new amici::model_model_dirac::Model_model_dirac()); } +} // namespace generic_model + +} // namespace amici + diff --git a/deps/AMICI/models/model_dirac/wrapfunctions.h b/deps/AMICI/models/model_dirac/wrapfunctions.h index 89a084444..b3bc99a58 100644 --- a/deps/AMICI/models/model_dirac/wrapfunctions.h +++ b/deps/AMICI/models/model_dirac/wrapfunctions.h @@ -3,6 +3,14 @@ #include "model_dirac.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel(); +} // namespace generic_model + +} // namespace amici + #endif /* _amici_wrapfunctions_h */ diff --git a/deps/AMICI/models/model_events/CMakeLists.txt b/deps/AMICI/models/model_events/CMakeLists.txt index d28423efe..067f9f0a9 100644 --- a/deps/AMICI/models/model_events/CMakeLists.txt +++ b/deps/AMICI/models/model_events/CMakeLists.txt @@ -6,6 +6,10 @@ endif(POLICY CMP0060) if(POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif(POLICY CMP0065) +if(POLICY CMP0074) + # Use package_ROOT environment variables + cmake_policy(SET CMP0074 NEW) +endif(POLICY CMP0074) project(model_events) diff --git a/deps/AMICI/models/model_events/main.cpp b/deps/AMICI/models/model_events/main.cpp index 07ff62a32..f957df9ad 100644 --- a/deps/AMICI/models/model_events/main.cpp +++ b/deps/AMICI/models/model_events/main.cpp @@ -54,7 +54,7 @@ int main(int argc, char **argv) { hdffile = argv[1]; } - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); // Read AMICI settings and model parameters from HDF5 file diff --git a/deps/AMICI/models/model_events/model_events.h b/deps/AMICI/models/model_events/model_events.h index f3d592eb5..763f7ad70 100644 --- a/deps/AMICI/models/model_events/model_events.h +++ b/deps/AMICI/models/model_events/model_events.h @@ -1,6 +1,6 @@ #ifndef _amici_model_events_h #define _amici_model_events_h -/* Generated by amiwrap (R2017b) 5193a397de39f5bd4b7d98718067dc71f02f916e */ +/* Generated by amiwrap (R2017b) 667c9f20a05dd5266e9453b50081d7fb933f7389 */ #include #include #include "amici/defines.h" @@ -9,9 +9,10 @@ #include "amici/model_ode.h" namespace amici { + class Solver; -} +namespace model_model_events{ extern void J_model_events(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void JB_model_events(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx); @@ -51,6 +52,7 @@ class Model_model_events : public amici::Model_ODE { 3, 3, 3, + 0, 1, 1, 2, @@ -75,7 +77,7 @@ class Model_model_events : public amici::Model_ODE { virtual amici::Model* clone() const override { return new Model_model_events(*this); }; - const std::string getAmiciCommit() const override { return "5193a397de39f5bd4b7d98718067dc71f02f916e"; }; + const std::string getAmiciCommit() const override { return "667c9f20a05dd5266e9453b50081d7fb933f7389"; }; virtual void fJ(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) override { J_model_events(J, t, x, p, k, h, w, dwdx); @@ -236,4 +238,8 @@ class Model_model_events : public amici::Model_ODE { }; +} // namespace model_model_events + +} // namespace amici + #endif /* _amici_model_events_h */ diff --git a/deps/AMICI/models/model_events/model_events_J.cpp b/deps/AMICI/models/model_events/model_events_J.cpp index 7401e806c..9a1cfca29 100644 --- a/deps/AMICI/models/model_events/model_events_J.cpp +++ b/deps/AMICI/models/model_events/model_events_J.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void J_model_events(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) { J[0+0*3] = p[0]*(h[3]-1.0); J[1+0*3] = p[1]*exp(t*(-1.0/1.0E1)); @@ -13,3 +17,7 @@ void J_model_events(realtype *J, const realtype t, const realtype *x, const doub J[2+2*3] = -1.0; } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_JB.cpp b/deps/AMICI/models/model_events/model_events_JB.cpp index f27cba50d..3b82bd824 100644 --- a/deps/AMICI/models/model_events/model_events_JB.cpp +++ b/deps/AMICI/models/model_events/model_events_JB.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void JB_model_events(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JB[0+0*3] = -p[0]*(h[3]-1.0); JB[0+1*3] = -p[1]*exp(t*(-1.0/1.0E1)); @@ -13,3 +17,7 @@ void JB_model_events(realtype *JB, const realtype t, const realtype *x, const re JB[2+2*3] = 1.0; } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_JDiag.cpp b/deps/AMICI/models/model_events/model_events_JDiag.cpp index 5bc16478c..1675d35fd 100644 --- a/deps/AMICI/models/model_events/model_events_JDiag.cpp +++ b/deps/AMICI/models/model_events/model_events_JDiag.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void JDiag_model_events(realtype *JDiag, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JDiag[0+0*3] = p[0]*(h[3]-1.0); JDiag[1+0*3] = -p[2]; JDiag[2+0*3] = -1.0; } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_JSparse.cpp b/deps/AMICI/models/model_events/model_events_JSparse.cpp index 9f6a1b180..cc527b9d3 100644 --- a/deps/AMICI/models/model_events/model_events_JSparse.cpp +++ b/deps/AMICI/models/model_events/model_events_JSparse.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void JSparse_model_events(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JSparse->indexvals[0] = 0; JSparse->indexvals[1] = 1; @@ -22,3 +26,7 @@ void JSparse_model_events(SUNMatrixContent_Sparse JSparse, const realtype t, con JSparse->data[3] = -1.0; } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_JSparseB.cpp b/deps/AMICI/models/model_events/model_events_JSparseB.cpp index 1f7a14502..15526bed6 100644 --- a/deps/AMICI/models/model_events/model_events_JSparseB.cpp +++ b/deps/AMICI/models/model_events/model_events_JSparseB.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void JSparseB_model_events(SUNMatrixContent_Sparse JSparseB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JSparseB->indexvals[0] = 0; JSparseB->indexvals[1] = 0; @@ -22,3 +26,7 @@ void JSparseB_model_events(SUNMatrixContent_Sparse JSparseB, const realtype t, c JSparseB->data[3] = 1.0; } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_Jrz.cpp b/deps/AMICI/models/model_events/model_events_Jrz.cpp index c716b1bea..6f3aa7bf7 100644 --- a/deps/AMICI/models/model_events/model_events_Jrz.cpp +++ b/deps/AMICI/models/model_events/model_events_Jrz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void Jrz_model_events(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) { switch(iz){ case 0: @@ -17,3 +21,7 @@ switch(iz){ } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_Jy.cpp b/deps/AMICI/models/model_events/model_events_Jy.cpp index 6934e2d03..237bf2c0e 100644 --- a/deps/AMICI/models/model_events/model_events_Jy.cpp +++ b/deps/AMICI/models/model_events/model_events_Jy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void Jy_model_events(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -14,3 +18,7 @@ switch(iy){ } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_Jz.cpp b/deps/AMICI/models/model_events/model_events_Jz.cpp index 224274d01..49e741c1b 100644 --- a/deps/AMICI/models/model_events/model_events_Jz.cpp +++ b/deps/AMICI/models/model_events/model_events_Jz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void Jz_model_events(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) { switch(iz){ case 0: @@ -17,3 +21,7 @@ switch(iz){ } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_dJrzdsigma.cpp b/deps/AMICI/models/model_events/model_events_dJrzdsigma.cpp index 175af2571..a0bde90ff 100644 --- a/deps/AMICI/models/model_events/model_events_dJrzdsigma.cpp +++ b/deps/AMICI/models/model_events/model_events_dJrzdsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void dJrzdsigma_model_events(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) { switch(iz){ case 0: @@ -17,3 +21,7 @@ switch(iz){ } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_dJrzdz.cpp b/deps/AMICI/models/model_events/model_events_dJrzdz.cpp index 04bdb05be..c82ffa207 100644 --- a/deps/AMICI/models/model_events/model_events_dJrzdz.cpp +++ b/deps/AMICI/models/model_events/model_events_dJrzdz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void dJrzdz_model_events(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) { switch(iz){ case 0: @@ -17,3 +21,7 @@ switch(iz){ } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_dJydsigma.cpp b/deps/AMICI/models/model_events/model_events_dJydsigma.cpp index 478196957..9ad536a14 100644 --- a/deps/AMICI/models/model_events/model_events_dJydsigma.cpp +++ b/deps/AMICI/models/model_events/model_events_dJydsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void dJydsigma_model_events(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -14,3 +18,7 @@ switch(iy){ } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_dJydy.cpp b/deps/AMICI/models/model_events/model_events_dJydy.cpp index 48387ae2d..7fed2977b 100644 --- a/deps/AMICI/models/model_events/model_events_dJydy.cpp +++ b/deps/AMICI/models/model_events/model_events_dJydy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void dJydy_model_events(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -14,3 +18,7 @@ switch(iy){ } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_dJzdsigma.cpp b/deps/AMICI/models/model_events/model_events_dJzdsigma.cpp index 7af501307..a45d1fbf0 100644 --- a/deps/AMICI/models/model_events/model_events_dJzdsigma.cpp +++ b/deps/AMICI/models/model_events/model_events_dJzdsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void dJzdsigma_model_events(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) { switch(iz){ case 0: @@ -17,3 +21,7 @@ switch(iz){ } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_dJzdz.cpp b/deps/AMICI/models/model_events/model_events_dJzdz.cpp index d5d807764..9fb3b9a0e 100644 --- a/deps/AMICI/models/model_events/model_events_dJzdz.cpp +++ b/deps/AMICI/models/model_events/model_events_dJzdz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void dJzdz_model_events(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) { switch(iz){ case 0: @@ -17,3 +21,7 @@ switch(iz){ } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_deltasx.cpp b/deps/AMICI/models/model_events/model_events_deltasx.cpp index 23b43fc1d..62516b1ab 100644 --- a/deps/AMICI/models/model_events/model_events_deltasx.cpp +++ b/deps/AMICI/models/model_events/model_events_deltasx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void deltasx_model_events(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) { switch (ip) { case 0: { @@ -115,3 +119,7 @@ switch (ip) { } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_drzdx.cpp b/deps/AMICI/models/model_events/model_events_drzdx.cpp index 2ef2ccd22..850fb1e51 100644 --- a/deps/AMICI/models/model_events/model_events_drzdx.cpp +++ b/deps/AMICI/models/model_events/model_events_drzdx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void drzdx_model_events(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { drzdx[0+1*2] = 1.0; drzdx[0+2*2] = -1.0; @@ -13,3 +17,7 @@ void drzdx_model_events(double *drzdx, const int ie, const realtype t, const rea drzdx[1+2*2] = -1.0; } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_dxdotdp.cpp b/deps/AMICI/models/model_events/model_events_dxdotdp.cpp index 212da2205..90e07ff62 100644 --- a/deps/AMICI/models/model_events/model_events_dxdotdp.cpp +++ b/deps/AMICI/models/model_events/model_events_dxdotdp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void dxdotdp_model_events(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) { switch (ip) { case 0: { @@ -26,3 +30,7 @@ switch (ip) { } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_dydp.cpp b/deps/AMICI/models/model_events/model_events_dydp.cpp index 3ab99d958..45090f6a8 100644 --- a/deps/AMICI/models/model_events/model_events_dydp.cpp +++ b/deps/AMICI/models/model_events/model_events_dydp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void dydp_model_events(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) { switch (ip) { case 3: { @@ -16,3 +20,7 @@ switch (ip) { } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_dydx.cpp b/deps/AMICI/models/model_events/model_events_dydx.cpp index e638172ec..82f7a3217 100644 --- a/deps/AMICI/models/model_events/model_events_dydx.cpp +++ b/deps/AMICI/models/model_events/model_events_dydx.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void dydx_model_events(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { dydx[0+0*1] = p[3]; dydx[0+1*1] = p[3]; dydx[0+2*1] = p[3]; } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_dzdx.cpp b/deps/AMICI/models/model_events/model_events_dzdx.cpp index c039eafa2..7b7713690 100644 --- a/deps/AMICI/models/model_events/model_events_dzdx.cpp +++ b/deps/AMICI/models/model_events/model_events_dzdx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void dzdx_model_events(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { dzdx[0+1*2] = -1.0/(h[2]+x[2]-p[2]*x[1]+p[1]*x[0]*exp(t*(-1.0/1.0E1))-1.0); dzdx[0+2*2] = 1.0/(h[2]+x[2]-p[2]*x[1]+p[1]*x[0]*exp(t*(-1.0/1.0E1))-1.0); @@ -13,3 +17,7 @@ void dzdx_model_events(double *dzdx, const int ie, const realtype t, const realt dzdx[1+2*2] = 1.0/(h[2]+x[2]+p[0]*x[0]*(h[3]-1.0)-1.0); } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_root.cpp b/deps/AMICI/models/model_events/model_events_root.cpp index fc0f262e6..4da74dc79 100644 --- a/deps/AMICI/models/model_events/model_events_root.cpp +++ b/deps/AMICI/models/model_events/model_events_root.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void root_model_events(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { root[0] = x[1]-x[2]; root[1] = x[0]-x[2]; @@ -15,3 +19,7 @@ void root_model_events(realtype *root, const realtype t, const realtype *x, cons root[5] = t-p[3]; } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_rz.cpp b/deps/AMICI/models/model_events/model_events_rz.cpp index 24edd8c1d..357f7c5a3 100644 --- a/deps/AMICI/models/model_events/model_events_rz.cpp +++ b/deps/AMICI/models/model_events/model_events_rz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void rz_model_events(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { switch(ie) { case 0: { @@ -37,3 +41,7 @@ void rz_model_events(double *rz, const int ie, const realtype t, const realtype } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_sigmay.cpp b/deps/AMICI/models/model_events/model_events_sigmay.cpp index 52a03da63..42fac3dfb 100644 --- a/deps/AMICI/models/model_events/model_events_sigmay.cpp +++ b/deps/AMICI/models/model_events/model_events_sigmay.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void sigmay_model_events(double *sigmay, const realtype t, const realtype *p, const realtype *k) { sigmay[0] = 1.0; } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_sigmaz.cpp b/deps/AMICI/models/model_events/model_events_sigmaz.cpp index 2199c58fd..340598b2f 100644 --- a/deps/AMICI/models/model_events/model_events_sigmaz.cpp +++ b/deps/AMICI/models/model_events/model_events_sigmaz.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void sigmaz_model_events(double *sigmaz, const realtype t, const realtype *p, const realtype *k) { sigmaz[0] = 1.0; sigmaz[1] = 1.0; } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_srz.cpp b/deps/AMICI/models/model_events/model_events_srz.cpp index 2db8c3537..392d1ba15 100644 --- a/deps/AMICI/models/model_events/model_events_srz.cpp +++ b/deps/AMICI/models/model_events/model_events_srz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void srz_model_events(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) { switch (ip) { case 0: { @@ -139,3 +143,7 @@ switch (ip) { } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_stau.cpp b/deps/AMICI/models/model_events/model_events_stau.cpp index bc15add76..9649efab4 100644 --- a/deps/AMICI/models/model_events/model_events_stau.cpp +++ b/deps/AMICI/models/model_events/model_events_stau.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void stau_model_events(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) { switch (ip) { case 0: { @@ -141,3 +145,7 @@ switch (ip) { } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_sz.cpp b/deps/AMICI/models/model_events/model_events_sz.cpp index 1c7a54533..4e6af3fb7 100644 --- a/deps/AMICI/models/model_events/model_events_sz.cpp +++ b/deps/AMICI/models/model_events/model_events_sz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void sz_model_events(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) { switch (ip) { case 0: { @@ -139,3 +143,7 @@ switch (ip) { } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_x0.cpp b/deps/AMICI/models/model_events/model_events_x0.cpp index e8e61504a..471859603 100644 --- a/deps/AMICI/models/model_events/model_events_x0.cpp +++ b/deps/AMICI/models/model_events/model_events_x0.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void x0_model_events(realtype *x0, const realtype t, const realtype *p, const realtype *k) { x0[0] = k[0]; x0[1] = k[1]; x0[2] = k[2]; } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_xdot.cpp b/deps/AMICI/models/model_events/model_events_xdot.cpp index 62f7980f2..e1ad2d95d 100644 --- a/deps/AMICI/models/model_events/model_events_xdot.cpp +++ b/deps/AMICI/models/model_events/model_events_xdot.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void xdot_model_events(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { xdot[0] = p[0]*x[0]*(h[3]-1.0); xdot[1] = -p[2]*x[1]+p[1]*x[0]*exp(t*(-1.0/1.0E1)); xdot[2] = -h[2]-x[2]+1.0; } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_y.cpp b/deps/AMICI/models/model_events/model_events_y.cpp index 163de528a..d5698f046 100644 --- a/deps/AMICI/models/model_events/model_events_y.cpp +++ b/deps/AMICI/models/model_events/model_events_y.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void y_model_events(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { y[0] = p[3]*(x[0]+x[1]+x[2]); } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/model_events_z.cpp b/deps/AMICI/models/model_events/model_events_z.cpp index e217e21e9..a4579c035 100644 --- a/deps/AMICI/models/model_events/model_events_z.cpp +++ b/deps/AMICI/models/model_events/model_events_z.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_events{ + void z_model_events(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { switch(ie) { case 0: { @@ -37,3 +41,7 @@ void z_model_events(double *z, const int ie, const realtype t, const realtype *x } } +} // namespace model_model_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/wrapfunctions.cpp b/deps/AMICI/models/model_events/wrapfunctions.cpp index c8dadc6e2..91742b50c 100644 --- a/deps/AMICI/models/model_events/wrapfunctions.cpp +++ b/deps/AMICI/models/model_events/wrapfunctions.cpp @@ -1,7 +1,16 @@ #include "amici/model.h" #include "wrapfunctions.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel() { - return std::unique_ptr(new Model_model_events()); + return std::unique_ptr( + new amici::model_model_events::Model_model_events()); } +} // namespace generic_model + +} // namespace amici + diff --git a/deps/AMICI/models/model_events/wrapfunctions.h b/deps/AMICI/models/model_events/wrapfunctions.h index 70a5497a9..4644891ea 100644 --- a/deps/AMICI/models/model_events/wrapfunctions.h +++ b/deps/AMICI/models/model_events/wrapfunctions.h @@ -3,6 +3,14 @@ #include "model_events.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel(); +} // namespace generic_model + +} // namespace amici + #endif /* _amici_wrapfunctions_h */ diff --git a/deps/AMICI/models/model_jakstat_adjoint/CMakeLists.txt b/deps/AMICI/models/model_jakstat_adjoint/CMakeLists.txt index b7a43019f..a52411f69 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/CMakeLists.txt +++ b/deps/AMICI/models/model_jakstat_adjoint/CMakeLists.txt @@ -6,6 +6,10 @@ endif(POLICY CMP0060) if(POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif(POLICY CMP0065) +if(POLICY CMP0074) + # Use package_ROOT environment variables + cmake_policy(SET CMP0074 NEW) +endif(POLICY CMP0074) project(model_jakstat_adjoint) diff --git a/deps/AMICI/models/model_jakstat_adjoint/main.cpp b/deps/AMICI/models/model_jakstat_adjoint/main.cpp index 07ff62a32..f957df9ad 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/main.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/main.cpp @@ -54,7 +54,7 @@ int main(int argc, char **argv) { hdffile = argv[1]; } - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); // Read AMICI settings and model parameters from HDF5 file diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint.h b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint.h index 3cf5fdec2..853d1d2f7 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint.h +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint.h @@ -1,6 +1,6 @@ #ifndef _amici_model_jakstat_adjoint_h #define _amici_model_jakstat_adjoint_h -/* Generated by amiwrap (R2017b) 5193a397de39f5bd4b7d98718067dc71f02f916e */ +/* Generated by amiwrap (R2017b) 667c9f20a05dd5266e9453b50081d7fb933f7389 */ #include #include #include "amici/defines.h" @@ -9,9 +9,10 @@ #include "amici/model_ode.h" namespace amici { + class Solver; -} +namespace model_model_jakstat_adjoint{ extern void J_model_jakstat_adjoint(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void JB_model_jakstat_adjoint(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx); @@ -40,6 +41,7 @@ class Model_model_jakstat_adjoint : public amici::Model_ODE { 9, 9, 9, + 0, 3, 3, 0, @@ -64,7 +66,7 @@ class Model_model_jakstat_adjoint : public amici::Model_ODE { virtual amici::Model* clone() const override { return new Model_model_jakstat_adjoint(*this); }; - const std::string getAmiciCommit() const override { return "5193a397de39f5bd4b7d98718067dc71f02f916e"; }; + const std::string getAmiciCommit() const override { return "667c9f20a05dd5266e9453b50081d7fb933f7389"; }; virtual void fJ(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) override { J_model_jakstat_adjoint(J, t, x, p, k, h, w, dwdx); @@ -214,4 +216,8 @@ class Model_model_jakstat_adjoint : public amici::Model_ODE { }; +} // namespace model_model_jakstat_adjoint + +} // namespace amici + #endif /* _amici_model_jakstat_adjoint_h */ diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_J.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_J.cpp index 1b01cd575..4eebc5b44 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_J.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_J.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void J_model_jakstat_adjoint(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) { J[0+0*9] = -p[0]*w[0]; J[0+8*9] = (k[1]*p[3])/k[0]; @@ -27,3 +31,7 @@ void J_model_jakstat_adjoint(realtype *J, const realtype t, const realtype *x, c J[8+8*9] = -p[3]; } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JB.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JB.cpp index 6c08157d6..a01468fb9 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JB.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JB.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void JB_model_jakstat_adjoint(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JB[0+0*9] = p[0]*w[0]; JB[0+1*9] = -p[0]*w[0]; @@ -27,3 +31,7 @@ void JB_model_jakstat_adjoint(realtype *JB, const realtype t, const realtype *x, JB[8+8*9] = p[3]; } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JDiag.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JDiag.cpp index 91c91c84a..151be6191 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JDiag.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JDiag.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void JDiag_model_jakstat_adjoint(realtype *JDiag, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JDiag[0+0*9] = -p[0]*w[0]; JDiag[1+0*9] = p[1]*dwdx[0]*-2.0; @@ -18,3 +22,7 @@ void JDiag_model_jakstat_adjoint(realtype *JDiag, const realtype t, const realty JDiag[8+0*9] = -p[3]; } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JSparse.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JSparse.cpp index 72536439c..e30cd2d04 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JSparse.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JSparse.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void JSparse_model_jakstat_adjoint(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JSparse->indexvals[0] = 0; JSparse->indexvals[1] = 1; @@ -56,3 +60,7 @@ void JSparse_model_jakstat_adjoint(SUNMatrixContent_Sparse JSparse, const realty JSparse->data[17] = -p[3]; } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JSparseB.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JSparseB.cpp index 2c56677dc..dfbf8c4e5 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JSparseB.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_JSparseB.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void JSparseB_model_jakstat_adjoint(SUNMatrixContent_Sparse JSparseB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JSparseB->indexvals[0] = 0; JSparseB->indexvals[1] = 8; @@ -56,3 +60,7 @@ void JSparseB_model_jakstat_adjoint(SUNMatrixContent_Sparse JSparseB, const real JSparseB->data[17] = p[3]; } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_Jy.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_Jy.cpp index 5befb2c78..2db2d128e 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_Jy.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_Jy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void Jy_model_jakstat_adjoint(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -20,3 +24,7 @@ switch(iy){ } } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dJydsigma.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dJydsigma.cpp index b1ed88018..1a11141f4 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dJydsigma.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dJydsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void dJydsigma_model_jakstat_adjoint(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -20,3 +24,7 @@ switch(iy){ } } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dJydy.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dJydy.cpp index 5990a27f0..32e0314af 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dJydy.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dJydy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void dJydy_model_jakstat_adjoint(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -20,3 +24,7 @@ switch(iy){ } } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dsigmaydp.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dsigmaydp.cpp index 4426c6b8c..38045122b 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dsigmaydp.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dsigmaydp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void dsigmaydp_model_jakstat_adjoint(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) { switch (ip) { case 14: { @@ -26,3 +30,7 @@ switch (ip) { } } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dwdp.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dwdp.cpp index 6e039e51c..431552d3c 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dwdp.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dwdp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void dwdp_model_jakstat_adjoint(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) { dwdp[0] = amici::Dspline_pos(4,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); dwdp[1] = amici::Dspline_pos(6,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); @@ -14,3 +18,7 @@ void dwdp_model_jakstat_adjoint(realtype *dwdp, const realtype t, const realtype dwdp[4] = amici::Dspline_pos(12,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dwdx.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dwdx.cpp index 3fa252482..c9c14945c 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dwdx.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dwdx.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void dwdx_model_jakstat_adjoint(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) { dwdx[0] = x[1]*2.0; } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dxdotdp.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dxdotdp.cpp index f47e3be9b..18473afb3 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dxdotdp.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dxdotdp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void dxdotdp_model_jakstat_adjoint(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) { switch (ip) { case 0: { @@ -70,3 +74,7 @@ switch (ip) { } } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dydp.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dydp.cpp index 636118492..c37f018f8 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dydp.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dydp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void dydp_model_jakstat_adjoint(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) { switch (ip) { case 4: { @@ -62,3 +66,7 @@ switch (ip) { } } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dydx.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dydx.cpp index 6bb0987bf..3a16b74c1 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dydx.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_dydx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void dydx_model_jakstat_adjoint(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { dydx[0+1*3] = p[13]/p[4]; dydx[0+2*3] = (p[13]*2.0)/p[4]; @@ -14,3 +18,7 @@ void dydx_model_jakstat_adjoint(double *dydx, const realtype t, const realtype * dydx[1+2*3] = (p[12]*2.0)/p[4]; } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_sigmay.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_sigmay.cpp index f08909d2b..18172dff2 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_sigmay.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_sigmay.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void sigmay_model_jakstat_adjoint(double *sigmay, const realtype t, const realtype *p, const realtype *k) { sigmay[0] = p[14]; sigmay[1] = p[15]; sigmay[2] = p[16]; } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_sx0.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_sx0.cpp index ddcea951f..7dc533250 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_sx0.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_sx0.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void sx0_model_jakstat_adjoint(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) { switch (ip) { case 4: { @@ -16,3 +20,7 @@ switch (ip) { } } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_w.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_w.cpp index d31c83547..942ba399f 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_w.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_w.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void w_model_jakstat_adjoint(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) { w[0] = amici::spline_pos(t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); w[1] = x[1]*x[1]; } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_x0.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_x0.cpp index a1235a4b3..2498586d7 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_x0.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_x0.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void x0_model_jakstat_adjoint(realtype *x0, const realtype t, const realtype *p, const realtype *k) { x0[0] = p[4]; } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_xdot.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_xdot.cpp index 2bcc5892f..a31ae44a9 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_xdot.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_xdot.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void xdot_model_jakstat_adjoint(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { xdot[0] = (k[1]*p[3]*x[8]-k[0]*p[0]*w[0]*x[0])/k[0]; xdot[1] = p[1]*w[1]*-2.0+p[0]*w[0]*x[0]; @@ -18,3 +22,7 @@ void xdot_model_jakstat_adjoint(realtype *xdot, const realtype t, const realtype xdot[8] = p[3]*(x[7]-x[8]); } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_y.cpp b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_y.cpp index 307763587..87b30353b 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_y.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint_y.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint{ + void y_model_jakstat_adjoint(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { y[0] = p[11]+(p[13]*(x[1]+x[2]*2.0))/p[4]; y[1] = p[10]+(p[12]*(x[0]+x[1]+x[2]*2.0))/p[4]; y[2] = amici::spline_pos(t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); } +} // namespace model_model_jakstat_adjoint + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/wrapfunctions.cpp b/deps/AMICI/models/model_jakstat_adjoint/wrapfunctions.cpp index df5dbeb99..1b40155f0 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/wrapfunctions.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint/wrapfunctions.cpp @@ -1,7 +1,16 @@ #include "amici/model.h" #include "wrapfunctions.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel() { - return std::unique_ptr(new Model_model_jakstat_adjoint()); + return std::unique_ptr( + new amici::model_model_jakstat_adjoint::Model_model_jakstat_adjoint()); } +} // namespace generic_model + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint/wrapfunctions.h b/deps/AMICI/models/model_jakstat_adjoint/wrapfunctions.h index 382c1f532..cf6f1a7e2 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/wrapfunctions.h +++ b/deps/AMICI/models/model_jakstat_adjoint/wrapfunctions.h @@ -3,6 +3,14 @@ #include "model_jakstat_adjoint.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel(); +} // namespace generic_model + +} // namespace amici + #endif /* _amici_wrapfunctions_h */ diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/CMakeLists.txt b/deps/AMICI/models/model_jakstat_adjoint_o2/CMakeLists.txt index 199af7804..1cf065006 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/CMakeLists.txt +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/CMakeLists.txt @@ -6,6 +6,10 @@ endif(POLICY CMP0060) if(POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif(POLICY CMP0065) +if(POLICY CMP0074) + # Use package_ROOT environment variables + cmake_policy(SET CMP0074 NEW) +endif(POLICY CMP0074) project(model_jakstat_adjoint_o2) diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/main.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/main.cpp index 07ff62a32..f957df9ad 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/main.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/main.cpp @@ -54,7 +54,7 @@ int main(int argc, char **argv) { hdffile = argv[1]; } - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); // Read AMICI settings and model parameters from HDF5 file diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2.h b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2.h index ef9f6a163..d56512d52 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2.h +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2.h @@ -1,6 +1,6 @@ #ifndef _amici_model_jakstat_adjoint_o2_h #define _amici_model_jakstat_adjoint_o2_h -/* Generated by amiwrap (R2017b) 5193a397de39f5bd4b7d98718067dc71f02f916e */ +/* Generated by amiwrap (R2017b) 667c9f20a05dd5266e9453b50081d7fb933f7389 */ #include #include #include "amici/defines.h" @@ -9,9 +9,10 @@ #include "amici/model_ode.h" namespace amici { + class Solver; -} +namespace model_model_jakstat_adjoint_o2{ extern void J_model_jakstat_adjoint_o2(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void JB_model_jakstat_adjoint_o2(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx); @@ -40,6 +41,7 @@ class Model_model_jakstat_adjoint_o2 : public amici::Model_ODE { 9, 162, 9, + 0, 54, 3, 0, @@ -64,7 +66,7 @@ class Model_model_jakstat_adjoint_o2 : public amici::Model_ODE { virtual amici::Model* clone() const override { return new Model_model_jakstat_adjoint_o2(*this); }; - const std::string getAmiciCommit() const override { return "5193a397de39f5bd4b7d98718067dc71f02f916e"; }; + const std::string getAmiciCommit() const override { return "667c9f20a05dd5266e9453b50081d7fb933f7389"; }; virtual void fJ(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) override { J_model_jakstat_adjoint_o2(J, t, x, p, k, h, w, dwdx); @@ -214,4 +216,8 @@ class Model_model_jakstat_adjoint_o2 : public amici::Model_ODE { }; +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + #endif /* _amici_model_jakstat_adjoint_o2_h */ diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_J.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_J.cpp index 3c5ada267..346cdde58 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_J.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_J.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void J_model_jakstat_adjoint_o2(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) { J[0+0*162] = -k[0]*p[0]*w[0]*w[2]; J[0+8*162] = k[1]*p[3]*w[2]; @@ -393,3 +397,7 @@ void J_model_jakstat_adjoint_o2(realtype *J, const realtype t, const realtype *x J[161+161*162] = -p[3]; } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JB.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JB.cpp index 1c3c2531d..e720a00a5 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JB.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JB.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void JB_model_jakstat_adjoint_o2(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JB[0+0*162] = k[0]*p[0]*w[0]*w[2]; JB[0+1*162] = -p[0]*w[0]; @@ -393,3 +397,7 @@ void JB_model_jakstat_adjoint_o2(realtype *JB, const realtype t, const realtype JB[161+161*162] = p[3]; } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JDiag.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JDiag.cpp index 56b763d02..437f4a26a 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JDiag.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JDiag.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void JDiag_model_jakstat_adjoint_o2(realtype *JDiag, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JDiag[0+0*162] = -k[0]*p[0]*w[0]*w[2]; JDiag[1+0*162] = p[1]*dwdx[0]*-2.0; @@ -171,3 +175,7 @@ void JDiag_model_jakstat_adjoint_o2(realtype *JDiag, const realtype t, const rea JDiag[161+0*162] = -p[3]; } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JSparse.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JSparse.cpp index 1d1bd8778..eed36174c 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JSparse.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JSparse.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void JSparse_model_jakstat_adjoint_o2(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JSparse->indexvals[0] = 0; JSparse->indexvals[1] = 1; @@ -941,3 +945,7 @@ void JSparse_model_jakstat_adjoint_o2(SUNMatrixContent_Sparse JSparse, const rea JSparse->data[383] = -p[3]; } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JSparseB.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JSparseB.cpp index a8d69b294..ceba254ca 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JSparseB.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_JSparseB.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void JSparseB_model_jakstat_adjoint_o2(SUNMatrixContent_Sparse JSparseB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JSparseB->indexvals[0] = 0; JSparseB->indexvals[1] = 8; @@ -941,3 +945,7 @@ void JSparseB_model_jakstat_adjoint_o2(SUNMatrixContent_Sparse JSparseB, const r JSparseB->data[383] = p[3]; } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_Jy.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_Jy.cpp index a2d1ad15e..63abdf4b4 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_Jy.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_Jy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void Jy_model_jakstat_adjoint_o2(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -71,3 +75,7 @@ switch(iy){ } } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dJydsigma.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dJydsigma.cpp index 8d3a7e729..0a3c94610 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dJydsigma.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dJydsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void dJydsigma_model_jakstat_adjoint_o2(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -71,3 +75,7 @@ switch(iy){ } } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dJydy.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dJydy.cpp index 396b94dfd..f940654cd 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dJydy.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dJydy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void dJydy_model_jakstat_adjoint_o2(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -122,3 +126,7 @@ switch(iy){ } } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dsigmaydp.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dsigmaydp.cpp index 39c158151..7ebea670b 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dsigmaydp.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dsigmaydp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void dsigmaydp_model_jakstat_adjoint_o2(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) { switch (ip) { case 14: { @@ -26,3 +30,7 @@ switch (ip) { } } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dwdp.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dwdp.cpp index 68ddfda00..3035ef9c7 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dwdp.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dwdp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void dwdp_model_jakstat_adjoint_o2(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) { dwdp[0] = amici::Dspline_pos(4,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); dwdp[1] = amici::DDspline_pos(4,4,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); @@ -39,3 +43,7 @@ void dwdp_model_jakstat_adjoint_o2(realtype *dwdp, const realtype t, const realt dwdp[29] = amici::DDspline_pos(12,12,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dwdx.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dwdx.cpp index ddb360e09..0c441f5c2 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dwdx.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dwdx.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void dwdx_model_jakstat_adjoint_o2(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) { dwdx[0] = x[1]*2.0; dwdx[1] = 2.0; } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dxdotdp.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dxdotdp.cpp index 11ffdc3de..0f806991c 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dxdotdp.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dxdotdp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void dxdotdp_model_jakstat_adjoint_o2(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) { switch (ip) { case 0: { @@ -461,3 +465,7 @@ switch (ip) { } } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dydp.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dydp.cpp index 403ae88cb..678e6c020 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dydp.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dydp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void dydp_model_jakstat_adjoint_o2(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) { switch (ip) { case 4: { @@ -155,3 +159,7 @@ switch (ip) { } } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dydx.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dydx.cpp index f5221701e..ffd779697 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dydx.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_dydx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void dydx_model_jakstat_adjoint_o2(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { dydx[0+1*54] = p[13]/p[4]; dydx[0+2*54] = (p[13]*2.0)/p[4]; @@ -109,3 +113,7 @@ void dydx_model_jakstat_adjoint_o2(double *dydx, const realtype t, const realtyp dydx[52+155*54] = (p[12]*2.0)/p[4]; } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_sigmay.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_sigmay.cpp index eb516f90e..26120455a 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_sigmay.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_sigmay.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void sigmay_model_jakstat_adjoint_o2(double *sigmay, const realtype t, const realtype *p, const realtype *k) { sigmay[0] = p[14]; sigmay[1] = p[15]; @@ -15,3 +19,7 @@ void sigmay_model_jakstat_adjoint_o2(double *sigmay, const realtype t, const rea sigmay[53] = 1.0; } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_sx0.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_sx0.cpp index 2ef04bc13..bfc0aa257 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_sx0.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_sx0.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void sx0_model_jakstat_adjoint_o2(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) { switch (ip) { case 4: { @@ -16,3 +20,7 @@ switch (ip) { } } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_w.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_w.cpp index 48dcb5be2..2b1e113f0 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_w.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_w.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void w_model_jakstat_adjoint_o2(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) { w[0] = amici::spline_pos(t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); w[1] = x[1]*x[1]; @@ -19,3 +23,7 @@ void w_model_jakstat_adjoint_o2(realtype *w, const realtype t, const realtype *x w[9] = amici::Dspline_pos(12,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_x0.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_x0.cpp index 06f1844df..4ad7ee8cf 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_x0.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_x0.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void x0_model_jakstat_adjoint_o2(realtype *x0, const realtype t, const realtype *p, const realtype *k) { x0[0] = p[4]; x0[45] = 1.0; } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_xdot.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_xdot.cpp index 1494a3c32..50baba5d8 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_xdot.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_xdot.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void xdot_model_jakstat_adjoint_o2(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { xdot[0] = w[2]*(k[1]*p[3]*x[8]-k[0]*p[0]*w[0]*x[0]); xdot[1] = p[1]*w[1]*-2.0+p[0]*w[0]*x[0]; @@ -171,3 +175,7 @@ void xdot_model_jakstat_adjoint_o2(realtype *xdot, const realtype t, const realt xdot[161] = p[3]*x[160]-p[3]*x[161]; } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_y.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_y.cpp index e070f4ac6..17e3d938b 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_y.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2_y.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_jakstat_adjoint_o2{ + void y_model_jakstat_adjoint_o2(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { y[0] = p[11]+(p[13]*(x[1]+x[2]*2.0))/p[4]; y[1] = p[10]+(p[12]*(x[0]+x[1]+x[2]*2.0))/p[4]; @@ -51,3 +55,7 @@ void y_model_jakstat_adjoint_o2(double *y, const realtype t, const realtype *x, y[52] = (p[12]*x[153])/p[4]+(p[12]*x[154])/p[4]+(p[12]*x[155]*2.0)/p[4]; } +} // namespace model_model_jakstat_adjoint_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/wrapfunctions.cpp b/deps/AMICI/models/model_jakstat_adjoint_o2/wrapfunctions.cpp index f2db60bd4..470a21b4b 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/wrapfunctions.cpp +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/wrapfunctions.cpp @@ -1,7 +1,16 @@ #include "amici/model.h" #include "wrapfunctions.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel() { - return std::unique_ptr(new Model_model_jakstat_adjoint_o2()); + return std::unique_ptr( + new amici::model_model_jakstat_adjoint_o2::Model_model_jakstat_adjoint_o2()); } +} // namespace generic_model + +} // namespace amici + diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/wrapfunctions.h b/deps/AMICI/models/model_jakstat_adjoint_o2/wrapfunctions.h index 393523e52..0bb7f6473 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/wrapfunctions.h +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/wrapfunctions.h @@ -3,6 +3,14 @@ #include "model_jakstat_adjoint_o2.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel(); +} // namespace generic_model + +} // namespace amici + #endif /* _amici_wrapfunctions_h */ diff --git a/deps/AMICI/models/model_nested_events/CMakeLists.txt b/deps/AMICI/models/model_nested_events/CMakeLists.txt index 3c6dcc0a3..185fd6c17 100644 --- a/deps/AMICI/models/model_nested_events/CMakeLists.txt +++ b/deps/AMICI/models/model_nested_events/CMakeLists.txt @@ -6,6 +6,10 @@ endif(POLICY CMP0060) if(POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif(POLICY CMP0065) +if(POLICY CMP0074) + # Use package_ROOT environment variables + cmake_policy(SET CMP0074 NEW) +endif(POLICY CMP0074) project(model_nested_events) diff --git a/deps/AMICI/models/model_nested_events/main.cpp b/deps/AMICI/models/model_nested_events/main.cpp index 07ff62a32..f957df9ad 100644 --- a/deps/AMICI/models/model_nested_events/main.cpp +++ b/deps/AMICI/models/model_nested_events/main.cpp @@ -54,7 +54,7 @@ int main(int argc, char **argv) { hdffile = argv[1]; } - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); // Read AMICI settings and model parameters from HDF5 file diff --git a/deps/AMICI/models/model_nested_events/model_nested_events.h b/deps/AMICI/models/model_nested_events/model_nested_events.h index 5ca7091d6..12bf41468 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events.h +++ b/deps/AMICI/models/model_nested_events/model_nested_events.h @@ -1,6 +1,6 @@ #ifndef _amici_model_nested_events_h #define _amici_model_nested_events_h -/* Generated by amiwrap (R2017b) 5193a397de39f5bd4b7d98718067dc71f02f916e */ +/* Generated by amiwrap (R2017b) 667c9f20a05dd5266e9453b50081d7fb933f7389 */ #include #include #include "amici/defines.h" @@ -9,9 +9,10 @@ #include "amici/model_ode.h" namespace amici { + class Solver; -} +namespace model_model_nested_events{ extern void J_model_nested_events(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void JB_model_nested_events(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx); @@ -40,6 +41,7 @@ class Model_model_nested_events : public amici::Model_ODE { 1, 1, 1, + 0, 1, 1, 0, @@ -64,7 +66,7 @@ class Model_model_nested_events : public amici::Model_ODE { virtual amici::Model* clone() const override { return new Model_model_nested_events(*this); }; - const std::string getAmiciCommit() const override { return "5193a397de39f5bd4b7d98718067dc71f02f916e"; }; + const std::string getAmiciCommit() const override { return "667c9f20a05dd5266e9453b50081d7fb933f7389"; }; virtual void fJ(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) override { J_model_nested_events(J, t, x, p, k, h, w, dwdx); @@ -214,4 +216,8 @@ class Model_model_nested_events : public amici::Model_ODE { }; +} // namespace model_model_nested_events + +} // namespace amici + #endif /* _amici_model_nested_events_h */ diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_J.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_J.cpp index 323034295..f9c622bd2 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_J.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_J.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void J_model_nested_events(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) { J[0] = -p[4]-p[3]*(h[0]-1.0); } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_JB.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_JB.cpp index 931bbec4c..a023ccc77 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_JB.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_JB.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void JB_model_nested_events(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JB[0] = p[4]+p[3]*(h[0]-1.0); } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_JDiag.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_JDiag.cpp index ad0fa8bf5..8b38af4b1 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_JDiag.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_JDiag.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void JDiag_model_nested_events(realtype *JDiag, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JDiag[0] = -p[4]-p[3]*(h[0]-1.0); } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_JSparse.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_JSparse.cpp index 0311b1156..9db399af7 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_JSparse.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_JSparse.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void JSparse_model_nested_events(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JSparse->indexvals[0] = 0; JSparse->indexptrs[0] = 0; @@ -14,3 +18,7 @@ void JSparse_model_nested_events(SUNMatrixContent_Sparse JSparse, const realtype JSparse->data[0] = -p[4]-p[3]*(h[0]-1.0); } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_JSparseB.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_JSparseB.cpp index 40e9b6324..40ce1def5 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_JSparseB.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_JSparseB.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void JSparseB_model_nested_events(SUNMatrixContent_Sparse JSparseB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JSparseB->indexvals[0] = 0; JSparseB->indexptrs[0] = 0; @@ -14,3 +18,7 @@ void JSparseB_model_nested_events(SUNMatrixContent_Sparse JSparseB, const realty JSparseB->data[0] = p[4]+p[3]*(h[0]-1.0); } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_Jy.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_Jy.cpp index 9fbf007da..fe34fe3a1 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_Jy.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_Jy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void Jy_model_nested_events(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -14,3 +18,7 @@ switch(iy){ } } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_dJydsigma.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_dJydsigma.cpp index 0dc3517e2..5bcf4e5fa 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_dJydsigma.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_dJydsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void dJydsigma_model_nested_events(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -14,3 +18,7 @@ switch(iy){ } } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_dJydy.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_dJydy.cpp index dbfb0f0ee..1b5d06f40 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_dJydy.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_dJydy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void dJydy_model_nested_events(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -14,3 +18,7 @@ switch(iy){ } } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_deltaqB.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_deltaqB.cpp index b38366a61..e1e1571b5 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_deltaqB.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_deltaqB.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void deltaqB_model_nested_events(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) { switch (ip) { } } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_deltasx.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_deltasx.cpp index f9a69baf8..d464477b4 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_deltasx.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_deltasx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void deltasx_model_nested_events(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) { switch (ip) { case 0: { @@ -141,3 +145,7 @@ switch (ip) { } } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_deltax.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_deltax.cpp index 431a17cb3..ec62e695a 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_deltax.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_deltax.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void deltax_model_nested_events(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) { switch(ie) { case 2: { @@ -21,3 +25,7 @@ void deltax_model_nested_events(double *deltax, const realtype t, const realtype } } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_dxdotdp.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_dxdotdp.cpp index 50108bff0..7d073f070 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_dxdotdp.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_dxdotdp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void dxdotdp_model_nested_events(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) { switch (ip) { case 3: { @@ -21,3 +25,7 @@ switch (ip) { } } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_dydx.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_dydx.cpp index 8c5b99c26..add7a4698 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_dydx.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_dydx.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void dydx_model_nested_events(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { dydx[0] = 1.0; } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_root.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_root.cpp index 20912e020..c18683f8e 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_root.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_root.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void root_model_nested_events(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { root[0] = -x[0]+1.0; root[1] = x[0]-1.0; @@ -13,3 +17,7 @@ void root_model_nested_events(realtype *root, const realtype t, const realtype * root[3] = -t+p[2]; } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_sigmay.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_sigmay.cpp index 2bd6dcd90..4852d83e1 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_sigmay.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_sigmay.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void sigmay_model_nested_events(double *sigmay, const realtype t, const realtype *p, const realtype *k) { sigmay[0] = 1.0; } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_stau.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_stau.cpp index 16d231a46..c97800dea 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_stau.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_stau.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void stau_model_nested_events(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) { switch (ip) { case 0: { @@ -133,3 +137,7 @@ switch (ip) { } } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_sx0.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_sx0.cpp index 624338f35..01a33b32a 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_sx0.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_sx0.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void sx0_model_nested_events(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) { switch (ip) { case 0: { @@ -16,3 +20,7 @@ switch (ip) { } } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_x0.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_x0.cpp index 52afe4b7e..ad0addfb6 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_x0.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_x0.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void x0_model_nested_events(realtype *x0, const realtype t, const realtype *p, const realtype *k) { x0[0] = p[0]; } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_xdot.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_xdot.cpp index d5722d2d0..0fd26c1b7 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_xdot.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_xdot.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void xdot_model_nested_events(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { xdot[0] = -p[4]*x[0]-p[3]*x[0]*(h[0]-1.0); } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/model_nested_events_y.cpp b/deps/AMICI/models/model_nested_events/model_nested_events_y.cpp index 263ceeaf6..308c9ad8f 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events_y.cpp +++ b/deps/AMICI/models/model_nested_events/model_nested_events_y.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_nested_events{ + void y_model_nested_events(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { y[0] = x[0]; } +} // namespace model_model_nested_events + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/wrapfunctions.cpp b/deps/AMICI/models/model_nested_events/wrapfunctions.cpp index 247071fc5..190a4caa1 100644 --- a/deps/AMICI/models/model_nested_events/wrapfunctions.cpp +++ b/deps/AMICI/models/model_nested_events/wrapfunctions.cpp @@ -1,7 +1,16 @@ #include "amici/model.h" #include "wrapfunctions.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel() { - return std::unique_ptr(new Model_model_nested_events()); + return std::unique_ptr( + new amici::model_model_nested_events::Model_model_nested_events()); } +} // namespace generic_model + +} // namespace amici + diff --git a/deps/AMICI/models/model_nested_events/wrapfunctions.h b/deps/AMICI/models/model_nested_events/wrapfunctions.h index 4e649f8e9..2eb9041ec 100644 --- a/deps/AMICI/models/model_nested_events/wrapfunctions.h +++ b/deps/AMICI/models/model_nested_events/wrapfunctions.h @@ -3,6 +3,14 @@ #include "model_nested_events.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel(); +} // namespace generic_model + +} // namespace amici + #endif /* _amici_wrapfunctions_h */ diff --git a/deps/AMICI/models/model_neuron/CMakeLists.txt b/deps/AMICI/models/model_neuron/CMakeLists.txt index eb41751c0..f64a3d3c1 100644 --- a/deps/AMICI/models/model_neuron/CMakeLists.txt +++ b/deps/AMICI/models/model_neuron/CMakeLists.txt @@ -6,6 +6,10 @@ endif(POLICY CMP0060) if(POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif(POLICY CMP0065) +if(POLICY CMP0074) + # Use package_ROOT environment variables + cmake_policy(SET CMP0074 NEW) +endif(POLICY CMP0074) project(model_neuron) diff --git a/deps/AMICI/models/model_neuron/main.cpp b/deps/AMICI/models/model_neuron/main.cpp index 07ff62a32..f957df9ad 100644 --- a/deps/AMICI/models/model_neuron/main.cpp +++ b/deps/AMICI/models/model_neuron/main.cpp @@ -54,7 +54,7 @@ int main(int argc, char **argv) { hdffile = argv[1]; } - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); // Read AMICI settings and model parameters from HDF5 file diff --git a/deps/AMICI/models/model_neuron/model_neuron.h b/deps/AMICI/models/model_neuron/model_neuron.h index fa33f518a..795c3c6bf 100644 --- a/deps/AMICI/models/model_neuron/model_neuron.h +++ b/deps/AMICI/models/model_neuron/model_neuron.h @@ -1,6 +1,6 @@ #ifndef _amici_model_neuron_h #define _amici_model_neuron_h -/* Generated by amiwrap (R2017b) 5dfc4abddf5cb50611e9881fcab074d8859ccc6b */ +/* Generated by amiwrap (R2017b) 667c9f20a05dd5266e9453b50081d7fb933f7389 */ #include #include #include "amici/defines.h" @@ -9,9 +9,10 @@ #include "amici/model_ode.h" namespace amici { + class Solver; -} +namespace model_model_neuron{ extern void J_model_neuron(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void JB_model_neuron(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx); @@ -54,6 +55,7 @@ class Model_model_neuron : public amici::Model_ODE { 2, 2, 2, + 0, 1, 1, 1, @@ -78,7 +80,7 @@ class Model_model_neuron : public amici::Model_ODE { virtual amici::Model* clone() const override { return new Model_model_neuron(*this); }; - const std::string getAmiciCommit() const override { return "5dfc4abddf5cb50611e9881fcab074d8859ccc6b"; }; + const std::string getAmiciCommit() const override { return "667c9f20a05dd5266e9453b50081d7fb933f7389"; }; virtual void fJ(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) override { J_model_neuron(J, t, x, p, k, h, w, dwdx); @@ -242,4 +244,8 @@ class Model_model_neuron : public amici::Model_ODE { }; +} // namespace model_model_neuron + +} // namespace amici + #endif /* _amici_model_neuron_h */ diff --git a/deps/AMICI/models/model_neuron/model_neuron_J.cpp b/deps/AMICI/models/model_neuron/model_neuron_J.cpp index c1a43bb2f..dda2e572c 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_J.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_J.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void J_model_neuron(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) { J[0+0*2] = x[0]*(2.0/2.5E1)+5.0; J[0+1*2] = -1.0; @@ -13,3 +17,7 @@ void J_model_neuron(realtype *J, const realtype t, const realtype *x, const doub J[1+1*2] = -p[0]; } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_JB.cpp b/deps/AMICI/models/model_neuron/model_neuron_JB.cpp index 449b73308..19b44145f 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_JB.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_JB.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void JB_model_neuron(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JB[0+0*2] = x[0]*(-2.0/2.5E1)-5.0; JB[0+1*2] = -p[0]*p[1]; @@ -13,3 +17,7 @@ void JB_model_neuron(realtype *JB, const realtype t, const realtype *x, const re JB[1+1*2] = p[0]; } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_JDiag.cpp b/deps/AMICI/models/model_neuron/model_neuron_JDiag.cpp index befacaf57..15e576966 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_JDiag.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_JDiag.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void JDiag_model_neuron(realtype *JDiag, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JDiag[0+0*2] = x[0]*(2.0/2.5E1)+5.0; JDiag[1+0*2] = -p[0]; } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_JSparse.cpp b/deps/AMICI/models/model_neuron/model_neuron_JSparse.cpp index fd4622dea..bb293ee60 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_JSparse.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_JSparse.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void JSparse_model_neuron(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JSparse->indexvals[0] = 0; JSparse->indexvals[1] = 1; @@ -21,3 +25,7 @@ void JSparse_model_neuron(SUNMatrixContent_Sparse JSparse, const realtype t, con JSparse->data[3] = -p[0]; } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_JSparseB.cpp b/deps/AMICI/models/model_neuron/model_neuron_JSparseB.cpp index 821a42471..453a0240b 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_JSparseB.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_JSparseB.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void JSparseB_model_neuron(SUNMatrixContent_Sparse JSparseB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JSparseB->indexvals[0] = 0; JSparseB->indexvals[1] = 1; @@ -21,3 +25,7 @@ void JSparseB_model_neuron(SUNMatrixContent_Sparse JSparseB, const realtype t, c JSparseB->data[3] = p[0]; } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_Jrz.cpp b/deps/AMICI/models/model_neuron/model_neuron_Jrz.cpp index 02da72d5b..506e4cb90 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_Jrz.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_Jrz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void Jrz_model_neuron(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) { switch(iz){ case 0: @@ -14,3 +18,7 @@ switch(iz){ } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_Jy.cpp b/deps/AMICI/models/model_neuron/model_neuron_Jy.cpp index b71a5b738..34432dff6 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_Jy.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_Jy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void Jy_model_neuron(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -14,3 +18,7 @@ switch(iy){ } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_Jz.cpp b/deps/AMICI/models/model_neuron/model_neuron_Jz.cpp index 391ff9f35..7139094a9 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_Jz.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_Jz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void Jz_model_neuron(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) { switch(iz){ case 0: @@ -14,3 +18,7 @@ switch(iz){ } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_dJrzdsigma.cpp b/deps/AMICI/models/model_neuron/model_neuron_dJrzdsigma.cpp index bc4b13b13..86144a405 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_dJrzdsigma.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_dJrzdsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void dJrzdsigma_model_neuron(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) { switch(iz){ case 0: @@ -14,3 +18,7 @@ switch(iz){ } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_dJrzdz.cpp b/deps/AMICI/models/model_neuron/model_neuron_dJrzdz.cpp index bb84a489c..f797c1433 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_dJrzdz.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_dJrzdz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void dJrzdz_model_neuron(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) { switch(iz){ case 0: @@ -14,3 +18,7 @@ switch(iz){ } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_dJydsigma.cpp b/deps/AMICI/models/model_neuron/model_neuron_dJydsigma.cpp index 7e70f7588..719f08074 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_dJydsigma.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_dJydsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void dJydsigma_model_neuron(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -14,3 +18,7 @@ switch(iy){ } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_dJydy.cpp b/deps/AMICI/models/model_neuron/model_neuron_dJydy.cpp index 8e01cef04..7a6dc85c8 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_dJydy.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_dJydy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void dJydy_model_neuron(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -14,3 +18,7 @@ switch(iy){ } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_dJzdsigma.cpp b/deps/AMICI/models/model_neuron/model_neuron_dJzdsigma.cpp index 222a7d46e..a321ec18d 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_dJzdsigma.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_dJzdsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void dJzdsigma_model_neuron(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) { switch(iz){ case 0: @@ -14,3 +18,7 @@ switch(iz){ } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_dJzdz.cpp b/deps/AMICI/models/model_neuron/model_neuron_dJzdz.cpp index 6baa33b05..14cf0a3e0 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_dJzdz.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_dJzdz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void dJzdz_model_neuron(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) { switch(iz){ case 0: @@ -14,3 +18,7 @@ switch(iz){ } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_deltaqB.cpp b/deps/AMICI/models/model_neuron/model_neuron_deltaqB.cpp index add8529e4..1cc27dbbe 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_deltaqB.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_deltaqB.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void deltaqB_model_neuron(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) { switch (ip) { case 2: { @@ -33,3 +37,7 @@ switch (ip) { } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_deltasx.cpp b/deps/AMICI/models/model_neuron/model_neuron_deltasx.cpp index 0dac57435..35dc79a78 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_deltasx.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_deltasx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void deltasx_model_neuron(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) { switch (ip) { case 0: { @@ -59,3 +63,7 @@ switch (ip) { } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_deltax.cpp b/deps/AMICI/models/model_neuron/model_neuron_deltax.cpp index 20e55ed25..7fdf2e372 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_deltax.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_deltax.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void deltax_model_neuron(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) { switch(ie) { case 0: { @@ -17,3 +21,7 @@ void deltax_model_neuron(double *deltax, const realtype t, const realtype *x, co } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_deltaxB.cpp b/deps/AMICI/models/model_neuron/model_neuron_deltaxB.cpp index ed90da5b8..3e45e3ba8 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_deltaxB.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_deltaxB.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void deltaxB_model_neuron(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) { switch(ie) { case 0: { @@ -16,3 +20,7 @@ void deltaxB_model_neuron(double *deltaxB, const realtype t, const realtype *x, } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_drzdx.cpp b/deps/AMICI/models/model_neuron/model_neuron_drzdx.cpp index c7de81dfd..7bf19536e 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_drzdx.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_drzdx.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void drzdx_model_neuron(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { drzdx[0+0*1] = 1.0; } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_dxdotdp.cpp b/deps/AMICI/models/model_neuron/model_neuron_dxdotdp.cpp index abe1e8537..e86601271 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_dxdotdp.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_dxdotdp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void dxdotdp_model_neuron(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) { switch (ip) { case 0: { @@ -21,3 +25,7 @@ switch (ip) { } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_dydx.cpp b/deps/AMICI/models/model_neuron/model_neuron_dydx.cpp index 5d026ed92..e6c0a52ab 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_dydx.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_dydx.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void dydx_model_neuron(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { dydx[0+0*1] = 1.0; } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_dzdx.cpp b/deps/AMICI/models/model_neuron/model_neuron_dzdx.cpp index 3a6705c95..20b163839 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_dzdx.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_dzdx.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void dzdx_model_neuron(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { dzdx[0+0*1] = -1.0/(k[1]+x[0]*5.0-x[1]+(x[0]*x[0])*(1.0/2.5E1)+1.4E2); } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_root.cpp b/deps/AMICI/models/model_neuron/model_neuron_root.cpp index 56f04a9d6..516bc9130 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_root.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_root.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void root_model_neuron(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { root[0] = x[0]-3.0E1; } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_rz.cpp b/deps/AMICI/models/model_neuron/model_neuron_rz.cpp index fd8c3675d..a85f19c88 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_rz.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_rz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void rz_model_neuron(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { switch(ie) { case 0: { @@ -16,3 +20,7 @@ void rz_model_neuron(double *rz, const int ie, const realtype t, const realtype } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_sigmay.cpp b/deps/AMICI/models/model_neuron/model_neuron_sigmay.cpp index 43764cc6f..092c62615 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_sigmay.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_sigmay.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void sigmay_model_neuron(double *sigmay, const realtype t, const realtype *p, const realtype *k) { sigmay[0] = 1.0; } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_sigmaz.cpp b/deps/AMICI/models/model_neuron/model_neuron_sigmaz.cpp index 5e2a3675a..ce17fae26 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_sigmaz.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_sigmaz.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void sigmaz_model_neuron(double *sigmaz, const realtype t, const realtype *p, const realtype *k) { sigmaz[0] = 1.0; } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_srz.cpp b/deps/AMICI/models/model_neuron/model_neuron_srz.cpp index 00f79994a..19ff0285c 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_srz.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_srz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void srz_model_neuron(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) { switch (ip) { case 0: { @@ -55,3 +59,7 @@ switch (ip) { } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_stau.cpp b/deps/AMICI/models/model_neuron/model_neuron_stau.cpp index 41e0b5505..66b351857 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_stau.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_stau.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void stau_model_neuron(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) { switch (ip) { case 0: { @@ -55,3 +59,7 @@ switch (ip) { } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_sx0.cpp b/deps/AMICI/models/model_neuron/model_neuron_sx0.cpp index 5e0700420..3712b9004 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_sx0.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_sx0.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void sx0_model_neuron(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) { switch (ip) { case 1: { @@ -16,3 +20,7 @@ switch (ip) { } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_sz.cpp b/deps/AMICI/models/model_neuron/model_neuron_sz.cpp index 7210f8927..e82da414f 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_sz.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_sz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void sz_model_neuron(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) { switch (ip) { case 0: { @@ -55,3 +59,7 @@ switch (ip) { } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_x0.cpp b/deps/AMICI/models/model_neuron/model_neuron_x0.cpp index 8dbe50223..348a787e2 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_x0.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_x0.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void x0_model_neuron(realtype *x0, const realtype t, const realtype *p, const realtype *k) { x0[0] = k[0]; x0[1] = k[0]*p[1]; } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_xdot.cpp b/deps/AMICI/models/model_neuron/model_neuron_xdot.cpp index 9a98933e0..c39724e74 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_xdot.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_xdot.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void xdot_model_neuron(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { xdot[0] = k[1]+x[0]*5.0-x[1]+(x[0]*x[0])*(1.0/2.5E1)+1.4E2; xdot[1] = -p[0]*(x[1]-p[1]*x[0]); } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_y.cpp b/deps/AMICI/models/model_neuron/model_neuron_y.cpp index 01876d48e..97818ac92 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_y.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_y.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void y_model_neuron(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { y[0] = x[0]; } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/model_neuron_z.cpp b/deps/AMICI/models/model_neuron/model_neuron_z.cpp index 3c2a2136c..9571db044 100644 --- a/deps/AMICI/models/model_neuron/model_neuron_z.cpp +++ b/deps/AMICI/models/model_neuron/model_neuron_z.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron{ + void z_model_neuron(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { switch(ie) { case 0: { @@ -16,3 +20,7 @@ void z_model_neuron(double *z, const int ie, const realtype t, const realtype *x } } +} // namespace model_model_neuron + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/wrapfunctions.cpp b/deps/AMICI/models/model_neuron/wrapfunctions.cpp index e37e6e89f..74dc0ab02 100644 --- a/deps/AMICI/models/model_neuron/wrapfunctions.cpp +++ b/deps/AMICI/models/model_neuron/wrapfunctions.cpp @@ -1,7 +1,16 @@ #include "amici/model.h" #include "wrapfunctions.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel() { - return std::unique_ptr(new Model_model_neuron()); + return std::unique_ptr( + new amici::model_model_neuron::Model_model_neuron()); } +} // namespace generic_model + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron/wrapfunctions.h b/deps/AMICI/models/model_neuron/wrapfunctions.h index 8c547dfff..dee20b752 100644 --- a/deps/AMICI/models/model_neuron/wrapfunctions.h +++ b/deps/AMICI/models/model_neuron/wrapfunctions.h @@ -3,6 +3,14 @@ #include "model_neuron.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel(); +} // namespace generic_model + +} // namespace amici + #endif /* _amici_wrapfunctions_h */ diff --git a/deps/AMICI/models/model_neuron_o2/CMakeLists.txt b/deps/AMICI/models/model_neuron_o2/CMakeLists.txt index 110b901d9..4c2a730aa 100644 --- a/deps/AMICI/models/model_neuron_o2/CMakeLists.txt +++ b/deps/AMICI/models/model_neuron_o2/CMakeLists.txt @@ -6,6 +6,10 @@ endif(POLICY CMP0060) if(POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif(POLICY CMP0065) +if(POLICY CMP0074) + # Use package_ROOT environment variables + cmake_policy(SET CMP0074 NEW) +endif(POLICY CMP0074) project(model_neuron_o2) diff --git a/deps/AMICI/models/model_neuron_o2/main.cpp b/deps/AMICI/models/model_neuron_o2/main.cpp index 07ff62a32..f957df9ad 100644 --- a/deps/AMICI/models/model_neuron_o2/main.cpp +++ b/deps/AMICI/models/model_neuron_o2/main.cpp @@ -54,7 +54,7 @@ int main(int argc, char **argv) { hdffile = argv[1]; } - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); // Read AMICI settings and model parameters from HDF5 file diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2.h b/deps/AMICI/models/model_neuron_o2/model_neuron_o2.h index a4fb5d03d..3db832546 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2.h +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2.h @@ -1,6 +1,6 @@ #ifndef _amici_model_neuron_o2_h #define _amici_model_neuron_o2_h -/* Generated by amiwrap (R2017b) 5dfc4abddf5cb50611e9881fcab074d8859ccc6b */ +/* Generated by amiwrap (R2017b) 667c9f20a05dd5266e9453b50081d7fb933f7389 */ #include #include #include "amici/defines.h" @@ -9,9 +9,10 @@ #include "amici/model_ode.h" namespace amici { + class Solver; -} +namespace model_model_neuron_o2{ extern void J_model_neuron_o2(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void JB_model_neuron_o2(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx); @@ -56,6 +57,7 @@ class Model_model_neuron_o2 : public amici::Model_ODE { 2, 10, 2, + 0, 5, 1, 5, @@ -80,7 +82,7 @@ class Model_model_neuron_o2 : public amici::Model_ODE { virtual amici::Model* clone() const override { return new Model_model_neuron_o2(*this); }; - const std::string getAmiciCommit() const override { return "5dfc4abddf5cb50611e9881fcab074d8859ccc6b"; }; + const std::string getAmiciCommit() const override { return "667c9f20a05dd5266e9453b50081d7fb933f7389"; }; virtual void fJ(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) override { J_model_neuron_o2(J, t, x, p, k, h, w, dwdx); @@ -246,4 +248,8 @@ class Model_model_neuron_o2 : public amici::Model_ODE { }; +} // namespace model_model_neuron_o2 + +} // namespace amici + #endif /* _amici_model_neuron_o2_h */ diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_J.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_J.cpp index ea06eea2e..10f532df2 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_J.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_J.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void J_model_neuron_o2(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) { J[0+0*10] = x[0]*(2.0/2.5E1)+5.0; J[0+1*10] = -1.0; @@ -36,3 +40,7 @@ void J_model_neuron_o2(realtype *J, const realtype t, const realtype *x, const d J[9+9*10] = -p[0]; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JB.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JB.cpp index 0cff52bfe..ce464d664 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JB.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JB.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void JB_model_neuron_o2(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JB[0+0*10] = x[0]*(-2.0/2.5E1)-5.0; JB[0+1*10] = -p[0]*p[1]; @@ -36,3 +40,7 @@ void JB_model_neuron_o2(realtype *JB, const realtype t, const realtype *x, const JB[9+9*10] = p[0]; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JDiag.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JDiag.cpp index 05a0e3a4f..04c5d798c 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JDiag.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JDiag.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void JDiag_model_neuron_o2(realtype *JDiag, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JDiag[0+0*10] = x[0]*(2.0/2.5E1)+5.0; JDiag[1+0*10] = -p[0]; @@ -19,3 +23,7 @@ void JDiag_model_neuron_o2(realtype *JDiag, const realtype t, const realtype *x, JDiag[9+0*10] = -p[0]; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JSparse.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JSparse.cpp index c09eca511..1ef9bc119 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JSparse.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JSparse.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void JSparse_model_neuron_o2(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JSparse->indexvals[0] = 0; JSparse->indexvals[1] = 1; @@ -75,3 +79,7 @@ void JSparse_model_neuron_o2(SUNMatrixContent_Sparse JSparse, const realtype t, JSparse->data[26] = -p[0]; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JSparseB.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JSparseB.cpp index bafbd3085..a6c50612e 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JSparseB.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_JSparseB.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void JSparseB_model_neuron_o2(SUNMatrixContent_Sparse JSparseB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JSparseB->indexvals[0] = 0; JSparseB->indexvals[1] = 1; @@ -75,3 +79,7 @@ void JSparseB_model_neuron_o2(SUNMatrixContent_Sparse JSparseB, const realtype t JSparseB->data[26] = p[0]; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_Jrz.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_Jrz.cpp index 3c1f8815f..a2f3b57e4 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_Jrz.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_Jrz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void Jrz_model_neuron_o2(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) { switch(iz){ case 0: @@ -18,3 +22,7 @@ switch(iz){ } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_Jy.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_Jy.cpp index dee1f7806..6df39fa04 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_Jy.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_Jy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void Jy_model_neuron_o2(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -18,3 +22,7 @@ switch(iy){ } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_Jz.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_Jz.cpp index c00f7d038..aa263ca00 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_Jz.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_Jz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void Jz_model_neuron_o2(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) { switch(iz){ case 0: @@ -18,3 +22,7 @@ switch(iz){ } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJrzdsigma.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJrzdsigma.cpp index 2800e43a9..b6a0e08a6 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJrzdsigma.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJrzdsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void dJrzdsigma_model_neuron_o2(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) { switch(iz){ case 0: @@ -18,3 +22,7 @@ switch(iz){ } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJrzdz.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJrzdz.cpp index 0732381b0..84963ae35 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJrzdz.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJrzdz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void dJrzdz_model_neuron_o2(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) { switch(iz){ case 0: @@ -22,3 +26,7 @@ switch(iz){ } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJydsigma.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJydsigma.cpp index 8b75171d4..4313cb2c7 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJydsigma.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJydsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void dJydsigma_model_neuron_o2(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -18,3 +22,7 @@ switch(iy){ } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJydy.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJydy.cpp index ba8b96a42..673a2eb12 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJydy.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJydy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void dJydy_model_neuron_o2(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -22,3 +26,7 @@ switch(iy){ } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJzdsigma.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJzdsigma.cpp index 7b365ef93..8b2465d46 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJzdsigma.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJzdsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void dJzdsigma_model_neuron_o2(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) { switch(iz){ case 0: @@ -18,3 +22,7 @@ switch(iz){ } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJzdz.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJzdz.cpp index 2facadf6d..96ba0d254 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJzdz.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dJzdz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void dJzdz_model_neuron_o2(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) { switch(iz){ case 0: @@ -22,3 +26,7 @@ switch(iz){ } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltaqB.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltaqB.cpp index 2030ebd41..7e19de1c0 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltaqB.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltaqB.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void deltaqB_model_neuron_o2(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) { switch (ip) { case 0: { @@ -55,3 +59,7 @@ switch (ip) { } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltasx.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltasx.cpp index e7332dc12..621cb92ed 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltasx.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltasx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void deltasx_model_neuron_o2(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) { switch (ip) { case 0: { @@ -91,3 +95,7 @@ switch (ip) { } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltax.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltax.cpp index 4e0041392..c77cf46cf 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltax.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltax.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void deltax_model_neuron_o2(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) { switch(ie) { case 0: { @@ -25,3 +29,7 @@ void deltax_model_neuron_o2(double *deltax, const realtype t, const realtype *x, } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltaxB.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltaxB.cpp index fa4aea82b..7d804618e 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltaxB.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_deltaxB.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void deltaxB_model_neuron_o2(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) { switch(ie) { case 0: { @@ -21,3 +25,7 @@ void deltaxB_model_neuron_o2(double *deltaxB, const realtype t, const realtype * } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_drzdx.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_drzdx.cpp index a5f1457d6..17787035b 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_drzdx.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_drzdx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void drzdx_model_neuron_o2(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { drzdx[0+0*5] = 1.0; drzdx[1+2*5] = 1.0; @@ -14,3 +18,7 @@ void drzdx_model_neuron_o2(double *drzdx, const int ie, const realtype t, const drzdx[4+8*5] = 1.0; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dwdx.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dwdx.cpp index 70beb0307..6ec331519 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dwdx.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dwdx.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void dwdx_model_neuron_o2(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) { dwdx[0] = 2.0/2.5E1; dwdx[1] = dwdx[0]; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dxdotdp.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dxdotdp.cpp index fa12e7c37..e9d6c535e 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dxdotdp.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dxdotdp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void dxdotdp_model_neuron_o2(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) { switch (ip) { case 0: { @@ -29,3 +33,7 @@ switch (ip) { } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dydx.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dydx.cpp index 407b3808d..977653516 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dydx.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dydx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void dydx_model_neuron_o2(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { dydx[0+0*5] = 1.0; dydx[1+2*5] = 1.0; @@ -14,3 +18,7 @@ void dydx_model_neuron_o2(double *dydx, const realtype t, const realtype *x, con dydx[4+8*5] = 1.0; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dzdx.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dzdx.cpp index f31216f67..7c60b2b6e 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dzdx.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_dzdx.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void dzdx_model_neuron_o2(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { dzdx[0+0*5] = -1.0/(k[1]+x[0]*5.0-x[1]+(x[0]*x[0])*(1.0/2.5E1)+1.4E2); dzdx[1+0*5] = x[2]*(x[0]*(2.0/2.5E1)+5.0)*1.0/pow(k[1]+x[0]*5.0-x[1]+(x[0]*x[0])*(1.0/2.5E1)+1.4E2,2.0); @@ -22,3 +26,7 @@ void dzdx_model_neuron_o2(double *dzdx, const int ie, const realtype t, const re dzdx[4+8*5] = -1.0/(k[1]+x[0]*5.0-x[1]+(x[0]*x[0])*(1.0/2.5E1)+1.4E2); } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_root.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_root.cpp index c7a488706..852a2806b 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_root.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_root.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void root_model_neuron_o2(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { root[0] = x[0]-3.0E1; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_rz.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_rz.cpp index 041268f4f..ff5a6c1f8 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_rz.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_rz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void rz_model_neuron_o2(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { switch(ie) { case 0: { @@ -20,3 +24,7 @@ void rz_model_neuron_o2(double *rz, const int ie, const realtype t, const realty } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sigmay.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sigmay.cpp index 282329527..5938f5e08 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sigmay.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sigmay.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void sigmay_model_neuron_o2(double *sigmay, const realtype t, const realtype *p, const realtype *k) { sigmay[0] = 1.0; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sigmaz.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sigmaz.cpp index e2c1e43ba..8ef2b748a 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sigmaz.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sigmaz.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void sigmaz_model_neuron_o2(double *sigmaz, const realtype t, const realtype *p, const realtype *k) { sigmaz[0] = 1.0; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_srz.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_srz.cpp index 64b2ecacc..22c9a50f4 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_srz.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_srz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void srz_model_neuron_o2(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) { switch (ip) { case 0: { @@ -71,3 +75,7 @@ switch (ip) { } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_stau.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_stau.cpp index 588bd7a65..70a8cf3a5 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_stau.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_stau.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void stau_model_neuron_o2(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) { switch (ip) { case 0: { @@ -55,3 +59,7 @@ switch (ip) { } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sx0.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sx0.cpp index adb0c6817..4fdd5f4a2 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sx0.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sx0.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void sx0_model_neuron_o2(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) { switch (ip) { case 1: { @@ -16,3 +20,7 @@ switch (ip) { } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sz.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sz.cpp index a0164573f..9720d8441 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sz.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_sz.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void sz_model_neuron_o2(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) { switch (ip) { case 0: { @@ -71,3 +75,7 @@ switch (ip) { } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_w.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_w.cpp index d7270709b..4f49da479 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_w.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_w.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void w_model_neuron_o2(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) { w[0] = x[0]*(2.0/2.5E1); w[1] = w[0]+5.0; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_x0.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_x0.cpp index 7921c85c1..0a997336b 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_x0.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_x0.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void x0_model_neuron_o2(realtype *x0, const realtype t, const realtype *p, const realtype *k) { x0[0] = k[0]; x0[1] = k[0]*p[1]; x0[5] = k[0]; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_xdot.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_xdot.cpp index 8778dbdff..809a83fa7 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_xdot.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_xdot.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void xdot_model_neuron_o2(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { xdot[0] = k[1]+x[0]*5.0-x[1]+(x[0]*x[0])*(1.0/2.5E1)+1.4E2; xdot[1] = -p[0]*(x[1]-p[1]*x[0]); @@ -19,3 +23,7 @@ void xdot_model_neuron_o2(realtype *xdot, const realtype t, const realtype *x, c xdot[9] = -p[0]*x[9]+p[0]*p[1]*x[8]; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_y.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_y.cpp index 3dbf2a602..f6aef48c8 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_y.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_y.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void y_model_neuron_o2(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { y[0] = x[0]; y[1] = x[2]; @@ -14,3 +18,7 @@ void y_model_neuron_o2(double *y, const realtype t, const realtype *x, const rea y[4] = x[8]; } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_z.cpp b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_z.cpp index 094dc8bbc..18af0194f 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2_z.cpp +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2_z.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_neuron_o2{ + void z_model_neuron_o2(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) { switch(ie) { case 0: { @@ -20,3 +24,7 @@ void z_model_neuron_o2(double *z, const int ie, const realtype t, const realtype } } +} // namespace model_model_neuron_o2 + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/wrapfunctions.cpp b/deps/AMICI/models/model_neuron_o2/wrapfunctions.cpp index b782c41cd..572bd4a1f 100644 --- a/deps/AMICI/models/model_neuron_o2/wrapfunctions.cpp +++ b/deps/AMICI/models/model_neuron_o2/wrapfunctions.cpp @@ -1,7 +1,16 @@ #include "amici/model.h" #include "wrapfunctions.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel() { - return std::unique_ptr(new Model_model_neuron_o2()); + return std::unique_ptr( + new amici::model_model_neuron_o2::Model_model_neuron_o2()); } +} // namespace generic_model + +} // namespace amici + diff --git a/deps/AMICI/models/model_neuron_o2/wrapfunctions.h b/deps/AMICI/models/model_neuron_o2/wrapfunctions.h index 159db4a98..52c7094f9 100644 --- a/deps/AMICI/models/model_neuron_o2/wrapfunctions.h +++ b/deps/AMICI/models/model_neuron_o2/wrapfunctions.h @@ -3,6 +3,14 @@ #include "model_neuron_o2.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel(); +} // namespace generic_model + +} // namespace amici + #endif /* _amici_wrapfunctions_h */ diff --git a/deps/AMICI/models/model_robertson/CMakeLists.txt b/deps/AMICI/models/model_robertson/CMakeLists.txt index 6e5ddf1a7..f96b13ec0 100644 --- a/deps/AMICI/models/model_robertson/CMakeLists.txt +++ b/deps/AMICI/models/model_robertson/CMakeLists.txt @@ -6,6 +6,10 @@ endif(POLICY CMP0060) if(POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif(POLICY CMP0065) +if(POLICY CMP0074) + # Use package_ROOT environment variables + cmake_policy(SET CMP0074 NEW) +endif(POLICY CMP0074) project(model_robertson) diff --git a/deps/AMICI/models/model_robertson/main.cpp b/deps/AMICI/models/model_robertson/main.cpp index 07ff62a32..f957df9ad 100644 --- a/deps/AMICI/models/model_robertson/main.cpp +++ b/deps/AMICI/models/model_robertson/main.cpp @@ -54,7 +54,7 @@ int main(int argc, char **argv) { hdffile = argv[1]; } - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); // Read AMICI settings and model parameters from HDF5 file diff --git a/deps/AMICI/models/model_robertson/model_robertson.h b/deps/AMICI/models/model_robertson/model_robertson.h index c526ad14a..381cd40d0 100644 --- a/deps/AMICI/models/model_robertson/model_robertson.h +++ b/deps/AMICI/models/model_robertson/model_robertson.h @@ -1,6 +1,6 @@ #ifndef _amici_model_robertson_h #define _amici_model_robertson_h -/* Generated by amiwrap (R2017b) 5193a397de39f5bd4b7d98718067dc71f02f916e */ +/* Generated by amiwrap (R2017b) 667c9f20a05dd5266e9453b50081d7fb933f7389 */ #include #include #include "amici/defines.h" @@ -9,9 +9,10 @@ #include "amici/model_dae.h" namespace amici { + class Solver; -} +namespace model_model_robertson{ extern void J_model_robertson(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx); extern void JB_model_robertson(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *xB, const realtype *dx, const realtype *dxB, const realtype *w, const realtype *dwdx); @@ -38,6 +39,7 @@ class Model_model_robertson : public amici::Model_DAE { 3, 3, 3, + 0, 3, 3, 0, @@ -62,7 +64,7 @@ class Model_model_robertson : public amici::Model_DAE { virtual amici::Model* clone() const override { return new Model_model_robertson(*this); }; - const std::string getAmiciCommit() const override { return "5193a397de39f5bd4b7d98718067dc71f02f916e"; }; + const std::string getAmiciCommit() const override { return "667c9f20a05dd5266e9453b50081d7fb933f7389"; }; virtual void fJ(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) override { J_model_robertson(J, t, x, p, k, h, cj, dx, w, dwdx); @@ -213,4 +215,8 @@ class Model_model_robertson : public amici::Model_DAE { }; +} // namespace model_model_robertson + +} // namespace amici + #endif /* _amici_model_robertson_h */ diff --git a/deps/AMICI/models/model_robertson/model_robertson_J.cpp b/deps/AMICI/models/model_robertson/model_robertson_J.cpp index b6e8dfe5c..7e67c2069 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_J.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_J.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void J_model_robertson(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) { J[0+0*3] = -cj-p[0]; J[0+1*3] = dwdx[0]; @@ -18,3 +22,7 @@ void J_model_robertson(realtype *J, const realtype t, const realtype *x, const d J[2+2*3] = 1.0; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_JB.cpp b/deps/AMICI/models/model_robertson/model_robertson_JB.cpp index b5565cb44..f8fbea25f 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_JB.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_JB.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void JB_model_robertson(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *xB, const realtype *dx, const realtype *dxB, const realtype *w, const realtype *dwdx) { JB[0+0*3] = cj+p[0]; JB[0+1*3] = -p[0]; @@ -18,3 +22,7 @@ void JB_model_robertson(realtype *JB, const realtype t, const realtype *x, const JB[2+2*3] = -1.0; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_JDiag.cpp b/deps/AMICI/models/model_robertson/model_robertson_JDiag.cpp index ee4036b31..4f00b7aaf 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_JDiag.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_JDiag.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void JDiag_model_robertson(realtype *JDiag, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) { JDiag[0+0*3] = -cj-p[0]; JDiag[1+0*3] = -cj-dwdx[0]-p[2]*x[1]*2.0; JDiag[2+0*3] = 1.0; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_JSparse.cpp b/deps/AMICI/models/model_robertson/model_robertson_JSparse.cpp index 69a051c36..46c0faa1d 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_JSparse.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_JSparse.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void JSparse_model_robertson(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) { JSparse->indexvals[0] = 0; JSparse->indexvals[1] = 1; @@ -32,3 +36,7 @@ void JSparse_model_robertson(SUNMatrixContent_Sparse JSparse, const realtype t, JSparse->data[8] = 1.0; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_JSparseB.cpp b/deps/AMICI/models/model_robertson/model_robertson_JSparseB.cpp index 044221c74..4ff239944 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_JSparseB.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_JSparseB.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void JSparseB_model_robertson(SUNMatrixContent_Sparse JSparseB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *xB, const realtype *dx, const realtype *dxB, const realtype *w, const realtype *dwdx) { JSparseB->indexvals[0] = 0; JSparseB->indexvals[1] = 1; @@ -32,3 +36,7 @@ void JSparseB_model_robertson(SUNMatrixContent_Sparse JSparseB, const realtype t JSparseB->data[8] = -1.0; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_Jy.cpp b/deps/AMICI/models/model_robertson/model_robertson_Jy.cpp index a39d31719..f3f5fe1a8 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_Jy.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_Jy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void Jy_model_robertson(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -20,3 +24,7 @@ switch(iy){ } } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_M.cpp b/deps/AMICI/models/model_robertson/model_robertson_M.cpp index 510596185..51b497e8f 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_M.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_M.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void M_model_robertson(realtype *M, const realtype t, const realtype *x, const realtype *p, const realtype *k) { M[0+0*3] = 1.0; M[1+1*3] = 1.0; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_dJydsigma.cpp b/deps/AMICI/models/model_robertson/model_robertson_dJydsigma.cpp index cc77cc1a8..b4a4419f8 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_dJydsigma.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_dJydsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void dJydsigma_model_robertson(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -20,3 +24,7 @@ switch(iy){ } } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_dJydy.cpp b/deps/AMICI/models/model_robertson/model_robertson_dJydy.cpp index 7844707aa..6b337d31e 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_dJydy.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_dJydy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void dJydy_model_robertson(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -20,3 +24,7 @@ switch(iy){ } } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_dwdp.cpp b/deps/AMICI/models/model_robertson/model_robertson_dwdp.cpp index 0d517496b..e7db2c139 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_dwdp.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_dwdp.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void dwdp_model_robertson(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) { dwdp[0] = x[1]*x[2]; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_dwdx.cpp b/deps/AMICI/models/model_robertson/model_robertson_dwdx.cpp index 79e13a04e..8e25dc518 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_dwdx.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_dwdx.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void dwdx_model_robertson(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) { dwdx[0] = p[1]*x[2]; dwdx[1] = p[1]*x[1]; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_dxdotdp.cpp b/deps/AMICI/models/model_robertson/model_robertson_dxdotdp.cpp index a0202e20a..0067e86b8 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_dxdotdp.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_dxdotdp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void dxdotdp_model_robertson(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *dx, const realtype *w, const realtype *dwdp) { switch (ip) { case 0: { @@ -28,3 +32,7 @@ switch (ip) { } } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_dydx.cpp b/deps/AMICI/models/model_robertson/model_robertson_dydx.cpp index ad07d5771..5ffe7dab1 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_dydx.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_dydx.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void dydx_model_robertson(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { dydx[0+0*3] = 1.0; dydx[1+1*3] = 1.0E4; dydx[2+2*3] = 1.0; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_sigmay.cpp b/deps/AMICI/models/model_robertson/model_robertson_sigmay.cpp index 658893539..6e57e3c50 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_sigmay.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_sigmay.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void sigmay_model_robertson(double *sigmay, const realtype t, const realtype *p, const realtype *k) { sigmay[0] = 1.0; sigmay[1] = 1.0; sigmay[2] = 1.0; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_w.cpp b/deps/AMICI/models/model_robertson/model_robertson_w.cpp index 987d470d3..f5e90c8e4 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_w.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_w.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void w_model_robertson(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) { w[0] = p[1]*x[1]*x[2]; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_x0.cpp b/deps/AMICI/models/model_robertson/model_robertson_x0.cpp index 5133754a8..ce0f24bfc 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_x0.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_x0.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void x0_model_robertson(realtype *x0, const realtype t, const realtype *p, const realtype *k) { x0[0] = k[0]; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_xdot.cpp b/deps/AMICI/models/model_robertson/model_robertson_xdot.cpp index 83a9045e0..a756a318a 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_xdot.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_xdot.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void xdot_model_robertson(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx, const realtype *w) { xdot[0] = w[0]-dx[0]-p[0]*x[0]; xdot[1] = -w[0]-dx[1]+p[0]*x[0]-p[2]*(x[1]*x[1]); xdot[2] = x[0]+x[1]+x[2]-1.0; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/model_robertson_y.cpp b/deps/AMICI/models/model_robertson/model_robertson_y.cpp index 5491953c5..9e66126e9 100644 --- a/deps/AMICI/models/model_robertson/model_robertson_y.cpp +++ b/deps/AMICI/models/model_robertson/model_robertson_y.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_robertson{ + void y_model_robertson(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { y[0] = x[0]; y[1] = x[1]*1.0E4; y[2] = x[2]; } +} // namespace model_model_robertson + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/wrapfunctions.cpp b/deps/AMICI/models/model_robertson/wrapfunctions.cpp index d2ba9511c..31b42cd13 100644 --- a/deps/AMICI/models/model_robertson/wrapfunctions.cpp +++ b/deps/AMICI/models/model_robertson/wrapfunctions.cpp @@ -1,7 +1,16 @@ #include "amici/model.h" #include "wrapfunctions.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel() { - return std::unique_ptr(new Model_model_robertson()); + return std::unique_ptr( + new amici::model_model_robertson::Model_model_robertson()); } +} // namespace generic_model + +} // namespace amici + diff --git a/deps/AMICI/models/model_robertson/wrapfunctions.h b/deps/AMICI/models/model_robertson/wrapfunctions.h index 91c667ca6..0771b13b6 100644 --- a/deps/AMICI/models/model_robertson/wrapfunctions.h +++ b/deps/AMICI/models/model_robertson/wrapfunctions.h @@ -3,6 +3,14 @@ #include "model_robertson.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel(); +} // namespace generic_model + +} // namespace amici + #endif /* _amici_wrapfunctions_h */ diff --git a/deps/AMICI/models/model_steadystate/CMakeLists.txt b/deps/AMICI/models/model_steadystate/CMakeLists.txt index d91835a80..edf5951bb 100644 --- a/deps/AMICI/models/model_steadystate/CMakeLists.txt +++ b/deps/AMICI/models/model_steadystate/CMakeLists.txt @@ -6,6 +6,10 @@ endif(POLICY CMP0060) if(POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif(POLICY CMP0065) +if(POLICY CMP0074) + # Use package_ROOT environment variables + cmake_policy(SET CMP0074 NEW) +endif(POLICY CMP0074) project(model_steadystate) diff --git a/deps/AMICI/models/model_steadystate/main.cpp b/deps/AMICI/models/model_steadystate/main.cpp index 07ff62a32..f957df9ad 100644 --- a/deps/AMICI/models/model_steadystate/main.cpp +++ b/deps/AMICI/models/model_steadystate/main.cpp @@ -54,7 +54,7 @@ int main(int argc, char **argv) { hdffile = argv[1]; } - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); // Read AMICI settings and model parameters from HDF5 file diff --git a/deps/AMICI/models/model_steadystate/model_steadystate.h b/deps/AMICI/models/model_steadystate/model_steadystate.h index 4489e3a66..cec809635 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate.h +++ b/deps/AMICI/models/model_steadystate/model_steadystate.h @@ -1,6 +1,6 @@ #ifndef _amici_model_steadystate_h #define _amici_model_steadystate_h -/* Generated by amiwrap (R2017b) 5dfc4abddf5cb50611e9881fcab074d8859ccc6b */ +/* Generated by amiwrap (R2017b) 667c9f20a05dd5266e9453b50081d7fb933f7389 */ #include #include #include "amici/defines.h" @@ -9,9 +9,10 @@ #include "amici/model_ode.h" namespace amici { + class Solver; -} +namespace model_model_steadystate{ extern void J_model_steadystate(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void JB_model_steadystate(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx); @@ -37,6 +38,7 @@ class Model_model_steadystate : public amici::Model_ODE { 3, 3, 3, + 0, 3, 3, 0, @@ -61,7 +63,7 @@ class Model_model_steadystate : public amici::Model_ODE { virtual amici::Model* clone() const override { return new Model_model_steadystate(*this); }; - const std::string getAmiciCommit() const override { return "5dfc4abddf5cb50611e9881fcab074d8859ccc6b"; }; + const std::string getAmiciCommit() const override { return "667c9f20a05dd5266e9453b50081d7fb933f7389"; }; virtual void fJ(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) override { J_model_steadystate(J, t, x, p, k, h, w, dwdx); @@ -208,4 +210,8 @@ class Model_model_steadystate : public amici::Model_ODE { }; +} // namespace model_model_steadystate + +} // namespace amici + #endif /* _amici_model_steadystate_h */ diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_J.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_J.cpp index 830cd0aac..f505ef8ae 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_J.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_J.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void J_model_steadystate(realtype *J, const realtype t, const realtype *x, const double *p, const double *k, const realtype *h, const realtype *w, const realtype *dwdx) { J[0+0*3] = -p[1]*x[1]-p[0]*dwdx[0]*2.0; J[0+1*3] = p[2]*2.0-p[1]*x[0]; @@ -18,3 +22,7 @@ void J_model_steadystate(realtype *J, const realtype t, const realtype *x, const J[2+2*3] = -k[3]-dwdx[1]; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_JB.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_JB.cpp index 4d336b1cc..0debd8213 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_JB.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_JB.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void JB_model_steadystate(realtype *JB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JB[0+0*3] = p[1]*x[1]+p[0]*dwdx[0]*2.0; JB[0+1*3] = p[1]*x[1]-p[0]*dwdx[0]; @@ -18,3 +22,7 @@ void JB_model_steadystate(realtype *JB, const realtype t, const realtype *x, con JB[2+2*3] = k[3]+dwdx[1]; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_JDiag.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_JDiag.cpp index 278cd6e36..21bdc9ff5 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_JDiag.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_JDiag.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void JDiag_model_steadystate(realtype *JDiag, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JDiag[0+0*3] = -p[1]*x[1]-p[0]*dwdx[0]*2.0; JDiag[1+0*3] = -p[2]-p[1]*x[0]; JDiag[2+0*3] = -k[3]-dwdx[1]; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_JSparse.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_JSparse.cpp index e8ddf773f..7cd519d68 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_JSparse.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_JSparse.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void JSparse_model_steadystate(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { JSparse->indexvals[0] = 0; JSparse->indexvals[1] = 1; @@ -32,3 +36,7 @@ void JSparse_model_steadystate(SUNMatrixContent_Sparse JSparse, const realtype t JSparse->data[8] = -k[3]-dwdx[1]; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_JSparseB.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_JSparseB.cpp index 035844f5b..abd8a84ca 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_JSparseB.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_JSparseB.cpp @@ -7,6 +7,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void JSparseB_model_steadystate(SUNMatrixContent_Sparse JSparseB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *xB, const realtype *w, const realtype *dwdx) { JSparseB->indexvals[0] = 0; JSparseB->indexvals[1] = 1; @@ -32,3 +36,7 @@ void JSparseB_model_steadystate(SUNMatrixContent_Sparse JSparseB, const realtype JSparseB->data[8] = k[3]+dwdx[1]; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_Jy.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_Jy.cpp index deca32c13..c2e525821 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_Jy.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_Jy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void Jy_model_steadystate(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -20,3 +24,7 @@ switch(iy){ } } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_dJydsigma.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_dJydsigma.cpp index 9b5e5b538..3b1d5259d 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_dJydsigma.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_dJydsigma.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void dJydsigma_model_steadystate(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -20,3 +24,7 @@ switch(iy){ } } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_dJydy.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_dJydy.cpp index 778d218c8..137c754b4 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_dJydy.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_dJydy.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void dJydy_model_steadystate(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) { switch(iy){ case 0: @@ -20,3 +24,7 @@ switch(iy){ } } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_dwdp.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_dwdp.cpp index 0f67cf641..20e991668 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_dwdp.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_dwdp.cpp @@ -6,7 +6,15 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void dwdp_model_steadystate(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) { dwdp[0] = x[2]; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_dwdx.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_dwdx.cpp index 55c5a862b..34b1f15eb 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_dwdx.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_dwdx.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void dwdx_model_steadystate(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) { dwdx[0] = x[0]*2.0; dwdx[1] = p[3]; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_dxdotdp.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_dxdotdp.cpp index 6dde31e4c..0ed5e880c 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_dxdotdp.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_dxdotdp.cpp @@ -6,6 +6,10 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void dxdotdp_model_steadystate(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) { switch (ip) { case 0: { @@ -42,3 +46,7 @@ switch (ip) { } } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_dydx.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_dydx.cpp index 6e1899c70..3f69ca1c4 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_dydx.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_dydx.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void dydx_model_steadystate(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) { dydx[0+0*3] = 1.0; dydx[1+1*3] = 1.0; dydx[2+2*3] = 1.0; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_sigmay.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_sigmay.cpp index a91a835f2..8e9ebc441 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_sigmay.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_sigmay.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void sigmay_model_steadystate(double *sigmay, const realtype t, const realtype *p, const realtype *k) { sigmay[0] = 1.0; sigmay[1] = 1.0; sigmay[2] = 1.0; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_w.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_w.cpp index a35d770d7..c968a93c4 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_w.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_w.cpp @@ -6,8 +6,16 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void w_model_steadystate(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) { w[0] = p[3]*x[2]; w[1] = x[0]*x[0]; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_x0.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_x0.cpp index 116ab783f..119314816 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_x0.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_x0.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void x0_model_steadystate(realtype *x0, const realtype t, const realtype *p, const realtype *k) { x0[0] = k[0]; x0[1] = k[1]; x0[2] = k[2]; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_xdot.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_xdot.cpp index 9fd005ec9..65b2ca396 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_xdot.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_xdot.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void xdot_model_steadystate(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { xdot[0] = p[4]+w[0]-p[0]*w[1]*2.0+p[2]*x[1]*2.0-p[1]*x[0]*x[1]; xdot[1] = w[0]+p[0]*w[1]-p[2]*x[1]-p[1]*x[0]*x[1]; xdot[2] = -w[0]-k[3]*x[2]+p[1]*x[0]*x[1]; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/model_steadystate_y.cpp b/deps/AMICI/models/model_steadystate/model_steadystate_y.cpp index d78c68cd8..9b2ea9ad6 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate_y.cpp +++ b/deps/AMICI/models/model_steadystate/model_steadystate_y.cpp @@ -6,9 +6,17 @@ typedef amici::realtype realtype; using namespace amici; +namespace amici { + +namespace model_model_steadystate{ + void y_model_steadystate(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) { y[0] = x[0]; y[1] = x[1]; y[2] = x[2]; } +} // namespace model_model_steadystate + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/wrapfunctions.cpp b/deps/AMICI/models/model_steadystate/wrapfunctions.cpp index 1395ad592..a7a0f3cf9 100644 --- a/deps/AMICI/models/model_steadystate/wrapfunctions.cpp +++ b/deps/AMICI/models/model_steadystate/wrapfunctions.cpp @@ -1,7 +1,16 @@ #include "amici/model.h" #include "wrapfunctions.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel() { - return std::unique_ptr(new Model_model_steadystate()); + return std::unique_ptr( + new amici::model_model_steadystate::Model_model_steadystate()); } +} // namespace generic_model + +} // namespace amici + diff --git a/deps/AMICI/models/model_steadystate/wrapfunctions.h b/deps/AMICI/models/model_steadystate/wrapfunctions.h index b05061c7f..57011adfa 100644 --- a/deps/AMICI/models/model_steadystate/wrapfunctions.h +++ b/deps/AMICI/models/model_steadystate/wrapfunctions.h @@ -3,6 +3,14 @@ #include "model_steadystate.h" +namespace amici { + +namespace generic_model { + std::unique_ptr getModel(); +} // namespace generic_model + +} // namespace amici + #endif /* _amici_wrapfunctions_h */ diff --git a/deps/AMICI/python/amici/__init__.py b/deps/AMICI/python/amici/__init__.py index e39816c26..1ca9a9579 100644 --- a/deps/AMICI/python/amici/__init__.py +++ b/deps/AMICI/python/amici/__init__.py @@ -40,6 +40,8 @@ import sys from contextlib import suppress from types import ModuleType +from typing import Optional, Union, Sequence, List + def _get_amici_path(): """ @@ -59,8 +61,7 @@ def _get_commit_hash(): ( file for file in [ os.path.join(basedir, '.git', 'FETCH_HEAD'), - os.path.join(basedir, '.git', 'ORIG_HEAD'), - ] + os.path.join(basedir, '.git', 'ORIG_HEAD'), ] if os.path.isfile(file) ), None @@ -72,6 +73,28 @@ def _get_commit_hash(): return 'unknown' +def _imported_from_setup() -> bool: + """Check whether this module is imported from `setup.py`""" + + from inspect import getouterframes, currentframe + + # in case we are imported from setup.py, this will be the AMICI package + # root directory (otherwise it is most likely the Python library directory, + # we are not interested in) + package_root = os.path.realpath(os.path.dirname(os.path.dirname(__file__))) + + for frame in getouterframes(currentframe()): + # Need to compare the full path, in case a user tries to import AMICI + # from a module `*setup.py`. Will still cause trouble if some package + # requires the AMICI extension during its installation, but seems + # unlikely... + frame_path = os.path.realpath(os.path.expanduser(frame.filename)) + if frame_path == os.path.join(package_root, 'setup.py'): + return True + + return False + + # redirect C/C++ stdout to python stdout if python stdout is redirected, # e.g. in ipython notebook capture_cstdout = suppress @@ -81,80 +104,50 @@ def _get_commit_hash(): except ModuleNotFoundError: pass -hdf5_enabled = False -has_clibs = False - -try: - # Try importing AMICI SWIG-interface with HDF5 enabled - from . import amici - from .amici import * - hdf5_enabled = True - has_clibs = True -except ModuleNotFoundError: - # import from setuptools or installation with `--no-clibs` - pass -except (ImportError, AttributeError) as e: - # No such module exists or there are some dynamic linking problems - if isinstance(e, AttributeError) or "cannot import name" in str(e): - # No such module exists (ImportError), - # or python tries to import a HDF5 function from the non-hdf5 - # swig interface (AttributeError): - # try importing AMICI SWIG-interface without HDF5 - try: - from . import amici_without_hdf5 as amici - from .amici_without_hdf5 import * - has_clibs = True - except ModuleNotFoundError: - # import from setuptools or installation with `--no-clibs` - pass - except ImportError as e: - if "cannot import name" in str(e): - # No such module exists - # this probably means, the model was imported during setuptools - # `setup` or after an installation with `--no-clibs`. - pass - else: - # Probably some linking problem that we don't want to hide - raise e - else: - # Probably some linking problem that we don't want to hide - raise e - -from typing import Optional, Union, Sequence, List -AmiciModel = Union['amici.Model', 'amici.ModelPtr'] -AmiciSolver = Union['amici.Solver', 'amici.SolverPtr'] -AmiciExpData = Union['amici.ExpData', 'amici.ExpDataPtr'] -AmiciExpDataVector = Union['amici.ExpDataPtrVector', Sequence[AmiciExpData]] - # Initialize AMICI paths amici_path = _get_amici_path() amiciSwigPath = os.path.join(amici_path, 'swig') amiciSrcPath = os.path.join(amici_path, 'src') amiciModulePath = os.path.dirname(__file__) +hdf5_enabled = os.path.isfile(os.path.join(amici_path, 'amici.py')) +has_clibs = any([os.path.isfile(os.path.join(amici_path, wrapper)) + for wrapper in ['amici.py', 'amici_without_hdf5.py']]) + +AmiciModel = Union['amici.Model', 'amici.ModelPtr'] +AmiciSolver = Union['amici.Solver', 'amici.SolverPtr'] +AmiciExpData = Union['amici.ExpData', 'amici.ExpDataPtr'] +AmiciExpDataVector = Union['amici.ExpDataPtrVector', Sequence[AmiciExpData]] + # Get version number from file with open(os.path.join(amici_path, 'version.txt')) as f: __version__ = f.read().strip() __commit__ = _get_commit_hash() -try: - # These module require the swig interface and other dependencies which will - # be installed if the the AMICI package was properly installed. If not, - # AMICI was probably imported from setup.py and we don't need those. +# Import SWIG module and swig-dependent submodules if required and available +if not _imported_from_setup(): + if has_clibs: + if hdf5_enabled: + from . import amici + from .amici import * + else: + from . import amici_without_hdf5 as amici + from .amici_without_hdf5 import * + + # These module require the swig interface and other dependencies + from .numpy import ReturnDataView, ExpDataView + from .pandas import ( + getEdataFromDataFrame, + getDataObservablesAsDataFrame, + getSimulationObservablesAsDataFrame, + getSimulationStatesAsDataFrame, + getResidualsAsDataFrame + ) + + # These modules don't require the swig interface from .sbml_import import SbmlImporter, assignmentRules2observables - from .numpy import ReturnDataView, ExpDataView - from .pandas import getEdataFromDataFrame, \ - getDataObservablesAsDataFrame, getSimulationObservablesAsDataFrame, \ - getSimulationStatesAsDataFrame, getResidualsAsDataFrame from .ode_export import ODEModel, ODEExporter -except (ModuleNotFoundError, ImportError) as e: - # import from setuptools or installation with `--no-clibs` - if has_clibs: - # cannot raise as we may also end up here when installing from an - # already installed in-source installation without all requirements - # installed (e.g. fresh virtualenv) - print(f'Suppressing error {str(e)}') def runAmiciSimulation( @@ -268,6 +261,7 @@ def writeSolverSettingsToHDF5( class add_path: """Context manager for temporarily changing PYTHONPATH""" + def __init__(self, path: str): self.path: str = path @@ -302,5 +296,4 @@ def import_model_module(module_name: str, importlib.reload(sys.modules[module_name]) return sys.modules[module_name] - return importlib.import_module(module_name) diff --git a/deps/AMICI/python/amici/custom_commands.py b/deps/AMICI/python/amici/custom_commands.py index 7daea05ad..c0efa1cb6 100644 --- a/deps/AMICI/python/amici/custom_commands.py +++ b/deps/AMICI/python/amici/custom_commands.py @@ -1,5 +1,6 @@ """Custom setuptools commands for AMICI installation""" +import contextlib import glob import os import subprocess @@ -113,6 +114,15 @@ def build_libraries(self, libraries: List[Library]): set_compiler_specific_library_options( libraries, self.compiler.compiler_type) + # Monkey-patch setuptools, to force recompilation of library sources + # --force does not work as expected + + # need full import here, not module-level imported build_clib + import setuptools.command.build_clib + # the patched function may return anything but `([], [])` to trigger + # recompilation + setuptools.command.build_clib.newer_pairwise_group = lambda *_: None + build_clib.build_libraries(self, libraries) @@ -189,7 +199,13 @@ def run(self): no_clibs |= 'install' in self.distribution.command_obj \ and self.get_finalized_command('install').no_clibs + lib_dir = "" if self.inplace \ + else self.get_finalized_command('build_py').build_lib + + remove_swig_wrappers(self.extensions, no_clibs, lib_dir) + if no_clibs: + # Nothing to build return if not self.dry_run and self.distribution.has_c_libraries(): @@ -335,3 +351,26 @@ def set_compiler_specific_extension_options( except AttributeError: # No compiler-specific options set pass + + +def remove_swig_wrappers(extensions: 'setuptools.Extension', + no_clibs: bool, lib_dir: str) -> None: + """Remove swig wrapper files not needed by the built extensions""" + + # remove swig-python-wrapper files + unused_swig_wrappers = {'amici/amici_wrap.cxx', + 'amici/amici_wrap_without_hdf5.cxx'} + if not no_clibs: + # check for used c++ interface files + for ext in extensions: + unused_swig_wrappers -= set(ext.sources) + + if 'amici/amici_wrap.cxx' in unused_swig_wrappers: + unused_swig_wrappers.add('amici/amici.py') + if 'amici/amici_wrap_without_hdf5.cxx' in unused_swig_wrappers: + unused_swig_wrappers.add('amici/amici_without_hdf5.py') + + for filename in unused_swig_wrappers: + with contextlib.suppress(FileNotFoundError): + log.info(f"Removing unused SWIG wrapper {os.path.realpath(filename)}") + os.remove(os.path.join(lib_dir, filename)) diff --git a/deps/AMICI/python/amici/gradient_check.py b/deps/AMICI/python/amici/gradient_check.py index 1ab90fabf..8ce065d34 100644 --- a/deps/AMICI/python/amici/gradient_check.py +++ b/deps/AMICI/python/amici/gradient_check.py @@ -152,10 +152,10 @@ def check_derivatives(model: Model, leastsquares_applicable = \ solver.getSensitivityMethod() == SensitivityMethod_forward - if 'ssigmay' in rdata.keys(): - if rdata['ssigmay'] is not None: - if rdata['ssigmay'].any(): - leastsquares_applicable = False + if 'ssigmay' in rdata.keys() \ + and rdata['ssigmay'] is not None \ + and rdata['ssigmay'].any(): + leastsquares_applicable = False if leastsquares_applicable: fields += ['res', 'x', 'y'] diff --git a/deps/AMICI/python/amici/logging.py b/deps/AMICI/python/amici/logging.py index 6120f9606..6b7a5df6f 100644 --- a/deps/AMICI/python/amici/logging.py +++ b/deps/AMICI/python/amici/logging.py @@ -13,6 +13,8 @@ import time import functools +from inspect import getouterframes, currentframe + LOG_LEVEL_ENV_VAR = 'AMICI_LOG' BASE_LOGGER_NAME = 'amici' # Supported values for LOG_LEVEL_ENV_VAR @@ -175,12 +177,25 @@ def log_execution_time(description: str, logger: logging.Logger) -> Callable: def decorator_timer(func): @functools.wraps(func) def wrapper_timer(*args, **kwargs): + + # append pluses to indicate recursion level + recursion_level = sum( + frame.function == 'wrapper_timer' + and frame.filename == __file__ + for frame in getouterframes(currentframe()) + ) + + recursion = '' + if recursion_level > 1: + recursion = '+' * (recursion_level - 1) + tstart = time.perf_counter() rval = func(*args, **kwargs) tend = time.perf_counter() - spacers = ' ' * max(55 - len(description) - len(logger.name), 0) + spacers = ' ' * max(54 - len(description) - len(logger.name) - + len(recursion), 0) logger.info(f'Finished {description}{spacers}' - f'({(tend - tstart):.2E}s)') + f'{recursion} ({(tend - tstart):.2E}s)') return rval return wrapper_timer return decorator_timer diff --git a/deps/AMICI/python/amici/numpy.py b/deps/AMICI/python/amici/numpy.py index 76a075766..bfc83e6a8 100644 --- a/deps/AMICI/python/amici/numpy.py +++ b/deps/AMICI/python/amici/numpy.py @@ -1,39 +1,37 @@ import numpy as np import copy import collections + from . import ExpDataPtr, ReturnDataPtr, ExpData, ReturnData +from typing import Union, List, Dict, Iterator class SwigPtrView(collections.abc.Mapping): - """ Interface class to expose std::vector and scalar members of + """ + Interface class to expose std::vector and scalar members of swig wrapped C++ objects as numpy array attributes and fields. This class is memory efficient as copies of the underlying C++ objects is only created when respective fields are accessed for the first time. Cached copies are used for all subsequent calls. - Attributes: - _swigptr: pointer to the c++ object - @type SwigPtr - _field_names: names of members that will be exposed as numpy arrays - @type list - _field_dimensions: dimensions of numpy arrays @type list - _cache: dictionary with cached values @type dict + :ivar _swigptr: pointer to the c++ object + :ivar _field_names: names of members that will be exposed as numpy arrays + :ivar _field_dimensions: dimensions of numpy arrays + :ivar _cache: dictionary with cached values """ _swigptr = None - _field_names = [] - _field_dimensions = dict() + _field_names: List[str] = [] + _field_dimensions: Dict[str, List[int]] = dict() - def __getitem__(self, item): - """Access to field names, copies data from C++ object into numpy + def __getitem__(self, item: str) -> Union[np.ndarray, float]: + """ + Access to field names, copies data from C++ object into numpy array, reshapes according to field dimensions and stores values in cache. - Arguments: - item: field name - - Returns: - value @type numpy.array or float + :param item: field name + :return: value """ if self._swigptr is None: raise NotImplementedError('Cannot get items from abstract class.') @@ -47,70 +45,61 @@ def __getitem__(self, item): if item not in self._field_names: self.__missing__(item) - value = fieldAsNumpy( + value = field_as_numpy( self._field_dimensions, item, self._swigptr ) self._cache[item] = value return value - def __missing__(self, key): - """Default behaviour for missing keys - - Arguments: - key: field name - - Returns: + def __missing__(self, key: str) -> None: + """ + Default behaviour for missing keys - Raises: - KeyError + :param key: field name """ raise KeyError(f'Unknown field name {key}.') - def __getattr__(self, item): - """Attribute accessor for field names + def __getattr__(self, item) -> Union[np.ndarray, float]: + """ + Attribute accessor for field names - Arguments: - item: field name + :param item: field name - Returns: - value @type numpy.array or float + :returns: value """ return self.__getitem__(item) def __init__(self, swigptr): - """Constructor - - Arguments: - swigptr: pointer to the C++ object + """ + Constructor + :param swigptr: pointer to the C++ object """ self._swigptr = swigptr self._cache = dict() super(SwigPtrView, self).__init__() - def __len__(self): - """Returns the number of available keys/fields + def __len__(self) -> int: + """ + Returns the number of available keys/fields - Returns: - length of _field_names @type int + :returns: length of _field_names """ return len(self._field_names) - def __iter__(self): - """Create an iterator of the keys/fields + def __iter__(self) -> Iterator: + """ + Create an iterator of the keys/fields - Returns: - iterator over _field_names @type iter + :returns: iterator over _field_names """ return iter(self._field_names) def __copy__(self): - """Create a shallow copy - - Arguments: + """ + Create a shallow copy - Returns: - SwigPtrView shallow copy @type SwigPtrView + :return: SwigPtrView shallow copy """ other = SwigPtrView(self._swigptr) other._field_names = self._field_names @@ -118,25 +107,23 @@ def __copy__(self): other._cache = self._cache return other - def __contains__(self, item): - """Faster implementation of __contains__ that avoids copy of the field + def __contains__(self, item) -> bool: + """ + Faster implementation of __contains__ that avoids copy of the field - Arguments: - item: item to check for + :param item: item to check for - Returns: - whether item is available as key @type bool + :returns: whether item is available as key """ return item in self._field_names def __deepcopy__(self, memo): - """Create a deep copy + """ + Create a deep copy - Arguments: - memo: dict with id-to-object mapping + :param memo: dict with id-to-object mapping - Returns: - SwigPtrView deep copy @type SwigPtrView + :returns: SwigPtrView deep copy """ other = SwigPtrView(self._swigptr) other._field_names = copy.deepcopy(self._field_names) @@ -146,7 +133,8 @@ def __deepcopy__(self, memo): class ReturnDataView(SwigPtrView): - """ Interface class for C++ Return Data objects that avoids possibly costly + """ + Interface class for C++ Return Data objects that avoids possibly costly copies of member data. """ @@ -154,20 +142,22 @@ class ReturnDataView(SwigPtrView): 'ts', 'x', 'x0', 'x_ss', 'sx', 'sx0', 'sx_ss', 'y', 'sigmay', 'sy', 'ssigmay', 'z', 'rz', 'sigmaz', 'sz', 'srz', 'ssigmaz', 'sllh', 's2llh', 'J', 'xdot', 'status', 'llh', - 'chi2', 'res', 'sres', 'FIM', 'w', 'wrms_steadystate', 't_steadystate', - 'newton_numlinsteps', 'newton_numsteps', 'newton_cpu_time', - 'numsteps', 'numrhsevals', 'numerrtestfails', - 'numnonlinsolvconvfails', 'order', 'cpu_time', - 'numstepsB','numrhsevalsB', 'numerrtestfailsB', + 'chi2', 'res', 'sres', 'FIM', 'w', + 'preeq_wrms', 'preeq_t', 'preeq_numlinsteps', 'preeq_numsteps', + 'preeq_numstepsB', 'preeq_status', 'preeq_cpu_time', + 'preeq_cpu_timeB', 'posteq_wrms', 'posteq_t', 'posteq_numlinsteps', + 'posteq_numsteps', 'posteq_numstepsB', 'posteq_status', + 'posteq_cpu_time', 'posteq_cpu_timeB', 'numsteps', 'numrhsevals', + 'numerrtestfails', 'numnonlinsolvconvfails', 'order', 'cpu_time', + 'numstepsB', 'numrhsevalsB', 'numerrtestfailsB', 'numnonlinsolvconvfailsB', 'cpu_timeB' ] - def __init__(self, rdata): - """Constructor - - Arguments: - rdata: pointer to the ReturnData instance + def __init__(self, rdata: Union[ReturnDataPtr, ReturnData]): + """ + Constructor + :param rdata: pointer to the ReturnData instance """ if not isinstance(rdata, (ReturnDataPtr, ReturnData)): raise TypeError(f'Unsupported pointer {type(rdata)}, must be' @@ -207,8 +197,12 @@ def __init__(self, rdata): 'J': [rdata.nx_solver, rdata.nx_solver], 'w': [rdata.nt, rdata.nw], 'xdot': [rdata.nx_solver], - 'newton_numlinsteps': [rdata.newton_maxsteps, 2], - 'newton_numsteps': [1, 3], + 'preeq_numlinsteps': [rdata.newton_maxsteps, 2], + 'preeq_numsteps': [1, 3], + 'preeq_status': [1, 3], + 'posteq_numlinsteps': [rdata.newton_maxsteps, 2], + 'posteq_numsteps': [1, 3], + 'posteq_status': [1, 3], 'numsteps': [rdata.nt], 'numrhsevals': [rdata.nt], 'numerrtestfails': [rdata.nt], @@ -221,14 +215,14 @@ def __init__(self, rdata): } super(ReturnDataView, self).__init__(rdata) - def __getitem__(self, item): - """Custom getitem implementation shim to map `t` to `ts` + def __getitem__(self, item: str) -> Union[np.ndarray, ReturnDataPtr, + ReturnData, float]: + """ + Custom getitem implementation shim to map `t` to `ts` - Arguments: - item: field/attribute key + :param item: field/attribute key - Returns: - self[item] @type numpy.array/float + :returns: self[item] """ if item == 't': item = 'ts' @@ -236,7 +230,8 @@ def __getitem__(self, item): class ExpDataView(SwigPtrView): - """ Interface class for C++ Exp Data objects that avoids possibly costly + """ + Interface class for C++ Exp Data objects that avoids possibly costly copies of member data. """ @@ -247,12 +242,11 @@ class ExpDataView(SwigPtrView): 'fixedParametersPresimulation' ] - def __init__(self, edata): - """Constructor - - Arguments: - edata: pointer to the ExpData instance + def __init__(self, edata: Union[ExpDataPtr, ExpData]): + """ + Constructor + :param edata: pointer to the ExpData instance """ if not isinstance(edata, (ExpDataPtr, ExpData)): raise TypeError(f'Unsupported pointer {type(edata)}, must be' @@ -279,22 +273,21 @@ def __init__(self, edata): super(ExpDataView, self).__init__(edata) -def fieldAsNumpy(field_dimensions, field, data): - """ Convert data object field to numpy array with dimensions according to +def field_as_numpy(field_dimensions: Dict[str, List[int]], + field: str, data: SwigPtrView) -> Union[np.ndarray, + float, + None]: + """ + Convert data object field to numpy array with dimensions according to specified field dimensions - Arguments: - field_dimensions: dimension specifications + :param field_dimensions: dimension specifications dict({field: list([dim1, dim2, ...])}) - data: object with fields - field: Name of field - - Returns: - Field Data as numpy array with dimensions according to specified field - dimensions - - Raises: + :param data: object with fields + :param field: Name of field + :returns: Field Data as numpy array with dimensions according to + specified field dimensions """ attr = getattr(data, field) if field in field_dimensions.keys(): diff --git a/deps/AMICI/python/amici/ode_export.py b/deps/AMICI/python/amici/ode_export.py index 096c21ef7..6e202c354 100644 --- a/deps/AMICI/python/amici/ode_export.py +++ b/deps/AMICI/python/amici/ode_export.py @@ -24,7 +24,9 @@ except ImportError: pysb = None -from typing import Callable, Optional, Union, List, Dict, Tuple, SupportsFloat +from typing import ( + Callable, Optional, Union, List, Dict, Tuple, SupportsFloat, Sequence +) from string import Template import sympy.printing.cxxcode as cxxcode from sympy.matrices.immutable import ImmutableDenseMatrix @@ -242,7 +244,7 @@ sensi_functions = [ function for function in functions if 'const int ip' in functions[function]['signature'] - and function is not 'sxdot' + and function != 'sxdot' ] # list of multiobs functions multiobs_functions = [ @@ -624,6 +626,58 @@ def __init__(self, } +def smart_jacobian(eq: sp.MutableDenseMatrix, + sym_var: sp.MutableDenseMatrix) -> sp.MutableDenseMatrix: + """ + Wrapper around symbolic jacobian with some additional checks that reduce + computation time for large matrices + + :param eq: + equation + :param sym_var: + differentiation variable + :return: + jacobian of eq wrt sym_var + """ + if min(eq.shape) and min(sym_var.shape) \ + and not smart_is_zero_matrix(eq) \ + and not smart_is_zero_matrix(sym_var) \ + and not sym_var.free_symbols.isdisjoint(eq.free_symbols): + return eq.jacobian(sym_var) + return sp.zeros(eq.shape[0], sym_var.shape[0]) + + +def smart_multiply(x: sp.MutableDenseMatrix, + y: sp.MutableDenseMatrix) -> sp.MutableDenseMatrix: + """ + Wrapper around symbolic multiplication with some additional checks that + reduce computation time for large matrices + + :param x: + educt 1 + :param y: + educt 2 + :return: + product + """ + if not x.shape[0] or not y.shape[1] or smart_is_zero_matrix(x) or \ + smart_is_zero_matrix(y): + return sp.zeros(x.shape[0], y.shape[1]) + return x * y + + +def smart_is_zero_matrix(x: sp.MutableDenseMatrix) -> bool: + """A faster implementation of sympy's is_zero_matrix + + Avoids repeated indexer type checks and double iteration to distinguish + False/None. Found to be about 100x faster for large matrices. + + :param x: Matrix to check + """ + + return not any(xx.is_zero is not True for xx in x._mat) + + class ODEModel: """ Defines an Ordinary Differential Equation as set of ModelQuantities. @@ -724,6 +778,10 @@ class ODEModel: derivative expressions. Receives sympy expressions as only argument. To apply multiple simplifications, wrap them in a lambda expression. NOTE: This does currently not work with PySB symbols. + + :ivar _x0_fixedParameters_idx: + Index list of subset of states for which x0_fixedParameters was + computed """ def __init__(self, simplify: Optional[Callable] = sp.powsimp): @@ -821,9 +879,11 @@ def __init__(self, simplify: Optional[Callable] = sp.powsimp): self._lock_total_derivative: List[str] = list() self._simplify: Callable = simplify + self._x0_fixedParameters_idx: Union[None, Sequence[int]] def import_from_sbml_importer(self, - si: 'sbml_import.SbmlImporter') -> None: + si: 'sbml_import.SbmlImporter', + compute_cls: Optional[bool] = True) -> None: """ Imports a model specification from a :class:`amici.sbml_import.SbmlImporter` @@ -833,24 +893,91 @@ def import_from_sbml_importer(self, imported SBML model """ + # get symbolic expression from SBML importers symbols = copy.copy(si.symbols) - # setting these equations prevents native equation generation - self._eqs['dxdotdw'] = si.stoichiometric_matrix - self._eqs['w'] = si.flux_vector - self._syms['w'] = sp.Matrix( - [sp.Symbol(f'flux_r{idx}', real=True) - for idx in range(len(si.flux_vector))] - ) - self._eqs['dxdotdx'] = sp.zeros(si.stoichiometric_matrix.shape[0]) - if len(si.stoichiometric_matrix): - symbols['species']['dt'] = \ - si.stoichiometric_matrix * self.sym('w') - else: - symbols['species']['dt'] = sp.zeros( - *symbols['species']['identifier'].shape - ) - + # assemble fluxes and add them as expressions to the model + fluxes = [] + for ir, flux in enumerate(si.flux_vector): + flux_id = sp.Symbol(f'flux_r{ir}', real=True) + self.add_component(Expression( + identifier=flux_id, + name=str(flux), + value=flux + )) + fluxes.append(flux_id) + nr = len(fluxes) + + # correct time derivatives for compartment changes + + dxdotdw_updates = [] + def dx_dt(x_index, x_Sw): + ''' + Produces the appropriate expression for the first derivative of a + species with respect to time, for species that reside in + compartments with a constant volume, or a volume that is defined by + an assignment or rate rule. + + :param x_index: + The index (not identifier) of the species in the variables + (generated in "sbml_import.py") that describe the model. + + :param x_Sw: + The element-wise product of the row in the stoichiometric + matrix that corresponds to the species (row x_index) and the + flux (kinetic laws) vector. Ignored in the case of rate rules. + ''' + x_id = symbols['species']['identifier'][x_index] + + # Rate rules specify dx_dt. + # Note that the rate rule of species may describe amount, not + # concentration. + if x_id in si.compartment_rate_rules: + return si.compartment_rate_rules[x_id] + elif x_id in si.species_rate_rules: + return si.species_rate_rules[x_id] + + # The derivation of the below return expressions can be found in + # the documentation. They are found by rearranging + # $\frac{d}{dt} (vx) = Sw$ for $\frac{dx}{dt}$, where $v$ is the + # vector of species compartment volumes, $x$ is the vector of + # species concentrations, $S$ is the stoichiometric matrix, and $w$ + # is the flux vector. The conditional below handles the cases of + # species in (i) compartments with a rate rule, (ii) compartments + # with an assignment rule, and (iii) compartments with a constant + # volume, respectively. + v_name = si.species_compartment[x_index] + if v_name in si.compartment_rate_rules: + dv_dt = si.compartment_rate_rules[v_name] + xdot = (x_Sw - dv_dt*x_id)/v_name + for w_index, flux in enumerate(fluxes): + dxdotdw_updates.append((x_index, w_index, xdot.diff(flux))) + return xdot + elif v_name in si.compartment_assignment_rules: + v = si.compartment_assignment_rules[v_name] + dv_dt = v.diff(si.amici_time_symbol) + dv_dx = v.diff(x_id) + xdot = (x_Sw - dv_dt*x_id)/(dv_dx*x_id + v) + for w_index, flux in enumerate(fluxes): + dxdotdw_updates.append((x_index, w_index, xdot.diff(flux))) + return xdot + else: + v = si.compartment_volume[list(si.compartment_symbols).index( + si.species_compartment[x_index])] + for w_index, flux in enumerate(fluxes): + if si.stoichiometric_matrix[x_index, w_index] != 0: + dxdotdw_updates.append((x_index, w_index, + si.stoichiometric_matrix[x_index, w_index] / v)) + return x_Sw/v + + # create dynamics without respecting conservation laws first + Sw = smart_multiply(MutableDenseMatrix(si.stoichiometric_matrix), + MutableDenseMatrix(fluxes)) + symbols['species']['dt'] = sp.Matrix([Sw.row(x_index).applyfunc( + lambda x_Sw: dx_dt(x_index, x_Sw)) + for x_index in range(Sw.rows)]) + + # create all basic components of the ODE model and add them. for symbol in [s for s in symbols if s != 'my']: # transform dict of lists into a list of dicts protos = [dict(zip(symbols[symbol], t)) @@ -858,6 +985,27 @@ def import_from_sbml_importer(self, for proto in protos: self.add_component(symbol_to_type[symbol](**proto)) + # process conservation laws + if compute_cls: + dxdotdw_updates = si.process_conservation_laws(self, + dxdotdw_updates) + + # set derivatives of xdot, this circumvents regular computation. we + # do this as we can save a substantial amount of computations by + # knowing the right solutions here + nx_solver = si.stoichiometric_matrix.shape[0] + nw = len(self._expressions) + # append zero rows for conservation law `w`s, note that + # _process_conservation_laws is called after the fluxes are added as + # expressions, if this ordering needs to be changed, this will have + # to be adapted. + self._eqs['dxdotdw'] = si.stoichiometric_matrix.row_join( + sp.zeros(nx_solver, nw-nr) + ) + for ix, iw, val in dxdotdw_updates: + self._eqs['dxdotdw'][ix, iw] = val + + # fill in 'self._sym' based on prototypes and components in ode_model self.generate_basic_variables() def add_component(self, component: ModelQuantity) -> None: @@ -874,7 +1022,8 @@ def add_component(self, component: ModelQuantity) -> None: component ) return - Exception(f'Invalid component type {type(component)}') + + raise ValueError(f'Invalid component type {type(component)}') def add_conservation_law(self, state: sp.Symbol, @@ -882,20 +1031,27 @@ def add_conservation_law(self, state_expr: sp.Basic, abundance_expr: sp.Basic) -> None: """ - Adds a new conservation law to the model. + Adds a new conservation law to the model. A conservation law is defined + by the conserved quantity T = sum_i(a_i * x_i), where a_i are + coefficients and x_i are different state variables. :param state: symbolic identifier of the state that should be replaced by - the conservation law + the conservation law (x_j) :param total_abundance: - symbolic identifier of the total abundance + symbolic identifier of the total abundance (T/a_j) :param state_expr: - symbolic algebraic formula that replaces the the state + symbolic algebraic formula that replaces the the state. This is + used to compute the numeric value of of `state` during simulations. + x_j = T/a_j - sum_i≠j(a_i * x_i)/a_j :param abundance_expr: - symbolic algebraic formula that computes the total abundance + symbolic algebraic formula that computes the value of the + conserved quantity. This is used to update the numeric value for + `total_abundance` after (re-)initialization. + T/a_j = sum_i≠j(a_i * x_i)/a_j + x_j """ try: ix = [ @@ -903,8 +1059,8 @@ def add_conservation_law(self, for s in self._states ].index(state) except ValueError: - raise Exception(f'Specified state {state} was not found in the ' - f'model states.') + raise ValueError(f'Specified state {state} was not found in the ' + f'model states.') state_id = self._states[ix].get_id() @@ -949,6 +1105,18 @@ def ncl(self) -> int: """ return self.nx_rdata()-self.nx_solver() + def nx_solver_reinit(self) -> int: + """ + Number of solver states which would be reinitialized after + preequilibraiton + + :return: + number of state variable symbols with reinitialization + """ + reinit_states = self.eq('x0_fixedParameters') + solver_states = self.eq('x_solver') + return sum([1 for ix in reinit_states if ix in solver_states]) + def ny(self) -> int: """ Number of Observables. @@ -1016,7 +1184,7 @@ def sparsesym(self, name: str) -> List[str]: """ if name not in sparse_functions: - raise Exception(f'{name} is not marked as sparse') + raise ValueError(f'{name} is not marked as sparse') if name not in self._sparsesyms: self._generate_sparse_symbol(name) return self._sparsesyms[name] @@ -1034,7 +1202,8 @@ def eq(self, name: str) -> sp.Matrix: """ if name not in self._eqs: - self._compute_equation(name) + dec = log_execution_time(f'computing {name}', logger) + dec(self._compute_equation)(name) return self._eqs[name] def sparseeq(self, name) -> sp.Matrix: @@ -1046,16 +1215,17 @@ def sparseeq(self, name) -> sp.Matrix: name of the symbolic variable :return: - linearized symengine.DenseMatrix containing the symbolic formulas + linearized matrix containing the symbolic formulas """ if name not in sparse_functions: - raise Exception(f'{name} is not marked as sparse') + raise ValueError(f'{name} is not marked as sparse') if name not in self._sparseeqs: self._generate_sparse_symbol(name) return self._sparseeqs[name] - def colptrs(self, name: str) -> List[sp.Number]: + def colptrs(self, name: str) -> Union[List[sp.Number], + List[List[sp.Number]]]: """ Returns (and constructs if necessary) the column pointers for a sparsified symbolic variable. @@ -1068,12 +1238,13 @@ def colptrs(self, name: str) -> List[sp.Number]: """ if name not in sparse_functions: - raise Exception(f'{name} is not marked as sparse') + raise ValueError(f'{name} is not marked as sparse') if name not in self._sparseeqs: self._generate_sparse_symbol(name) return self._colptrs[name] - def rowvals(self, name: str) -> List[sp.Number]: + def rowvals(self, name: str) -> Union[List[sp.Number], + List[List[sp.Number]]]: """ Returns (and constructs if necessary) the row values for a sparsified symbolic variable. @@ -1086,7 +1257,7 @@ def rowvals(self, name: str) -> List[sp.Number]: """ if name not in sparse_functions: - raise Exception(f'{name} is not marked as sparse') + raise ValueError(f'{name} is not marked as sparse') if name not in self._sparseeqs: self._generate_sparse_symbol(name) return self._rowvals[name] @@ -1158,14 +1329,22 @@ def _generate_symbol(self, name: str) -> None: if state.conservation_law is None ]) return + elif name == 'sx0': + self._syms[name] = sp.Matrix([ + f's{state.get_id()}_0' + for state in self._states + if state.conservation_law is None + ]) + return elif name == 'dtcldp': + # check, whether the CL consists of only one state. Then, + # sensitivities drop out, otherwise generate symbols self._syms[name] = sp.Matrix([ - [ - sp.Symbol(f's{strip_pysb(tcl.get_id())}__' - f'{strip_pysb(par.get_id())}', - real=True) - for par in self._parameters - ] + [sp.Symbol(f's{strip_pysb(tcl.get_id())}__' + f'{strip_pysb(par.get_id())}', real=True) + for par in self._parameters] + if self.conservation_law_has_multispecies(tcl) + else [0] * self.np() for tcl in self._conservationlaws ]) return @@ -1333,38 +1512,21 @@ def _compute_equation(self, name: str) -> None: # if x0_fixedParameters>0 else 0 # sx0_fixedParameters = sx+deltasx = # dx0_fixed_parametersdx*sx+dx0_fixedParametersdp - if len(self.sym('p')): - self._eqs[name] = \ - self.eq('x0_fixedParameters').jacobian(self.sym('p')) - else: - self._eqs[name] = sp.zeros( - len(self.eq('x0_fixedParameters')), - len(self.sym('p')) - ) + self._eqs[name] = smart_jacobian( + self.eq('x0_fixedParameters'), self.sym('p') + ) - if len(self.sym('x')): - dx0_fixed_parametersdx = \ - self.eq('x0_fixedParameters').jacobian(self.sym('x')) - else: - dx0_fixed_parametersdx = sp.zeros( - len(self.eq('x0_fixedParameters')), - len(self.sym('x')) - ) + dx0_fixed_parametersdx = smart_jacobian( + self.eq('x0_fixedParameters'), self.sym('x') + ) - if dx0_fixed_parametersdx.is_zero is not True: + if not smart_is_zero_matrix(dx0_fixed_parametersdx): + if isinstance(self._eqs[name], ImmutableDenseMatrix): + self._eqs[name] = MutableDenseMatrix(self._eqs[name]) for ip in range(self._eqs[name].shape[1]): - self._eqs[name][:, ip] += \ - dx0_fixed_parametersdx \ - * self.sym('sx0') \ - - for index, formula in enumerate(self.eq('x0_fixedParameters')): - if formula == 0 or formula == 0.0: - # sp.simplify returns ImmutableDenseMatrix, if we need to - # change them, they need to be made mutable - if isinstance(self._eqs[name], ImmutableDenseMatrix): - self._eqs[name] = MutableDenseMatrix(self._eqs[name]) - self._eqs[name][index, :] = \ - sp.zeros(1, self._eqs[name].shape[1]) + self._eqs[name][:, ip] += smart_multiply( + dx0_fixed_parametersdx, self.sym('sx0') + ) elif name == 'JB': self._eqs[name] = -self.eq('J').transpose() @@ -1374,14 +1536,14 @@ def _compute_equation(self, name: str) -> None: elif name == 'x0_fixedParameters': k = self.sym('k') - self._eqs[name] = sp.Matrix([ - eq - # check if the equation contains constants + self._x0_fixedParameters_idx = [ + ix + for ix, eq in enumerate(self.eq('x0')) if any([sym in eq.free_symbols for sym in k]) - # if not set to zero - else 0.0 - for eq in self.eq('x0') - ]) + ] + eq = self.eq('x0') + self._eqs[name] = sp.Matrix([eq[ix] for ix in + self._x0_fixedParameters_idx]) elif name in ['JSparse', 'JSparseB']: self._eqs[name] = self.eq(name.replace('Sparse', '')) @@ -1406,7 +1568,7 @@ def _compute_equation(self, name: str) -> None: self._derivative(match_deriv.group(1), match_deriv.group(2)) else: - raise Exception(f'Unknown equation {name}') + raise ValueError(f'Unknown equation {name}') if name in ['Jy', 'dydx']: # do not transpose if we compute the partial derivative as part of @@ -1415,7 +1577,7 @@ def _compute_equation(self, name: str) -> None: self._eqs[name] = self._eqs[name].transpose() if self._simplify: - self._eqs[name] = self._simplify(self._eqs[name]) + self._eqs[name] = self._eqs[name].applyfunc(self._simplify) def sym_names(self) -> List[str]: """ @@ -1489,11 +1651,7 @@ def _derivative(self, eq: str, var: str, name: str = None) -> None: # branch sym_var = self.sym(var, needs_stripped_symbols) - if min(eq.shape) and min(sym_var.shape) \ - and eq.is_zero is not True and sym_var.is_zero is not True: - self._eqs[name] = eq.jacobian(sym_var) - else: - self._eqs[name] = sp.zeros(eq.shape[0], self.sym(var).shape[0]) + self._eqs[name] = smart_jacobian(eq, sym_var) def _total_derivative(self, name: str, eq: str, chainvars: List[str], var: str, dydx_name: str = None, @@ -1531,9 +1689,11 @@ def _total_derivative(self, name: str, eq: str, chainvars: List[str], # Dydz = dydx*dxdz + dydz # initialize with partial derivative dydz without chain rule - self._eqs[name] = copy.deepcopy( - self.sym_or_eq(name, f'd{eq}d{var}') - ) + self._eqs[name] = self.sym_or_eq(name, f'd{eq}d{var}') + if not isinstance(self._eqs[name], sp.Symbol): + # if not a Symbol, create a copy using sympy API + # NB deepcopy does not work safely, see sympy issue #7672 + self._eqs[name] = self._eqs[name].copy() for chainvar in chainvars: if dydx_name is None: @@ -1545,13 +1705,14 @@ def _total_derivative(self, name: str, eq: str, chainvars: List[str], dxdz = self.sym_or_eq(name, dxdz_name) # Save time for for large models if one multiplicand is zero, # which is not checked for by sympy - if dydx.is_zero is not True and dxdz.is_zero is not True: + if not smart_is_zero_matrix(dydx) and not \ + smart_is_zero_matrix(dxdz): if dxdz.shape[1] == 1 and \ self._eqs[name].shape[1] != dxdz.shape[1]: for iz in range(self._eqs[name].shape[1]): - self._eqs[name][:, iz] += dydx * dxdz + self._eqs[name][:, iz] += smart_multiply(dydx, dxdz) else: - self._eqs[name] += dydx * dxdz + self._eqs[name] += smart_multiply(dydx, dxdz) def sym_or_eq(self, name: str, varname: str) -> sp.Matrix: """ @@ -1616,11 +1777,7 @@ def _multiplication(self, name: str, x: str, y: str, yy = variables[y] - if not xx.shape[0] or not yy.shape[1] or xx.is_zero is True or \ - yy.is_zero is True: - self._eqs[name] = sp.zeros(xx.shape[0], yy.shape[1]) - else: - self._eqs[name] = sign * xx * yy + self._eqs[name] = sign * smart_multiply(xx, yy) def _equation_from_component(self, name: str, component: str) -> None: """ @@ -1668,7 +1825,7 @@ def _generate_value(self, name: str) -> None: if name in self._value_prototype: component = self._value_prototype[name] else: - raise Exception(f'No values for {name}') + raise ValueError(f'No values for {name}') self._vals[name] = [comp.get_val() for comp in getattr(self, component)] @@ -1687,7 +1844,7 @@ def _generate_name(self, name: str) -> None: elif name in self._equation_prototype: component = self._equation_prototype[name] else: - raise Exception(f'No names for {name}') + raise ValueError(f'No names for {name}') self._names[name] = [comp.get_name() for comp in getattr(self, component)] @@ -1740,6 +1897,23 @@ def state_is_constant(self, ix: int) -> bool: """ return self._states[ix].get_dt() == 0.0 + def conservation_law_has_multispecies(self, + tcl: ConservationLaw) -> bool: + """ + Checks whether a conservation law has multiple species or it just + defines one constant species + + :param tcl: + conservation law + + :return: + boolean indicating if conservation_law is not None + + """ + state_set = set(self.sym('x_rdata')) + n_species = len(state_set.intersection(tcl.get_val().free_symbols)) + return n_species > 1 + def _print_with_exception(math: sp.Basic) -> str: """ @@ -1756,7 +1930,7 @@ def _print_with_exception(math: sp.Basic) -> str: ret = re.sub(r'(^|\W)M_PI(\W|$)', r'\1amici::pi\2', ret) return ret except TypeError as e: - raise Exception( + raise ValueError( f'Encountered unsupported function in expression "{math}": ' f'{e}!' ) @@ -1936,7 +2110,7 @@ def _generate_c_code(self) -> None: self._write_wrapfunctions_cpp() self._write_wrapfunctions_header() - self._write_model_header() + self._write_model_header_cpp() self._write_c_make_file() self._write_swig_files() self._write_module_setup() @@ -2016,14 +2190,14 @@ def _generate_m_code(self) -> None: lines.append('') # write the actual compiling code - lines.append('''modelName = '{model_name}';'''.format( - model_name=self.model_name)) - lines.append('''amimodel.compileAndLinkModel(modelName, '', [], [], [], - []);''') - lines.append(f'''amimodel.generateMatlabWrapper({nxtrue_rdata}, - {nytrue}, {self.model.np()}, {self.model.nk()}, - {nz}, {o2flag}, [], ... ['simulate_' modelName - '.m'], modelName, 'lin', 1, 1);''') + lines.append(f"modelName = '{self.model_name}';") + lines.append("amimodel.compileAndLinkModel" + "(modelName, '', [], [], [], []);") + lines.append(f"amimodel.generateMatlabWrapper({nxtrue_rdata}, " + f"{nytrue}, {self.model.np()}, {self.model.nk()}, " + f"{nz}, {o2flag}, ...\n [], " + "['simulate_' modelName '.m'], modelName, ...\n" + " 'lin', 1, 1);") # write compile script (for mex) compile_script = os.path.join(self.model_path, 'compileMexFile.m') @@ -2046,10 +2220,12 @@ def _write_index_files(self, name: str) -> None: else: symbols = self.model.sym(name).T else: - raise Exception('Unknown symbolic array') + raise ValueError(f'Unknown symbolic array: {name}') for index, symbol in enumerate(symbols): symbol_name = strip_pysb(symbol) + if str(symbol) == '0': + continue lines.append( f'#define {symbol_name} {name}[{index}]' ) @@ -2083,7 +2259,6 @@ def _write_function_file(self, function: str) -> None: '#include "amici/defines.h"', '#include "sundials/sundials_types.h"', '#include ', - '' ] # function signature @@ -2099,7 +2274,12 @@ def _write_function_file(self, function: str) -> None: ): lines.append(f'#include "{sym}.h"') - lines.append('') + lines.extend([ + '', + 'namespace amici {', + f'namespace model_{self.model_name} {{', + '', + ]) lines.append(f'void {function}_{self.model_name}{signature}{{') @@ -2115,7 +2295,12 @@ def _write_function_file(self, function: str) -> None: for line in body] self.functions[function]['body'] = body lines += body - lines.append('}') + lines.extend([ + '}', + '', + '} // namespace amici', + f'}} // namespace model_{self.model_name}', + ]) # if not body is None: with open(os.path.join( self.model_path, f'{self.model_name}_{function}.cpp'), 'w' @@ -2140,8 +2325,8 @@ def _write_function_index(self, function: str, indextype: str) -> None: elif indextype == 'rowvals': values = self.model.rowvals(function) else: - raise ValueError('Invalid value for type, must be colptr or ' - 'rowval') + raise ValueError('Invalid value for indextype, must be colptrs or ' + f'rowvals: {indextype}') # function signature if function in multiobs_functions: @@ -2152,25 +2337,58 @@ def _write_function_index(self, function: str, indextype: str) -> None: lines = [ '#include "sundials/sundials_types.h"', '', - f'void {function}_{indextype}_{self.model_name}{signature}{{', + '#include ', + '#include ', + '', + 'namespace amici {', + f'namespace model_{self.model_name} {{', + '', ] - if function in multiobs_functions: - # list of index vectors - cases = {switch_case: [' ' * 4 + f'{indextype}[{index}] = {value};' - for index, value in enumerate(idx_vector)] - for switch_case, idx_vector in enumerate(values)} - lines.extend(get_switch_statement('index', cases, 1)) - else: - # single index vector - lines.extend( - [' ' * 4 + f'{indextype}[{index}] = {value};' - for index, value in enumerate(values)] - ) - lines.append('}') - with open(os.path.join( - self.model_path, - f'{self.model_name}_{function}_{indextype}.cpp' - ), 'w') as fileout: + + # Generate static array with indices + if len(values): + static_array_name = f"{function}_{indextype}_{self.model_name}_" + if function in multiobs_functions: + # list of index vectors + lines.append("static constexpr std::array, {len(values)}> " + f"{static_array_name} = {{{{") + lines.extend([' {' + + ', '.join(map(str, index_vector)) + '}, ' + for index_vector in values]) + lines.append("}};") + else: + # single index vector + lines.append("static constexpr std::array {static_array_name} = {{") + lines.append(' ' + ', '.join(map(str, values))) + lines.append("};") + + lines.extend([ + '', + f'void {function}_{indextype}_{self.model_name}{signature}{{', + ]) + + if len(values): + if function in multiobs_functions: + lines.append(f" std::copy({static_array_name}[index]" + f".begin(), {static_array_name}[index].end(), " + f"{indextype});") + else: + lines.append(f" std::copy({static_array_name}.begin(), " + f"{static_array_name}.end(), {indextype});") + + lines.extend([ + '}' + '', + '} // namespace amici', + f'}} // namespace model_{self.model_name}', + ]) + + filename = f'{self.model_name}_{function}_{indextype}.cpp' + filename = os.path.join(self.model_path, filename) + + with open(filename, 'w') as fileout: fileout.write('\n'.join(lines)) def _get_function_body(self, @@ -2184,7 +2402,6 @@ def _get_function_body(self, :param symbol: symbolic defintion of the function body - symengine.DenseMatrix :return: generated C++ code @@ -2193,8 +2410,10 @@ def _get_function_body(self, lines = [] - if len(symbol) == 0 or (isinstance(symbol, sp.Matrix) + if len(symbol) == 0 or (isinstance(symbol, (sp.Matrix, + sp.ImmutableDenseMatrix)) and min(symbol.shape) == 0): + # dJydy is a list return lines if not self.allow_reinit_fixpar_initcond \ @@ -2207,27 +2426,38 @@ def _get_function_body(self, cases = dict() for ipar in range(self.model.np()): expressions = [] - for index, formula in enumerate( - self.model.eq('x0_fixedParameters') + for index, formula in zip( + self.model._x0_fixedParameters_idx, + symbol[:, ipar] ): - if formula != 0 and formula != 0.0: - expressions.append(f'{function}[{index}] = ' - f'{symbol[index, ipar]};') + expressions.append(f'{function}[{index}] = ' + f'{_print_with_exception(formula)};') cases[ipar] = expressions lines.extend(get_switch_statement('ip', cases, 1)) + elif function == 'x0_fixedParameters': + for index, formula in zip( + self.model._x0_fixedParameters_idx, + symbol + ): + lines.append(f'{function}[{index}] = ' + f'{_print_with_exception(formula)};') + elif function in sensi_functions: cases = {ipar: _get_sym_lines(symbol[:, ipar], function, 0) - for ipar in range(self.model.np())} + for ipar in range(self.model.np()) + if not smart_is_zero_matrix(symbol[:, ipar])} lines.extend(get_switch_statement('ip', cases, 1)) elif function in multiobs_functions: if function == 'dJydy': cases = {iobs: _get_sym_lines(symbol[iobs], function, 0) - for iobs in range(self.model.ny())} + for iobs in range(self.model.ny()) + if not smart_is_zero_matrix(symbol[iobs])} else: cases = {iobs: _get_sym_lines(symbol[:, iobs], function, 0) - for iobs in range(self.model.ny())} + for iobs in range(self.model.ny()) + if not smart_is_zero_matrix(symbol[:, iobs])} lines.extend(get_switch_statement('iy', cases, 1)) else: @@ -2257,9 +2487,9 @@ def _write_wrapfunctions_header(self) -> None: template_data ) - def _write_model_header(self) -> None: + def _write_model_header_cpp(self) -> None: """ - Write model-specific header file (MODELNAME.h). + Write model-specific header and cpp file (MODELNAME.{h,cpp}). """ tpl_data = { @@ -2268,6 +2498,7 @@ def _write_model_header(self) -> None: 'NXTRUE_RDATA': str(self.model.nx_rdata()), 'NX_SOLVER': str(self.model.nx_solver()), 'NXTRUE_SOLVER': str(self.model.nx_solver()), + 'NX_SOLVER_REINIT': str(self.model.nx_solver_reinit()), 'NY': str(self.model.ny()), 'NYTRUE': str(self.model.ny()), 'NZ': '0', @@ -2349,6 +2580,12 @@ def _write_model_header(self) -> None: tpl_data ) + apply_template( + os.path.join(amiciSrcPath, 'model.ODE_template.cpp'), + os.path.join(self.model_path, f'{self.model_name}.cpp'), + tpl_data + ) + def _get_symbol_name_initializer_list(self, name: str) -> str: """ Get SBML name initializer list for vector of names for the given @@ -2401,6 +2638,8 @@ def _write_c_make_file(self): sources.append(self.model_name + '_' + function + '_rowvals.cpp ') + sources.append(f'{self.model_name}.cpp') + template_data = {'MODELNAME': self.model_name, 'SOURCES': '\n'.join(sources), 'AMICI_VERSION': __version__} @@ -2493,7 +2732,7 @@ def get_symbolic_diagonal(matrix: sp.Matrix) -> sp.Matrix: A Symbolic matrix with the diagonal of `matrix`. """ if not matrix.cols == matrix.rows: - raise Exception('Provided matrix is not square!') + raise ValueError('Provided matrix is not square!') diagonal = [matrix[index, index] for index in range(matrix.cols)] diff --git a/deps/AMICI/python/amici/pandas.py b/deps/AMICI/python/amici/pandas.py index bde4a4f63..0376273ac 100644 --- a/deps/AMICI/python/amici/pandas.py +++ b/deps/AMICI/python/amici/pandas.py @@ -87,10 +87,8 @@ def getDataObservablesAsDataFrame( # list of all column names using either ids or names cols = _get_extended_observable_cols(model, by_id=by_id) - # initialize dataframe with columns - df_edata = pd.DataFrame(columns=cols) - - # append all converted edatas + # aggregate recrods + dicts = [] for edata in edata_list: npdata = ExpDataView(edata) for i_time, timepoint in enumerate(edata.getTimepoints()): @@ -108,9 +106,9 @@ def getDataObservablesAsDataFrame( # add conditions _fill_conditions_dict(datadict, model, edata, by_id=by_id) - df_edata.loc[len(df_edata)] = datadict + dicts.append(datadict) - return df_edata + return pd.DataFrame.from_records(dicts, columns=cols) def getSimulationObservablesAsDataFrame( @@ -147,10 +145,8 @@ def getSimulationObservablesAsDataFrame( # list of all column names using either names or ids cols = _get_extended_observable_cols(model, by_id=by_id) - # initialize dataframe with columns - df_rdata = pd.DataFrame(columns=cols) - - # append all converted rdatas + # aggregate recrods + dicts = [] for edata, rdata in zip(edata_list, rdata_list): for i_time, timepoint in enumerate(rdata['t']): datadict = { @@ -167,9 +163,9 @@ def getSimulationObservablesAsDataFrame( _fill_conditions_dict(datadict, model, edata, by_id=by_id) # append to dataframe - df_rdata.loc[len(df_rdata)] = datadict + dicts.append(datadict) - return df_rdata + return pd.DataFrame.from_records(dicts, columns=cols) def getSimulationStatesAsDataFrame( @@ -204,10 +200,8 @@ def getSimulationStatesAsDataFrame( # get conditions and state column names by name or id cols = _get_state_cols(model, by_id=by_id) - # initialize dataframe with columns - df_rdata = pd.DataFrame(columns=cols) - - # append states + # aggregate recrods + dicts = [] for edata, rdata in zip(edata_list, rdata_list): for i_time, timepoint in enumerate(rdata['t']): datadict = { @@ -223,9 +217,9 @@ def getSimulationStatesAsDataFrame( _fill_conditions_dict(datadict, model, edata, by_id=by_id) # append to dataframe - df_rdata.loc[len(df_rdata)] = datadict + dicts.append(datadict) - return df_rdata + return pd.DataFrame.from_records(dicts, columns=cols) def getResidualsAsDataFrame(model: amici.Model, @@ -265,10 +259,8 @@ def getResidualsAsDataFrame(model: amici.Model, # get all column names using names or ids cols = _get_observable_cols(model, by_id=by_id) - # initialize dataframe with columns - df_res = pd.DataFrame(columns=cols) - - # iterate over rdata rows + # aggregate recrods + dicts = [] for row in df_rdata.index: datadict = { 'time': df_rdata.loc[row]['time'], @@ -290,9 +282,9 @@ def getResidualsAsDataFrame(model: amici.Model, datadict[par + '_presim'] = df_rdata.loc[row][par + '_presim'] # append to dataframe - df_res.loc[len(df_res)] = datadict + dicts.append(datadict) - return df_res + return pd.DataFrame.from_records(dicts, columns=cols) def _fill_conditions_dict(datadict: Dict[str, float], diff --git a/deps/AMICI/python/amici/parameter_mapping.py b/deps/AMICI/python/amici/parameter_mapping.py index 8bb1f8366..88b30877b 100644 --- a/deps/AMICI/python/amici/parameter_mapping.py +++ b/deps/AMICI/python/amici/parameter_mapping.py @@ -316,7 +316,7 @@ def unscale_parameter(value: numbers.Number, if petab_scale == LIN: return value if petab_scale == LOG10: - return np.pow(10, value) + return np.power(10, value) if petab_scale == LOG: return np.exp(value) raise ValueError(f"Unknown parameter scale {petab_scale}. " diff --git a/deps/AMICI/python/amici/petab_import.py b/deps/AMICI/python/amici/petab_import.py index b177a93df..23a9f0b23 100644 --- a/deps/AMICI/python/amici/petab_import.py +++ b/deps/AMICI/python/amici/petab_import.py @@ -185,10 +185,13 @@ def species_to_parameters(species_ids: List[str], for species_id in transformables: # loop, since removeX only removes one instance while reaction.removeReactant(species_id): + # remove from reactants pass while reaction.removeProduct(species_id): + # remove from products pass while reaction.removeModifier(species_id): + # remove from modifiers pass return transformables @@ -471,7 +474,7 @@ def import_model(sbml_model: Union[str, 'libsbml.Model'], key=lambda symbol: symbol.name) for free_sym in free_syms: sym = str(free_sym) - if sbml_model.getElementBySId(sym) is None: + if sbml_model.getElementBySId(sym) is None and sym != 'time': output_parameters[sym] = None logger.debug(f"Adding output parameters to model: {output_parameters}") for par in output_parameters.keys(): diff --git a/deps/AMICI/python/amici/petab_objective.py b/deps/AMICI/python/amici/petab_objective.py index 01db9afe8..c8b509bf0 100644 --- a/deps/AMICI/python/amici/petab_objective.py +++ b/deps/AMICI/python/amici/petab_objective.py @@ -16,16 +16,16 @@ import numpy as np import pandas as pd import petab -from .logging import get_logger, log_execution_time from petab.C import * # noqa: F403 + +from . import AmiciModel, AmiciExpData +from .logging import get_logger, log_execution_time from .petab_import import PREEQ_INDICATOR_ID from .parameter_mapping import ( fill_in_parameters, ParameterMappingForCondition, ParameterMapping) logger = get_logger(__name__) -AmiciModel = Union[amici.Model, amici.ModelPtr] - # string constant definitions LLH = 'llh' @@ -44,6 +44,7 @@ def simulate_petab( solver: Optional[amici.Solver] = None, problem_parameters: Optional[Dict[str, float]] = None, simulation_conditions: Union[pd.DataFrame, Dict] = None, + edatas: List[AmiciExpData] = None, parameter_mapping: ParameterMapping = None, scaled_parameters: Optional[bool] = False, log_level: int = logging.WARNING @@ -63,6 +64,9 @@ def simulate_petab( :param simulation_conditions: Result of `petab.get_simulation_conditions`. Can be provided to save time if this has be obtained before. + Not required if `edatas` and `parameter_mapping` are provided. + :param edatas: + Experimental data. Parameters are inserted in-place for simulation. :param parameter_mapping: Optional precomputed PEtab parameter mapping for efficiency, as generated by `create_parameter_mapping`. @@ -100,7 +104,8 @@ def simulate_petab( # number of amici simulations will be number of unique # (preequilibrationConditionId, simulationConditionId) pairs. # Can be optimized by checking for identical condition vectors. - if simulation_conditions is None: + if simulation_conditions is None and parameter_mapping is None \ + and edatas is None: simulation_conditions = \ petab_problem.get_simulation_conditions_from_measurement_df() @@ -112,13 +117,21 @@ def simulate_petab( scaled_parameters=scaled_parameters, amici_model=amici_model) - edatas = create_parameterized_edatas( - amici_model=amici_model, - petab_problem=petab_problem, + # Get edatas + if edatas is None: + # Generate ExpData with all condition-specific information + edatas = create_edatas( + amici_model=amici_model, + petab_problem=petab_problem, + simulation_conditions=simulation_conditions) + + # Fill parameters in ExpDatas (in-place) + fill_in_parameters( + edatas=edatas, problem_parameters=problem_parameters, scaled_parameters=scaled_parameters, parameter_mapping=parameter_mapping, - simulation_conditions=simulation_conditions) + amici_model=amici_model) # Simulate rdatas = amici.runAmiciSimulations(amici_model, solver, edata_list=edatas) diff --git a/deps/AMICI/python/amici/pysb_import.py b/deps/AMICI/python/amici/pysb_import.py index f23f06bfa..9fb97d8b0 100644 --- a/deps/AMICI/python/amici/pysb_import.py +++ b/deps/AMICI/python/amici/pysb_import.py @@ -38,6 +38,7 @@ def pysb2amici(model: pysb.Model, assume_pow_positivity: bool = False, compiler: str = None, compute_conservation_laws: bool = True, + compile: bool = True, ): """ Generate AMICI C++ files for the model provided to the constructor. @@ -77,6 +78,10 @@ def pysb2amici(model: pysb.Model, applied such that the state-jacobian of the ODE right-hand-side has full rank. This option should be set to True when using the newton algorithm to compute steadystates + + :param compile: + If true, build the python module for the generated model. If false, + just generate the source code. """ if observables is None: observables = [] @@ -104,9 +109,12 @@ def pysb2amici(model: pysb.Model, exporter.set_name(model.name) exporter.set_paths(output_dir) exporter.generate_model_code() - exporter.compile_model() + + if compile: + exporter.compile_model() +@log_execution_time('creating ODE model', logger) def ode_model_from_pysb_importer(model: pysb.Model, constant_parameters: List[str] = None, observables: List[str] = None, @@ -318,7 +326,7 @@ def _get_sigma_name_and_value( """ if obs_name in sigmas: if sigmas[obs_name] not in pysb_model.expressions: - raise Exception(f'value of sigma {obs_name} is not a ' + raise ValueError(f'value of sigma {obs_name} is not a ' f'valid expression.') sigma_name = pysb_model.expressions[sigmas[obs_name]].name sigma_value = pysb_model.expressions[sigmas[obs_name]].expand_expr() @@ -481,10 +489,10 @@ def _compute_possible_indices(cl_prototypes: CL_Prototype, ] if len(set(compartments)) > 1: - raise Exception('Conservation laws involving species in ' - 'multiple compartments are currently not ' - 'supported! Please run pysb2amici with ' - 'compute_conservation_laws=False') + raise ValueError('Conservation laws involving species in ' + 'multiple compartments are currently not ' + 'supported! Please run pysb2amici with ' + 'compute_conservation_laws=False') # TODO: implement this, multiply species by the volume of # their respective compartment and allow total_cl to depend # on parameters + constants and update the respective symbolic @@ -584,8 +592,8 @@ def _compute_target_index(cl_prototypes: CL_Prototype, ] # select target index as possible index with minimal appearance count if len(prototype['appearance_counts']) == 0: - raise Exception(f'Failed to compute conservation law for monomer ' - f'{monomer}') + raise RuntimeError(f'Failed to compute conservation law for ' + f'monomer {monomer}') idx = np.argmin(prototype['appearance_counts']) @@ -776,8 +784,8 @@ def _greedy_target_index_update(cl_prototypes: CL_Prototype) -> None: prototype['diff_fillin'] == -1 for prototype in cl_prototypes.values() ): - raise Exception('Could not compute a valid set of conservation ' - 'laws for this model!') + raise RuntimeError('Could not compute a valid set of conservation ' + 'laws for this model!') # this puts prototypes with high diff_fillin last cl_prototypes = sorted( diff --git a/deps/AMICI/python/amici/sbml_import.py b/deps/AMICI/python/amici/sbml_import.py index d1cd9c0fb..c6dd3d62a 100644 --- a/deps/AMICI/python/amici/sbml_import.py +++ b/deps/AMICI/python/amici/sbml_import.py @@ -21,6 +21,7 @@ from sympy.logic.boolalg import BooleanTrue as spTrue from sympy.logic.boolalg import BooleanFalse as spFalse +from sympy.printing.mathml import MathMLContentPrinter class SBMLException(Exception): @@ -38,6 +39,8 @@ class SBMLException(Exception): 'llhy': {}, } +ConservationLaw = Dict[str, Union[str, sp.Basic]] + logger = get_logger(__name__, logging.ERROR) @@ -50,7 +53,7 @@ class SbmlImporter: indicates whether libSBML warnings should be displayed - :ivar symbols: dict + :ivar symbols: dict carrying symbolic definitions :ivar sbml_reader: @@ -64,38 +67,38 @@ class SbmlImporter: :ivar sbml: sbml definition [!not storing this will result in a segfault!] - :ivar species_index: dict + :ivar species_index: maps species names to indices :ivar species_compartment: sympy.Matrix compartment for each species - :ivar constant_species: list[sting] + :ivar constant_species: ids of species that are marked as constant - :ivar boundary_condition_species: list[string] + :ivar boundary_condition_species: ids of species that are marked as boundary condition - :ivar species_has_only_substance_units: list[bool] + :ivar species_has_only_substance_units: flags indicating whether a species has only substance units - :ivar species_conversion_factor: sympy.Matrix + :ivar species_conversion_factor: conversion factors for every species - :ivar compartment_symbols: sympy.Matrix + :ivar compartment_symbols compartment ids - :ivar compartment_volume: sympy.Matrix + :ivar compartment_volume: numeric/symbolic compartment volumes - :ivar stoichiometric_matrix: sympy.Matrix + :ivar stoichiometric_matrix: stoichiometric matrix of the model - :ivar flux_vector: sympy.Matrix + :ivar flux_vector: reaction kinetic laws - :ivar local_symbols: dict + :ivar local_symbols: model symbols for sympy to consider during sympification see `locals`argument in `sympy.sympify` @@ -130,7 +133,7 @@ def __init__(self, sbml_doc = self.sbml_reader.readSBMLFromString(sbml_source) self.sbml_doc = sbml_doc - self.show_sbml_warnings = show_sbml_warnings + self.show_sbml_warnings : bool = show_sbml_warnings # process document self._process_document() @@ -141,7 +144,12 @@ def __init__(self, self.symbols = dict() self._reset_symbols() - self.local_symbols = {} + self.local_symbols : dict = {} + + self.compartment_rate_rules : dict = {} + self.species_rate_rules : dict = {} + self.compartment_assignment_rules : dict = {} + self.species_assignment_rules : dict = {} def _process_document(self) -> None: """ @@ -186,6 +194,8 @@ def sbml2amici(self, compiler: str = None, allow_reinit_fixpar_initcond: bool = True, compile: bool = True, + compute_conservation_laws: bool = True, + simplify: Callable = lambda x: sp.powsimp(x, deep=True), **kwargs) -> None: """ Generate AMICI C++ files for the model provided to the constructor. @@ -240,25 +250,36 @@ def sbml2amici(self, If True, compile the generated Python package, if False, just generate code. + :param compute_conservation_laws: + if set to true, conservation laws are automatically computed and + applied such that the state-jacobian of the ODE right-hand-side has + full rank. This option should be set to True when using the newton + algorithm to compute steadystate sensitivities. + + :param simplify: + see :meth:`ODEModel._simplify` """ set_log_level(logger, verbose) if observables is None: observables = {} - if constant_parameters is None: - constant_parameters = kwargs.pop('constantParameters', []) - if constant_parameters is not []: - logger.warning('Use of `constantParameters` as argument name ' - 'is deprecated and will be removed in a future ' - 'version. Please use `constant_parameters` as ' - 'argument name.') - else: - if 'constantParameters' in kwargs: + if 'constantParameters' in kwargs: + logger.warning('Use of `constantParameters` as argument name ' + 'is deprecated and will be removed in a future ' + 'version. Please use `constant_parameters` as ' + 'argument name.') + + if constant_parameters is not None: raise ValueError('Cannot specify constant parameters using ' 'both `constantParameters` and ' '`constant_parameters` as argument names.') + constant_parameters = kwargs.pop('constantParameters', []) + + elif constant_parameters is None: + constant_parameters = [] + if sigmas is None: sigmas = {} @@ -286,8 +307,14 @@ def sbml2amici(self, self._reset_symbols() self._process_sbml(constant_parameters) self._process_observables(observables, sigmas, noise_distributions) - ode_model = ODEModel(simplify=sp.powsimp) - ode_model.import_from_sbml_importer(self) + + self._process_time() + self._clean_reserved_symbols() + self._replace_special_constants() + + ode_model = ODEModel(simplify=simplify) + ode_model.import_from_sbml_importer( + self, compute_cls=compute_conservation_laws) exporter = ODEExporter( ode_model, outdir=output_dir, @@ -320,18 +347,17 @@ def _process_sbml(self, constant_parameters: List[str] = None) -> None: self.check_support() self._gather_locals() self._process_parameters(constant_parameters) + self._process_compartments() self._process_species() self._process_reactions() - self._process_compartments() self._process_rules() self._process_volume_conversion() - self._process_time() - self._clean_reserved_symbols() - self._replace_special_constants() def check_support(self) -> None: """ Check whether all required SBML features are supported. + Also ensures that the SBML contains at least one reaction, or rate + rule, or assignment rule, to produce change in the system over time. """ if len(self.sbml.getListOfSpecies()) == 0: raise SBMLException('Models without species ' @@ -344,10 +370,30 @@ def check_support(self) -> None: if len(self.sbml.getListOfEvents()) > 0: raise SBMLException('Events are currently not supported!') - if any([not(rule.isAssignment()) + # Contains condition to allow compartment rate rules + compartment_ids = list(map(lambda x: x.getId(), + self.sbml.getListOfCompartments())) + species_ids = list(map(lambda x: x.getId(), + self.sbml.getListOfSpecies())) + if any([not(rule.isAssignment()) and + not(rule.getVariable() in compartment_ids) and + not(rule.getVariable() in species_ids) + for rule in self.sbml.getListOfRules()]): + raise SBMLException('Algebraic rules are currently not supported, ' + 'and rate rules are only supported for ' + 'species and compartments.') + + if any([not(rule.isAssignment() or rule.isRate()) and + (rule.getVariable() in compartment_ids) for rule in self.sbml.getListOfRules()]): - raise SBMLException('Algebraic and rate ' - 'rules are currently not supported!') + raise SBMLException('Only assignment and rate rules are currently ' + 'supported for compartments!') + + if any([not(rule.isAssignment() or rule.isRate()) and + (rule.getVariable() in species_ids) + for rule in self.sbml.getListOfRules()]): + raise SBMLException('Only assignment and rate rules are currently ' + 'supported for species!') if any([reaction.getFast() for reaction in self.sbml.getListOfReactions()]): @@ -384,6 +430,35 @@ def _gather_locals(self) -> None: self.local_symbols['time'] = sp.Symbol('time', real=True) self.local_symbols['avogadro'] = sp.Symbol('avogadro', real=True) + @log_execution_time('processing SBML compartments', logger) + def _process_compartments(self) -> None: + """ + Get compartment information, stoichiometric matrix and fluxes from + SBML model. + """ + compartments = self.sbml.getListOfCompartments() + self.compartment_symbols = sp.Matrix( + [sp.Symbol(comp.getId(), real=True) for comp in compartments] + ) + + # Initial volumes may be overridden at the end of _process_species, + # where compartment assignment rules are processed. + self.compartment_volume = sp.Matrix([ + sp.sympify(comp.getVolume()) if comp.isSetVolume() + else sp.sympify(1.0) for comp in compartments + ]) + + compartment_ids = [comp.getId() for comp in compartments] + for initial_assignment in self.sbml.getListOfInitialAssignments(): + if initial_assignment.getId() in compartment_ids: + index = compartment_ids.index( + initial_assignment.getId() + ) + self.compartment_volume[index] = sp.sympify( + sbml.formulaToL3String(initial_assignment.getMath()), + locals=self.local_symbols + ) + @log_execution_time('processing SBML species', logger) def _process_species(self) -> None: """ @@ -492,6 +567,196 @@ def get_species_initial(index, conc): for specie in species ]) + # Process assignment and rate rules for species and compartments. + # Compartments with rate rules are implemented as species. Species and + # compartments with assignments are implemented as observables (and + # replaced with their assignment in all expressions). Note that, in the + # case of species, rate rules may describe the change in amount, not + # concentration, of a species. + rules = self.sbml.getListOfRules() + compartmentvars = self.compartment_symbols.free_symbols + # compartments with rules are replaced with constants in the relevant + # equations during the _replace_in_all_expressions call inside + # _process_rules + for rule in rules: + ### Taken from _process_rules + if rule.getFormula() == '': + continue + variable = sp.sympify(rule.getVariable(), + locals=self.local_symbols) + formula = sp.sympify(_parse_logical_operators( + sbml.formulaToL3String(rule.getMath())), + locals=self.local_symbols) + formula = _parse_special_functions(formula) + _check_unsupported_functions(formula, 'Rule') + ### + + # Species rules are processed first, to avoid processing + # compartments twice (as compartments with rate rules are + # implemented as species). Could also be avoided with a + # `not in self.compartment_rate_rules` condition. + if variable in self.symbols['species']['identifier']: + if rule.getTypeCode() == sbml.SBML_ASSIGNMENT_RULE: + # Handled in _process_rules and _process_observables. + pass + elif rule.getTypeCode() == sbml.SBML_RATE_RULE: + self.add_d_dt( + formula, + variable, + self.symbols['species']['value'], + sbml.SBML_SPECIES) + else: + raise SBMLException('The only rules currently supported ' + 'for species are assignment and rate ' + 'rules!') + + if variable in compartmentvars: + if rule.getTypeCode() == sbml.SBML_ASSIGNMENT_RULE: + # Handled in _process_rules and _process_observables + # SBML Assignment Rules can be used to specify initial + # values (see SBML L3V2 manual, Section 3.4.8). + # Priority appears to be above InitialAssignment. + self.compartment_volume[list( + self.compartment_symbols + ).index(variable)] = formula + elif rule.getTypeCode() == sbml.SBML_RATE_RULE: + self.add_d_dt( + formula, + variable, + self.compartment_volume[list( + self.compartment_symbols + ).index(variable)], + sbml.SBML_COMPARTMENT) + else: + raise SBMLException('The only rules currently supported ' + 'for compartments are assignment and ' + 'rate rules!') + + def add_d_dt( + self, + d_dt: sp.Expr, + variable: sp.Symbol, + variable0: Union[float, sp.Expr], + component: int, + name: str = None + ) -> None: + ''' + Creates or modifies species, to implement rate rules for compartments + and species, respectively. + + :param d_dt: + The rate rule (or, right-hand side of an ODE). + + :param variable: + The subject of the rate rule. + + :param variable0: + The initial value of the variable. + + :param component: + The type of SBML component. Currently, only libsbml.SBML_SPECIES + and libsbml.SBML_COMPARTMENT are supported. + ''' + if name is None: + name = '' + + ### d_dt may contain speciesReference symbols, that may be defined in + # an initial assignment (e.g. see SBML test suite case 1498, which + # uses a speciesReference Id in a species rate rule). + # Here, such speciesReference symbols are replaced with the initial + # assignment expression, if the expression is a constant (time- + # dependent expression symbols are not evaluated at zero, rather raise + # an error). + # One method to implement expressions with time-dependent symbols + # may be to produce a dictionary of speciesReference symbols and + # their initial assignment expressions here, then add this dictionary + # to the _replace_in_all_expressions method. After _process_sbml, + # substitute initial values in for any remaining symbols, evaluate the + # the expressions at $t=0$ (self.amici_time_symbol), then substitute + # them into d_dt. + + # Initial assignment symbols may be compartments, species, parameters, + # speciesReferences, or an (extension?) package element. Here, it is + # assumed that a symbol is a speciesReference if it is not a + # compartment, species, or parameter, and is the symbol of an initial + # assignment. + alternative_components = [s.getId() for s in + list(self.sbml.getListOfCompartments()) +\ + list(self.sbml.getListOfSpecies()) +\ + list(self.sbml.getListOfParameters())] + initial_assignments = {ia.getId(): ia for ia in + self.sbml.getListOfInitialAssignments()} + for symbol in d_dt.free_symbols: + if str(symbol) not in alternative_components and\ + str(symbol) in initial_assignments: + # Taken from _process_species + sym_math = sp.sympify(_parse_logical_operators( + sbml.formulaToL3String(initial_assignments[ + str(symbol) + ].getMath())), + locals=self.local_symbols + ) + if sym_math is not None: + sym_math = _parse_special_functions(sym_math) + _check_unsupported_functions(sym_math, 'InitialAssignment') + + if not isinstance(sym_math, sp.Float): + raise SBMLException('Rate rules that contain ' + 'speciesReferences, defined in ' + 'initial assignments that contain ' + 'symbols, are currently not ' + 'supported! Rate rule symbol: ' + f'{variable}, species reference ' + f'symbol: {symbol}, initial ' + f'assignment: {sym_math}, type: ' + f'{type(sym_math)}.') + else: + d_dt = d_dt.subs(symbol, sym_math) + ### + + if component == sbml.SBML_COMPARTMENT: + self.symbols['species']['identifier'] = \ + self.symbols['species']['identifier'].col_join( + sp.Matrix([variable])) + self.symbols['species']['name'].append(name) + self.symbols['species']['value'] = \ + self.symbols['species']['value'].col_join( + sp.Matrix([variable0])) + self.species_index[str(variable)] = len(self.species_index) + self.compartment_rate_rules[variable] = d_dt + elif component == sbml.SBML_SPECIES: + if str(variable) in self.species_index: + # SBML species are already in the species symbols + x_index = self.species_index[str(variable)] + if self.species_has_only_substance_units[x_index]: + self.symbols['species']['value'][x_index] *= \ + self.species_compartment[x_index] + self.species_rate_rules[variable] = d_dt + else: + # For Jakob to specify rules independently of SBML (untested) + # Remove assert statement to use + # Currently untested... + assert False, "Error while processing species rate rules." + self.symbols['species']['identifier'] = \ + self.symbols['species']['identifier'].col_join( + sp.Matrix([variable])) + self.symbols['species']['name'].append(name) + self.symbols['species']['value'] = \ + self.symbols['species']['value'].col_join( + sp.Matrix([variable0])) + self.species_index[str(variable)] = len(self.species_index) + self.species_rate_rules[variable] = d_dt + # May need to modify this function (`add_d_dt`) to allow + # specification of whether the argument `d_dt` describes change + # in amount or concentration. + #if self.species_has_only_substance_units[x_index]: + # self.symbols['species']['value'][x_index] *= \ + # self.species_compartment[x_index] + else: + raise TypeError(f'Rate rules are currently only supported for ' + 'libsbml.SBML_COMPARTMENT and ' + 'libsbml.SBML_SPECIES components.') + @log_execution_time('processing SBML parameters', logger) def _process_parameters(self, constant_parameters: List[str] = None) -> None: @@ -564,39 +829,16 @@ def _process_parameters(self, } ) - @log_execution_time('processing SBML compartments', logger) - def _process_compartments(self) -> None: - """ - Get compartment information, stoichiometric matrix and fluxes from - SBML model. - """ - compartments = self.sbml.getListOfCompartments() - self.compartment_symbols = sp.Matrix( - [sp.Symbol(comp.getId(), real=True) for comp in compartments] - ) - self.compartment_volume = sp.Matrix([ - sp.sympify(comp.getVolume()) if comp.isSetVolume() - else sp.sympify(1.0) for comp in compartments - ]) - - compartment_ids = [comp.getId() for comp in compartments] - for initial_assignment in self.sbml.getListOfInitialAssignments(): - if initial_assignment.getId() in compartment_ids: - index = compartment_ids.index( - initial_assignment.getId() - ) - self.compartment_volume[index] = sp.sympify( - sbml.formulaToL3String(initial_assignment.getMath()), - locals=self.local_symbols - ) - @log_execution_time('processing SBML reactions', logger) def _process_reactions(self): """ Get reactions from SBML model. """ reactions = self.sbml.getListOfReactions() - nr = len(reactions) + # nr (number of reactions) should have a minimum length of 1. This is + # to ensure that, if there are no reactions, the stoichiometric matrix + # and flux vector multiply to a zero vector with dimensions (nx, 1). + nr = max(1, len(reactions)) nx = len(self.symbols['species']['name']) # stoichiometric matrix self.stoichiometric_matrix = sp.SparseMatrix(sp.zeros(nx, nr)) @@ -668,12 +910,15 @@ def is_constant(specie): specie_index = self.species_index[ elements[index]['species'] ] + # Division by species compartment size (to find the + # rate of change in species concentration) now occurs + # in the `dx_dt` method in "ode_export.py", which also + # accounts for possibly variable compartments. self.stoichiometric_matrix[specie_index, reaction_index] += \ sign \ * elements[index]['stoichiometry'] \ - * self.species_conversion_factor[specie_index] \ - / self.species_compartment[specie_index] + * self.species_conversion_factor[specie_index] # usage of formulaToL3String ensures that we get "time" as time # symbol @@ -730,6 +975,10 @@ def _process_rules(self) -> None: assignments = {} for rule in rules: + # Rate rules should not be substituted for the target of the rate + # rule. + if rule.getTypeCode() == sbml.SBML_RATE_RULE: + continue if rule.getFormula() == '': continue variable = sp.sympify(rule.getVariable(), @@ -746,12 +995,24 @@ def _process_rules(self) -> None: self.stoichiometric_matrix.subs(variable, formula) if variable in specvars: - raise SBMLException('Species assignment rules are currently' - ' not supported!') + if rule.getTypeCode() == sbml.SBML_ASSIGNMENT_RULE: + self.species_assignment_rules[variable] = formula + assignments[str(variable)] = formula + else: + # Rate rules are handled in _process_species, and are + # skipped in this loop + raise KeyError('Only assignment and rate rules are ' + 'currently supported for species!') if variable in compartmentvars: - raise SBMLException('Compartment assignment rules are' - ' currently not supported!') + if rule.getTypeCode() == sbml.SBML_ASSIGNMENT_RULE: + self.compartment_assignment_rules[variable] = formula + assignments[str(variable)] = formula + else: + # Rate rules are handled in _process_species, and are + # skipped in this loop + raise KeyError('Only assignment and rate rules are ' + 'currently supported for compartments!') if variable in parametervars: if str(variable) in self.parameter_index: @@ -771,15 +1032,27 @@ def _process_rules(self) -> None: if variable in rulevars: for nested_rule in rules: + nested_formula = sp.sympify( - sbml.formulaToL3String(nested_rule.getMath()), - locals=self.local_symbols) - nested_formula = \ - nested_formula.subs(variable, formula) - nested_rule.setFormula(str(nested_formula)) + _parse_logical_operators(sbml.formulaToL3String(nested_rule.getMath())), + locals=self.local_symbols).subs(variable, formula) + nested_formula = _parse_special_functions(nested_formula) + _check_unsupported_functions(nested_formula, 'Rule') + + nested_rule_math_ml = mathml(nested_formula) + nested_rule_math_ml_ast_node = sbml.readMathMLFromString(nested_rule_math_ml) + + if nested_rule_math_ml_ast_node is None: + raise SBMLException(f'Formula {sbml.formulaToL3String(nested_rule.getMath())}' + f' cannot be correctly read by SymPy' + f' or cannot be converted to valid MathML by SymPy!') - for variable in assignments: - assignments[variable].subs(variable, formula) + elif nested_rule.setMath(nested_rule_math_ml_ast_node) != sbml.LIBSBML_OPERATION_SUCCESS: + raise SBMLException(f'Formula {sbml.formulaToL3String(nested_rule.getMath())}' + f' cannot be parsed by libSBML!') + + for assignment in assignments: + assignments[assignment] = assignments[assignment].subs(variable, formula) # do this at the very end to ensure we have flattened all recursive # rules @@ -791,7 +1064,7 @@ def _process_rules(self) -> None: for comp, vol in zip(self.compartment_symbols, self.compartment_volume): self._replace_in_all_expressions( - comp, vol + comp, vol ) def _process_volume_conversion(self) -> None: @@ -801,7 +1074,8 @@ def _process_volume_conversion(self) -> None: compartments = self.species_compartment for comp, vol in zip(self.compartment_symbols, self.compartment_volume): - compartments = compartments.subs(comp, vol) + if comp not in self.compartment_rate_rules: + compartments = compartments.subs(comp, vol) for index, sunits in enumerate(self.species_has_only_substance_units): if sunits: self.flux_vector = \ @@ -817,6 +1091,7 @@ def _process_time(self) -> None: """ sbml_time_symbol = sp.Symbol('time', real=True) amici_time_symbol = sp.Symbol('t', real=True) + self.amici_time_symbol = amici_time_symbol self._replace_in_all_expressions(sbml_time_symbol, amici_time_symbol) @@ -870,8 +1145,36 @@ def _process_observables(self, f"{unknown_ids}.") species_syms = self.symbols['species']['identifier'] - - # add user-provided observables or make all species observable + assignments = {str(c): str(r) + for c, r in self.compartment_assignment_rules.items()} + assignments.update({str(s): str(r) + for s, r in self.species_assignment_rules.items()}) + + def replace_assignments(formula: str) -> sp.Basic: + """ + Replace assignment rules in observables + + :param formula: + algebraic formula of the observable + + :return: + observable formula with assignment rules replaced + """ + formula = sp.sympify(formula, locals=self.local_symbols) + for s in formula.free_symbols: + r = self.sbml.getAssignmentRuleByVariable(str(s)) + if r is not None: + rule_formula = _parse_logical_operators( + sbml.formulaToL3String(r.getMath())) + rule_formula = sp.sympify( + rule_formula, locals=self.local_symbols) + rule_formula = _parse_special_functions(rule_formula) + _check_unsupported_functions(rule_formula, 'Rule') + formula = formula.replace(s, rule_formula) + return formula + + # add user-provided observables or make all species, and compartments + # with assignment rules, observable if observables: # Replace logX(.) by log(., X) since symengine cannot parse the # former. Also replace symengine-incompatible sbml log(basis, x) @@ -889,26 +1192,6 @@ def _process_observables(self, ) observables[observable]['formula'] = repl - def replace_assignments(formula: str) -> sp.Basic: - """ - Replace assignment rules in observables - - :param formula: - algebraic formula of the observable - - :return: - observable formula with assignment rules replaced - """ - formula = sp.sympify(formula, locals=self.local_symbols) - for s in formula.free_symbols: - r = self.sbml.getAssignmentRuleByVariable(str(s)) - if r is not None: - formula = formula.replace(s, sp.sympify( - sbml.formulaToL3String(r.getMath()), - locals=self.local_symbols - )) - return formula - observable_values = sp.Matrix([ replace_assignments(observables[observable]['formula']) for observable in observables @@ -924,7 +1207,7 @@ def replace_assignments(formula: str) -> sp.Basic: ]) observable_ids = observables.keys() else: - observable_values = species_syms + observable_values = species_syms.copy() # prefer sympy's copy over deepcopy, see sympy issue #7672 observable_ids = [ f'x{index}' for index in range(len(species_syms)) ] @@ -933,6 +1216,25 @@ def replace_assignments(formula: str) -> sp.Basic: [sp.symbols(f'y{index}', real=True) for index in range(len(species_syms))] ) + # Add compartment and species assignment rules as observables + # Useful for passing the SBML Test Suite (compartment volumes are + # used to calculate species amounts). + # The id's and names below may conflict with the automatically + # generated id's and names above. + for compartment in self.compartment_assignment_rules: + observable_values = observable_values.col_join(sp.Matrix( + [self.compartment_assignment_rules[compartment]])) + observable_ids.append(str(compartment)) + observable_names.append(str(compartment)) + observable_syms = observable_syms.col_join(sp.Matrix( + [compartment])) + for species in self.species_assignment_rules: + x_index = self.species_index[str(species)] + observable_values[x_index] = sp.Matrix( + [replace_assignments(str(species))]) + observable_ids[x_index] = str(species) + observable_names[x_index] = str(species) + observable_syms[x_index] = sp.Matrix([species]) sigma_y_syms = sp.Matrix( [sp.symbols(f'sigma{symbol}', real=True) @@ -945,8 +1247,7 @@ def replace_assignments(formula: str) -> sp.Basic: # set user-provided sigmas for iy, obs_name in enumerate(observables): if obs_name in sigmas: - sigma_y_values[iy] = sp.sympify(sigmas[obs_name], - locals=self.local_symbols) + sigma_y_values[iy] = replace_assignments(sigmas[obs_name]) measurement_y_syms = sp.Matrix( [sp.symbols(f'm{symbol}', real=True) for symbol in observable_syms] @@ -989,6 +1290,111 @@ def replace_assignments(formula: str) -> sp.Basic: self.symbols['llhy']['name'] = l2s(llh_y_syms) self.symbols['llhy']['identifier'] = llh_y_syms + def process_conservation_laws(self, ode_model, volume_updates) -> List: + """ + Find conservation laws in reactions and species. + + :param ode_model: + ODEModel object with basic definitions + + :param volume_updates: + List with updates for the stoichiometrix matrix accounting for + compartment volumes + + :returns volume_updates_solver: + List (according to reduced stoichiometry) with updates for the + stoichiometrix matrix accounting for compartment volumes + """ + conservation_laws = [] + + # So far, only conservation laws for constant species are supported + species_solver = self._add_conservation_for_constant_species( + ode_model, conservation_laws) + + # Check, whether species_solver is empty now. As currently, AMICI + # cannot handle ODEs without species, CLs must switched in this case + if len(species_solver) == 0: + conservation_laws = [] + species_solver = list(range(ode_model.nx_rdata())) + + # prune out species from stoichiometry and + volume_updates_solver = self._reduce_stoichiometry(species_solver, + volume_updates) + + # add the found CLs to the ode_model + for cl in conservation_laws: + ode_model.add_conservation_law(**cl) + + return volume_updates_solver + + def _add_conservation_for_constant_species( + self, + ode_model: ODEModel, + conservation_laws: List[ConservationLaw] + ) -> List[int]: + """ + Adds constant species to conservations laws + + :param ode_model: + ODEModel object with basic definitions + + :param conservation_laws: + List of already known conservation laws + + :returns species_solver: + List of species indices which remain later in the ODE solver + """ + + # decide which species to keep in stoichiometry + species_solver = list(range(ode_model.nx_rdata())) + + # iterate over species, find constant ones + for ix in reversed(range(ode_model.nx_rdata())): + if ode_model.state_is_constant(ix): + # dont use sym('x') here since conservation laws need to be + # added before symbols are generated + target_state = ode_model._states[ix].get_id() + total_abundance = sp.Symbol(f'tcl_{target_state}') + conservation_laws.append({ + 'state': target_state, + 'total_abundance': total_abundance, + 'state_expr': total_abundance, + 'abundance_expr': target_state, + }) + # mark species to delete from stoichiometrix matrix + species_solver.pop(ix) + + return species_solver + + def _reduce_stoichiometry(self, species_solver, volume_updates) -> List: + """ + Reduces the stoichiometry with respect to conserved quantities + + :param species_solver: + List of species indices which remain later in the ODE solver + + :param volume_updates: + List with updates for the stoichiometrix matrix accounting for + compartment volumes + + :returns volume_updates_solver: + List (according to reduced stoichiometry) with updates for the + stoichiometrix matrix accounting for compartment volumes + """ + + # prune out constant species from stoichiometric matrix + self.stoichiometric_matrix = \ + self.stoichiometric_matrix[species_solver, :] + + # updates of stoichiometry (later dxdotdw in ode_exporter) must be + # corrected for conserved quantities: + volume_updates_solver = [(species_solver.index(ix), iw, val) + for (ix, iw, val) in volume_updates + if ix in species_solver] + + return volume_updates_solver + + def _replace_in_all_expressions(self, old: sp.Symbol, new: sp.Symbol) -> None: @@ -1001,21 +1407,61 @@ def _replace_in_all_expressions(self, :param new: replacement symbolic variables """ - fields = [ - 'stoichiometric_matrix', 'flux_vector', - ] - for field in fields: - if field in dir(self): - self.__setattr__(field, self.__getattribute__(field).subs( - old, new - )) + # Avoid replacing variables with rates + if old not in set((*self.compartment_rate_rules.keys(), + *self.species_rate_rules.keys())): + fields = [ + 'stoichiometric_matrix', 'flux_vector', + ] + for field in fields: + if field in dir(self): + self.__setattr__(field, self.__getattribute__(field).subs( + old, new + )) + for compartment in self.compartment_rate_rules: + self.compartment_rate_rules[compartment] = \ + self.compartment_rate_rules[compartment].subs(old, new) + for species in self.species_rate_rules: + self.species_rate_rules[species] = \ + self.species_rate_rules[species].subs(old, new) + symbols = [ - 'species', 'observables', + 'species', 'observable', ] for symbol in symbols: if symbol in self.symbols: - self.symbols[symbol]['value'] = \ - self.symbols[symbol]['value'].subs(old, new) + # Initial species values that are specified as amounts need to + # be divided by their compartment volume to obtain + # concentration. The condition below ensures that species + # initial amount is divided by the initial compartment size, + # and not the expression for a compartment assignment rule. + if symbol == 'species' and ( + old in self.compartment_assignment_rules): + comp_v0 = self.compartment_volume[ + list(self.compartment_symbols).index(old)] + self.symbols[symbol]['value'] = \ + self.symbols[symbol]['value'].subs(old, comp_v0) + else: + # self.symbols['observable'] may not yet be defined. + if not self.symbols[symbol]: + continue + self.symbols[symbol]['value'] = \ + self.symbols[symbol]['value'].subs(old, new) + + for compartment in self.compartment_assignment_rules: + self.compartment_assignment_rules[compartment] = \ + self.compartment_assignment_rules[compartment].subs(old, new) + # Initial compartment volume may also be specified with an assignment + # rule (at the end of the _process_species method), hence needs to be + # processed here too. + for index in range(len(self.compartment_volume)): + if 'amici_time_symbol' in dir(self) and ( + new == self.amici_time_symbol): + self.compartment_volume[index] = \ + self.compartment_volume[index].subs(old, 0) + else: + self.compartment_volume[index] = \ + self.compartment_volume[index].subs(old, new) def _clean_reserved_symbols(self) -> None: """ @@ -1385,3 +1831,22 @@ def nllh_y_string(str_symbol): f"Cost identifier {noise_distribution} not recognized.") return nllh_y_string + +class MathMLSbmlPrinter(MathMLContentPrinter): + """Prints a SymPy expression to a MathML expression parsable by libSBML. + Differences from `sympy.MathMLContentPrinter`: + 1. underscores in symbol names are not converted to subscripts + 2. symbols with name 'time' are converted to the SBML time symbol + """ + def _print_Symbol(self, sym): + ci = self.dom.createElement(self.mathml_tag(sym)) + ci.appendChild(self.dom.createTextNode(sym.name)) + return ci + def doprint(self, expr): + mathml = super().doprint(expr) + mathml = '' + mathml + '' + mathml = mathml.replace(f'time', ' time ') + return mathml + +def mathml(expr, **settings): + return MathMLSbmlPrinter(settings).doprint(expr) diff --git a/deps/AMICI/python/amici/setup.template.py b/deps/AMICI/python/amici/setup.template.py index a154636c9..9f82182e0 100644 --- a/deps/AMICI/python/amici/setup.template.py +++ b/deps/AMICI/python/amici/setup.template.py @@ -3,13 +3,15 @@ import os from typing import List -from amici import amici_path, hdf5_enabled +from amici import amici_path, hdf5_enabled, compiledWithOpenMP from amici.custom_commands import (set_compiler_specific_extension_options, compile_parallel) from amici.setuptools import (get_blas_config, get_hdf5_config, add_coverage_flags_if_required, - add_debug_flags_if_required) + add_debug_flags_if_required, + add_openmp_flags, + ) from setuptools import find_packages, setup, Extension from setuptools.command.build_ext import build_ext @@ -29,6 +31,14 @@ def build_extension(self, ext): build_ext.build_extension(self, ext) + def find_swig(self) -> str: + """Find SWIG executable + + Overrides horribly outdated distutils function.""" + + from amici.swig import find_swig + return find_swig() + def get_model_sources() -> List[str]: """Get list of source files for the amici base library""" @@ -54,6 +64,11 @@ def get_extension() -> Extension: cxx_flags = ['-std=c++14'] linker_flags = [] + if compiledWithOpenMP(): + # Only build model with OpenMP support if AMICI base packages was built + # that way + add_openmp_flags(cxx_flags=cxx_flags, ldflags=linker_flags) + add_coverage_flags_if_required(cxx_flags, linker_flags) add_debug_flags_if_required(cxx_flags, linker_flags) diff --git a/deps/AMICI/python/amici/setuptools.py b/deps/AMICI/python/amici/setuptools.py index 300b07d9a..8731c472c 100644 --- a/deps/AMICI/python/amici/setuptools.py +++ b/deps/AMICI/python/amici/setuptools.py @@ -10,10 +10,12 @@ import subprocess import shutil +from distutils import log from .swig import find_swig, get_swig_version try: import pkgconfig # optional + # pkgconfig python module might be installed without pkg-config binary # being available pkgconfig.exists('somePackageName') @@ -68,17 +70,22 @@ def get_blas_config() -> PackageInfo: blaspkgcfg['extra_link_args'].extend( shlex.split(os.environ['MKL_LIB']) ) - blaspkgcfg['define_macros'].append(('AMICI_BLAS_MKL', None),) + blaspkgcfg['define_macros'].append(('AMICI_BLAS_MKL', None), ) return blaspkgcfg # Try pkgconfig if pkgconfig: - if pkgconfig.exists('cblas'): - blaspkgcfg = pkgconfig.parse('cblas') - blaspkgcfg['extra_compile_args'] = [pkgconfig.cflags('cblas')] - blaspkgcfg['extra_link_args'] = [pkgconfig.libs('cblas')] - - return blaspkgcfg + for blas_name in ['cblas', 'openblas']: + if pkgconfig.exists(blas_name): + blaspkgcfg = pkgconfig.parse(blas_name) + blaspkgcfg['extra_compile_args'] = [ + pkgconfig.cflags(blas_name) + ] + blaspkgcfg['extra_link_args'] = [ + pkgconfig.libs(blas_name) + ] + + return blaspkgcfg # If none of the previous worked, fall back to libcblas in default paths blaspkgcfg['libraries'] = ['cblas'] @@ -93,18 +100,6 @@ def get_hdf5_config() -> PackageInfo: :return: hdf5 related package information """ - if pkgconfig: - h5pkgcfg = {} - try: - h5pkgcfg = pkgconfig.parse('hdf5') - except pkgconfig.PackageNotFoundError: - pass - # NOTE: Cannot use pkgconfig.exists('hdf5f'), since this is true - # although no libraries or include dirs are available - h5pkgcfg['found'] = 'include_dirs' in h5pkgcfg \ - and h5pkgcfg['include_dirs'] - if h5pkgcfg['found']: - return h5pkgcfg h5pkgcfg = {'include_dirs': [], 'library_dirs': [], @@ -129,13 +124,6 @@ def get_hdf5_config() -> PackageInfo: '/usr/local/Cellar/hdf5/1.10.2_1/lib' # travis macOS ] - # Check for Environment Modules variables - if 'HDF5_BASE' in os.environ: - hdf5_include_dir_hints.insert( - 0, os.path.join(os.environ['HDF5_BASE'], 'include')) - hdf5_library_dir_hints.insert( - 0, os.path.join(os.environ['HDF5_BASE'], 'lib')) - # special treatment for conda environments # as the conda library dir is provided first, we should also check for # conda header files first @@ -145,11 +133,18 @@ def get_hdf5_config() -> PackageInfo: hdf5_library_dir_hints.insert( 0, os.path.join(os.environ['CONDA_DIR'], 'lib')) + # Check for Environment Modules variables + if 'HDF5_BASE' in os.environ: + hdf5_include_dir_hints.insert( + 0, os.path.join(os.environ['HDF5_BASE'], 'include')) + hdf5_library_dir_hints.insert( + 0, os.path.join(os.environ['HDF5_BASE'], 'lib')) + for hdf5_include_dir_hint in hdf5_include_dir_hints: hdf5_include_dir_found = os.path.isfile( os.path.join(hdf5_include_dir_hint, 'hdf5.h')) if hdf5_include_dir_found: - print('hdf5.h found in %s' % hdf5_include_dir_hint) + log.info('hdf5.h found in %s' % hdf5_include_dir_hint) h5pkgcfg['include_dirs'] = [hdf5_include_dir_hint] break @@ -159,13 +154,28 @@ def get_hdf5_config() -> PackageInfo: hdf5_library_dir_found = os.path.isfile( os.path.join(hdf5_library_dir_hint, lib_filename)) if hdf5_library_dir_found: - print(f'{lib_filename} found in {hdf5_library_dir_hint}') + log.info(f'{lib_filename} found in {hdf5_library_dir_hint}') h5pkgcfg['library_dirs'] = [hdf5_library_dir_hint] break if hdf5_library_dir_found: # break to not override hdf5_library_dir_found break + h5pkgcfg['found'] = hdf5_include_dir_found and hdf5_library_dir_found + if h5pkgcfg['found']: + return h5pkgcfg + + if pkgconfig: + try: + h5pkgcfg = pkgconfig.parse('hdf5') + except pkgconfig.PackageNotFoundError: + pass + # NOTE: Cannot use pkgconfig.exists('hdf5f'), since this is true + # although no libraries or include dirs are available + h5pkgcfg['found'] = 'include_dirs' in h5pkgcfg \ + and h5pkgcfg['include_dirs'] and \ + 'library_dirs' in h5pkgcfg \ + and h5pkgcfg['library_dirs'] return h5pkgcfg @@ -183,10 +193,10 @@ def add_coverage_flags_if_required(cxx_flags: List[str], """ if 'ENABLE_GCOV_COVERAGE' in os.environ and \ os.environ['ENABLE_GCOV_COVERAGE'] == 'TRUE': - print("ENABLE_GCOV_COVERAGE was set to TRUE." - " Building AMICI with coverage symbols.") - cxx_flags.extend(['-g', '-O0', '--coverage']) - linker_flags.extend(['--coverage','-g']) + log.info("ENABLE_GCOV_COVERAGE was set to TRUE." + " Building AMICI with coverage symbols.") + cxx_flags.extend(['-g', '-O0', '--coverage']) + linker_flags.extend(['--coverage', '-g']) def add_debug_flags_if_required(cxx_flags: List[str], @@ -203,8 +213,8 @@ def add_debug_flags_if_required(cxx_flags: List[str], """ if 'ENABLE_AMICI_DEBUGGING' in os.environ \ and os.environ['ENABLE_AMICI_DEBUGGING'] == 'TRUE': - print("ENABLE_AMICI_DEBUGGING was set to TRUE." - " Building AMICI with debug symbols.") + log.info("ENABLE_AMICI_DEBUGGING was set to TRUE." + " Building AMICI with debug symbols.") cxx_flags.extend(['-g', '-O0']) linker_flags.extend(['-g']) @@ -225,7 +235,7 @@ def generate_swig_interface_files() -> None: '-Iamici/swig', '-Iamici/include', ] - print(f"Found SWIG version {swig_version}") + log.info(f"Found SWIG version {swig_version}") # Swig AMICI interface without HDF5 dependency swig_cmd = [swig_exe, @@ -239,7 +249,7 @@ def generate_swig_interface_files() -> None: if swig_version >= (4, 0, 0): swig_cmd.insert(1, '-doxygen') - print(f"Running SWIG: {' '.join(swig_cmd)}") + log.info(f"Running SWIG: {' '.join(swig_cmd)}") sp = subprocess.run(swig_cmd, stdout=subprocess.PIPE, stderr=sys.stdout.buffer) if not sp.returncode == 0: @@ -256,9 +266,28 @@ def generate_swig_interface_files() -> None: 'amici/swig/amici.i'] if swig_version >= (4, 0, 0): swig_cmd.insert(1, '-doxygen') - print(f"Running SWIG: {' '.join(swig_cmd)}") + log.info(f"Running SWIG: {' '.join(swig_cmd)}") sp = subprocess.run(swig_cmd, stdout=subprocess.PIPE, stderr=sys.stdout.buffer) if not sp.returncode == 0: raise AssertionError('Swigging AMICI failed:\n' + sp.stdout.decode('utf-8')) + + +def add_openmp_flags(cxx_flags: List, ldflags: List) -> None: + """Add OpenMP flags to lists for compiler/linker flags (in-place)""" + + # Enable OpenMP support for Linux / OSX: + if sys.platform == 'linux': + log.info("Adding OpenMP flags...") + cxx_flags.append("-fopenmp") + ldflags.append("-fopenmp") + elif sys.platform == 'darwin': + if os.path.exists('/usr/local/lib/libomp.a'): + log.info("Adding OpenMP flags...") + cxx_flags.extend(["-Xpreprocessor", "-fopenmp"]) + ldflags.extend(["-Xpreprocessor", "-fopenmp", "-lomp"]) + else: + log.info("Not adding OpenMP flags, because /usr/local/lib/libomp.a" + " does not exist. To enable, run `brew install libomp` " + "or add flags manually.") diff --git a/deps/AMICI/python/amici/swig.py b/deps/AMICI/python/amici/swig.py new file mode 100644 index 000000000..42bd9aac8 --- /dev/null +++ b/deps/AMICI/python/amici/swig.py @@ -0,0 +1,77 @@ +"""Functions for downloading/building/finding SWIG""" + +from typing import Tuple +import os +import subprocess +import re + + +def find_swig() -> str: + """Get name and version of SWIG executable + + We need version >=3.0. Probably we should try some default paths and names, + but this should do the trick for now. + + Debian/Ubuntu systems have swig3.0 ('swig' is older versions), + OSX has swig 3.0 as 'swig'. + """ + + candidates = ['swig4.0', 'swig3.0', 'swig'] + # Environment variable has priority + if 'SWIG' in os.environ: + candidates.insert(0, os.environ['SWIG']) + + for candidate in candidates: + if swig_works(candidate): + return candidate + + raise RuntimeError("Unable to find SWIG executable with default names. " + "Ensure you have SWIG installed, e.g. by " + "`sudo apt install swig3.0` or `brew install swig`. " + "As non-root user, you can install SWIG using " + "https://github.com/ICB-DCM/AMICI/blob/master/scripts/" + "downloadAndBuildSwig.sh, or by following the " + "instructions at http://www.swig.org/Doc4.0/" + "SWIGDocumentation.html#Preface_installation. " + "If was not found despite being installed, set the SWIG" + " environment variable to the full path of the correct " + "executable.") + + +def swig_works(swig: str, verbose: bool = True) -> bool: + """Test if `swig` looks like a working SWIG executable.""" + + try: + # For python3.6 compatibility no `capture_output=True` + result = subprocess.run([swig, '-version'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + except (FileNotFoundError, PermissionError): + if verbose: + print(f'Testing SWIG executable {swig}... FAILED.') + return False + + if verbose: + if result.returncode == 0: + print(f'Testing SWIG executable {swig}... SUCCEEDED.') + else: + print(f'Testing SWIG executable {swig}... FAILED.') + + return result.returncode == 0 + + +def get_swig_version(swig_exe: str) -> Tuple: + """Determine version of the given SWIG executable + + Returns: + Version tuple + """ + result = subprocess.run([swig_exe, '-version'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + assert result.returncode == 0 + + version = re.sub(r'(?s).*Version\s+([\S]+).*', r'\1', + result.stdout.decode('utf-8')) + + return tuple(int(x) for x in version.split('.')) diff --git a/deps/AMICI/python/examples/example_constant_species/ExampleEquilibrationLogic.ipynb b/deps/AMICI/python/examples/example_constant_species/ExampleEquilibrationLogic.ipynb new file mode 100644 index 000000000..a2d957e94 --- /dev/null +++ b/deps/AMICI/python/examples/example_constant_species/ExampleEquilibrationLogic.ipynb @@ -0,0 +1,1200 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# AMICI documentation example of the steady state solver logic\n", + "\n", + "This is an example to document the internal logic of the steady state solver, which is used in preequilibration and postequilibration." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Steady states of dynamical system\n", + "\n", + "Not every dynamical system needs to run into a steady state. Instead, it may exhibit \n", + " * continuous growth, e.g., $$\\dot{x} = x, \\quad x_0 = 1$$\n", + " * a finite-time blow up, e.g., $$\\dot{x} = x^2, \\quad x_0 = 1$$\n", + " * oscillations, e.g., $$\\ddot{x} = -x, \\quad x_0 = 1$$\n", + " * chaotic beviour, e.g., the Lorentz attractor\n", + " \n", + "If the considered dynamical system has a steady state for positive times, then integrating the ODE long enough will equilibrate the system to this steady state. However, this may be computationally more demanding than other approaches and may fail, if the maximum number of integration steps is exceeded before reaching the steady state.\n", + "\n", + "In general, Newton's method will find the steady state faster than forward simulation. However, it only converges if started close enough to the steady state. Moreover, it will not work, if the dynamical system has conserved quantities which were not removed prior to steady state computation: Conserved quantities will cause singularities in the Jacobian of the right hand side of the system, such that the linear problem within each step of Newton's method can not be solved." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Logic of the steady state solver\n", + "\n", + "If AMICI has to equilibrate a dynamical system, it can do this either via simulating until the right hand side of the system becomes small, or it can try to find the steady state directly by Newton's method.\n", + "Amici decides automatically which approach is chosen and how forward or adjoint sensitivities are computed, if requested. However, the user can influence this behavior, if prior knowledge about the dynamical is available.\n", + "\n", + "The logic which AMICI will follow to equilibrate the system works as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "image/png": "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xFu2vJ8RMmPTll3Go9t7jB3RsCDwPvbeF6jqCGWBeLyYgh1M+kDluGH/jT3fMs1Y9eV9bmgO2xBlAny+8fnG59vpi4zPt9Ms7LjF55sde8U+dXKcB2+d3uHFprMP+iBrcmrtkkRr95L+6adeBkmMyUiABEiABEggogSw2Bo+kTYsMoZPNAwiXzAWTB0QL7ZUicLmk1GZ8HBGXNisGhZ/wycjQx0QbzYYC6ZNwZSTURrEMsYnFIOXtq+ndr68uUxoCt/ysCCdtSid7zHf3wj5gA+NBEiABIIlwOcbn2++Y4XPN18i/E0CziHARdac01esKQmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmkIeA4D16r9vTwtEi46zvRPJXd1XtsDQmQAAmQQLwIXHVFXRNCoUQUPI3j1aaMzgtPVSwwhkXhaCRAAiRAAu4lwOebe/uWLSMBEogsAccKvJHFwNJIgARIgARIgARIwLkELqlfzbmVD6HmCGnQ6rI6IeRkFhIgARIgAScR4PPNSb3FupIACcSTAEM0xJM+z00CJEACJEACJEACJEACJEACJEACJEACJEACJEACYRCgwBsGPGYlARIgARIgARIgARIgARIgARIgARIgARIgARIggXgSoMAbT/o8NwmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmEQYACbxjwmJUESIAESIAESIAESIAESIAESIAESIAESIAESIAE4kmAAm886fPcJEACJEACJEACJEACJEACJEACJEACJEACJEACJBAGAQq8YcBjVhIgARIgARIgARIgARIgARIgARIgARIgARIgARKIJ4Gc8Tw5z00CJEACJEACJOAsAjf2fMtZFWZtSYAESIAESCAIAny+BQGJSUiABEiABGxLgB68tu0aVowESIAESIAESCBeBP7+6n7Bh0YCbiDA8eyGXmQbSCAyBHg/iAxHluJOArw+3NmvidKqbP+pOamxdXqfZaq7pP86J1WbdQ2SAPs3SFAOTZYtWzZTc4fddhxKm9UmARIIhwDvV+HQY167EeB4tluPsD4kED8CvB/Ejz3PbH8CvD7s30esYWAC9OANzIZHSIAESIAESIAESIAESIAESIAESIAESIAESIAESMDWBCjw2rp7WDkSIAESIAESIAESIAESIAESIAESIAESIAESIAESCEyAAm9gNjxCAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAArYmkNPWtbNZ5Z765D75ZsGX6WqVPVt2KVW4jNSoUFtua9lbqpatni5NZjvWbF0lO/ftkAolKkrJQqUzS87jJEACJEACJEACJEACJEACJEACJEACJEACJEACJCD04A1hEBTKW1iqla/l+SSXriK7/90l036ZKKlvXC1/bFyR5VI/mvqu9Hink0z/ZVKW8zIDCZAACZAACZAACZAACZAACZAACZAACZAACZBAYhKgB28I/d60VnPpc/3raXIePHxAur/dSX7bsEw+/2GoPN35lTTH+YMESIAESIAESIAESIAESIAESIAESIAESIAESIAEIk2AAm+EiObJlVfqVKpvBN5d+3emKXXhyjkybPr7smztEilWsKRcVLWR9LzyAcmfu4Bs3LlOnvv8UVm15U+T5zMVh2cs+07uvuoROSPnmdJv7HNSoXiSPHHti54yd+zdJk9+3Fvy5c4vr98y0Ox/8KPbZf+hffJGj8Hy+ti+MnnxeLmuUVdpfn5reWP8C3Le2XXlijpt5J1vXpGFq+YKvJDb1r9Wbml+l+TInsNTNjdIgARIgARIgARIgARIgARIgARIgARIgARIgAScQ4ACbwT7au4fP5jSKpWu6ikVMXufHfmgZNM4vdU1rMP2PVvl01kfycK/5siAOz+Vo8eOytptfxtxFpl27dsph48ckkP6OXjkoMz780fZc+AfT3nYOHL0sNkPkdayRSra/vPvbnlx1OOeOMHH/zsuew/uMWlx7Ks5I6Wg5ilwSlh+b+JrkuvM3JLa7DarGH6TAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAk4iAAF3hA6a+s/m2Xmr1M8OSGeInbu3+qFmz9PQbmucVdzbK8Ks6989azkPiOPDLn3K6lStpqcOHFCnv/iURkz9zP5aMq78mD7p2Xis3Pl6U/ul68XjJY71bO3c+NuJv/Cv+Z6zhHsxndLvpEH2z0tzetcJXlz5ZPf1i8zWf/YuFzubfOYdLusp6nD/758Sr74aYR8t+RrCrzBwmU6EiABEiABEiABEiABEiABEiABEiABEiABErAZAQq8IXQIvGrx8TWIu+/ePlxKFiptDn27aKzsUw9aiKoQd2HZs2eX+9o+KePmfaEi70gNxfCw5DojtzkWiX86NOwiN6T0SFdUwbyF5KZTnrqoQ/PzrzIC7+ZdG9Ol5Q4SIAESIAESIAESIAESIAESIAESIAESIAESIAFnEKDAG0I/VS1XQ1J0oTXLduzdLj+umC7b9myRR4fdJaMemWLi4/69ZaVJMuf3WbJm2yorufnOmeMMOXD4X9m9f5eULlI2zbFwflxau6Xf7GWLVkgTa9c653//nfCbnjtJgARIgARIgARIgARIgARIgARIgARIgARIgATsT4ACbwh9VK1cTenZ6oE0OXft2yFtX2gqm3dvlCk/T5B2F11nvHeR6Mixw/Lvof1p0mPRM9iJE8fT7A/3R6nC/sXi7BoDmEYCJEACJEACJEACJEACJEACJEACJEACJEACJOAuAhR4I9SfRQsUl0uqp8hkjWm7bvtqU2r54hXN99X1O5kwDVk9Vc7sOUyWvQf2pMm679C+NL+9f+TQ8As0EiABEiABEiABEiABEiABEiABErAI/P333zJs2DDrpzzzzDPStWtXSU5O9uzjBgkkKgFeH4na8+5qN9XACPZniVOxd3ft32FKrVe5ofn+ZsGXcvTYEc+Zfl37s1z4QCW5+vnG8t9//53cny2b+T7ilc6K5btp13rZsnuTJ//s32Z4tiO5MWHhVzJ4yjsycdG4SBbLskiABEiABEiABEiABEiABEiABGJMYP/+/TJkyBBp2rSpVKpUSfr27eupAbaxD8eQBmlpJJBIBHh9JFJvJ0Zb6cEbwX7On7uAKW3H3m3mu0HVRnLROU1k7h+z5Oa3rpGWF1wt2/XYxIVj5djxo9Lt0p6S7ZSwW6JgSZPn8x+GyY49WzXEQ2dJKllJKqgX8Poda+XeQbdI63odVOjdKBBio2GjfvpYlq5eKPWrXCKt6raNxilYJgmQAAmQAAmQAAmQAAmQAAmQQJQIwIFoxowZMnToUBk9erQcOHDAnClPnjzSvHlzad+unfk9ZuxYmTJlisyaNct8evXqJR07dpRu3bpJSkqK5+/UKFWTxZJAXAjw+ogLdp40RgQo8EYQdHLpyqa0BSvnyJ5//5FC+QpLv1sGymtj+8r4eV/I8nVLzfEi+YvJE51elA4XX+85e4eGXWTmr1Nk1ZY/ZcSMD6VhtSaSXLqK9Ln+dXls+N3y58YV5lOmaHl5tdv7cvt7XTx5uUECJEACJEACJEACJEACJEACJJC4BKwp5sOHD5c1a9Z4QNSrW1faqajbokULyZcvn2d/gwYN5Kknn5TJkyfLWBV7Fy5aJMiLT1JSkqSmpjKEg4cWN5xOgNeH03uQ9Q+GQDZ9g3EqRkAwyeOfpk7vs0wllvRfF//KZAtkXd8AAEAASURBVKEGCNGwetsqOSPHGYLYvPj2ZwePHJTjJ46J5Q2MNMeOH5ONGqYBXr+VSlf1l801+5zav67pgCg3xPJYd9htJ8pUWDwJkIAdCfB+ZcdeYZ1CJcDxHCo55iMBexPAFPNRo0YZb1144lpWtmxZadu2rbTTT4UKFazdGX6vX79exo4bJ+P0s2nT6fCATZo0MV69nTp1kvz582dYBg+SgJ0I8PqwU2+wLrEgQIE3FpR5jqAJUOANGpUjE/IPTEd2GytNAglJgPerhOx21zaa49m1XcuGJSCBYKaY169fP+QQCyh//vz5YoVwOHjwoKGcN29ehnBIwPHmtCbz+nBaj7G+kSRAgTeSNFlW2AQo8IaN0NYF8A9MW3cPK0cCJOBFgPcrLxjcdDwBjmfHdyEbQAKS1SnmkUD277//pgnhYJXJEA4WCX7bhQCvD7v0BOsRTwIUeONJn+dOR4ACbzokrtrBPzBd1Z1sDAm4mgDvV67u3oRrHMdzwnU5G+wSApGcYh4uEoZwCJcg80eaAK+PSBNleU4nQIHX6T3osvpT4HVZh/o0h39g+gDhTxIgAdsS4P3Ktl3DioVAgOM5BGjMQgJxIhDtKebhNoshHMIlyPzhEOD1EQ495nU7AQq8bu9hh7WPAq/DOiyL1eUfmFkExuQkQAJxI8D7VdzQ88RRIMDxHAWoLJIEIkwgHlPMw20CQziES5D5gyXA6yNYUkyXyAQo8CZy79uw7RR4bdgpEawS/8CMIEwWRQIkEFUCvF9FFS8LjzEBjucYA+fpSCBIAnaaYh5klQMmYwiHgGh4IEQCvD5CBMdsCUuAAm/Cdr09G06B1579Eqla8Q/MSJFkOSRAAtEmwPtVtAmz/FgS4HiOJW2eiwQyJmD3KeYZ1z7zowzhkDkjpghMgNdHN0lJSRHruR2YFI+QQHoCFHjTM+GeOBKgwBtH+DE4tfWgwoObRgIkQAJ2JsD7lZ17h3XLKgGO56wSY3oSiDwBJ04xD5cCQziESzBx8vP6WOTp7KSkJElNTZWuXbtKcnKyZz83SCAzAhR4MyPE4zElQIE3prhjfjL+gRlz5DwhCZBAiAR4vwoRHLPZkgDHsy27hZVKAAJummIebncxhEO4BN2Xn9fH6T7l9XGaBbdCJ0CBN3R2zBkFAhR4owDVRkXyD0wbdQarQgIkkCEB3q8yxMODDiPA8eywDmN1HU3A7VPMw+0chnAIl6Cz8/P6yLj/eH1kzIdHMybgWIE342bxqNMJLOm/zulNYP39EOAfmH6gcBcJkIAtCfB+ZctuYaVCJMDxHCI4ZiOBLBBIxCnmWcDjNylDOPjF4sqdvD6y3q28PrLOLNFzUOBN9BFg0/ZT4LVpx4RZLf6BGSZAZicBEogZAd6vYoaaJ4oBAY7nGEDmKRKSAKeYR67bOUU9ciztUhKvj8j1BK+PyLF0c0mOE3jd3BlsGwm4nQD/wHR7D7N9JOAeArxfuacv2RLxrMaNqZ80EiCB8Ahwinl4/DLLzSnqmRGy93FeH9HtH14f0eXr9NIp8Dq9B1l/EnAQAQomDuosVpUEEpwA71cJPgBc1nyOZ5d1KJsTFwKcYh577JyiHnvmoZ6R10eo5ELPx+sjdHZuzUmB1609y3aRgA0J8A9MG3YKq0QCJOCXAO9XfrFwp0MJcDw7tONY7bgT4BTzuHeBpwKcou5BYZsNXh+26Qrh9WGfvohnTSjwxpM+z00CCUaAf2AmWIezuSTgYAK8Xzm481j1dAQ4ntMh4Q4SCEiAU8wDorHFAU5Rj2838PqIL//Mzs7rIzNC7j5Ogdfd/cvWkYCtCPAPTFt1BytDAiSQAQHerzKAw0OOI8Dx7LguY4XjQIBTzOMAPcxTcop6mACzkJ3XRxZg2SQprw+bdEQMq0GBN4aweSoSSHQC/AMz0UcA208CziHA+5Vz+oo1zZwAx3PmjJgiMQlwirl7+p1T1CPfl7w+Is80XiXy+ogX+dielwJvbHnzbCSQ0AT4B2ZCdz8bTwKOIsD7laO6i5XNhADHcyaAeDihCHCKubu7m1PUw+tfXh/h8bN7bl4fdu+h8OpHgTc8fsxNAiSQBQL8AzMLsJiUBEggrgR4v4orfp48wgQ4niMMlMU5kgCnmEem267p2FEuvPBCefSRR2TBggXStVs3mT5tmpQuXVq6d+8uJUuVkpdefDEyJwuzFE5RDx6gm6+PefPmSYGCBaVG9erBA4lQymXLlsl1nTvLtxMmSFJSktx///1y6PBhee/dd2XdunXSslUrGfnpp3LeeedF6IzBF8PrI3hWTkmZ0ykVZT1JgARIgARIgARIgARIgARIgARIIFgCnGIeLKnQ0hUpUkSaN28uuXPnDq2AKOfKly+fdOjQwXy8p6ivWbNG+vbtaz5NmjSRbipSd+rUSfLnzx/lGtmr+ES5Pvq/+aZUV3H36aeeinsH1K5dW44ePRr3eqACvD5s0Q0RrQQF3ojiZGEkQAIkQAIkQAIkQAIkQAIkQALxIsAp5rEjX7lyZXmzf//YnTCMM1WoUEHu7tVLet11l8yfP1/GjB0rU6ZMkVmzZplPLz3WUb2TIfampKSINfMhjFPaMiuvj/h2C8aXHY3Xhx17Jet1YoiGrDNjDhIggRAJWP+jhP+xoJEACZCAnQnwfmXn3mHdskqA4zmrxJjeiQTsPsX8lltuMZ6ky1esMMLiYZ2mXbduXXns0UellIY1gH388ceCdtx+++3yyquvyp49e2TQhx+ab/z+6aef5Mwzz5RGjRrJAzrVGx54ls2ZO9dM+/7jzz+l2jnnGI/UNm3aWIcF07GtMv755x9p2rSpdGjfXuDdiOniJUqUkCeefFKSk5Olu9bVssWLF8tLL78sQ4cMMefzDtGwQtvyzLPPyvsDBkixYsU8IRpqn3uujBw5UrZu2ya1atWS+3r3Nt9WmXb5TqQp6na7PoK5HjBOdu7cKa/q2F+wcKHgmkEogwcfeEDOPvtszzAaPny4fKrjbfPmzVK8eHFpc9VVcs8998i69evloYceMtcUvMzLli0rz6nndrVq1YwX7Ts67r/77jtzbTRo0EB633uvlCtXzlPuokWLBGkQZgHe6t26dpVdu3fL3r175YnHHxd4gj/08MPy+muvyVlnneXJ9/L//ie5cuUy4943RMMb+kLkyJEj8ojms0I0fPD++/LVmDHmxQO8yBs3biwPPfigKcNTaBw2Eun6iAPeqJySHrxRwcpCSYAESIAESIAESIAESIAESIAEoknASVPMf/v9dyOwQsy9/bbbTBzOYcOGSecuXWScepMW1BihW7ZskZUrV8r9KmBBXLn88suNqNXl+uslb968cq+KVgcPHpQPBw2SNatXyyD9zp49u8yYMUPuUXEKYQaQFsLUYypA5ciRQ6688kqBc8UtGh8XghLEW4i5EydOlAdV/IKIDMEJtmrVqnThFvbt3y/Lly+XY8eOpetK1BHHvKec//jjj0aoSr3pJsmnYtXo0aMlVYWxT1S8xjR5O5nbp6jb+foI5nrYt2+fdLr2WjNkeuj4zaUiLV6CXHvddfL5Z5+ZlxFff/21/O+VV8xLkRo1ashvv/0mAwcOlPwFCki7tm2lmXpj79ixw4z5FH2pUahQIVPefffdJ3jZcmuPHpInTx75+JNPpLtuf6ZCceHChWXJkiXmmqlTp448+cQTRtj9QMvFWMdLC9ihQ4fM+Ifw7G24znKrwOvP1usxxOD1NrxYwUuRRzSu9cYNG2TQ4MHmWhzy0UfeyWK+7fbrI+ZAY3BCCrwxgMxTkAAJkAAJkAAJkAAJkAAJkAAJhE/AyVPMc+bM6fGEBYnLLr1UWqkAC+/DO9RrF7ZIPWY7q4D1lMYLhff9R+o5a4S6L77weOxefPHFcrWKV3N18aiL1PMQAtdNN95ovBVRxpW6cFNeFa3efOstI/BOmz7deCFCMIKnIgzevT1U0EIZkbTd6uH4zTffSFLFiqbYq1q3lnbqKTxAvRTfUm9hu5pbpqg76frI7HoYMnSo7Nq1yyxQBu9bWKuWLeVKHVPvvPOO9OvXzwixZXSBv3vuvtscv/yyy+S/Eydk69atxpv3zjvvlB/0pQNeLmAbNnvOHJmpoTnGjxvn8QS+4oorpLV6/sKT9pabb5b31Cu9oo7hgR98YLzmka+pxmvGdRdpg0fx22+/7QkLYuqqoURmz54tuNbtYG65PuzAMpp1oMAbTbosmwRIgARIgARIgARIgARIgARIIGwCdptiHkqDWquY6x1WAaIVFvmaraEXLIEXHrmYXm6FVoHIU7NmTTMd3PucmBI+depUOUtjy65du1YQDxfetJZVqVpVBqug+6eGbJivIm7ZMmU84i7S4Dwd1eM30gJvg/r1PeIuzoOp8W1VFBusXolOMHCHCI7PU+pZOXnyZBmrHtYL1SsaoQDwSUpKktTUVOmqnskIaWEHc+L1kdn1gLGfoh64lrgLzvBkb9+unYxUD14YPGw/+/xzuV9DlmBBvQsuuMBcP+ZggH/maLnly5eXAwcOpLlmaul1hmvqZo2Tu2DBArmzZ0+PuIuiKlWqJPXq1QtQaui7O15zjed6Ryloc8mSJU1IFrsIvFbrnHp9WPV3+zcFXrf3MNtHAiRAAiRAAiRAAiRAAiRAAiQQdwLeQpVVGcT8xLRyyxA+AVPELVuvcUTxmTlzprXL8322Co2IMwrDNG9/tk3j4G5Rb8YyKvD6mne8Ud9jof4O1EaIaQgHYU2RD7V85nMPgUBjxboeNm3aJPU0TrWvldeXGoiDixAh8ERHKIfhI0bIJPWCP+OMM4zXK2JU46WHP8M1g5ciVvgH7zSoE7zQEbYkUP22b9/unSXs7UDnQUxhGglkhQAF3qzQYloSIAESIAESIAESIAESIAESIIGYE4CnZJ8+feTZZ581MWeH6vRtxHeFZyU+L7z4ojRv3tx499VXL1LLAzbmFc3ghHtUlPI1CFWFNP6uZYjF621YvAxeiVhYytcgZiFuL+wj9ZCtUqWKbxIpoLFIp06bls4DGAn3quCamSHmb1bMbxv1PIgH7O29nJUyY5kWIQ7mz58vY9Rrd8qUKSbmMc4Pz9GOHTtKN/XuhIel3caXE68Pv2PF63rAwma7dUFAX9utYRuw2CD6BHa9xp3GB6ItXoQghi1iTk/XcY8wEL6GawrxerG4ma/Bsx3XDMYrrk1fC/aaCRSD17c8/PZ7Hj23v+vZX/5Y7nPq9RFLRvE8V/Z4npznJgESIAESIAESIAESIAESIAESIIFgCUBYa9asmWCBMsTZ/EjDECDMAYTI8ePHy826iFhzjaf5tsbohOernQyLoXnb8ePHTZzNczQGZyCDELVCF4MqWrSoQJjCB16wL7zwgok/+n/2zgM+qqKL4lfpvfcWQm9SpUOCdJQiRUURUPBTrKgUC03sFcWCBRQQsdBBpEPoEJr0DqH33qvfPZO8ZbPsJrvJbrKbnOtvs7uvzJv5z7xIzrtzBj6hELowRd/aj3csmDZw4EC5rX6kZdV/FN8decCH1D7g24uMX/vYsGGD/ddYP69UOwhHURgLr2F6uzOxLdYCE+gAsMGYwdjBGMJYQjswtjDGMNYw5jD2/E3ctUcUSPdHbPcDvGiXq1+utQig1c4wFXFLlypl+uFz9eFF9i4C9wKsM17TBdSwsJqrDFjcUxERESbb1/6egaXJ39Onm3FaUh+W4Dr2gSz0cLVusAKLsyHs7xksvLZ9+3brELfeHTkc0sxl3K+ltI3+Eknl/vAXnr6qBwVeX5FluSRAAiRAAiRAAiRAAiRAAiRAAj4jkDFjRnlKF0RC1h4EkQEDBhh/VEztHqaLJDXVBZkg+EycONFM5/ZZRdwseOPGjfLRxx8b4enQoUPSX+sLcaiL1tFVdFWf171798rgwYMF50D8+ezzz81ibMhUTpMmjVlgbagu0jR79mxjg7BGM5rfe+89CVZRFR64rVq1MuJvTxW+MP39rGZF/qWLto0bNy7aZUuqoLR48WLDE3YK06ZNMwumRTsoli9YEO5VnR4PwfnUqVPy008/ySItE+2wAt6/ffr2tb4m2jum+GNsYIxgrGDMYOzAYxdjCWMKYwtjDGMt0MLf74/Y7of/PfOMuT8wVg4ePCiwRsCCgmt1IcLnnnvOdAcybr/77jvBQwSIqzhmqXrsIgvXsj5Ip/cA+hLXg0jbUhdTAxuM0127dplxCk/fMWPGSP169Uy53TQDGGVC9EeZuAd79e4d7fcIbE+QcY/F4CI0exj3Zj9dHPHGjRseDZU/9V6EjzCsIXbu3Cm9evUyNi2t9b5F4L5+WP2F5+tiiQkZSf3+SEiWCXWtu/PVE+rKvA4JkAAJkAAJkAAJkAAJkAAJkAAJeIFAIExRx+JNa9etk4aNGpkW58mTR4apOBVTph4WgxoxfLgRHCEEYep4VfUl/UAzeK0MwhdeeEFuajbwW2+/bQQsTG0PCQmRZ7p3N9eByDtas0/7vvGGtFObAQT8d998800jHJsN+qObZq5CPOvx/PNmEzIoIXRi0Td3o6lmwCJaqjiF6dwQ2vr26SNtdGEsK7Zt22YWebO+J+R7cp1i7o/3R2z3A+r8i2bVDhw0SJo0bWqGCTyqP1WRFzYZCCyEhkxdjFlkxCOKFi0q36gwi3sFgQcceLDy6GOPyRjN9oXlCSxe3nrrLWmt4xJjwox1FWeRBYxooQsiwkJi6NChRviHkPyQCsPNtB7n1fMXAZuIAXrOAM2Ux/F42NKpUydpovfAFRWS3Y1Xe/Y0WeJ4iIMooxn9yBa3LCjwQAZZwXjo4utIrveHr7kmVPn3aAf+l1AX43VIgASSNwFrOhN/7STvccDWk0AgEODvq0DoJdbRXQIcz+6S4nFJjQCySZGlCjFnkZ0dATL7WrduLW30VUgXbEqIqFW7tjyvItSTKgBZizRBrPIkIPRAaHL06bXKwL+xIXblzZvXpYAKJrAewLUh5nZ68kmZoxmC9guuIfMW14FQHNeAGIVrgbX1OyiuZXnjPEwxnzxlikzRF7J0rYAFQ1cV3jtoVnEgZula7YjLe2LeH57eDxhPsGpwdc8gM/e4ZtpmULsSV8c4Y4Tz8MqZM6ez3WYb7incC3hQ0leziU9rpu1PP/5oO/7mzZvGwiN37tzG9sG2w8MPyFLGve3q/vawOI8O5/3hES6/PZgCr992DStGAkmPgPWPOwq8Sa9v2SISSGoE+PsqqfVo8m4Px3Py7n+2PpIALAOQFTd69Gjjv2lxqabZsMgubaqZeb5cBMxe0LKundjvrgTexK6Xt66PKeazZs2SybpgGhbiswIWDLBl6KK2EcgSZYix1EjI+8Mf7wd3xoEzgded8/zxGN4f/tgr8asTLRrix49nkwAJkAAJkAAJkAAJkAAJkAAJ+DkBf5yi7ufIArJ6SCQJDw+XSSrqzpkzx7bgG6a7t1d7CmTrhur0fuvBV0A20geV5v3hA6h+WCTvDz/sFC9WiRm8XoTJokiABGImYP1Dihm8MXPiXhIggcQnwN9Xid8HrIH3CHA8e48lS0paBBJyivo+XYQJ07wTY/q1q17DolRHjx4V+PymTBnYuV+cYu6ql+O+3Zf3hz/eD+6Qgr0KvH5hgxJIwfsjkHor7nWlwBt3djyTBEjAQwL8A9NDYDycBEgg0Qjw91WioeeFfUCA49kHUFlkkiOQ2BYOSQ5oAjSIU8wTAHLUJXh/JBxrb12J94e3SAZOORR4A6evWFMSCHgC/AMz4LuQDSCBZEOAv6+STVcni4ZyPCeLbmYjvUQAM83CwsLMwmzjx483CzCh6HTp0knjxo3lYfXrrV69Oqf4e4m3p8VwirmnxLx7PO8P7/L0dmm8P7xNNLDKo8AbWP3F2pJAQBPgH5gB3X2sPAkkKwL8fZWsujvJN5bjOcl3MRvoIwK+nKLuoyon2WI5xdz/upb3h//0Ce8P/+mLxKwJBd7EpM9rk0AyI8A/MJNZh7O5JBDABPj7KoA7j1W/iwDH811IuIEEPCbAKeoeI4v3CZxiHm+ECVYA748EQ227EO8PGwp+iCJAgZdDgQRIIMEI8A/MBEPNC5EACcSTAH9fxRMgT/crAhzPftUdrEyAE+AUdd92IKeY+5avr0vn/eFbwrw/fMs30EunwBvoPcj6k0AAEeAfmAHUWawqCSRzAvx9lcwHQBJrPsdzEutQNsdvCHCKuve6glPMvcfSX0ri/eG9nuD94T2WSbkkCrxJuXfZNhLwMwL8A9PPOoTVIQEScEmAv69couGOACTA8RyAncYqBxwBTlH3vMs4xdxzZoF6Bu8Pz3uO94fnzJL7GRR4k/sIYPtJIAEJ8A/MBITNS5EACcSLAH9fxQsfT/YzAhzPftYhrE6SJsAp6jF3L6eYx8wnqe/l/RFzD/P+iJkP98ZMgAJvzHy4lwRIwIsE+AemF2GyKBIgAZ8S4O8rn+Jl4QlMgOM5gYHzciQQRYBT1O8MBU4xv8OCnyIJ8P64MxJ4f9xhwU9xJ0CBN+7seCYJkICHBPgHpofAeDgJkECiEeDvq0RDzwv7gADHsw+gskgS8JBAcpyizinmHg6SZHw47481tt4PCgqSzp07S5cuXSQ4ONi2nR9IIDYCFHhjI8T9JEACXiPAPzC9hpIFkQAJ+JgAf1/5GDCLT1ACHM8JipsXI4EYCST1KeqcYh5j93NnLAR4f3SV0NBQsf6/HQsu7iaBaAQo8EbDwS8kQAK+JGD9jwr/42aQAAmQgD8T4O8rf+4d1s1TAhzPnhLj8SSQMASS0hR1TjFPmDGTnK7C+yM59Tbb6g0CFHi9QZFlkAAJuEWAf2C6hYkHkQAJ+AEB/r7yg05gFbxGgOPZayhZEAn4jEAgTlGnBYPPhgMLdiDA+8MBCL+SgBMCFHidQOEmEiAB3xDgH5i+4cpSSYAEvE+Av6+8z5QlJh4BjufEY88rk4CnBPx9ijotGDztUR7vTQK8P7xJk2UlNQIUeJNaj7I9JODHBPgHph93DqtGAiQQjQB/X0XDwS8BToDjOcA7kNVPtgT8aYo6LRiS7TD024bz/vDbrmHFEokABd5EAs/LkkByJMA/MJNjr7PNJBCYBPj7KjD7jbV2ToDj2TkXbiWBQCKQGFPUacEQSCMkedeV90fy7n+2PpIABV6OBBIggQQjwD8wEww1L0QCJBBPAvx9FU+APN2vCHA8+1V3sDIkEC8Cvp6iTguGeHUPT05kArw/ErkDePlEJUCBN1Hx8+IkkLwI8A/M5NXfbC0JBDIB/r4K5N5j3R0JcDw7EuF3EkgaBLw5RZ0WDEljTLAVdwjw/rjDgp+SBwEKvMmjn9lKEvALAvwD0y+6gZUgARJwgwB/X7kBiYcEDAGO54DpKlaUBOJMIC5T1GnBEGfcPDHACPD+CLAOY3XjRIACb5yw8SQSIIG4EOAfmHGhxnNIgAQSgwB/XyUGdV7TVwQ4nn1FluWSgP8RcGeKOmo9afJkmTNnjly5csU0In369NK+fXvp2rWrhIaGivV7w/9ayBqRQNwJ8P6IOzue6f8EKPD6fx+xhiSQZAhY/1DE/1gZJEACJODPBPj7yp97h3XzlADHs6fEeDwJJA0Crqao27eufv36RtTt0KGDZMyY0X4XP5NAkibA+yNJd2+ybBwF3mTZ7Ww0CSQOAf6BmTjceVUSIAHPCfD3lefMeIb/EuB49t++Yc1IIKEIWFPUBw8ebC45YMAA6dKliwQHBydUFXgdEvBbArw//LZrWDEPCFDg9QAWDyUBEogfAf6BGT9+PJsESCDhCPD3VcKx5pV8T4Dj2feMeQUSCBQC/H0QKD3FeiYGAd4fiUGd1/QWgXu9VRDLIQESIAESIAESIAESIAESIAESIAESIAESIAESIAESSFgCFHgTljevRgIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAJeI0CB12soWRAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJJCyBlAl7OV6NBEggOREYMWKEhIeH39XkZ5991ratevXq0q1bN9t3fiABEiABEiABEiABEiABEiABEiABEiABEnCfABdZc58VjyQBEvCQQFhYmDRo0CDGsxYsWCChoaExHsOdJEACJJDQBLjIRkIT5/V8SYDj2Zd0WTYJBBYB/j4IrP5ibROWAO+PhOXNq3mXAC0avMuTpZEACdgRgHAbEhJityX6R+yjuBudCb+RAAmQAAmQAAmQAAmQAAmQAAmQAAmQgCcEKPB6QovHkgAJeExg0KBBLs+JaZ/Lk7iDBEiABEiABEiABEiABEiABEiABEiABEjARoACrw0FP5AACfiCgKssXmbv+oI2yyQBEiABEiABEiABEiABEiABEiABEkhuBCjwJrceZ3tJIBEIOMvUdbYtEarGS5IACZAACZAACZAACZAACZAACZAACZBAQBOgwBvQ3cfKk0BgEHDM4mX2bmD0G2tJAiRAAiRAAiRAAiRAAiRAAiRAAiTg/wQo8Pp/H7GGJJAkCNhn7Np/ThKNYyNIgARIgARIgARIgARIgARIgARIgARIIJEI3POfRiJdm5clARJIZgSQyYsICwsz7/xBAiRAAv5K4J577jFV4z+T/LWHWC9PCHA8e0KLx5JA0ibA3wdJu3/ZuvgR4P0RP348O3EJBJzAW7ln4cQlxquTAAmQgIcE1n2538MzeDgJkEBiE+A/8BO7B3h9bxLgePYmTZZFAoFNgL8PArv/WHvfEuD94Vu+LN23BFL6tniWTgIkQAIkQAIkQAIkQAIkQAIkQAIkkBgERowYIeHh4Xdd+tlnn7Vtq169unTr1s32nR9IgARIgAQCj0DACryjPhsWeLRZYxIggWRFoEuvHsmqvWwsCZAACZAACZAACZCAfxEoVqyYdO/e/a5K/fjjj7ZtHTt2tH3mBxIgARIggcAkwEXWArPfWGsSIAESIAESIAESIAESIAESIAESiJEA1sAICQlxeQz2WetkuDyIO0iABEiABPyeAAVev+8iVpAESIAESIAESIAESIAESIAESIAE4kZg0KBBLk+MaZ/Lk7iDBEiABEjA7whQ4PW7LmGFSIAESIAESIAESIAESIAESIAESMA7BFxl8TJ71zt8WQoJkAAJ+AMBCrz+0AusAwmQAAmQAAmQAAmQAAmQAAmQAAn4iICzTF1n23x0eRZLAiRAAiTgYwIUeH0MmMWTAAmQAAmQAAmQAAmQAAmQAAmQQGIScMziZfZuYvYGr00CJEAC3idAgdf7TFkiCZAACZAACZAACZAACZAACZAACfgVAfuMXfvPflVJVoYESIAESCBOBFLG6SyeRAIkQAIkQAIkQAIkQAIkQAIkQAIkEDAE7LN48ZlBAiRAAiSQdAhQ4E06fcmWkAAJkAAJkAAJkAAJkAAJkEC8CBRrNyRe5/Nk/yZw5XY5U0H2s3/3U3xrt3vCq/EtgueTAAkEGAEKvAHWYawuCZAACZAACZAACZAACZAACZAACcSFQLpcxeNyGs8hARIgARLwcwIUeP28g1g9EiABEiABEiABEiABEiABEkhoAmOGvZzQl+T1SIAE4kmgU4+h8SyBp5MACQQqAS6yFqg9x3qTAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAkkewIUeJP9ECAAEiABEiABEiABEiABEiABEiABEiABEiABEiCBQCVAgTdQe471JgESIAESIAES8DqBPXv2yMCBA23l4jO2MUggEAlwPAdir7HOJEACJEACJEACJOA5AQq8njPjGSRAAiRAAiRAAkmIwMWLF+WXX36RkJAQKVasmAwePNjWOnzGNuzDMTiWQQL+TIDj2Z97h3UjARIgARIgARIgAd8Q4CJrvuHKUkmABEiABEiABPyYwH///SdhYWEycuRIGT9+vFy+fNnUNl26dNK4cWN5uE0b833S5MkyZ84cWbRokXm9+OKL0r59e+natauEhobKPffc48etZNWSCwGO5+TS02wnCZAACZAACZAACTgncI/+g/A/57v8c2vlnoVNxUZ9Nsw/K8hakQAJkEAUgS69ephP677cTyYkQAJ+QgBT1keNGiWjR4+WiIgIW62qVa0qbVTUbdq0qWTIkMG2HR8uXboks2bNkskq9q5es8a2LygoSDp37ixdunSR4OBg23Z+IIGEIsDxnFCkk9d1irUbYho8ZtjLyavhbC0JJAECnXoMNa3YPeHVJNCahG+C9eA+wGSyhAfFK/olgSQr8Pb+cIAcP3UiVujNQhpJx5btYj3O2we89dm7cujoYen/Ym8pHpRwfxROmv23TJ49XZrWbyiPt2rvUbOOnTwuZ86dk9w5ckr2rNnMuUeOH5U3PnlHsmbOIl8N+Mij8vzxYGdtPHriuPT9eKBkyZRZhg782FS7/xfvy/7DB+Wt51+TUsEl4tWUYydPKNezkitHDsmRNXu8yorLyf+EzZE//54oDWrWla7tn4hLER6fs3t/hNy4cUOKFioiaVKnjvv5BQtLmjRpPD7f8YQ5SxbImMl/Sd1qNeWZx7o47o7zdwq8cUbHE0nAqwQwZX3cuHEmWxeZuFbkz59fWrduLW30VahQIWtzjO8HDhyQyVOmyBR9HT582HZs/fr1TVZvhw4dJGPGjLbt/EAC3ibA8extoizPkQAFXkci/E4CgUOAAm/8+ooCb/z48ezEJZBkLRogxt24cd1G9/zFC3Lr9m1JlzatpE19RxBKnzad7ZiE/JAlYya5rKJoipQpEvKy8brWzIXzZP7yRfLIgw/Lgw2amLLuvTeFZNN2ZNFXUghnbUxx772mjZkyZvZJE2cvni9zl4ZJu+atpFXD5j65hr8V+u2vP8mpM6fl/df7ScF8BTyu3ndjhsvJ06fk3dfelsL5C3p8vuMJafR3AsZxhvTpHXfxOwmQQIAScGfKevXq1T22WIAQ/JLaNLz4wgsSHh4utHAI0AESYNXmeA6wDmN1SYAESIAESIAESCCBCSRZgbffi72ioXznq49kz4F90lIFNEucjHZAAn/p+1zPBL6iby6XJ2cu+TIJZO7GRCeXZiwn9TbG1P7ksK9+9dqCF4MESCDwCcRlynpcWo0Mjxo1aphX/379olk4wP4BL1o4xIUsz7EnwPFsT4OfSYAESIAESIAESIAEXBFIsgKvqwY7bkcm4UVdWOWVrs/Kn9MnyYq1q6RUsRJy7fp1yZ87rzz58KPRTvl7/kzZvHO7mcpdp2qNaPusL5i6P3XuP7Jtzy65cuWK5MiWTWpVqS4tH2gmKVNGIv/5rzFy4swp6dT6ESmQN58sWLFYwtevlab1HhDYHszWKeNXr1410/+f6vCEIHPj96njZevuHVpedql+XxUJrVnPZCTjusN++1mQpfx0h06SK3sOqyoyduo4OXDksLRv3lqKFQ6ybbf/gLZOXzBLVv67xmRVpk6VSqfOB0mrRs3M9c+ePyc//D7S1Avnha1YIpt2bJWHmzxk2jb8z18lY/oM8sKT3W3FXrp8ScbPmCrb9+7SMk9J/jz5pFKZCvLQA00lRYrIrGVYH4ya+LsU0QzMB2rXV5uASbJ113bTJvBq0/hBGy9bwXYfUCfUrWu7xwVCsxW/T5tg7BPaNW1p7C8WrlwqK/5dLU3qNpCbt27KrEXzzf48OXPLw00flCrlKppyXLUxp/L86Y9R2sb02sZnrMu49b5i3SqZsyRMDqodh8h/UiBPfoEtSPWKVeT8hfMybOwvcvT4MVPW4vBl2v4d0rpRCymtYxCxe99emTZvpuzav1cypksvZYqXknbNWkrGDHem/15Xq4N/Fsw2bQTrlClTSZBaF7Rs2EzK6vH2gXE2b+lCOXrimOTMnlMa1wnVat2x4b5y9Yp8PepHralINx1LaLsVGNdgm1mzz3s88bS1Odr7jZs3dOzPMGPp9NnTklYz5EsVLa6cH5KCefPLmk3/arbyQtN2nPjzuN+MxcLr3V+UlDouYJGB9mJ8YTxn0nbeV7qcnt9SsmfJKms3rzc8z2m/I34Z/5ukTZNWXu/2gm2szF++WJatWanMD5lrVi1fyTC3ptuYEx1+WPWqULKMtIjKTsf4nDJnut7v2+SS/o7ImiWL3K/3XZvGLcw1HYrgVxIggUQk4M0p63FpBjx727Zta172Fg7w+B08eLB50cIhLmST5zkcz8mz39lqEiABEiABEiABEogPgWQv8G5XEfacCm2jJ/4hS1UUQmRMn1HWbYbYtl3aNHnQiEzYflstHiAOQnhy5dsL39/3v/1crl67aqaO51YRbd8h9etT39tjKhg9FyWMQbCDBy8ENQT2bVEh6YKWDZELYthe9WVdt2WDnPv5nB53VU6pYIbp7PsO7pc96mF6Uqe4WwL0DhVST589o8L0NVOe9WPvgf2CfRfVc9dVDB35vRHU7lUrAgiDN2/e1O9bZPueHTLg5b6SQYVFCIKXVaxGXLx00Qil165flesqDqPe8OC1AlPnweD0uTOSXs+FqLn/8AFT543bN8sbPV4zYt6Va1fMuWfPn5VVG9YaYRLHnzh90oh8qE9bFfZcxc69u82xjm0GHwjhjeuGmlPhcYs63nvPvdqmnVIofwGdkiumTkNH/iDv9HzD9HlsbYTthyexeNVyGf7naG1rSilWJEjHzUXZrf2Ohwq3bj9txHNc89KVyJXbLxiut2x9CNHxu19HyO3/bktQgUJyQRf5gUUGBMe+z71i8+v97tfhZpxAwET/3bp127QXbe33Qi8JjhL2J8ycZh48oA0Qt1Ppw4ZfJ/+pDwRy2pqVTgVZiOC4L8K1T1qENrbtW6kiOTg2qhNi2+b4YdiYESrirjf3TPGgYnL42BFZvXGdbNP+GPzqW2YMoc03b90yp55UQdoI/ioyn9bxjnGD+zGt+uqWUG/q46dOyiIVvtGWD3sPvOt82Dzg/P+MJC0ycsJYWaACL6xYCuYtIIf0+jsjJkqEjolnH39KMKacBe4dtA0iMgJ98d63n5n7MX+evMZ3GvfxDPUr3q/vfZ59xVkx3EYCJJCABHw1ZT2+TaCFQ3wJJs/zOZ6TZ7+z1SRAAiRAAiRAAiTgLQLJXuC1QCJ79bGH2kqNyvcbj95Dxw4bQXLNxn81U7auOWxnxG4j7hbQbFRXvp/rtmw04m5NLcfKcoQ49cF3X5gMy466sFlMQuExFYghhOXT7OGDRw7J25+/Z6wlsJBXv5d6m0zZsJVL5BfNfESWY3wDAhzKgQj5YZ8BKmRFZsL+oZmaMxbOlbUq1kHkHtLvAxk14XcjMD6kmaGWzQWyjR3jr38mG3EXmbHI6kXWMkS7j7//UsW2PZpBGmYWebPOO3zsqMk2RZYx/sAZp+dP14zUcO2TmARe63x337fu3i5vq+CJTOZr167J4K8/MZm1q7WP2zVr5bKNyOSMSyxbG25O6/5YZ6ml4wHx13S0bZbAdxfbwPXXSX8aD15kjloevMiqxkMHCNH9ntc6FykamcWt/TJr0TyZNOtv6f5oZzmhAigeAkC4/KBXfzNucJ0JM6eaTFqIxBB4IbojyxfxP11ErI4uJoZYv3WTfDHiW/PZ+lFbM9Mh8K5avyaawLtqwzpzCLKrnQUeQqzdHFmXj994xzwYuKVC7sAvP9Qs8kOydO1K075699eS195/22SL9/nfyzYPXvQ3xknh/IVk0Ct9jXALIfidrz42YnyECqtYBA2v1z/oZ9rU65mXbPfitt07jbhbRMVwlIssZ4jnn/zwlbn3qleqKsjmdSdwT+BhS9kSpaVvlJiLLOwBurgeBPZDR4+YzHt3yuIxJEAC3iWQUFPW41trWjjEl2DyOJ/jOXn0M1tJAiRAAiRAAiRAAr4mQIE3ijD8N5vbZSvCfgFZsuEqclkCL4RARM0qkWJd1KnR3tKkTm2+I2sW0+1LBRc3mZojPv7GbMeCXTHF/RUq20Q6ZOtm04zCM5rZWK1CJSPu4lxr2j0yX+MbGdRaAWJYerUfsMRdlInF0xDnLp437+7+gMiHTE+0s0u7jrZp8xC1sTjbkJ+/EwjUTe0yipFJCjsGBP4grl6xqhF4kaHszYDgbNlUpNEM0UplKxiB19vXsepsjYXlKvQGq+UFbCQ6tGgtbdViIbZA1ivsJxrowwWIuwiwwfmwWYB4jCzytJqpiv6DFQIeClhhZaqeu3DBbNqi2ejIzMV4tMRd7KhYprw5z16or35fVRmjojM8q5EhC0sQiJvILEe2b/EiwdZlor2nUmuPFDpucJ15yxZKo9qhmsGdzjywuK3C/b1Qq2OICqXKSqF8L0tuzS62bDxweIoUkfcMLC1iCixUh4BYb1lYIPscDwkgYsMqw12B1+o7ZOtCBC+v1g3Iqv/pw6EmVzi2+9hUhD9IgAS8RiCxp6zHtyG0cIgvwaR1Psdz0upPtoYESIAESIAESIAE/IEABd6oXqiqAqp91KxUTcZOGWem+sOSAIIRsiERtSq5Fnjh0TkjbK6xNPjo+yHGoqC4CnSVy94ndTVzET6jMQXENPuAQAWBF1mNVqROFSkiQzSLb0B4hX8urBMwhR9CHzKHj+g0+rgEpt8j8ubKE822AdvKFCuJNxUKTxi7C/NFf2TLks0mBGObxQDZvN4MewHbXCdrJOv/1HrDFwF7g43bthiBECJhTu3bUsqghgrYEFZjCmRWI3ZoxvNXv3wf7VAIpdc1sxWWBoX0IQB8eTdu32Kyeg8fP2LEWGRF24eVhYxMcMeA76y9wAtRtnK5+4wnNKwz4Bm8RgVnRM3K1RxPt33H2EYWMvynJ6j/MrKMUT9kwYboAxR7Adp2kt0HeFHD5xZZ43OWHNQ6HTPWCrBEcScsZjM1wxk+0VZYFh4nNDve3Shfsqz6UBeRvSpyQxyGZUSxwkVNv9WvXkdSqrDOIAES8C0Bf52yHt9W08IhvgQD83yO564SGhpqHlYHZg+y1iRAAiRAAiRAAiTg3wQo8Eb1T/as2aL1FATd+1SEW6dTzuEpWrhAQZPNiOzFXDnueJZGO0m/QJCFxcKi8KXyr9o17Nq3RzZs22xeWDitv9os4BhXgSxNZ2FlZDrbF59tEM9gHwGBDz66ELUwlR3Zo1iczNO4qtYHiNRRmcz258OqAe3DtP0b6vNrhas2W/u99R5bBqm3rmOVU1IXF/uo7yBjG7B551azsNvS1SsErxAVCZ9+pJN16F3vlt/xTV207Ir6OdsHFsBDYKRc1MXsPho2xFggQKxHpnA1zQK/WEz9epctMsfhx/Ub183nNKnT2LZZH3LbLVBnbUMGOxb9wwsCr5W9XtuFPYN1HhaAK1O8pC5yFm58d+FbixdsJbBAHTLRXQUsFj4f8Y3xdUa2LDLYW+mCc4tXLTNluDrP2n45yssYgq7jwwGI4Ol0MTZ3AwsNwr94yZoVKjhvUGuR3caaAfYMMxfOU2/qPia73t3yeBwJkID7BAJlyrr7LXJ+JP7fV6NGDfPq36+fzJo1SyZPniyr16yR0aNHm1dQUJB07txZunTpIsHBwc4L4la/JsDxzPHs1wOUlSMBEiABEiABEkgyBCjwRnUlFuByDIhcEHghcmHxNEStGOwZsB/erjdv35IGterrIl8NjJiJ6fEjdLEtiKgr162WB2rXx6FeDUyNR1gil1W4tYib9d3xfd7ShaZeNTRj+Tm7RaimzZvpeKhb3/Pmym2OQ5YuFmuDqGsFsoIhvMF2wpoCb+2Ly7slel+6HLlImVXG5aiF66zvifUO/1dkwz7yYButQhuzoB4WXvtNM8MX6gMAeBs7Pliw6po76iECMsI7tMD5zuPv+TONuFu1PPyOn7FZG0CEtI9c2XOYr1aGtf0+LETmGBVKlTMLpWFROFiN7D980Hjd5lf/aVcBv1yIq8VUZLZsRE6o9+9f0yeae2jKnH9iFHj/1OOwaF83Fb6RJWvFqg1rrI8xvkOoPqMPJh5Xn2tXNhIxFmC3Ex7IsJqoW7WmhNaoazLOIfKO+OtXk4GOhx/oPwYJkIB3CAT6lPX4UqCFQ3wJ+tf5HM8ZpG3btuZ14IAuNDxlikzRV0REhAwePNi86tevL127dpUOHTpIxowZ/asDWRsSIAESIAESIAESCEACd6uaAdgIX1UZHq3p1dt0665txvMUgiL8YWOK36aOk+f7v64Lko01h8FLFN6ilVWAQ1x1yMY0G73wA6IpAlmQVsA/1Zq2bm1zfMeUfgS8WS3BFN8hZt0VUcnFyCp1FagHpuJDaIbXrn1Yi3yV0yn73ojsVpv37LAVB9sC+MXGOdxoo7tlv/nJO2YsWNYe6XQsNan3gE3UtcaClcEMQdyK0lF2FivWrbJl32IfFvfq/sbL8vI7fVWAvCWH1cYAUbJoCZu4i++O/YcMVgQeVoCRFfiMazgGxi1Ef8TP48aYd1eLq5md+uOAisAY+6+8+4Zc0sxiBITllg2bm89We/ElCrPcUBHVCssmokyxyLpiOx5QHDhyd3/eE1WCM2aLVi6zijTvELu79n5efvpjVLTtMX2ZNm+GacvXo380h+HegL2FxcC+LTGVw30kQAKuCeCB34IFC0x2ap48eeTpp5+WRYsWSTp9MNaqVSv55eefZc7s2fLSiy8KbA2SS1gWDmg7GIAFmIANGIEVMnrBznG2QnJh5I/t5Hh23iscz865JJWt734+Xjr1GCrjpi6/q0kDPvrT7Bv0yV937ftz8jKz7/0vJph9z77+g/l+8lTM6y3cVVAMG7btPCR43brlGyu2GC7tdNeFi1dMfQ4cOhltvy/aHu0Cdl92Rxw1nPu886vdVn70JoGjx88axi/0He7NYlkWCZAACbhF4E56pVuHJ6+DUqVMZewK4Od5+uwZua90OcmcMVOMELCIE7L7lug0fIhQQWp5cOrMKfMdCzOhDF9E2RKlBAu7zVg414irsJhAvbHw1a0o2wRn1y2Uv6AR/SbNnq7nXTH2Ef9u3Wh8Y3H8LvWA3b1vr1noK2umLKaIsBVL5bIupoYMZyyQ5hhPtG4vn/30jYyZ/JfJLi2gWZ+Y2g7LClgEtGve2vGUOH2Ht+vW3Ttk9qL5KgReNX0D9qgTbCDiEs7aaHkee1oerBKw2NivE/9QhhFq7ZHDZMNiLGHBNSsbNmvmzKboRVp3ZI7W1ixxY5VRsYrpm8FDP5HayhqiKcTYGyqwNwtpafycC6uNAYw0IEjChgH9vlEtQdZuXm/K3KMZuBB7SwQV0wXGKhq7kfe++dRYRIguF7YofJnccuFBjP7FwmXIXocIDV/qmAJjCYuwnTh9Uq0WvjVWERjzS9esNKfB19eKLGoHgsXtfps8zoytRzRLuVC+gmYMfztmuNStVlNu3Lghi9SewcpKD1c/4CIFChmBHMxwnbH6QKWY2qYgy7m5WknMX77YZEdfvnrZCLIHDh/ShzMrlVVKI65b14/tHZ7Z0xfMNmP2h99HSgm9xjld5A02Kwg8/GGQAAnEjUBymbIeNzp3zqKFwx0W/vyJ49m93uF4do9ToB1VtlRB2b7rsOzQl31cvnJN9u4/bjbt2XdMrl69rgsCp7Ydsn3XIfO5QtnCtm3e/vDhl5PMv3G//+x/+u9j9226vF0Pqzxw+vKH6VJOmb3Zs621me9JjMC9996js1UzSObMri0Zk1iT2RwSIAE/IsAM3lg6AyKXFVb2nvXd2TsWz3qqwxNmejum4SOT9+/5sySHLuj1ylM9jK+os/Piu61Z/Ua6AFQFI4ZB5J08+2+1iAiNdao6zsMCcxfUi3f8jCkyauLvRsh64cnuxkcXU/MhkCHq6UJZhVXEO33ujPqQzjUCm7N6Y3p/n2dfMdmbEJlhSQBxFyLj4FffFCvz1tm5nmxrUq+BWQwMlgzweEWbG9Sqp9msxT0pJtqx7rYx2kkuvsAqAPW5cOmSioWzZOT4sSrYrhEs4NX3uZ62s+pWq2WES9gLgOuxk5FP9v/Xsas0rf+AWWzsz78nmnEEIfuxh9oKFnBDNKoTarLK4cU7YeZUM95O6gMF2DWkVc9Z2C8sDo/MqnjuiW5G2IW/8sRZ0/T1ty5ol0M6tmxvq4v9h+DCQWaxPGxDhrcrOwnrHCyy1uuZF81iengogDqPnTpe23PctOPRBx+2DpXW6q2bScVoiM9o8+3/bsvTet/kz5PXLGz266Q/5Q89v0j+Qlq/dua8ZSoUYzwi4M2bSR+27NQHEOZ8tUVBhvTAl/ua66/asM48YMA9mDtnblMviMPuRjFdGLHHE0+bhfFwXdwXk+dMNw9Anu/UTawMa3fL43EkkNwJYMr6L7/8IiEhIVKsmP6/QKdpY7p2/vz5pUePHjJr5kzjOYtp3bArYEQnYFk4wJsXrMAM7Kwp72AKtmAM1gzfEuB4jh9fjuf48fOns8uVivy31e6IY2ZmmVW3rTsOmhkGeNB/+/Z/sn33HQH4+o2bguMRFcoUsU7hOwkkCQK5c2aRrz/qJu+/1TFJtIeNIAESCCwC9+iUsv8CqcqVe0Y+6R312bAEqTYsDz4c9oXJPB068CMjmrlzYWSQQmi7cOmiZNHMV8sD1Z1z43MMxLszOu2+gC5ShYWi3A2cg+n6ObNl1/pGZpRCNIRnKzJwIZ5ZgUxRtM9+m7XP8f28Zj2e0ozVvLny6PG+eXqOzEpkxRbIm0/bfCc7wLEunnz3pI2xlYvp/PCihZ0AxgGybJ3Fdc1YxTHw7bUPsDb2BZpFi8xfZJY7BvodnHPoYoFYLA8BD2Cclz93vmhl4hoQfnGc1deO5Vnf+3w00Ai0T3foJCE17vjiWvtdvaNPkKGbRscgvHFd9QuyxlOmTGHbj19HGHPIZIafM0RqxIlTJ017CmnGMuwjrHA839oOIRzlgDXGtGWDYe139/22ZjfD6uTcxfMqSGcSeCN7UlaXXj3MpdZ9ud/dS/I4EkgyBHA/h4WFyciRI2X8+PFyOcovHXYDjRs3lofbtJHq1at7dE8lGTheaAj4hoeHyyRdmG3OnDlyRX+fItKnTy/t27eXrupvGhoaSr5eYI0iOJ69BNJFMRzPLsAk0uZi7YaYK48Z9nKMNbh585b877UfdBbZTRnU5xEpXjSvOX70nwtldth6eaBueZm/ZJM82LiKdGxb1+yD+Pv+kIkmq/a7T55Ri7h7BDYFly5fk48HdJI5CzfIuo17dV2Gm4IM4Sfa19Mkgzv/dt534IRMnblatmkW8MVLV/Xfs+mlaqVi0u7BGvqAMK2ELd0sy1fvkM3bDpjrlS5RwFyr57PO106YOf9fc72WTavJrr1HZN7CjaY9ZUoWlO6dGur6KjfktwmLjb1CnlxZpUbVEtKgbjn92/DOv8fPnrsksJ1Alu716zeklF6zZZOqElQ4cm2SYSNny/6DJ+TAoVOSIX0as71KhaLS9IFKHrUdYvmMeWtl9b97tKyTkj1bRilZLL90aFVLsjhkjMKe4q8pulDxwZNqOZhaat5fUiqVC5IPv5ok+fNmk08GPhlj3y4N3yZzlcWhI/gb5rbkzZNVGtavIA3r3ZnFNvTHf/Tf59fk1ecekrHKaPmqHdIopII82qaOnL9w2TBBPa5oBjf6AeOgWFDkGHF28b9nr5GNW/dLTcO4vDkE4+CLYdN03qHIUx0bSN7ckbaEGzbvk+lz10rJ4HzSrmVNcyxsMNAPGGPmmsULSPNGlaWEHhNTfPfzLE1wuizdnnhA/26J/DsKx/82frHsV87ttXyrjCUrwWWDHDx8yvz/tWD+HNJC23W/jkHE6bMX5YdRcyRj+rTy0jPNzTb0P8bIS92by7RZq7X/dpvxXqp4fjO+7a+JewmWJxs27TN1wjFo94+j55qM9Ff+10L/rktjynX1A7YpiN0TXnV1CLfHQMD6Ww//X2KQQKARuHt+faC1wEf1hTiGmxqZlwhk8lpikzuXhAiVRzPa4FnCAABAAElEQVQH8UrIgGhnCXyeXBfeuZaPr3VexvQZnGYAG7Huzr9prMOdvmdWsRgvXwZEytiESk+v70kbYysb4wbCZGwBQd6ZKI+xVDCW8531e4Z06Z32Hxa+iymbFeI2hM01G/814i58qGOzZ3Bsm7t94ihm43+o8HB2jFwqrOZy3KjfHc+3DsHDBNhcxDfgvWuurddnkAAJuEeAU9bd4xTfo/D7skaNGubVv18/mTVrlkxWsXf1mjUmGxrZvkFBQdK5c2fj2RscHBzfSybL8zmeE6bbOZ4ThrO3r4KH9KVK5JeNW/YbmwZL4IW4mkr3tWpWzQi8W7ZHzsDC9bftjMzmLVe6kBF37ev09fAZRhiEoBtx+oSsXLNTTp2+IAN7dzBiGkS199S3F+IdhFKImxAgZy9YLxB++7/eXmclXpGjx87Yij1+4pw+YLxm++744fDR00YMvnDhiv6795wmjGQz9hIQ4VDW6TMXzXv+vNlVAD4qO/cckXPnL6uIWdsUBc9VeAmfUQEvXx5NtNDp+aj3v5sijPBZXtsJb+EzZyPXp4BgifqdC8oTrSqxtR3i7qffTDECKLgXKZhTjmnbIGiv3bBH+r3WToXb7KZMiJ+ffjtF/5YV/TssneTInsmIkmvX74l2TVdfIHqPGbfI7IagCvEYWde/jF1ghPfmDSubfRDZzyu3kb8vEAifCNTzhLb3PfVnPqXscH72bJlk1bpd8u/GCIFAWbF8kDnW8Qeug7FzW32TG+jDAcQu9Q3eFCXWQ7i1BN5wLQ/HQihHnNRxgmviPU+uLDpLUa+pfbhu0155uXsLqXxf5HHmYIcfOzTDHOdBzLcP2IxAoG7WoJLZPH/xJvl57HwztoO1/9B2jIev1HoDYm6NKiUMH9TLXnBH+SdOnpfvVejFGMqdM7PpuzXaH+hDZPumSHGv8Yv+QB9+4Jg0qVNK4YK5ZKte/+OvJ6ugfNpoE/7iKW3PiZ9JgAT8hwAFXhd98f1vP8sG9TJFQOhs3biFiyO5mQSSFoENWzeLtbgYWta+RWtJkybmJ8VJiwBbQwIk4CkBTFkfN26cydbFYmBWwEagdevW0kZfyWmhNKv9CfVuTXmHxcWBAwdk8pQpMkVfloUDLDHq169vsno7dOggGTPeyYZLqDoG0nU4nhO3tzieE5e/p1eHTQMEXtgwIJMRQuchFU2RfZszR2aTLRqh4it8eZF5CFEQUaHM3f678Mp9p+8jJjsWot5Hmm0KsQsiK0TKhcu2GHG3kgqEr/VoaQRi+Pv2eWeMyZ5F9iQycfHq8sI3JuPxg36Pmwze2Np18vR5+aj/E/pgP7MR7d75dJwp876yReT9tzuaus+Yt85kdSLL1BJ4x05YYtrcqUN9aaYZuYg163fLkO+nqyA6Xz4d1NkIzxCM4cFbslg+px68sbV98YqtRtzNpeJgv1fbGR5IyPhBMzuXqrg6RrNN+7zY2gisv6o4C3EXIunTjzcw4vixE2cFbXInZmo7EchotYTWLdsPyAfqa7xCs6Mtgdcqa4UK2o+3qyu1qpXUvxlSyYjf5htxF4zQF4j1myNUoJ5qBNIv3u1qBE2zw+5HxXJFtK4q6mqf39BM1lSpUsr2qAcCeAi0Y/cRu/pEPjSwhNu/NHMXIi2ymVs3v9+Uin76RMVRiLJDynU165fYXc7jj8hqRvR4qqlUr1LcfEaWL8YFHjJA4I0p8GDgi3e7mLG0d99x6f/RHyYTGA8ZChXIKWHLNpu2I8MaDysyZUynC7TfMMI+s0ljIst9JEACFgEKvBYJh/cKpcpqxm4as2hUg5r14pQV61Akv5JAQBBAxmqtyvebBfrg61xNPZoZJEACJOBIAH9s0ILBkUrif4eQ/tKLL8qLL7wQzcIBwjteL+o+Wjjc3U8cz3cz8YctHM/+0Asx18Hy4YX4hoAQiCirFgfW++GjZ0wmZEW1CNilGY8IZwustVFhzrI+wGJkELiQRQvhDgJvneqlBCIgpsXD2gFxj77jhTivApq9nYPZ6OaP2veXMuIuDkcmcnrNEEbmL4Q8a0q81dazKiQjTp25YLJn86l9gSXuYnvVisXMYmqbNXMZwmblqCxT7HMVsbV9gVpdIDq0rGVY4DNmmnV+JERWazYrsnYhcEMYPaIZwhBan1DRFcIoAvYS1bResMyIKSAaw5oCAZHeClwLAZHSMULrlJMWjaqYzbBmQAZzTu2vh9Smwgr0PYR5ZDYjc9USSK39eM+cKb2xcIDAi4xh2DpgQT7wzaCWB8iWRWA8HDfZ1tmNpcIltepYtmq7saxA1rgVeIhQuUKw6aPV63ZLTRWg4xNgikC2clDhXObaELYffTgymzu2sh9qWtU2looWyW3ORztOnrpgBN5l4dtNEW2aVzdjH1/S6jUhlA/+bHxsxXM/CZAACQgFXheDoEm9BwQvBgkkNwKwb3hOFxhjkAAJkIAzApyy7oyK/23jlHf3+oTj2T1OiX0Ux3Ni94Dr6xcplMuIoRBiIeRiejrCEgfhZTt30UYVfg8aAe+aWhQgQxFT6B0jt06ttwJ9Do9ZlGtlL8LTFl6mazfstWU+Yho9/HvjGxCQrcC1M2i2MQRetM+K1DptHnEb6bEah46cNu+Xr1zXjN2/zWfrx3Gdko+AgOdOxNb2w1G2E2VKRrd9g1UFpvJD/AT/W+qLjAjSeqdV7137gKgem8ALIbe8CqPIMP1n7jrTRmSYRuw/YV9UtM/VovxnsRF1QKCfkbFsHxCeETExqVRBHwKowLtF7RiQ7bxTP8OTFxnO0+esNRYe1kMEK3sXGeMI2F84XhMWHoiYrmkOcOPHQ5qhjvENSwy8kE1dWn1+a6m/MTK9Y4s8dv6+OBZjDvWyxpPFp1jR6PYdlpdzbOVzPwmQAAlQ4OUYIAESIAESIAESiJEAp6zHiMfvd3LKe/Qu4niOziPQvnE8+1ePIZMW2bqwIIDXKAQwZDpai2lZgiQEO/jTIpzZM2D7vVHZpvjsLFau3SnfjZhlrBcgehXMl90s3jZx+kpj4+DsHHe3QdR1FlamsLN9sJ1AwHcWvsD2AfEPLwiT7kRMbYfADfESkdpucTerXEt4vnYNC2FHis/I/HQM+8W8HPdZ33EtLOgFSwj4wCKbGX2JDGdYPziLHCrEW2GJ7cgEdmQCQRMvZGa7CmQ7j5+6wmR87ytf1PjillIRNVOUwLtzz1FBZjSiSpSvLgR2BITSuFzTnOzGj7JqR/KpLk4HkXyT2j9gAbvFJ7caVo10AbquuhhaTGFlmsd0DPbZLyhtjo3s0thO434SIAESYAYvxwAJkAAJkAAJkMDdBDhl/W4mSWFLcp3yzvGcFEbv3W1IruP5bhKJuwV2ChB4Fy3fYrxX71MbBSwahcC0+wIqxO5XMcyyX6jgRrajsxaN+WuREXf7vNQ6WsbklJmrnB3u8215cmY118CiXm/1bOuz60F8xjWQMYyMVCwuZwXE5SNRWbN5c2eT62rRgMDib45hZbo6brf/vmffMSNYQoh9783HbGLsvoOuM3jtRXDUEwH/5bgwKaLZyLDZQEbypm37TVmli+c3i+rhCx4ibNGHCBDOrUX9LOEa58XlmtZYtcRpc1H9YQn41nfsz6DXfezhOiL6wn4scgcfZmSpP/xgDevQOL0jqx0Lt+07cNxYXFiFROh3BgmQAAm4QyDy/7zuHMljSIAESIAESIAEkjwBTFkfOHCgBAcHywMPPCCjR4/WaaqXpVrVqvLeu+/KooUL5aMPP5QaNWrYvP2SPBQPG9iufXv56OOPzVmrVq2SsuXKydGjR833Hs8/L6+//rr5vGPHDrNv+/ZI3z0PLxOvwyEYoA/Rl+hT9C36GH2NPkffYwxgLGBMBGok5fG8cuVK2bJ1a6J0zcaNG83YxUJ+iNdee02eV99nxP79+82+9evXm+8J8SO5jOeEYBmXa5QrXcicZvnwQvC1D8uPF6IdxDR4q3oaWEwNC7gh0db+fPjgwsP0rohKyL0RZVlw134vbIBwjWzU3RFH5cChSCsAFIts296DRsuTz3+tWZ6RwqiVIBzX+pSPYgybAjywsgLes/DehSCbJ3cWI6ZnzpROjp04J+vUysKKm8oBC4HFFoeORNooFCqQwybu4hyrb2M7P2/urCZTe58urAf7DCvgDfzGu78ZJrBgiCng1Xvjxi2ZE7bBlAX7Cgir8F5evmqHGQcV9RjLFxiiMuw8Dh4+ZfrCKvvmrVvy1vtjzTUhDLuKbCoMI7buiFwAEJ8xrg4djrR+wHfE6wNGybOv/2B8hPEd3szwHs6SOT2+6oJo0bO4zUYPflhWF5P/WSUY7wj024RpKzwohYeSAAkkZwK0aEjOvc+2kwAJkAAJkIAS4JR17w6DWjVrSrFixZwWWqVyZZ1iG90X0emBCbgxqU15Ty7j+cuvvpIyZcrIgP79E3C0OL/Ufffdp4LMDec7E3hrUhvPCYwvTpfLnze7EeLgj4soWzJS8LUKgw/vnIUbzNeSwfnMwlHWPnff4SebS7NCT5w6L59/O1UX6Sqh3rtXZd7iTTbBE7YCyBxFdifsIE7pYlw/qd1AcFBuaa+Lk3k7YI3Q7qEaMvKPMHl/yARpHHqfyVJepYueHTl21iwqhoxUhGVPsXvvMRn5+wIpoyJ4DW2Du9GmRXVZqotwYYGyT76eIhA4j2mW7nxtP+LxtnUlZYoUOr9fpGXTavLb+MUydPg/0jikomTLmkHC1+5SEfpkrJcrUjCnOWb9pn0y+s+FuvhXDjmgwuk8zVBFYJE1iMqwbHAWKVOmkA6taslPv86VD7+aJE2USdo0qU29IcBC/Lcyb52dj22waYANAoRre0YQ9udGjaMqdgvX4aHBI3rN70fNkY+HTtZ+qKjia+Q1kTmO8+yznh2vi8Xztu08JDPmr5PLV69JZhXtFyzZrAtOp5Bb127bDocAi4zdn8fO1wX/SpvxiCxjMCmg9wAWsnOWOW0rIJYPsHlAuyGM9x70q47bPBKhQnkWFezxEMte2I+lKO4mARJIpgQo8CbTjmezSYAESIAEkjcBTln3Xf/36tXLZeHPPPOMy33+sCNQp7xzPCfu6OnatWviVsDF1QN1PLtojl9vhnAHATK9LvplvzAZKm358OIzFvqKazz/dFP5dsRM48EKH1ZYAzxQr4IR86bOXC2zNEO1fu2yRuDt0LKmjFKBcsOWfQLbAV8IvGhHo5D7VAhMqdP0F8uk6eGmaSl0obLQOuXkyUfq25oaXCSP1KpWUlas2Wmm8yMH1168tB3o4gMyhd9Vy4ThKpxCVNyoHrAI+N92eSxU/WiDbWc2b1jZ+BmP18zPf+auNduR4drzuYeMAGo70MkH9F3HtnUE584Oi8z4RUZwV73GwmVbzAJo46YudynwosgQ7QOIrhCZkY2KQF/Vq1laOj8aar7H9KNs6YKSSoViZDuXKpHfdiisGiDwgq/jOKpbs4zcq9ccoz7BU2ZEXhOiaJ0apaXLoyG2Mpx9aN6wkoqqx8zifTN0YTlcu0PrWuqze8CMH+uczlHl4EHCtFmrzWZkZldUS5LunRpah8X5HVnK777xqPw+cYnJmEbGO+xMnuxQX57v85MKvPDn5QTsOAPmiSSQDAjco/8gxv9fAiYq94z8R8Goz4YFTJ1Z0cAh0PPdN3Xaz1n5sPcAyZ8nn08r/tang+XQsSPS/6XeUrzInX+U+fSiLDxBCXTp1cNcb92Xkf8IT9CL82Ik4IIApqyPGjXKTMO3plfjUEzPb9OmjTRt2lSnQmZwcbZvNz/99NPStm1b2bxli8yZM0cXV7kmVbVeb77xhuTJE7mq9JgxY4xlwLPPPiuffPqpnDt3Tob/9JN5x/elS5eaDNm6devK6zpt3L4ty1eskO++/Va2qzVC6VKlpEOHDtKyZUtboy5dumTKRBlnz56VkJAQafvww4JMSZyXK1cuebtfP2Nd0E3rasXatWvlw48+kpG//GKu17dvXylbtqx06dJFYNHQRcWv+fPmSd68eY11Q5o0aeTVnj0FFg1ttPxffv5Z0K41Wk6WzJklJDRUXnv1Vb/J9AWXWbNmyeTJk2X1mjVWsyUoKEg6d+5s2hkcnDj/H/O38ezOGAbAU6dOyac6XletXm3GecWKFaWXWncULVrUxhdWGWN//12OHDkiOXPmlJYPPSQvv/yy7D9wQHr37m3ug7Rp00r+/Pnl3cGDpXTp0iaL9hsdq7Nnzxb0G2w4er7yihQocGdK/BrtQxwDm4Vs2bJJVx2np8+ckfPnz8vbb70l+L3Qu08f+fyzz6Rw4TtiHGxHrLGLcx997DH5Z/p0Mw6GfPmlTku/Ln31PFg0NGveXH74/nuZOGmShIeHS8aMGaVevXrSWx9+oIzEDH8ez4nJxf7axdoNMV/HDHvZfrNffL5167Zmx54xXrz51HPWWmDssPrQ3tIp+QXy5TBiolVZ+Kam1kxMiLC+DmQXX7x41VglYPq+s8DiY1gUDPvtvWudHetq29VrN4zvLjJzrcxgZ8fiz3xkEuM6sE7wJOAvi2zUjOnTmqxolAG7gP2aBQxLAvjFuhMnlcmFWJi4U44nx5zUzO3zFy6bjNoM+sDB3UAmLqwZCuoYssaVs3OxkNuJk+cFFhDw/3V3IT1nZdlvO37ynGGVU+02LNsH7IcFyMCP/zKWGcM+jf0hcaceQ02xuye8al88P7tJAA8GEAEmk7nZOh6W1An4/v90SZ0g20cCJEACJEACfk4gUKasb922zQisEHOf/d//1M/umhGjH+vYUaaouJhZxU942e7cuVNeUzEMQk2jRo2MQNbx8cc1cyy9vKIC2JUrV+Sn4cMlYu9eGa7v8OkLCwuTl1XogqiLYyFyvaliFlarbtGihfmH/NPduhlxCuItxNwZM2ZILxXSICJDvELs3r1bIKrZx4WLF2Xz5s36x2/k4ja79Jhs2bPbH2L7vG/fPv3DPvoK4hDTLCE7Qvf/rIIvjhv23Xe28xLzg79Neffn8ezOGL5w4YJ0eOQR06Xddcyl0fEEgf+RRx+VP//4wzxAmDZtmnz8ySeCBxl4WLBVvXZ//PFHyZgpk7Rp3Voa6EOAkydPmnEaqg8ismSJXNjoVX0wgAckz3TvLul0nI357Tfppp//UKE4a9assm7dOsE4r6xWIf3eftsIuz9oubBXKF++vKnT1atXzXjGAxb7gHCb1oU4e0D34X61DzwMua9CBcEDj0MHD8rwESPM/YMHGokZ/jaeE5NFIF4bGYzwYnWM/HmzOW4y3z0R+JwW4MFGWEjgFVPg/0fxFQTTpkklRYvkjukyZh+EKldcYjsZAjSyju0D9guO2+z3O/sMywy8EjIgkOLlaUBUtRdWXZ2fTu1CCkdZWbg6Ji7bN2zeZ+w+ShbLJ31ebK3/1kgtx9VL+e/ZkQ9Wy5eJbn0Sl2vwHBIggaRNgAJv0u5fto4ESIAESCCZEkDmAUTNkSNHyvjx483iWUAB0adx48bysGbrVq9e3e8WSkuZMqUtExb1baiLfTVXARaZjM+p2IVAputjKob1V+9R/AH7s2bOGtHvr79sGbu1a9eWViqErdCFqGpqFiPEsic7dTKZjyijhWYYQmj9auhQI/DOmz/fZDRCfELWIwLZvd1VHEMZvgxkbw754gvbJYoXL24WYkNmcJUqVWzb/eFDYk15D6TxHNsY/kXvydOnT5vsV2TfIpo3ayYtHnxQvvnmG/lCxwKE2Hya8f3ySy+Z/Y0aNpT/NPPv2LFjJpv3eV2sb/GSJcaDF58Ry5Yvl4WLFsnUKVNsmcBNmjSRBzXzF5m0Tz/1lHw3bJgUKVJEfvzhB1uGeEj9+uZeMYV48Qcyir/++mvb7xj4BWMhtmXLlgnuT3+IxBrP/tB21oEESMC/CNRVO4nlq3fI9l2HpYdaMmTOlN74SKOW+fJkNVYN/lVj1oYESMDfCFDg9bceSWb1+XrUj2pmf0V6PtVDfp86Tlb8u1oa1Q6V9i1ay/mLF+Sv6ZNl+56dcu36NSlZtLi0CG0swYWDolFavm6VzFsapnYHRzV76obkyZlbGtSsJw3rRPdbgvXCuBlTZFfEHjlz/qzkyZFLQmvWNccig8s+bmgW1m+T/5K1WzboKqZXpVSxEvJ4y/b6NPhOxgD+2Jy9eL6sXL9GDqvVQuH8haRGxap3XffS5Uvy+7SJsmn7ZrmkbS0ZVFweebCN/eX4mQRIgAS8RsDfpqx72rAHVcy1t1WAAFZfBahlaptgCbzIgMJUdWsaHQSjcuXKmanl9tfD9PK5c+dK4UKFTEYshFNk2lpRomRJGaGCLqwSwlXEzZ8vn03cxTG4TnvN+PW1wIusYvtoqqLcYM3IXKrt8jeB16on2EMIx6u/ZmraWzjAWgCvIC9YOATieI5tDGO8hmoGriXugimyz/HQ5XfN4EUgw/aPP/+U19RmBLYlGAcY8zHFci23YMGC5mGO/Tgvr/cG7oOn1CoEliHP9+hhE3dRHhYErFatWkxFx2lf+3btbPcoCkCbc+fObWxU/EXgtRqWUOPZuh7fSYAESMCRADJ23+z5sKxdv1d9pg8Yu4/7dWG3IPVFrqWL2tF/15EYv5MACTgSoMDrSITfE5TAtt075KIKoKMmjJWlayIzpG7/d1tXyD0pH3z3hZw+d0by5soj2bJkldUb18n6rRvl5a7PSoVS5Uw956qw++ukP83nPDlzSdbMWWTP/ggZPekPuXbjuhGEsRMC7IfDhhjRGCJt3px5ZP/hA+bc/YcPytMdOpkyrB8//j5Szp4/ZwTdk6dPyZqN/2qdTsk7Pd8wf/DjuGG//SwrVZDOkC69FMxbQPYdOmDE6ANHDkrX9k+Yoq7rlMd3hn4sx06eMNOAgwoUloNHD2ldvtAFAqKLyta1+U4CJEACyZmAvehlcYB/KKaoWwH7BEw3t+KAepLitXDhQmuT7b2oiozwLEVgyrizOH78uBzVzMh8KvA6hr13qeM+b32HsGwfEJaxDd6rjMAjENsYPnz4sPG8dmxZQX0QAR9cWI8gexxWDqN//VVmauZ6qlSpTNYrfKXxoMJZYJzD2sOyf7A/BnU6oz67sBpxVb8TJ07YnxLvz66uw3Edb7QsgARIIIkSSKlJR9WrFDevJNpENosESMCHBCjw+hAui3afQLhmwT7eqr1U1wxY+LuN+GuMEXcfffBhadGgiSlo/dZN8sWIb+WX8WPl0zcGG8F01qL5Zl+Xth3lgdr1zWdk/EIchviKjF8EMoGREdywdoh0avOIEWkjDu6XQV99JAtXLjXHQUi2Ik3qNPLZW+9JOvXFQ8bvu998agThYyePS77ceWXt5vWmfGQVv9bteT0unZr5n5cPVEResGKJ1Kh0v5QpXtJk+ELczZktu7z1wuuSI2t2swDEj3+MkhWaecwgARIgAW8TwGJX77zzjgwaNCiaRQMWx8Lr/Q8+8GuLhnMqcDkGRC8sPmYFvHjtI0eOHCbDEYtUOQaEMfj2In5WD9ASJUo4HiKZ1Nd0ri6CFhERcde+8+q/G1vA8zc+gfY5Bjg4ttPxmMT8jlksWDxrknojY0E8iwEyUdu3by9dNVsUGZtWlnVc6xqI4zm2MYyFzc7oIn6OcUZtG1KnTm2yebHvcfWKxguiLR5ewMMW/rlYsA82EI6B+wB+vVjczDHw0ADjHDOWnI03d8e5Kw9ex+vhu9Pr6Lh2dg86Oz8htyXUeE7INvFaJEACJEACJEACyYvAvcmruWytvxIIqVFXmtZvaDJ1kfW6asNayZU9pzSPEmhR74plyst9pcvp6qanZd2WjYJVaLu26yh9/veyhNSoY2ualRl7TgVXBN7XqdUC/miCYIw/chBBBQvLk20eNde9cu2q2Wb9eKhhUyPu4nvxoGDJniVy4YaTem3E3CVh5h1WCxB3EZkzZZbWjZqbz3OWLjDvG7ZtMu+tGz9oxF18wR9XTeo9YLbzBwmQAAn4igCEtQYNGphFyuDbiYW7YHUAIW7q1KnylC4k1litAL5Wz09kv/pLwDfYPrAqOqa0l1I/T1cBUWuLLiyVXRc2g8iFFxadev/9942XKTxHITxiur+1H+9YMG3gwIHm/ydl1R8U3x1ZwNPUPuDbi4xf+9iwYYP9V48/hzlkHu/VxeGQ5Vm6VCmPy/L1CeCDMYOxgzGEsYQxhbGFMYaxNmrUKDP24ivu2rclkMZzbGMYXrTL1S/XWrjPaifGAfocbf1cfXiRvYvA+O3cubO8pguoYWE1VxmwuA/wkAIPNezHOWxI/p4+3YjCJfUBh+N4u3z5soSrdYMV8OlG2I9z2FVt377dOsStd0cOh3RM4x4r5UfjOrHGs1sAeRAJkAAJkAAJkAAJeEDg7sf/HpzMQ0nAWwSqVqhkK+qweukirqrv7tCRP9i248PRE8fM9xOnThihtlzJMmqNsF9mLZonh48fVR/eI8Yqwf4kZN0i4LmbJk0a+113+eVaO3PrsfaRQ7NtYBeBDA8ELB8QU+fOkJQp7txGl69eNtthMYE4eiLy2qWCo2eMFVVxOb1aO1y+Enm8OZg/SIAESMBHBDJmzChP6QJLeDl6mg7TRZfwqla1qrRRD9CmTZtG88D1UZVcFrtx40b56OOPpYsKWniQ9+133xmhCd9dRdcuXeQvXWBt8ODBZlE0VcjkVxXHsBgbRF787scCa0N1waecOXMa39hdu3bJe++9J6EqgqfV2RqtWrWSb779VnqqiPbeu+8au4bZs2fLuHHjol22pIpTf6hPKjIqK1WqJItUAP7777+jHePpF9QVIh4WlEO2MawkYEPRQv2IEdOmTTMLySFDuU6dOw80Pb1OXI+HZYC9x65Vjjc8dq2yPHn39/Ec2xj+3zPPmDHTp29fQZ9ifGKhQCyq952OQQQeRn+nYz+4aFHjjwu7BngyIwvXsj7ALCMIprgefHRb6mJqWKTtVbVxePONNwSZwrM1u3rMmDEyTYV4RDfNAO7Vu7cR6bFQIRYn/PSzz4wthDlAf8CqBNnjWAyugHr6QjAeMmSI3NAH8J7En3pPBmu94CkNYXqAPkyBtUprvdcQuL+GabbxSy++KA/o2E+o8LfxnFDt5nVIgARIgARIgASSNoE7ylTSbidb5+cEcmSNzJBFNS2RFKtFO2bW5simmVn6ypQhoxFbfx43RhaFLzPZucULF5XgQkWkdpUaMmbyn7YWX9LMFERGPcfduFfFgZgCi6UhsPjbjXtv2g6955571ZqhlGRTL+DI/dfNu+OURvzhlku9gPcdosBrg8cPJEACCULA36e8P6VT+9euWycNGzUyPPLkySPDVOiKKesPC0uNGD5cBgwYIBCVMFOiqgrWH6i4a2UjvvDCC3JTs4HfevttswgVxK+QkBB5pnt3cx2IvKM187SvCmPt1GIAAf/dN9980wjHZoP+6KZZqxDiejz/vNmEbExcN7YFsKzznb2/qqIyxLz+/fub3RUqVJBRKq5h5gkC3qnInjyvIl9CRaBMWffH8RzbGEadf9Gs2oGDBkkTfaCCgKD/6SefSGhoqPmOhdCQqYtxhix2RFEVeyHgWgvD4qEEHoY8+thjMkYfEmAhtpE6bt566y1prQ9r0IdmfOq4wgMEBB4awEJi6NCh5sEO/j3ykArDzbQe1vjCuBug50CQxfEQoDvpA5ImKtReifo3lSkslh+v9uxpsrrx4AVRRrPwkd2NbHrEWbWpwLg+54YNijkhHj8CZTzHo4k8lQRIgARIgARIIJkTuEf/wROZkhggICr3LGxqOuqzYQFSY1YzJgIvDOhlFln77M13JVeOnObQA0cOSb/P3zMWCu/0fNPl6fDQHfjlh8bWYfCrb0nmjJnMsQePHpa3P3vXbP+y/4dy6OgReeuzwcYH9/O3349W3syF8zTL9qjUr15HggsHSc9335Qz587Kh70HSP48dxa9eU89eHeqF+/r3V80NhGoH+r5YZ+Bkl89eV2FddybPV6T0sVK2A67efOmvDCwt1xVa4j+L/WW4kWCbfv4IekQ6NKrh2nMui/3J51GsSVJkgCy+JCpCnEIGalWIFOwdevW0kZfhXQBKF9Hrdq15XkVtJBtay34BOHLk4BoBNHKlX8t/tkD4Sxv3rw2yx7H8sEDtgO4NsTcTk8+KXM029B+wbVTuvAmrgOh2BuBeh08eNCUhwzVxApMWZ88ZYpM0RdsIqyABUNXFd87dOggiVk/qz4xvSfmePZ0DEPchFWDq3EO+4TjuvhZBhVFXR3jjAXOwwsZ664C9wHGLx5u9NVs4tP6IOGnH3+0HY5/q8ByI3fu3CaL17bDww8Y17gfXd2THhbn0eFJYTx71GAvHVys3RBT0phhL3upRBZDAoFH4PKVa3LoyGnz//oCefG7MvKhq7+3pFOPoaaKuye86u9V9cv6WfZSASaT+SVLVirhCTCDN+GZ84qxEMibK7dkUT9bCLiwXyhSIFLUv3Hzhgwc8qGxYhjwUh+xrBcK5s1vE3dR9M6I3dGukCenrrauGbXwz8VCbfDyRZw6e1r+nD7RTAFu2bB5tHNi+1K6WEkj8C7SBdoea9nOdvikWX/LlLn/SOO6DeSJ1h2kbIlS5rjZS+ZLqeDitsVmsBAbxF372H/4oKkftjWqE2Lz9rU/hp9JgARIwBcE/HHKuydilj0TTAGPKfAPd2uKu6vjwCM2ERMep94M1CshRHRndU5qU9b9ZTy7M4bhFR1TINs1KCr7NqbjHPfhPCtT1nGf9R1WDDEFFnKzf6gR07Ex7UOGfUJGUhvPCcku0K71av+RcuLkeXn/7Y5SpKBnDwMDra3erG/vQb/KkWNn5J2+j0qxoDwy8e+VMnH6SmnesLI80b6eETX7Dh4j2bNmlKEfPm0u/ca7Y+Tg4dMysHcHKREc8+8Ob9R1554jOnvhtqlfqlSRksWk6eEy4e8V0uyBStKpQ+Ti2t64lmMZV6/dkD8mLZW5C+/466dNk0rataxpGDkez+8kQAIk4C8EKPD6S0+wHjYCqVLq/0CbtRLYL3z8/Vfqkxsq6XR64JpN643HbrkSpU22LTzhEJt2bJXRE/+QwgUK6j9IDsv85YvN9vMXL8iyteFq2VBd2jdvLcP/HC3f/jrciKf4o2XJ6hVG3K1V+X61fchuznH3R6uGzWTxquUyY+Fcs4gbsn/3qiC9XK8HO4aGtUNMUS1CmwjE3DUb/5UvRnwrFUqVNf69YSoMYwqk/QIrEQf3yfgZU8x5qLO1eJu7deJxJEACJOANAv445d0b7WIZ0QkgMyU8PFwmTZ4sc9SnFRnLCIiC7dWiAtm6oaGhtgeT0c8OnG8cz4HTV/GpaXIZz/FhlBTPzZo5g9y8cUttS+5Nis3zWZuyZE4vV69e14UXnXMDz2xZMkjWLJF2Kj6rSAwFf/7dNLl46aoMea+rzvLMbI5Mly61qVf6dNHXVImhmDjtGvHbPFm+aoeAU90apeXS5WsStnSz/DZ+sWTPllFqVLkzKzNOF+BJJEACJOAjAhR4fQSWxcaPQEiNOrp4WQoZO3W8LmT2jykMU2HrVqspTz78qPleKF8B6diyvUyYOUXmLVtotsGb94k2j8iyNStNJu+4fyYbgbfe/bWMZ93YKeNk+oLZ5lhkS4WoNcPjrSO9Fs1GN39k1gzjQa/0lZ9UNIaIjBciSBdP69y2oyALGYHM4YGabfz92F9kw7bN5pVC2/HIgw/LZhWmIU4zSIAESMAfCeB3ZANdgAyvb3XhJ3sLh6m6YBNe3rZw+OP3371meeAtpmXLlpV/pk8XeAEnhUiuU9YTajz74xh2Z9z26tXL5vXrzvH+ckxyHc/+wj+x64FsUobnBPq9dmf2obOz8+bOKl9/1M3ZrkTdhsxdvHwZh4+eMeLuvffeI58M6KSLzqY1l4PoPW/RRlm4dAsFXl92AMsmARKIFwF68MYLH09OCAInT5+SC5cvSp4cuSV9unR3XfLK1avqo3tM96k/nS5cBiEYvnHwyM2sq03nyBo9OxflXbx8SWDd4I0s2cua9YTrZ1F/Ocdr2Vf2wqWLckptIuDtmzoq+9h+Pz8nPQL04E16fcoWiezZs8cslDR69GiJiIiwIammi5q10YWdmupiTRkyZLBt54fEJ8Ap6677gOPZNRt/3cPx7PueCRQP3mEjZ8vZc5ek2+MPSO5cWWTWgn9l7Ya90rJpNbMdU+wPHD4l8E9t36qW3Fe2iEt4R4+flV9+XyCFC+aU2tVKye+TlsjefcclR/ZMUr50IXmkdW2dfReZG7X/4En5bcJiKVUsv1SvWlxG/h4msBQY1OcRKVo4t2zdcVD+nr1Gdkfg74P0Uk7Pb6/T+x0zT7ftPGSO27X3qNrTRR3X6u7jloZvk7AlmyXiwAnJmSOThNYuZ9o7c/6/UrNqCWlQt7wcPHJKfv1rkcl27d6poa2dFy5ekW9GzJQ0WvfXerQ0238cPUf/JrkoXR4NlfzKxtGi4eTpC/LTr3MlU8a08mK3SBs7y6LhjZfbGMbLVm3XZJx7pVjRvNLuoZqGm3XRb3+eqYs2XpFX/tdCxk9dIUu0/vVrljG2Cqjn1BmrZYsyQt3Q7sr3FZW2D9YwrJA5G7Zss2zbcUhu6YLbsINImzaV9H2pjSxZuU0Wr9gq91cqJo1C7rMup5yPypQZqyRi/wmzmGqRQrmkaYNKUql8kO0YZOAuX71Dt1fUvxNvy8z562Sf9iPEbFy7asVgc+zGrfuV40Jj+fFCt2a289GfsG0ILpJbBr/xmG27P36gB2/8egUPhBH04I0fR56dOASYwZs43HlVDwjkVNEWL1eRThcHKVoo+j/YYMHguM06P7byrOPcfYfoDIuG2ALZxXgxSIAESCCQCXDKe2D0Hqesu9dPHM/ucUrsozieE7sH/PP6O3YfNh68V65dNxU8otmXm7cdMJYNEFnhy/vf7f9kjwq1Xwz7Wz7s97jky+N8YUxYFuDcYyr0Llq2Re0LUkiBfNlln4qqB1Uk3r7rsAzo1V4XHEypU/avmmMhA81fvFHOnr9sro9xChESAipEoiAVGrFv9oL1RvR94+WHjYiJg5eFb5fvR82We/S/oMJRx4WtV+HzgLz5SlvbcRAux01dbspHffQSMmb8ItM2CL64BuLKlcj6F8wfPbHl5s1bpq7wkLVi556jxoP3irbZWVxTD1qwgAevY/w8doEuSH3RXP/EqfOyZv0e2aSiaO8XW0vpEgXM4TuUFQTk0X8uNDyw8bb2w7ETZ+W9zycY64X0ardQUgVyeAEjM3bn7iPygfbPRWV7VLfd/u+2KQvXSJUqReRn9VtGvQrlv/N3ITj+MGqOEYPzqMifPn0a2bhlv3k92qa2EftxMq6Nc5GZC2G9cIGcSl5M/375w3R5941HtR9yS4UyheWTgU+a61k/rl+/aWtH8QTwH7auy3cSIAES8JQABV5PifF4EiABEiABEiAB88drQls4EHvsBDhlPXZGzo5IKAsHZ9fmNtcEOJ5ds+Ee1wSQ/TlYFxArpCLe5SvX5O0PfjdCMMTIh5pUdX2i7kH2KjxWn3+6qRGKT+n3976YIHv3H9fM0i3S2C5zdPP2g8aTta9mtUJova2Lgn08dLLO1Esp/VUMhsAMYfPnsfONh+vUmavkyUdCTJ1Ga5YoxOIBr+txOFePG6kZxPOXbDLZqJ0fDVEh9ZJM/ifSBu5FzSatWa2kqfuqf3fLVypKJkZcu35DPur/hOTJldVkOA4fM08WKhdktyKD2T6QMQuRtY762EJgnjnvXyPuliqeX95+ta2ZdXn9xk15672xsv/QSTl89LThC8bP9frRHAsbDsuD175sfEbfgiMyfZ95spGE1C5rDtmwZZ/Aw3f8tBVSvUpxU1fr3C3aZxDqiwXl1QWvb8igT/4yAj6YQuB1DBzz+bdTzTG5c2aRNs3vdzyE30mABEjAbwg4d1b3m+qxIiRAAiRAAiRAAv5OIGPGjPLUU0/JwoULZffu3TJgwAAJCgqSw4cPy7Bhw6Rps2bSuXNnmThxomB6NcO7BMAUbMEYrMEc7NEH6Av0CfoGfYS+YsRMgOM5Zj6+3svx7GvCSb/8WveXNOIuWgpbhIrlgkyjId66E80aVrIt3AaLhnYP1TCnLV4efe0MZOz26NrEZH1myphOwlUkxIJcDetXMOIuTkLG6OPt6pp3CMTIBoUNARYQe6BeeSPuWsd11OOwVsdCtSiAkLpCBdIbmoF7X7kiNnEXx8KiIKfWKzECVgYQdxF4MNapQ30j3sJmAv619oEFymCXgUxg9EM1rTcsHiCew1LPCrQZcS4qE9raHtv7auUNjsgctsRdnAMrjtr3l1Jf8duyZMW2aMWg/hB3ERCdK1coaj67GhtYcG2rZvzCyqL/6+3U/i+9OZ4/SIAESMAfCTCD1x97hXUiARIgARIggQAlwCnvCdNxnLKeMJw5nhOGM8dzwnBOLlfBVH37sMRQjLPYAqJfcJHoi2qWKVnQnHb85Llop2dQOwDLlgA7Dh05bfbDx/Xo939HOzaF+tXC+uD8hcu242AZMMTZcSoCQ+w8diLyemWjrm9fIHx9kTmb0IHr2ke6tKkjfYdVBAUfCKFWQNC1D/gbw3cXmdQHkLGrVgzwOYZIG5ewBOUyJSOtIezLKFuqoPHrtY6x9rkcG5pB7RiXtF4Q2SFkw784mxPLCsdz+J0ESIAEEpMABd7EpM9rkwAJkAAJkEASJcAp777pWE5Z9w3X2ErleI6NUNz2czzHjRvPipkA7te4BjJ2Icbah+Vf6+hZmyNb9Czay5q9i4DvreOxWCwMcVtF5ktqLYC4cePu44oHR2aXQoy2ykhj559rTtQfmTPdvfC0tc+X77ApcIw0uggaAj7A9uHIZ/2mCBmi1hLgA7EXXrodWtcy1g3w4vU0YJ+ASJP6jr+wVQZsMhBXo/yZre2ejI0j6seMZwLFi+Yxi7FZZfCdBEiABPyVAAVef+0Z1osESIAESIAEkggBa8o7LAL27Nkjo0aNktGjR0tERISxE4ClQLWqVaVNmzbStGlTyZAhQxJpuXeagSnrs2bNksmTJ8vqNWtshcKCAbYMXbp0EWSaMhKGAMdz/DhzPMePH8/2LYGTuqjXDfWFhT+uFRD6EI6CJewX7MPKDq1bo4y0albNfle0z3miRFJYGLSOwdPVyjzGwm+OsVV9hu3Dsjy4dClSPLb2XXYQXa3tcX2HEFvUwavWql+O7NEtgBz5/DZhsRF3X3qmufE5tuqARdbiEvlyR1pFYBE8x7CyqV0tqud4vLPvObKp/dTjDRLNDsNZnbiNBEiABGIiEP3xZExHch8JkAAJkAAJkAAJxJOANeUdQu/8+fONQJk+fXojXPbr31/qh4TIG2++KStXrjQLuMTzcgF7OrK3wAAswARsIO6CFURdsAPDd955h+JuIvYyx7N78Dme3ePEoxKfwDW1R5i/eFO0isya/6/57swKwP5Aa//S8G1GyLT27Y44Jl1e/EZe6z/K/H/N/jiIyVbArqDrS9/Kq/1GmkXXyqi3LGJp+HZj7WAdB/uGPfuOWV/Ne/askQ9GsTDbsRN3BGEsOObNmL1gvdy8dctWJLJyjxw7qx67qTUrN5dtu+MHLCKH4xD2lhOwbIgpexdZzq4CNgxI1g5fu8vYQ1jHwfIhbOlm89XRUsI6xp33K1dvGHHXygZ25xweQwIkQAKJSeDOo8nErAWvTQIkQAIkQAIkkKwIcMq78+7mlHXnXPx9K8ez8x7ieHbOhVv9lwAW/BozfrEcVD/dgvmyyyb1yV23ca9Z/Kx5o8oxVrxsqUJmgS+IqoM/G2cWRoMYu0wFWiz49VCTqsbPFZ6+FXXhtPWbcdx4waJwOA6Lr8G+AMch+7V8mcImW3bv/uPyzqfjpH6tsub6YboIW6TVwB3f2KxZMhj/W3jOfqk2CMgOPnP2kixZGX2RsRgb4MbO/QdPyvtfTJTqVYrL6bMXZX5U9m2TBhXNomWuikB7YMmwX7134TuMRdBgsbBgySZjVYHzlmn78+fNLlkypxe0B0LtyD8WGAYd29a9q+hCBXJKaJ3ypox3lWNonXKaeZ3CeO+ibuXVL9haRO2uk93YgMXups9Za0TeL99/yo0zeAgJkAAJJC4BCryJy59XJwESIAESIIFkTyC5T3nnlPWkdQtwPNNSJGmN6OTVmpw5MkmLRlXk94lLjACJ1kNsfP6pJir45ogVxivPtpDfxi02C6Dt0YxcBPxyuz4WKg/UK287/+X/tZCxE5aYTFMIuIhMGdNJFz2uYf0KtuP6vNRavhk+QzZvPyjjpi4322tUKSFYwGzG3HW24yD4PvNkI/l2xExdwOyU1n+pWkpklFf0Ou8PmWg7Lr4fuj/ZUP6YtFR+UxEckTJlCsOr7YM1Yy362S6NZehP/8iO3UfMC9m3EK3r1Soj46euMEJtneqljMDb7qEaMnzMPNmi7d6+87A4E3hxwac6hpp2Tpu9Rib9E27qgDo1DrnP5TmxVpQHkAAJkECAErhHp0zdefQXAI2o3LOwqeWoz4YFQG1ZRRIggeRMoEuvHqb5677cn5wxsO0kECcC+OdJWFiYjBw5UsaPHy+XL1825aRLl04aN24sD6tfb/Xq1aOymOJ0iUQ9Ce37P3tnAnZT9f3xFSpTsyJSUhRNRCLiVfnLUCRSlKGElOakkgzNZWgkpVBSkaFJpYQGJUKD6idFhiZRGpSk//pu777Oe51733vve4czfNfzvO695+yzz96fvZx99tprr71gwQKZpnF1Z82apZvTbDblQQiG9u3bS7du3SQvL8+39cspXA/enPpMffagWsYs0mFnjzDnnhp1ecw0QTuxUo2sA+54RhBHd9iQrrJFQycgtmuZ0rvrse2xXpOpM8IYrPtuo9mwrfwBe0mJ4sVdLy+QTu8N46Sb/KHerOs0/i02OYOH65QX58v0Vz6UVs2OL2DIhKfwTxpHGJ7AB6nHbCYE4RYQ4xb3qFxpv5hldrv3tm3bTKgGhKaoUH6fiNfv9xpn+O8t/xgvXxtPGNf/qRvSgUlhYRJQph/X/2rKhLi70RvluZUlqMfOv+R+U7UVz18V1CpmtF7bveMl1GHCMgqYmWeUAD14M4qXmZMACZAACZAACaRCIKhL3levXi3TZ8yQGfq3bt26CJrGjRsbo26HDh0EHqCUYBGgPgerPVmb4BOAQbHqIeVTrigMugcfVK7Q6xNNV6ZMSalW9cBC84Nhs0L+5mOFJk4xgQm3oIbdVATG20oa+iJaYpW5dKndo5O6/kaZYuXhegEPkgAJkEAACdDAG8BGZZVIgARIgARIIEgE/L7knSEYgqSNRa8L9bnoDJkDCZAACZAACZAACZBAQQIM0VCQB3+RAAmQQNoIMERD2lAyIxLYiYDXl7wzBMNOTcYDcQhQn+PA4amsEwhjiIZNv/0p7+pmaAjJYDczyzr4JG64/Ovv5KtvvjdexkccXjGJK5k06AQYoqFoLcwQDUXjx6tzS4AG3tzy591JgAQCTIAG3gA3LqvmKQK///67TJ482cTrnTdvXqRsFStWlDZt2khb/atcuXLkeCa/MARDJumGI2/qczja2cu1DKOB18vtwbKRQDIEaOBNhtbOaWng3ZkJj/iHgG8NvP5BzJKSAAmEnQA3WQu7BrD+2STw9ddfy/jx42XChAmycuXKyK3r1qkjbXVjtubNm0uZMmUix9PxhSEY0kGRebgRoD67UeGxTBOggTfThJk/CWSOAA28RWNLA2/R+PHq3BKggTe3/Au9+5L7Vps0ta7IjudRoQViAhIoAoGw6jMNvEVQGl5KAikSyPSSd4ZgSLFheFlKBKjPKWHjRSkSoIE3RXC8jAQ8QIAG3qI1Ag28RePHq3NLwHcG3tziyv7d+YDJPnPeMXMEqM+ZY8ucSYAEYhNI55J3hmCIzZlnskOA+pwdzmG+Cw28YW591t3vBGjgLVoLcrxaNH68OrcEaODNLf9C784HTKGImMBHBKjPPmosFpUEAkoglSXvDMEQUGUIQLWozwFoRA9WgQZeDzYKi0QCCRKggTdBUDGScbwaAwwP+4IADbwebyY+YDzeQCxeUgSoz0nhYmISIIEMEkhkyTtuP236dJk1a5Zs3rzZlKZ06dLSvn176datm+Tl5Yl9rmWwqMyaBAolQH0uFBETJEGABt4kYDEpCXiMAA28RWsQ+16HfpVCAn4jQAOvx1uMDxiPNxCLlxQB6nNSuJiYBEggSwRiLXl33r5x48bGqNuhQwcpW7as8xS/k4CnCFCfPdUcviwMDby+bDYWmgQMARp4i6YIHK8WjR+vzi2BYrm9Pe9OAiRAAiRAAiRAArklAINt9+7dZe7cubJixQoZOHBgpED4jmM4hzQ07kbQ8ItHCVCfPdowLBYJkAAJkAAJkAAJZJAAPXgzCDcdWXMGKR0UmYdXCFCfvdISLAcJkEBhBPi8KowQz/uJAPXZT62V+7LSgzf3bcASkECqBOjBmyq57dexvywaP16dWwL04M0tf96dBEiABEiABEiABEiABEiABEiABEiABEiABEiABFImQANvyuh4IQmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAnklkCJ3N6edycBEiABEiABEiABEiABEiABEvAaAbvU22vlYnlIgARIgARIgAR2JkAP3p2Z8AgJkAAJkAAJkAAJkAAJkAAJkIAHCXw99WrBH4UEvEyAeurl1mHZSCCYBLjJmsfblUG+Pd5ALF5SBKjPSeFiYhIggRwS4PMqh/B567QToD6nHSkzzCEB6nMO4fPWCROgniaMylMJ2W6eag4WJkkC9OBNEhiTkwAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkIBXCNDA65WWYDlIgARIgARIgARIgARIgARIgARIgARIgARIgARIIEkCNPAmCSxbyb/++mu55ZZbIrfDdxyjkIAfCVCf/dhqLDMJkAAJkAAJkAAJkAAJkAAJkAAJkIAfCDAGr4da6ffff5fJkyfLuHHjZN68ea4la9y4sXTr1k06dOggZcuWdU3DgyTgBQLUZy+0AstAAiSQKgHGYEuVHK/zIgHqsxdbhWVKlQD1OVVyvC6bBKin2aSdvnux3dLHkjllnwANvNlnXuCO//33n8yZM8cYdadMmSJ//vmnOV+qVClp1qyZnNW2rfk9bfp0mTVrlmzevNn8Ll26tLRv394Ye/Py8sQ+iApkzh8kkGUC1OcsA+ftSIAEMkbA9qt4rlFIwO8EqM9+b0GW30mA+uykwe9eJUA99WrLxC8X2y0+H571NgEaeHPUPliyPn78eJkwYYKsXLkyUoq6depIWzXqNm/eXMqUKRM5ji9//PGHvPbaazJdjb0LFy2KnKtSpYp06dJFunbtKlWrVo0c5xcSyBYB6nO2SPM+JEAC2SLAF/xskeZ9skGA+pwNyrxHtghQn7NFmvcpCgHqaVHo5e5atlvu2PPORSdAA2/RGSacQ6wl6xUrVpQ2bdpIW/2rXLlyQvmtXr1aps+YITP0b926dZFrGMIhgoJfMkyA+pxhwMyeBEggpwT4gp9T/Lx5mglQn9MMlNnllAD1Oaf4efMECVBPEwTlsWRsN481CIuTFAEaeJPClXziRJas16tXL+UQC8h/wYIFwhAOybcNr0ieAPU5eWa8ggRIwJ8E+ILvz3Zjqd0JUJ/dufCoPwlQn/3ZbmErNfXUny3OdvNnu7HU2wnQwJshTUhlyXpRi8IQDkUlyOtjEaA+xyLD4yRAAkElwBf8oLZsOOtFfQ5nuwe11tTnoLZssOpFPfVne7Ld/NluLPV2AjTwplET0rlkvajFYgiHohLk9dRn6gAJkECYCfAFP8ytH7y6U5+D16ZhrhH1Ocyt75+6U0/901bOkrLdVrBK9AAAQABJREFUnDT43W8EaOAtYotlesl6EYsnDOFQVILhup76HK72Zm1JgARiE+ALfmw2POM/AtRn/7UZSxybAPU5Nhue8Q4B6ql32iKZkrDdkqHFtF4jQANvii2SiyXrKRY1chlDOERQ8EsUAepzFBD+JAESCD0BvuCHXgUCBYD6HKjmDH1lqM+hVwFfAKCe+qKZdiok220nJDzgIwI08CbRWF5asp5EsV2TMoSDK5ZQHaQ+h6q5WVkSIIEkCfAFP0lgTO5pAtRnTzcPC5cgAeuQMGTIEHPFwIEDpWvXrlK1atUEc2AyEsg8Aepp5hln8g7sLzNJl3lnmgANvIUQ9vqS9UKKX+hphnAoFFGgElCfu0leXp7YjjtQjcvKkAAJpJWAfU7guUkhAb8ToD77vQXDW/5YDglOIo0bN5Zu3bpJhw4dpGzZss5T/E4CWSFAPc0K5qzchP1lVjDzJhkiQANvDLB25m3ChAmycuXKSKq6depI27ZtpXnz5lKmTJnI8SB8YQiHILSiex2oz4siYKpUqSJdunShx0eECL+QAAm4EeALvhsVHvMrAeqzX1sunOVOxCEBZKZNny6zZs2SzZs3G1ClS5eW9u3bG2MvJ/TDqTvZrDX1NJu0s3cv9pfZY807pZ8ADbwOprFm3ipWrCht2rSRtvpXuXJlxxXB/coQDv5vW+rzjjakPu9gwW8kQAKJEeALfmKcmMofBKjP/minsJcyFYcEOqiEXWuyX3/qafaZZ/OO7C+zSZv3SjeB0Bt4E5l5q1evXmiXdIPPggULOEOe7v95GcqP+hwfLPU5Ph+eJQES2EGAL/g7WPCb/wlQn/3fhkGtQTodEjihH1QtyX29qKe5b4NslYD9ZbZI8z6ZIBBaA28qM2+ZaAA/5ckZcu+2FvU5+bahPifPjFeQQJgI8AU/TK0d/LpSn4Pfxn6qYaYdEjih7ydt8G5ZqafebZtMloz9ZSbpMu9MEwiVgTedM2+Zbhiv588Z8ty3EPU5fW1AfU4fS+ZEAkEhwBf8oLQk6wEC1GfqgRcI5MIhgRP6Xmh5f5WBeuqv9kp3adlfppso88smgcAbeDM985bNxvLivThDnt1WoT5nljf1ObN8mTsJ+IkAX/D91Fosa2EEqM+FEeL5TBHwkkMCJ/Qz1cr+z5d66v82TFcN2F+miyTzyQWBwBp4czHzlosG9NI9OUOeudagPmeObaycqc+xyPA4CYSDAF/ww9HOYakl9TksLe2NenrdIYET+t7Qk1yXgnqa6xbw5v3ZX3qzXViqxAgEysDrpZm3xPAHNxVnyIvettTnojNMVw7U53SRZD4k4B8CfMH3T1uxpIUToD4Xzogpik7Ajw4JnNAverv7LQfqqd9aLLvlZX+ZXd68W3oJ+N7A6/WZt/Q2l/9y4wx5cm1GfU6OV7ZTU5+zTZz3I4HcEeALfu7Y887pJ0B9Tj9T5ridQJAcEjihH1ytpp4Gt23TXTP2l+kmyvyyScC3Bl4/zrxls2G9eC/OkMduFepzbDZePUN99mrLsFwkkB4CfMFPD0fm4g0C1GdvtENQShF0hwRO6AdDU6mn3SQvLy+yyWYwWjXztWB/mXnGvEPmCPjKwBukmbfMNak/cuYMuQj12R+6mkgpqc+JUGIaEvAXAb7g+6u9WNr4BKjP8fnwbGIEwuiQwAn9xHTDS6mop4sizVGlShXp0qWLdO3aVapWrRo5zi+xCbC/jM2GZ7xPwPMG3qDPvHlfRTJbwrDNkFOfM6tPuc49bPqca968PwlkkgBf8DNJl3lnmwD1OdvEg3M/OiTsaEtO6O9g4bVv1NMdLUI93cEilW/sL1Ohxmu8QsCzBl6vz7z17dtXln/1lbw6c2aBtrzr7rtl/Pjxco9+tmrVKnLur7/+knonnii9evaUSy+9NHI8mS+jH3lEpkyeLG+88UYylyWUtv8NN8hPP/0kYx97LKH0mUgU5Blyr+tzvPbsojO+CxcudE1St25dmaD6XpisXbdOmjVrJk9OmCB16tSR22+/XZYsXSrPPftsYZfGPT9mzBh5RvOY/eabcdPl4mSQ9TkXPHlPEsg2Ab7gZ5s475dJAtTnTNINXt50SIjfppzQj88nW2epp/FJU0/j84l1lv1lLDI87gcCJbxUSD/NvMGw9ebs2bJx40bZZ599IhgXfPCBFCtWTD5YsKCAgfeTTz+VrVu3yon160fS8ktBAmXKlJF27dqZP+fM48qVK2XIkCHmr3HjxtKtWzfp0KGDlC1btmAGHvvlJ30uDN1hhx0m1/frt1Oyvfbaa6djbgdKlSxpDLzO/ytu6YJ0LGj6HKS2YV1IgARIgARIgAR2JuBnh4Sda5O5IzAAnaiOO/i7ecAAee2112T69OmycNEimaDODPjj0vjM8aeeJsaWepoYJ6YigSARyLkHr19n3pYtWybt1cj40IMPStOmTY1O/PLLL9KwUSNp06aNLP7oI5np8O6Fp+Go0aPlg/ffl9122y0lHQq6B68bFL/NPPpVn93Y22Pw4P33339l4lNP2UNF/gyDB68bJL/ps1sdeIwEwkKAHhxhaelw1JP6HI52TqWWQXJISKX+6bzG6aCyTlevWfGTg4ots9c+qafpaxHqaXyW7C/j8+FZbxPImYHX7zNvMHjVb9BAOnXqJFddeaVpZYROGKyepqNHjZIO55wjb6mHb/ny5c253pdcIv9s2SJjx441vydNmiRTp02Tb775xgQ8h+fquR07RrSlW/fu0vPii+XXTZvk6YkTjdF4/c8/FwjRAGPR7XfcIV9pqIg7dMl7hQoVjJfwg2p0fu31180mXvXVY/iKyy+Xgw46KJL3R2p8fkDTfPLJJ7L33nuboOufffZZzkM0RAoY44uXl7z7XZ9jIDeHEzHwbtu2TcY8+qhMU53+/vvvjXc1QjLcqKE/MKGB8B99NDTJkMGDpUaNGq4hGiaqnk95/nlzfZ3jj5eeGs7k2GOPjRRt1apVghAoixcvlhIlSkjbtm2ldKlSMnnKFE+GaIgUPMYXL+tzjCLzMAmEigBf8EPV3IGvLPU58E2cVAWD6JCQFIAMJ+aEfnoAU0/TwzFWLtRTdzLsL9258Kg/CGTVwBu0mbfevXvLZo2tO37cONPat6mRFSEb7r7rLjmpYUO56cYb5YwzzhA8PBucdJJ0V6MtYvAOGz7cGHrPO+88gSEL8U0RR7R3r15yuRpjIYjXe/bZZ8tkjbmLcBA9evQw6WwMXuQ5SI1lr7zyijyq3sG1atUy1/XV62G4hXG4lBq/Jj79tPz222/yjBqUsTx+qcY9hcEO6duqp/FG9TpGzOAtanyuWbNmTmPwmgok+I8XZh6Dps+x0Cdi4IV3OSYWumv4jKOPPlpg8H5YJzowuQDdLSwG74iRIwUGXvz/OPDAA+XFF180MXoxuYHwED/88IO0PessOeCAAwT/b/5TgzImSX5av97ouRdj8Mbi6XbcC/rsVi4eI4EwE+ALfphbP3h1pz4Hr01TqVGQHRJS4ZGNazihnzxl6mnyzIp6BfV0B0H2lztY8Jv/CGTcwBvkmbfHdEMyhF1A3N3ixYvLmWow7XLBBdK+fXvBJmzwjh06dKjZjA1hG2CsgoGqRcuWcrEaYC9zbLY2Ug1cT6ih+HWN4QSvXxh4//77bxPD6bh8L0ZniAYYk2fMmCGPqdek9XJ8X8M/XKwGsunqRQmjGOTPP/+UVq1bS+fOnaXHRRdJLzUif/fddzJFvR5tqAh4EZ9x5pkmjlQuN1lL5b9Ptmceg6zPsfjDwLtkyRKjz9Fp4KUO3T9Hvc8POeQQs7mgTXOR6hti9A7XCY14Bt61a9dKS92QcOSIEZFwJ+Dc+fzz5dBDD5Xbbr1V7tRJk6lTp5r/H/h/Bdmk3u2nt2ghJTW+r98NvJZZtvXZ3pefJEACOxPgC/7OTHjEvwSoz/5tu6KWPCwOCUXllI3rOaEfmzL1NDabbJ8Ju56yv8y2xvF+6SSQsU3WwjDzdsIJJ8hwNUp9+b//SXk13CJUAkIiQBB0/8n8mKWIx1u6dGnj2fiyetz+888/0km9EJ2CUA9Y4r5Ig/O3VAMw5NRTThFr3LVp/9Mv99xzj/F2HDxoUMS4i/PvzZ8vlSpVkr/UqxghF6zAoxLhI2DgXfDhh8bIa427SAMjGuriR8EDOBubHIRBn+O1/wH77y/naNiRaLEd4HPqgW7lZw0lgjAKyz7/XOrWqWMPx/z8UHUSUq5cuQJ6i4kLhHyAgXeBblrYNC+vgJF5zz33lNNPP13mzJljrg/CP9nS5yCwYh1IgARIgARIgATcCYTRIcGdhLeOVq5cWfpedplx8sG77TTdmG3WrFkyb94883eZnoOjEDaUztP3Xvue7a1apK801NP0sUxnTtTTdNJkXiSQXQIZM/Bmtxq5uRtCGsB7cIkas/bZd1+pWLFiJNbtiWroRXxceMt+pOcRigFxQxFwH8befTW9U+DZu+uuu5rz9ni1atXs18gn8kPsXnjojtPQCvAMtsZazLZ9++23Jv5v5IL8L1j2jk3g4BWMckZLJT32ncZOpZCAG4HyGt8ZMXFjyZo1a+Shhx+Wd99914QpOfzwwwUG2ETkW9VbTHp0PPdc1+SYsEBc3yaNG+90HhMaFBIgARIgARIgARIgATEhshB6bcKECbJy5coIEky4Y++C5s2bS5kyZSLH+SU3BMI+oR92x5ncaF3ydw27niZPjFeQQO4JZMzAW7VqVRmsMWIHqZcpPOzGafgBhAVYqB6q+EOIAWzCdJa+bNSrV8+XM5QwyNY67jgTK7SMGm3rq9eulWpq4IIRFx6z8Ga03o+Ig4uwCTBawThsBXFvYOTaW89bcTOQ4ZpxTzxhNlODQQxevzbUw3777Sc1jjxSxmhM3mjBA3qPPfYwRuZNv/4afVo2aZxeP0q2lrSHQZ9TbX/oLTYFRGiRhzQO75Gqg/i/cfkVV5j404XlW071FpMer736qmvS3Xff3fxfwoaD0YIwDUGSbOlzkJixLiRAAiRAAiQQZgJc2u7v1ofBHZtt48+5NB4G+iG6eTf+GquTA7x6O3ToYDYy9mONqad+bLUdZQ6Lnu6oMb+RgD8JZMzAa3HAsNi0aVPz99BDD5lNw2DsxVKUF154wfzBoxSeqNj0C0sC/CQIbYDlNYhDemmfPgWKfqIarl95+WXTWeM7pEaNGuZz7ty5Zhbd/NB/7DLzmvnn7fHoz33VAHzEEUeYwwjz8KgaeFvoMnV49OLa6VoWeAoj9qmVe++9Vw5Q4xviA1evXl3m6L3P1/imVjZv3iwfaBxhhHLwizhfgOAVbSXTL0BB12fLMZlPxHBGGwzRCZ1jjjkmcim8ehPxsIUnPCY9ENoB+mnlKQ1xsk491vtdd53ZAPDtt9+Wf//91/xfs2nw/ygIkit9DgI71oEESIAESIAEwkbAD0vb4cyC9zZ6DCeunUFbGu8HPU28dZjSEgiantp68ZMEgkCgWDYrUbZsWemunn4wyqxYsUIGDhwoVapUMcahUaNGSXM1VHbp0sVspgSPVj9I3bp1BYasVatWmViwzjIjNuzb77xjZlqtYRcxdRs0aGA8mGGw+k09Z+eqsfuOO++Ukxs1MoYsZx7xvl+hHpLwCL5FvaTRgbbWzdTg9Xv11Vebjd1gMHtGY6NOePJJaXzyySYrbHz13nvvyf333y8//fSTWb51rRrQMKvqdYFOYKMt6Ah0BToDwyJ0CLoEnYJuQcega5mWIOpzKsysp/k81We0ETZUu1099L/44gv5VcOCbNmyJW62tWrVMiFMoIdLly6VX9XDHDGjh+nmbDamdXf1WkBb3zRggPn/hlAlt952myxfvjxu3l4+6TV99jIrlo0ESIAESIAESGB7CIZbbrlFsLLsFN2rA6EYMEmOEAy36sbO8/Q9+E4NEYcxCJwSciEYk1xx5ZVSX8c7l0Q5v+SiPEW5J0LuTdRNsrMtaDu0IdoSbYq2RRujrdHmaHvoAHQB4Q68JiiT1/U0HcxefPFFqXnUUZGs2p51lsCxKlHZsGGDuR4h7hIVrF58/fXXPTF297ueJsqc6UjATwR20U4Y+3blTHB7eK/CqxchHNBxQUqVKuWLEA6IaVtPO+CDDz5YXlSPZKesVKMvNkxDkPyH1XvZCoy6Q3XjqNdee82EZUAM3dM1JtYANV5ZwyTyvOLyy6Vz5872Mhn9yCMyZfJkY/yyBxGYHy9Rg7SDRxgIGJpvvOkmWbJkiTH6wrB8bseOZkmPveZZNfqOvO8+Y0grVqyYtG7VSrbqDPvGjRtl7GOP2WSe+IR+ODchgLcxBEv6vbgJgd/12a3Ru3TtajwwJuZvGuiW5gENzfCY6g7CNSA8A9rmMH3xhBG2R48e0lF1ECFZntSX0jr6ggoD8BI15trN2aB7MNJjsmPr1q1yyCGHSCvVSxt+BPfEOSxTg3EXghffo/WlChsXzn7zTXPM6//4TZ+9zpPlI4FMErDGEfy/pZCA3wlQn/3bgn5b2o73doTuQkg57MkQve+In1oCBt7L+/YtMB7LZfm9vOLLb3qajnaEgff6/v1lWf7m5nfrRuhYadvmzDMTyh7M4LxySe/eJsRdIhd9rptYn63jrBkzZghCQnpRvKynifBif5kIJabxKoGcG3idYMLWMcCQ9cMPP5jYpQirkE6BoRx/5cqVi5ktDGXwAHbGAo6ZOMsn/N4xAFfY9BkeqfAaR8gVq8/wEoeO2d+FqRG8fWHsRTzfWII8MQFkJ0NipfPS8SDos5d4siwkkA0CfMHPBmXeI1sEqM/ZIp2e+/jZYWDSpEkyfMQI+VANvX4Xrxl4LU+vOAz4WU8ty6J8Rht4i5JXotf6wcBr6+IVPbXlSfST/WWipJjOiwQ8ZeB1AuLumk4a4fgOAyG8mhFHGBvxWUEIBoRl6KqepFiO5EehPvux1YpW5iDrc9HI8GoS8AcBvuD7o51YysQIUJ8T45TrVH5/X+x3/fWySN/hv//+exN27kz1ZLxA9/2AUwv2Ynlz9myzEgubQl944YVmlSOYw0Gg9yWXyPBhw8xKxZd0D5OWLVrIqzouwCrI/fff3zTNc889J5N1xSfS2X1bsFz9SQ1H94R6DMOh4AX1qsR3bFKG39jMGysdkQecX7pq2K/bdCXloo8+kmnTpslll11mQtk9qSvVpuvvFRpe4Ej1wuzXr58JMeElD143/czF+6bf9TSaIxiOGDnS6B7CJkBXsKFd7169IknXr19vQip+qBuoY8Vic119Cz0erKsLrQcvws0dpxuwQ+chWHk6Qic7ELIRDizYL+fSSy81qxlxHmHpelx8sQzQ1be4Dqt1URbs8YNQhAhFh312cB77nGAj9RdfesmEJTxcj1dXPb1XvYb9ILnQ01S5sL9MlRyv8wIBzxp4LZywzwxaDkH99OvMXqrtQX1OlZw/rgubPvujVVhKEkiNAF/wU+PGq7xJgPrszXZBqYK04gsG2NlvvSXz58+XXj17CvZZOOmkk6SPGrWwBwj2AjlUHTdeU6Psmxpe6y7dg+SMM84wBuFTTj3VhPVCKDmE4cKeGghVd8/dd5uwXWDVW5eyY88HxKRt164dDsn1alSGoWz06NEmnNclaig+U/NspHub/KZL4LHvSAMNtTBc93YAa4TBQ/iwp59+2hy/XPc0eV0NyQ89/LCce+65Zl+ITz791Bh/sVEcNvt1hswzN/XoP5lcMRYkPY1uPuxfM//9982G5AgrAl19VnUZOoV9bDAxcKZuBq/xDwWh6xAqEPvCYKNp6J418CIGb6OGDeXaa6+Vbdu2yXmdOpk0PdWIiw3PMYEAJybke5LGqIYxuZHm/6gabhvqdTdruDpMkPyn10LnEEoRe+lghSN0FLF6EdoSZTtPN1uvXq2aCYMXXR+v/86knqaj7uwv00GReeSKgOcNvE4wQe5YnPUMw3evP9iz0QbU52xQzs49qM/Z4cy7kEA2CfAFP5u0ea9ME6A+Z5pwcvkHecI/OkTD+2o4u1ANu8PU67aFbpJspa/Gtv1s2TJ5deZMY+iCgReekzC8VtJwX5AOur/IkeolOVS9JMGsgRqL8btSpUrGCxdp8po2NYZf7DmCjacXq2cuVgPCOAbBfWfp5r24jzXw7rXXXjJJ74NVgjDQnXraacZj83r12rWC/WEQU/WmG2/0jYHXlj1dDgdB1lPLCsbThjoZACPsxfpnBYbX89UTF1682NgOuvCyes9inxAIrmt39tlmkzs3A68N32D3H8E1MPp21jyxh8/U5593NfDCq/wFja9rV61i42lMQmCvH3jz+ilEA+ocT9Klp/Hukco59pepUOM1XiGQ3sCvGa4VYm5iNhd/0UtDsIwBf9hhtG3btmbZRJkyZTJcImafDAE/Lc1Ipl6ppqU+p0rOG9dRn73RDiwFCZAACZAACfiFQPT4xZY7yOOX99SbF/sxYENpp8C7EZ608IKEwRUCI6017uL3KWq8nabGWsiKFSvMpr/nq2fjvWq0hSAMw48//ih5TZqY34PVwGsFxtxlakCGxy+W1DulnXpawrgL+Uw3yIKH5lk6fnQKlujDqOdHgYEKXtD4u1k38XKGwIOxEn+of6wQeGHSU2x27owXvW7dOuPBi5AKVm8+0HjSx9euHTHuQidwXVv16kW8aTd5V72Aq1evHgnHgDSYdICO36CTBsjfTaoeemjEuIvzNWrWNMl++eUXt+S+PlZUPfV15Vl4EsgQAV8ZeJ0MMKs1ePBgGaQdOZYqYJZ1isZkwrIH/N12++3SrFkz01kj9pKdiXHmwe+ZJ+DVmbnM1zy5O1Cfk+OVq9TU51yR531JgARIgARIgAT8SAAGM3jcRo/FKh90kKkOzlsDbzVdcu6UvLw8eeDBB2Wtplm8eLHUViNb3bp15dtvvxVsuvvBBx8Yj94KFSqYyzZt2iSPaBzTNzT8w5o1a8x999hjD2eW5rvzPogXDMEmwU6Bo9Dee+/tPMTvASXw8ccfm/i2C/Lj6x511FHi1BvoSDUN3RAtFVWvYwn0+iCX8wc59P7AAw/c6fK9dTLEKbvk//jPeZDfSYAESCAGAd8aeG198LLQVGd38Yfg/ZMnTzbG3nnz5skLupQBf+iw2+gMG2bZbEB+ez0/M0OAS9ZT40p9To1bpq+iPmeaMPMnARIgARIggeATCOOEPrx3ly5dulPjbsj3YMR5K3vuuaf9aj5r6KZUMN5+oGEePlIDbx1dqQmjK+KkfqShGGDghRHYCjwjv/ziC+MEhLQlS5Y0G1dN0fGhU5z32Xfffc2pX9U4jNV1VrCcHqu1/ChFdUgIk57CEIsQItCjZyZNMp7N8LQ9XTf5s5MS0BHoR7T85nLMpoFeY2O2aLGeu9GG3Oh0YfhdVD0NAyPWkQSSJeB7A6+zwlzy7qSR/e9csp5e5tTn9PJMNjfqc7LEmJ4ESIAESIAESCARAmGa0K+hMXMnTpwoy5cvF6fn7FxdgYll7jAmIkRCLIHhDYZceFmerTFPIfDixYpNeFwidB/k33//lXfeeUf6XnaZ2bDKHNR/1qxebb+6fh5xxBFm6TzK00nDRljBRlt2ib495vXPdDskhEFPsakZ9K+/btZXrlw508TYXM9pnK2pYRIQGxpjA2cIyDlz58ZUCUxOwJscnuaILW0FK48xSXGgTlwEMeyCrWe8z3Trabx78RwJhI1AsaBW2M48IobQ7NmzTYwh7HiJl4EBN98sjTVWU/8bbjAvDJg9oqRGAOzw0gWWYAq2YAzWiOsE9mgDhNNAm1BSI0B9To1bsldRn5MlxvQkQAIkQAIkQAJFIWAn9OeqsQhxZgcOHGi8COFZiP1FmuvGZHinnjp1qi89Slu3bm1CJVxz7bXyySefmE3NUJcnNLweDKpOb1o3jk3VwDtXV2Z+p8vkjz3mGJMEBt6XdMMreFoeffTR5ljx4sWNBy6Mvhs2bJCff/7ZGJZfePFF+UMNeLG8cbFMvmXLljLyvvsEG1ph07UPFy40G7a5lcdrx1Av8ISOQFegM9CdKhpjF7oEnYJuwRDu9FBOth5B1dM98+M/Y8y6efNmw+vqa64xRl/o0datWwVxn/F55VVXmXEtjL+jRo+WtzW+cyzpdN55svvuu5trMLkBY+748eNlum6ghg3d7CaAsa6PdbxUqVLmFLzav/rqq1jJPHc8W3rquYqzQCSQZQK7qEEjNNZNBNt3hnCwrBnCwZJI/JMzb4mzylRK6nP6yFKf08eSOZFAUAjYpZkhek0KStOxHi4EqM8uUDx8CM8d5x4j1sMVxh2v7zEySZe5Y+Op6I2rblYnEGxWhdAHcASBcffyvn2lRIkSghinp5x6qox74gnB3ilO2bJli5zUsKGJtfvUk0+aU2ZjNQ3PB4/eoUOGRJK//PLLMlh/4x0ZBrRGjRrJeWpo69OnjzRo0EBGarnq6cZjDz7wgJxyyimR62DYGzJ0qMycOVNwP3C+UcM93H333aaMndXA5yWBfixQltiAbtasWcYwifKBa/v27aVbt24Cz2f7/z5TZfeznlom8Py+vn9/eeWVV8whMLxU9WXdd9+ZCYJ7VAdatWolS9WDHDqBTQEh8ExvoWEcoOvLdKM+SFvdvK+R6uq1OpkBgQF2gG5y98mnnwpYYTKjZ8+e0l3bB20DA3Kjk0+WR8eMMV7nN6tBftWqVTJBDcFWYKw/TfcVwsZ42IwR5e3Vu7d8qBMZh+qGbNOnTbNJPffpFT1NFoz9f4PyU0jAbwRCZeB1Nk6Ydgd11rso3zHz5tyF1eaFGeJYu7DaNPzMLAHqc/J8qc/JM+MVJBAmAnzBD1NrB7+u1Gf/tnGQJvT//vtvWa+etRXVa9bqZLpbBgZaGIwPOOAAE4MX+SPuKYy2iMkbTxCS4UddUo/l86l6WMbLv6jnvOyQ4Hc9hYctxgZw/LK6CT0qX7585DfaD7qE824b8LVp21ZO1kkFa+C17Y18sQGg26ZqNk2QPr2sp4lwtu1PA28itJjGawRCa+C1DYH/uH6dIbd1yOSnX2feMsnEy3lTn+O3DvU5Ph+eJQES2EGAL/g7WPCb/wlQn/3fhqgBJ/SD0Y7J1MKPDglh01N4pcMYDA/efv36Sfv8WNHJtLPf0/pRT2MxZ38ZiwyP+4FA6A28zkby+8yjsy5F/e73mbei1j8I11Ofd7Qi9XkHC34jARJIjABf8BPjxFT+IEB99kc7JVpKTugnSsqf6YLikBAWPV2zZo38X/PmZhPB8Rpb2s2715+aGL/UQdHT6Fqyv4wmwt9+IkADb4zWCtvMIzAEaeYtRrOG9jD1eVGk7RlSJIKCX0iABOIQ4At+HDg85TsC1GffNVnCBeaEfsKoPJ8wyA4JQdZTxMXFpn4ICxIGCbKeov3YX4ZBi4NbRxp4C2nboM88BnXmrZBmDe1p6nN2Np0IrYKx4iQQIAJ8wQ9QY7IqHLCGRAfCOKHv96YNo4MN9dR/WhsmPeX7n//0kyXeQYAG3h0sCv0WpJnHoM+8FdqYTGB2GJ48ebKM06VE8+bNixDB5gJt2rSRtvpXuXLlyHEvf6E+e7l1WDYS8CcBvuD7s91YancC1Gd3LkE9GvQJfb+3Gx1strcg9dTbmhxWPWV/6W29ZOniE6CBNz6fmGf9OPMYppm3mA3HE64EqM+uWHiQBEggxAT4gh/ixg9g1anPAWzUBKsUJAeVBKvs2WR0SIjdNNTT2GyyfSbsesr+Mtsax/ulkwANvEWk6fWZx7DOvBWxWUN7OfU5tE3PipMACUQR4At+FBD+9DUB6rOvmy9thffjhH7aKp+jjOhgkzx46mnyzIp6BfV0B0H2lztY8Jv/CNDAm8Y289LMY9hn3tLYrKHNivoc2qZnxUmABJQAX/CpBkEiQH0OUmsWvS5en9Aveg1zmwMdbNLDn3qaHo6xcqGeupNhf+nOhUf9QYAG3gy1Uy5mHjnzlqHGZLZCfaYSkAAJhI0AX/DD1uLBri/1OdjtW5TaeWlCvyj18MK1dLDJXCtQT9PHlnoanyX7y/h8eNbbBGjgzXD7ZHrmkTNvGW5AZl+AAPW5AA7+IAESCDABvuAHuHFDWDXqcwgbPYUq52JCP4VieuoSOthkvzmop8kzp54mzoz9ZeKsmNJ7BGjgzWKbpHPmkTNvWWw43sqVAPXZFQsPkgAJBIQAX/AD0pCshiFAfaYiJEMg0xP6yZTFi2npYOONVqGexm8H6ml8PrHOsr+MRYbH/UCABt4ctVIqM4+cectRY/G2hRKgPheKiAlIgAR8RoAv+D5rMBY3LgHqc1w8PBmHQDon9OPcxhen6GDj3Wainu5oG+rpDhapfGN/mQo1XuMVAjTw5rglEpl5RBGnTZ8us2bNks2bN5sSly5dWtq3by/dunWTvLy8yGYwOa4Obx9yAtTnkCsAq08CASLAF/wANSarEnlPRD9NIYFUCaQyoZ/qvbxyHR1svNISiZeDerooAqtKlSrSpUsX6dq1q1StWjVynF9iE+D7X2w2PON9AjTweqiNYs08OovYuHFjY9Tt0KGDlC1b1nmK30nAUwSoz55qDhaGBEggSQJ8wU8SGJN7mgD12dPN47vCJTKhX69evcjEgt8qiPotWLCADjZ+a7io8lJP6QgWpRIJ/WR/mRAmJvIoARp4PdowduZxyJAhpoQDBw7kzJtH24rFKpwA9blwRkxBAiTgLQJ8wfdWe7A0RSNAfS4aP14dm0CsCf2KFStKmzZtpK3+Va5cOXYGHjrDpe0eaow0F4V6mmagAc6O/WWAGzcEVaOB1+ONzAeMxxuIxUuKAPU5KVxMTAIkkEMCfF7lED5vnXYC1Oe0I2WGLgTshP6ECRNk5cqVkRR169SRtm3bSvPmzaVMmTKR4174whAMXmiF7JaBeppd3n67G/tLv7UYy+skQAOvk4YHv/MB48FGYZFSJkB9ThkdLyQBEsgyAT6vsgyct8soAepzRvEy8ygCXl8azxAMUQ0W0p/U05A2fCHVZn9ZCCCe9jQBGng93TwSiV2FDohCAn4nwA7T7y3I8pNAeAjweRWetg5DTanPYWhlb9bRS0vjGYLBmzrihVJRT73QCt4oA/tLb7QDS5EaARp4U+OWtav4gMkaat4oCwSoz1mAzFuQAAmkhQCfV2nByEw8QoD67JGGCHkxcrE0niEYQq50KVSfepoCtABdwv4yQI0ZwqrQwOvxRucDxuMNxOIlRYD6nBQuJiYBEsghAT6vcgift047Aepz2pEywyIQyPTSeIZgKELj8NIIAeppBEWovrC/DFVzB66yNPB6vEn5gPF4A7F4SRGgPieFi4lJgARySIDPqxzC563TToD6nHakzDBNBNK5NJ4hGNLUKMxmJwLU052QBPYA+8vANm0oKkYDr8ebmQ8YjzcQi5cUAepzUriYmARIIIcE+LzKIXzeOu0EqM9pR8oMM0AglaXxDMGQgYZglnEJUE/j4vH9SfaXvm/CUFeABl6PNz8fMB5vIBYvKQLU56RwMTEJkEAOCfB5lUP4vHXaCVCf046UGWaQQCJL43H7adOny6xZs2Tz5s2mNKVLl5b27dtLt27dJC8vL7JZdQaLyqxDTIB6GszGZ38ZzHYNS61o4PV4S/MB4/EGYvGSIkB9TgoXE5MACeSQAJ9XOYTPW6edAPU57UiZYZYIxFoa77x948aNjVG3Q4cOUrZsWecpfieBrBCgnmYFc1Zuwv4yK5h5kwwRoIE3Q2DTlS0fMOkiyXy8QID67IVWYBlIgAQSIcDnVSKUmMYvBKjPfmkpljMeAbs0fsiQISbZwIEDpWvXrlK1atV4l/EcCWSVAPU0q7jTfjP2l2lHygyzSIAG3izCTuVWfMCkQo3XeJUA9dmrLcNykQAJRBPg8yqaCH/7mQD12c+tx7JHE6A+RxPhby8SoJ56sVUKLxPbrXBGTOFdAsW8WzSWjARIgARIgARIgARIgARIgARIgARIgARIgARIgARIIB4BGnjj0eE5EiABEiABEiABEiABEiABEiABEiABEiABEiABEvAwARp4Pdw4LBoJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJxCNQIt5Jnss+gbFjx8qCBQt2unGvXr0ix+rVqycXXXRR5De/kAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJhJMAN1nzWLvPmTNHmjZtGrdUb731luTl5cVNw5Mk4EUCDFrvxVZhmUiABNwI8HnlRoXH/EqA+uzXlmO53QhQn92o8JjXCFBPvdYiiZWH7ZYYJ6byJgGGaPBYu8Bw26RJk5ilwjkad2Pi4QkSIAESIAESIAESIAESIAESIAESIAESIAESCBUBGng92NyDBg2KWap452JexBMkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAKBJEADrwebNZYXL713PdhYLBIJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJ5JAADbw5hB/v1m6eum7H4uXBcyRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAsEmQAOvR9s32ouX3rsebSgWiwRIgARIgARIgARIgARIgARIgARIgARIgARySIAG3hzCL+zWTo9d5/fCruN5EiABEiABEiABEiABEiABEiABEiABEiABEiCBcBDY5T+VcFTVn7WEJy9kzpw55pP/kICfCeyyyy6m+Hzs+LkVWXYSCAcBPq/C0c5hqSX1OSwtHY56Up/D0c5+ryX11J8tyHbzZ7ux1NsJ+M7AW/vKg9l2ISCweOS3Iahl+KrIDjN8bc4ak4BfCfB55deWY7ndCFCf3ajwmF8JUJ/92nLhKjf11J/tzXbzZ7ux1NsJlCAIEiABEiABEiABEiABEiCB4BAYO3asLFiwYKcK9erVK3KsXr16ctFFF0V+8wsJkAAJkEDqBPjcTZ1dLq9ku+WSPu+dbgK+9eClh2e6VcEb+VkPbbavN9oj3aXgjGi6iTI/EiCBTBHg8ypTZJlvNgggtFfTpk3j3uqtt94SGwosbkKeJAGPEeDz2WMNwuIYAnzu+lMR2G7+bDeW2p0AN1lz58KjJEACJEACJEACJEACJOBLAjDcNmnSJGbZcY7G3Zh4eIIESIAEkibA527SyDxxAdvNE83AQqSJAA28aQLJbEiABEiABEiABEiABEjAKwQGDRoUsyjxzsW8iCdIgARIgATiEoj3bI13Lm6mPJlxAvHaJt65jBeMNyCBJAnQwJskMCYnARIgARIgARIgARIgAa8TiOWVRO9dr7ccy0cCJOBXAnzu+rPl2G7+bDeWemcCNPDuzIRHSIAESIAESIAESIAESMD3BNw8j9yO+b6irAAJkAAJeISA2zPW7ZhHisti5BNwayO3YwRGAl4mQAOvl1uHZSMBEiABEiABEiABEiCBFAlEeyXRezdFkLyMBEiABBIkwOdugqA8lozt5rEGYXFSIkADb0rYeBEJkAAJkAAJkAAJkAAJeJ+A0wPJ+d37JWcJSYAESMCfBJzPWud3f9YmPKV2tpXze3gIsKZ+J1DC7xVg+UmABEiABEiABEiABEiABNwJOL2S8J1CAiRAAiSQWQJ87maWb6ZyZ7tliizzzRYBGnizRZr3IQESIAESIAESIAESKEBgl112KfCbPzJLgLwzy9fm/t9//9mv/CQBEvAJgUw9HzOVr0+w+raYbDffNl1aC+63/pwhGtLa/MyMBEiABEiABEiABEiABEiABEiABEiABEiABEiABLJHgB682WPNO5EACZAACZAACZAACbgQWPbZZy5HeYgE/EWg5lFH+avALC0JkMBOBNgf7YSEB0ggdAT82p/Tgzd0qsoKkwAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJBIUADbxBaUnWgwRIgARIgARIgARIgARIgARIgARIgARIgARIIHQEaOANXZOzwiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAkEhwBi8SbTkzROvkpc+fH6nK4rtUkzK732g1Kx8rPQ8/UqpXrHGTmkKO7DyhxXy82/rpfL+h8gBe1UoLDnPkwAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkIDQgzcFJdir9N5y5EFHR/6qVqgmG//YIG9+PFO6jDhTvly7LOlcH3/jIenxYAeZ/fGrSV/LC0iABEiABEiABEiABEiABEiABEiABEiABEiABMJJgB68KbR7k6ObyeBOwwpcufnvP+WiBzrI52s+kWffHicDz727wHn+IAESIAESIAESIAESIAESIAESIAESIAESIAESIIF0E6CBN01ES+1eWmofVs8YeDf8/nOBXBcuny/jZ4+WT1Ytlv32PEDqV28kl7S8RsqW3EPW/vytDH22v6z4/n/mmmfUODznk9elb+vrZdcSu8nw6UOlcrkqctM5t0fyXL/pRxnw1JVSpmRZGXbhGHP82sd7ye9//SYjeoyVYdOHyGsfvSAdG3WVZrVayYgXbpPjDq0j/1f7DHnwpbtl4Yr3BV7IbeqdIxc2u1SKFyseyZtfSIAESIAESIAESIAESIAESIAESIAESIAESIAE/EOABt40ttX7X75tcjusQvVIrojZO2jStbKLxumtoWEdfvr1B3l63uOy8Kv5MqrP0/LP1n9k1Y9fG+MsLtrw28/y95a/5C/927xls3zwv3fk1z9/ieSHL1v++dsch5HWyiI12v7yx0a5ffKNkTjB//73r2za/KtJi3NT50+SPfWaPfINyw/PvFd2362kdGna02bDTxIgARIgARIgARIgARIgARIgARIgARIgARIgAR8RoIE3hcb64ZfvZO6nsyJXwniK2Llfqxdu2VJ7SseTu5pzm9Qwe/fUQVJy11LyxBVTpVrFI2Xbtm1y63P9Zdr7z8jjsx6Sa88aKDMHvS8DJ14tL344RfqoZ++5J3cz1y/86v3IPRL98vril+TatgOlWe3WUnr3MvL56k/MpV+u/UyuOOMG6XbqJaYMdz1/szz37pPy+uIXaeBNFC7TkQAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkIDHCNDAm0KDwKsWf9EC4+5DvSbIAXtVMKdeWTRdflMPWhhVYdyFFCtWTK5qM0BmfPCcGnknaSiGfrL7riXNuXT8067BedI5r8dOWe1Zei+5IN9TF2VoVqu1MfB+t2HtTml5gARIgARIgARIgARIgARIgARIgARIgARIgARIwB8EaOBNoZ2qV6opebrRmpX1m36Sd5bNlh9//V76j79UJl8/y8TH/fr75SbJ/C/mycofV9jk5rNE8V3lz7//kI2/b5AK+1QscK4oP0459nTXyyvuW7lArF17z//+2+aangdJgARIgARIgARIgARIgARIgARIgARIgARIgAS8T4AG3hTa6MhKR8klLa4pcOWG39ZLm9uayHcb18qsJS9L2/odjfcuEm3Z+rf88dfvBdJj0zPItm3/Fjhe1B/l93Y3FhfTGMAUEiABEiABEiABEiABEiABEiABEiABEiABEiCBYBGg1S9N7bnvHuWkYY08k9u3P31jPg8qd4j5PLNeBxlz6TOufxX3q2zSuP1Tolhxc3jTn78WOP3bX78V+O38UVzDL1BIgARIgARIgARIgAR2EOjbt6+c3qLFjgP53+66+26pedRR8vLLLxc499dff8mxxx0nDz30UIHjmfpxZps2Mmz4cJP9e++9Z8r0888/m989Lr5Y+vfvn6lbFznfSy+7TK66+uqU89mwYYO8/vrr8vfffyeVx6effioLFy1K6homJgESIIFME6hVu7Z5hqNvifW3/KuvpMM558gdd9yR6eIknP9HH31kyrt27fYQjpf06SPXXFPQqa2wzFD3KVOmFJYscv6ff/4xz/+ffvopciyVL59//rl88MEHqVya0jUtWraU+x94IKVrE7no22+/lTdnz04kaYE0YAAWRZFvvvnG6AH6WIr/CNAamMY22z8/9u6G39ebXOse3sB8vvTh8/LP1i2RO326aomccM1hcuatJ8t///23/fguu5jPLY50Npbvug2r5fuN6yLXv/f5nMj3dH55eeFUGTvrQZm5aEY6s2VeJEACJEACJEACJJBTAnXr1hUMmDZu3FigHAt0MIS9CT5YsKDA8U90YLN161Y5sX79Ascz9eOkk06SatWqZSp7T+f7v//9T6686irZtGlTUuWc+PTTMurhh5O6holJgARIINMEHtaJwTGPPGL+Bg8aZG53YffukWM4V/HAAzNdjCLnf7waa4899tik8jnttNOk0kEHJXzN5s2bzfN/2bJlCV/jlnDK88/LiJEj3U758ti7776b0sTuiBEj5PmpU4tU5zJlykizZs1kzz33LFI+vDg3BBiiIY3cy5bcw+S2ftOP5vPE6o2k/hGN5f0v50n3+8+W048/U37SczMXTpet//4j3U65RHbJN+zuv+cB5ppn3x4v63/9QUM8nCtVDjhMKqsX8Or1q+SKxy6UVnXbqaF3rcAQmwmZ/O5TsvSbhVKvWkNpUadNJm7BPEmABEiABEiABEgg6wROOOEEc88lS5ZI06ZNzfdffvlFvvjyS2mj3rMfRhl4F6sn0+677y7HHnNMVsra//rrs3If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wqFJXp7xZm1ZhA01PV5NFo8ESCAGAXrwxgDDwyRAAiRAAiRAAiRAAiRAAiRAAiRAAiTgBwLwqJytG4AiHADFmwQe1fi6YQlb5M0WCHapaOANdvuydiRAAiRAAiTw/+ydCbxVU/vHVwqVaDQVzUVCgxSiUUUyhczVK/M8hMgYkVfImNfQX6YMIbNCZSqlUSmaNBepDJmH/s933buOfU/n3PnWPff8nj6nc+4+e1jru/fZw28967dEQAREQAREQAREQAREoIQTwMZB4m7x3sk52WQU79KrdMWdgCwaivseUvlEQAREQAREQAREQAREQAREQAREQAREQAREQAREIAkBCbxJwGiyCIiACIiACIiACIiACIiACIiACIiACIiACIiACBR3AhJ4i/seUvlEQAREQAREQAREQAREQAREQAREQAREQAREQAREIAkBCbxJwGiyCIiACIiACIiACIiACIiACIiACIiACIiACIiACBR3AhJ4i/seUvlEQAREQAREQAREQAREQAREQAREQAREQAREQAREIAkBCbxJwGiyCIiACIiACIiACIiACIiACIiACIiACIiACIiACBR3AhJ4i/seUvlEQAREQAREQAREQAREQAREQAREQAREQAREQAREIAkBCbxJwGiyCIiACIiACIiACIiACIiACIiACIiACIiACIiACBR3AhJ4i/seUvlEQAREQAREQAREQAREQAREQAREQAREQAREQAREIAkBCbxJwGiyCIiACIiACIiACIiACIiACIiACIiACIiACIiACBR3AqU2WhT3Qqp8IiACJYNAqVKlfEV02ikZ+1O1EAEREIGCEgjXhYKuR8uLQHEioPuc4rQ3VBYRyB0BXY9yx0lziUA6EUi167kyeNPp6FRdRUAEREAEREAEREAEREAEREAEREAEREAEREAEShSBMiWqNqqMCIiACIiACIiACIhAyhBItcyIlAEbV9CQmSbecWD0pwiIgAhkEtD5UYcCBHS91HGQygSUwZvKe09lFwEREAEREAEREAEREAEREAEREAEREAEREAERSGsCEnjTever8iIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAqlMQAJvKu89lV0EREAEREAEREAEREAEREAEREAEREAEREAERCCtCUjgTevdr8qLgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAikMgEJvKm891R2ERABERABERABERABERABERABERABERABERCBtCYggTetd78qLwIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIikMoEJPCm8t5T2UVABERABERABERABERABERABERABERABERABNKagATetN79qrwIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiEAqE5DAm8p7T2UXAREQAREQAREQAREQAREQAREQAREQAREQARFIawISeNN696vyIiACIiACIiACIiACIiACIiACIiACIiACIiACqUxAAm8q7z2VXQREQAREQAREQAREQAREQAREQAREQAREQAREIK0JSOBN692vyouACIiACIiACIiACIiACIiACIiACIiACIiACKQyAQm8qbz3VHYREAEREAEREAEREAEREAEREAEREAEREAEREIG0JiCBN613vyovAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiKQygQk8Kby3lPZRUAEREAEREAEREAEREAEREAEREAEREAEREAE0pqABN603v2qvAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIQCoTkMCbyntPZRcBERABERABERABERABERABERABERABERABEUhrAhJ403r3q/IiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAKpTKBMKhdeZRcBESjeBB5//HE3efLkTQp5zjnnxKa1bNnS9enTJ/a3PoiACIiACIiACIiACIiACIiACIiACIiACOSeQKmNFrmfXXOKgAiIQO4JjB8/3rVv3z7bBcaNG+fatWuX7Tz6UgREQAREQAREIP8ESpUq5RfWbX/+GWpJERABERCBkk9A18uSv49Lcg1l0VCS967qJgJbmADCbdu2bZOWgu8k7ibFoy9EQAREQAREQAREQAREQAREQAREQAREIEcCEnhzRKQZREAECkLgpptuSrp4dt8lXUhfiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIxAhI4I2h0AcREIGiIJAsi1fZu0VBW+sUAREQAREQAREQAREQAREQAREQARFINwISeNNtj6u+IrAFCCTK1E00bQsUTZsUAREQAREQAREQAREQAREQAREQAREQgZQmIIE3pXefCi8CqUEgPotX2bupsd9UShEQAREQAREQAREQAREQAREQAREQgeJPQAJv8d9HKqEIlAgC0Yzd6OcSUTlVQgREQAREQAREQAREQAREQAREQAREQAS2EIFSGy220La1WREQgTQjQCYvMX78eP+u/0RABERABERABIqeQKlSpfxGdNtf9Ky1BREQAREQgdQloOtl6u47ldy5lBN4m11aU/tNBERABFKKwPQhS1OqvCqsCIiACIhAySKgB9aStT9VGxEQAREQgaIhoOtl0XDVWjcPgTKbZzPaigiIgAiIgAiIgAiIgAiIwOYg8Pjjj7vJkydvsqlzzjknNq1ly5auT58+sb/1QQREQAREQATSjYCul+m2x0t2fVM2g3f44KEle8+odiIgAilPoFff83wdlMGb8rtSFRABERCBlCKAFVL79u2zLfO4ceNcsE7KdkZ9KQIiIAIiIAIllICulyV0x6ZptTTIWprueFVbBERABERABERABESgZBJAuG3btm3SyvGdxN2kePSFCIiACIhAmhDQ9TJNdnSaVFMCb5rsaFVTBERABERABERABEQgfQjcdNNNSSub3XdJF9IXIiACIiACIlACCWR3TczuuxKIQlVKcQISeFN8B6r4IiACIiACIiACIiACIhBPIFlWkrJ340npbxEQAREQgXQmoOtlOu/9klV3Cbwla3+qNiIgAiIgAiIgAiIgAiLgCSTKPEo0TbhEQAREQAREIJ0JJLo2JpqWzoxU9+JPQAJv8d9HKqEIiIAIiIAIiIAIiIAI5JlAfFaSsnfzjFALiIAIiIAIpAEBXS/TYCenQRUl8KbBTlYVRUAEREAEREAEREAE0pNANAMp+jk9aajWIiACIiACIpCYQPQaGf2ceG5NFYHiR6BM8SuSSiQCIiACIiACIiACIiACIlAYBKJZSXxWiIAIiIAIiIAIbEpA18tNmWhKahGQwJta+0ulFQEREAERyCeBZpfWzOeSWkwEREAEUpxA04zy6zyY4vsxxYs/fcjSFK+Bil+SCej8WJL3bu7r9lO13/zMOh5yz6wkz5lq1y0JvCX5aFTdREAEREAEREAEREAEREAEREAEREAEREAEciSw/W5lc5xHM4hAcSUggbe47hmVSwREQAREoEgIDB88tEjWq5WKgAiIgAiIgAhsSqBX3/M2nagpIlBMCeg+sZjuGBVLBDYjgVS9bmmQtc14kGhTIiACIiACIiACIiACIiACIiACIiACIiACIiACIlCYBCTwFiZNrUsEREAEREAEREAEREAEREAEREAEREAEREAEREAENiMBCbybEbY2JQIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAKFSUACb2HS1LpEQAREQAREQAREQAREQAREQAREQAREQAREQAREYDMSkMC7GWFrUyIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiJQmATKFObKtC4RSFUCG3752X2z5lv3519/uh2rVHNVKlV2pUqVStXqqNwiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAJpQiAtBN5HRjzhPpk6aZNdioCHkFdnt1ru6E5dXc3qu20yT2FMQDxcvmqlK1+uXKFvY97XC90///zj6teq48qUSb47P57yqXv0ueG+Ohf3Psftt3fTLFX74acf3cU3X+2nPXzrPa5c2bJZvi+qP3Jb/qLa/vc//uBGvDbSTZo51W3cuDG2GY6FE7oe4/bds3FsWm4/rPxmlbvmzgGucsVKbsj1t+d2sSKbj+Nj2ItPu88+n+b+sTqeevQJrl2rg4tse6m64jVrv3Nrv1/vqlWu4qpVqZqq1VC5RUAEREAEREAEREAEREAEREAEREAE0oxAWlk0VCi/natVY/fYq8bOu7qfft7gpsya7gbc91+3dOXyItn9C5d87W4ferd76pXnC339dz12v1839chtPP3KC+7333/P7exFOl9+yl9YBfr1t9/cf/93r/t0xhTL2q3q2h94iGu9Xyu3U9Vq/li4+/EH3Yw5swprc1tsPdTvo88muq1KbeWa7bWvq7T9DlusLMV5w+9P/ND/lj6YPKE4F1NlEwEREAEREAEREAEREAEREAEREAEREIEsBJKnfGaZrWT80azxvu7ME3tmqQxC520mvi5evtS99/F4d0aP07J8XxL/WPfDevfymDfcyUceVxKrl+s6TZ/zuVth2bY7V9vJDex7ndu6zNaxZe8w4XfO/C/dyLdfdU332ic2PRU/LF2xzBe740Ft3fFdj07FKqjMIiACIiACIiACIiACIiACIiACIiACIiACSQiklcCbiMG2227rGtap7wXeHzf8lGWWuQvmubfGj3GLli52FS3rsXGDPV33w440+4JysfmWrFjqXnvvHffVovmOjNCq1r279X4t3REdDnNlSpd2jz3/lGMeYvmqFQ7hcN899nKHt+vkp02c/pl7/5PxJjSudn+Z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0teL+GAwmQrBub/9S05/+5GEblxtflA4afoMkqXrS5K5U7htUYCKwPn+Gi+nBrwrl2b/a36QL2Xx0pLjrY8kRd5wexPs8+eURMOm9evCe9KjffKbxm788Yj3NJotdZqAv43v3urhCyQUXbbbaUbM6D0EOL7eM1ZsqecSwNRoJC/7c8VzgbJlXkGgcOsfTDsje3N6RePZSBIgAb8i0LH3z6a/+ye+7pH99tb/L2HRcPD0fkmeTL2dNSoXr1Gl0Buhcut2mFjRwMgTditMjqtNA6J+C+cqFlUxn9nnreMbeQB85f/Gm6eD5JYuuBbwUF4JyJzFdPPWhXPq1XtEUhQsohG1aSN33X4fFnJKF24LkiSaJ3me/JI0RUSvdCvjLV1w7ebRgxr5m12S53zI2u3Rrwk1vl4bwWvdyB49imwcCThJwLrhnczObCRAAiRAAiRAAiRAAiRAAiRAAj5KIHlACimWu+QDe5c6xT0/ZitzgE6DL5CdC1FZPPiacASS58gl+HFMyTJmFvw8KMHX1/L2jSlvsnTpJVnJMjFl8dtj97vP+y0KdpwESIAESIAESIAESIAESIAESIAESIAESIAESIAEvIuA10Xw0prBuy4wtjZmArRmiJkPj5IACZAACZAACZAACZAACZAACZAACZAACcRMgBG8MfPhURIgARIgARIgARIgARIgARIgARIgARIgARIgARLwWAIUeD12aNgwEiABEiABEiABEiABEiABEiABEiABEiABEiABEoiZAAXemPnwKAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAl4LAEKvB47NGwYCZAACZAACZAACZAACZAACZAACZAACZAACZAACcRMgAJvzHx4lARIgARIgARIgARIgARIgARIgARIgARIgARIgAQ8lgAFXo8dGjaMBEiABEiABEiABEiABEiABEiABEiABEiABEiABGImQIE3Zj48SgIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIeSyDAY1vGhpEACZAACZAACZAACZCAHxPo2PtnP+49u04CJEACriPwaJ/8rquMNZGAmwjsrV7cTTWzWn8gwAhefxhl9pEESIAESIAESIAESIAEEpjAgUlvCH6YSIAE4k6A91Hc2bEkCZAACfgTgSR3NPlTh9lXEiABEiABEiAB7yGQJEkS01j+ueI9Y8aW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JEACJOBPBBwjDR23/YkB+0oC8SXgeO84bse3XpYnARIgARLwPQJJ7mjyvW6xRyRAAiRAAiRAAr5AIEmSJKYb/HPFF0aTffA3AohARFq0aJF55S8SIIHYE+B9FHtmLEECJEAC/kiAAq8/jjr7TAIkQAIkQAJeQiCxBN5H++T3EkJsJgmQgLcS2PjjEW9tul+2m98Lfjns7DQJJCgBfi8kKG6fOxktGnxuSNkhEiABEiABEiABEiABEiABEiABEiABEiABEiABfyEQ4C8dZT9JgARIgARIgARIILYEhn/7e2yLMD8JkAAJxEigy1u9YzzOg55NgN8Lnj0+bB0JeCMBfi9446h5XpsZwet5Y8IWkQAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkIBTBCjwOoWJmUiABEiABEiABEiABEiABEiABEiABEiABEiABEjA8whQ4PW8MWGLSIAESIAESIAESIAESIAESIAESIAESIAESIAESMApAhR4ncLETCRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiTgeQQo8HremLBFJEACJEACJEACJEACJEACJEACJEACJEACJEACJOAUAQq8TmFiJhIgARIgARIgARIgARIgARIgARIgARIgARIgARLwPAIUeD1vTNgiEiABEiABEiABEiABEiABEiABEiABEiABEiABEnCKAAVepzAxEwmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAl4HgEKvJ43JmwRCZAACZAACZAACZAACZAACZAACZAACZAACZAACThFgAKvU5iYiQRIgARIgARIgARIgARIgARIgARIgARIgARIgAQ8jwAFXs8bE7aIBEiABEiABEiABEiABEiABEiABEiABEiABEiABJwiQIHXKUzMRAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAKeR4ACr+eNCVtEAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAk4RoMDrFCZmIgESIAESIAESIAESIAESIAESIAESIAESIAESIAHPI0CB1/PGhC0iARIgARIgARIgARIgARIgARIgARIgARIgARIgAacIUOB1ChMzkQAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkIDnEaDA63ljwhaRAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQgFME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wFO+F+KCgN8l/C6Jy3XjTBl+vjtD6cF5+L3wYEbM8WAC989re3AZ5iABEiABEiABEiABEnAjgSsaCQuxbvrC2eYsiL6yBCpnTgthDwtbRV7cypmy8cmTKUNGwU9sE0TGyEIjPFqt6fiO9aVInkIkueOe6LczqFiMH29J8RFR0Uc8EHFcFCy6fqdMmdJEQ0d33HE/xOa4Cs5WPSgfG3sHq1x8XhH5C1E2csqRNXvkXTG+RzQvfphIwBsJ8LtEzOwIfpe47+rl57v72LJmEogtAQq8sSXG/CRAAiRAAiRAAiTgZgJ//DNEsBgVEoTO5vUaufmMrJ4ESIAESMDXCPC7xNdGlP0hARIggegJUOCNng2PkAAJkAAJkAAJkECiEHik+MMasZtSrRWySe3KT8QpKjZRGs6TkgAJkAAJeAwBfpd4zFCwISRAAiTgdgIUeN2OmCcgARIgARIgARIggdgRqP/Ek4IfJhIgARIgARKIKwF+l8SVHMuRAAmQgPcRSOp9TWaLSYAESIAESIAESIAESIAESIAESIAESIAESIAESIAEQIACL68DEiABEiABEiABEiABEiABEiABEiABEiABEiABEvBSAhR4vXTg2GwSIAESIAESIAESIAESIAESIAESIAESIAESIAESoMDLa4AESIAESIAESIAESIAESIAESIAESIAESIAESIAEvJQABV4vHTg2mwRIgARIgARIgARIgARIgARIgARIgARIgARIgAQo8PIaIAESIAESIAESIAE/JtD3q4+ly1u95cCRQzaFPQf3y679eyUsLMzeN3HWVJNv7LRJ9j5nNt795hNTbv/hg3b2vYfC678ZdtPeN3nONJNv1NQJ9j5v3DgVctqwO3v+nN38oODTpm+vfvKOve/D7z83+3Yf2Gvvi+vGqZBgc84z58/GtYp4lZuxaK7py7AJ/8SrntgU3q/XK67R6zduxKaYndcuf/26vY8bJODrBPh579oR5ue9a3lGV5v9ee0hn/dzly0033l/jRkeXZO5nwQShQAF3kTBzpOSAAmQAAmQAAmQgGcQyJA+g2TOkFECAgLsBn036Bf54vfv5dKVy/a+1ClTmXypU6e29zmzkTGdVX8yO/v3g38z9V+8dMnelzplalN/mlSxq9+uwEM2Zi2eb/q2cuNau0XJkiY1fcuYPqO9z5Ubc5YuMOdcvn61K6v16Lp+HfGX6XPwmeA4tfO3kYNM+VNxLB+nk7IQCSQyAX7eu3YA+HnvWp7R1eZpn/cpU6Q03+lp06SJrsncTwKJQuDeX/KJcnqelARIgARIgARIgARIIDEJvPfiG06dvlHt+oKf2Ka+vV93qkjDmnUEP76YsmfNJj/2+9IXu8Y+kQAJeBEBft67f7D4ee9+xol9hhoVqwp+mEjA0whQ4PW0EWF7SIAESIAESIAEfI5A6LVQgQXB+m2b5fyFC4Koj1LFSkqr+k0E/wxa6c6dOzJTp7uv3bpRTp4OksA8+aXSo49J7cpPWFlk7rJFsmH7ZmmsYuuly5dk7vJFcuzkCcmdM5e0bthUHileys57+PgRmTpvlsAGIPTaNcmaOYtUq1BRGj/ZUAKShUfUDhr7t5xRO4HOLdsZm4ZlGgVqTXv/beRgSa0RtW90f1GWrl0pKzaskUplK0jVCpXk52F/yK3bt6Vr62ckZ7Yc9jm379kp0xbOkQK580r7pq1l8LgREnLurHTS+g8fOyJLtJ5r16+Z/L//M0TrTyVv9nhZlq9bJTj342XKy5NV7vUXdhHTFsyW/YcPSIb06eXhIsWlVcNmkjb1vciZoyePaz9nyE6dsh8aGipZMmWWKuUfl6Z1GkrygOR22yJvDBw9TM5fvKB96KB9yG4fHv3fRDly4pi0btBUigQWksWrl8uqTeukfvXaEnYrTGYvWWCOo98tGzSW8qXKmnpQH8YNadGqZbJNWbTUMc6WJatgKmc6HfeXOj1vn8eZjVUaCYwxPxZ0QrPfkTw5c6sQXlcqli0vFy9dlN9HDZWg06dMVUvXrJCd+/ZI87qNpEThomYfrDH+mz9L9h05KOmUWUnlh+skXdp09ulv3LwpM3TM0Mcz585oNHdyCcyb3/ADb8e0cNVSmb98sQQFn9J+ZZN61Wpps+7YWXCt/zL8T22pSPe2HU3frYNgCrYZ0qWX3s92s3ZHeIVtx9R5M2X1pvVyVi0nUun1V7xgEeXcRPLmyq330CaZp+dH35GGjP9HUqZMaa4hXNOYMo3+gv1FvT/Saz/LlCil5ZtKloyZzL0Dnhd03JGGqq1EKo1Of7P7S3YU+4KVS2WFXovHgo6bc1YoXc4wT5IkiSnDXyQQEwF+3vPznp/3Yr4jffXz3voeekT/jrMefMOK6d+502X73l1y5epVyZQxo/l7pkW9RuY7JqbPDB4jAVcRoMDrKpKshwRIgARIgARIgASiIfDNX7+oQHnQTOkrqoIhBEkISBBeP339PRV805qSvwwfaETgdPo+b648cvDYYRUt98iJoJPybIunTZ6g4CDZof9AQMyCmJcvdx4V0+7IwaOH5Ychv8tnb34guXPkUgHutHz+6/cq1l6X/LnzqZCcTI4cPyaTZk+TU2dCpGf7Lqa+fYcOyEkV6yAAX756xQh3EJqRMP0d4hfSad3GeQPz5JMUyZMbTQ/v127ZKE2ebGDy4NdyFYGxv2yJ0mbfPhVmT5wKMsLrZf2nB8KgXf/ZEK0rhcl3WrdRLt9Decx7/FqtguNAFTCRCqjgCFEP4t6OfbvlnV59JJNaSwSfPaP9/Na0H2VzqOh45MRR/Udrhoqtp1RQ7WHKR/Vrr4rHwXpeMHJMEKLBvV71WmY3PG7RtqRJkpoxA3NofTjPz8MGyid9+qp4m8707aoKzEiX1d4CYvD1G9fkhvoGonxGtcOITYKoDgE+IFmAFC4QqILlZdmvQi2mq9663U2KFypqznkl9KqpFpYaYbdu2f3BP6G/jRgst+/cNuN26coVWbByifkH9J0XXpOsmbKYcr+NGCQbd2zRPiUxwu6tW7dNe3F9fvDSW1Iof6DJN3HWf0ZIxxuI28nV1mPElLGSXZlbCQ8E0O/dB/bJmi0bpFGtetYhM57gULdaTXtf5I3f9aECHoRAmC0SWFivnZOyTh947NLx6K/3CvjiGkI/kUJUkE6GhxV6zZ69cF6vhe/kgl4nqVT0xb12Wq/1JSp8oy9f/N9H95U/ow8fUB73ENKwiaNkoQq8ePCAe/C4nn/voUlySK+JXh2ek6Rqt8FEAjER4Oc9P+/5eR/+/e2rn/fw2Eff8NAQCd+9n+nfIXjojoftOfTB/eHjR80D+yP6+nav12L6yOAxEnAZAQq8LkPJikiABEiABEiABEjgfgLBKjBB3IVo+817n5qIUkSwvvtNf42WPGsiEmtUrGYiFiFsIcKyz3MvGGEV0aUQrObogh6I5C1SoJB9Aghe/V59W8XbvEbc7PfDACPCbtA6cj+ZSzZqlC+Ey2oabdvzma6mHAThL//4wYjLz2h0LUQ0x9SgRh3BT6/3+2iU7XX56LW+kvnuPzCO+bBdRduzbc8Owfksgfe2RvRu3rHVZEWEaeQEwRQ/vT98U4W2q9LvlbdNVHHkfHgPwXnE5LGSTEXE91980wiPEIaxb/6KxUbA7aLRw5t3bjV5cT4rOhaLuIHbms3rpUOzNtH2IarzxrRv5/7d8r4KnoVV8LyufPr/8rWJrF23dZNGxTaTHz4YIMMnjjYiahONHkaUNRLE9rgkREwj9WjfWXk/brbHTZ8i0xfOFvjuYh/OCSbzNJIbkUTN6jxl8iEK++9JY4wQ/cGL2uYCBY2wjoiq2Uvmy2QV+nu066wifogRdyFcDnjrQ3lIHw4gYVE9RNJCJIbAG6JCOqJ8kfBwoNpjlc325p3b5PvBv5pt6xcivCHwrlX+jgIvHgYgVSlf0coa4RVjvmH7FiOiftX3ExOlfUuF3I9+/MI8FFm+YbXp3xOPV5E3Pn/f3D9v93xV8t59KLBGo34h7uKBxsevvWOEWwjBn/z0lRHjD+k/2tW13fh5c8AHpk9vPf+KuYfQECzaBnG3gD7EQL2IcoZ4/vXAn0x0c8VyFQTRvEwkEB0Bft7fI8PP+3ssnNni530a8dbPe8wYgbj7cNES+vA5XMzFrJt+upgqInqP60P6PLkecuYyYB4SiBcBPoKOFz4WJgESIAESIAESIIGYCaRMER6hiujYpWtXGWEQUbHfvfeZDP7qfyo2VTEVQKBDat+klR01iwjVpnXCo2MxrdwxVSr3mC1MIdoQ09CRIBojYREQJEQuQriC+FqySDFzzkFf/mIEZ5Mhjr8qPFLORJYiohRCNBK20c9iOqUeNgnxSas3rzNRMf/P3nnAOVF8cfzRe6/SO9KkCqgIp4ggiCBSrICiYkGwY0dRUf/2glgAKSpShMNKFwHpVQSk9957l//7zd2EXEjucpdcLpv8Hp9cNltmZ74zs8v+9s2bGBW/ES4ABg/TTq1uNcIdvFshlNtyrlVPZHjUoJwV1fNzkJYRfMEwWIZQDBB3YQgLUKtqDbOMEBSpYbbtzFGhF17EsA4t25hyQWhOzOD1inqBmAlxFwZ+OD6ztkmICce1rrJq24GY+VKPZ1ziLva1nqqH4yfCg9c0PHMrl6vgEnexX80q1RMch3X1r6hrvHs3qFe5bY942EX4BHj7ur+owP7WMqlneIb0GUwdQsSHty68a+G5i7q8+bqLnuL2GPfvGpWrmrL07NrdHGe3ZcgQ98hjwzrY9Z7ftg9CrLchLBAKpJ2Gd4B59kHP4/mbBGyf5fU+eW2B13vcs+P+r8DrvfOu97bu4K2Ll54QqhFS6Ou3PjH3Lnj10kggFATowRsKyjwHCZAACZAACZBA1BLArOVNGlxj4rgO1eHf3+qQdngIVtfYbTENGrk8WDEUHYYQChnchoEfP3ncrIdnmLsVLnAxZizWI74u7IIOx4c1UG/DCTOmGGHwrQEfGG9IxJOtVfUKI/rZGLxm5xT8wVD8mlWryyL1XoXXJeLmLlkR572LcwdqlgdCJXz8zRcJkoPoh7AHh44ckXoqNP+qnqWIffuOelpm13yZclapIdfWv8oVazhBAin8cQnz+BAHF1RUTg2D9+vyf1eaB0Y8NBbUOq5cvpKJgwxhNTGz/Nao8O3JL70KvWf0ARQhDRDWAl7jy1evNF69O/bsNF7JCKvhbtYLGWEhPA1xCG3sYWzLni2b1K52hXpQL9YQHotN/NpFKjjDGqrnty9Dm4QXMuIp//j7TyY/yB+8oprohDbWu9jX8fCQQtxDeJVPnrXNhOhAaAXE4vXHLLMJ6uGMGMrWbAgPhCyhkUBiBHi9T4yO72227/F6z+u9E6/31StVlbIlS5tQWRjRghBB5UuVNS9AMUIro75IpZFAKAhQ4A0FZZ6DBEiABEiABEggqgncp5NN1VHBa+6ShfKvetRu2LLJfDCh2tMP9DRekZiYB4aYrek01qu19OrRCAEO4p67JTXhE+L6vv7Ei/Ln/L9kqYZNgHctREJ8pmjIB3hsQogLxBrWujJO4NVh/BB4l8bHccVEaYGajWV79tw5ORk/KZtNEw9OcXbBTALX94nnTZxVCMyI+fv3vyvMZ6KGMUAYC4THCIZBGA2lwRP67d6vmrABK9auMpPWYDI6fJroQ+N9He/2mR3L75xOWubJr2zJMuY4lAaehm8P+NCEQECM4HK6rV6N2nKsvMbrnT3Dlf6Zs2fMsvWYdm3QhcJuE9TZ9QgNAoEXH0wKhzAWsKt9hGewx2ECOHiaz14038TdRRxDfBBWAiE4IOj7Mniqvz/oMyP+w3sKoRtu0QnnZi6YbdLwdZxdj7AhMAi6Nk603YY+mC0+HrVdx28S8EaA13tvVBJfZ69XvN7zeu/E6z3mJUC8+lmL5uoLxr81bvt6E5oB4Rkm/DnV/D/EV7irxHsGt5JA8ghQ4E0eL+5NAiRAAiRAAiRAAskicE4FytMqjlWpcLnxnsXB8Hb8NnaUxrBdZeKpXl6+ohTUoesYwn5/py46jL1Ass7hbWfEiD3333m5/uomcuO115shg3jYwKRdmDhq/t+LjAext2P9XVdLPXjhqYLh+1t2bDPpVlUhLLmTiXk7n/WWRZzZtje28raLWWfLGdPwWp28K8YM70d+Bo0cbnjOWbzANVmaZyI2DAFmvHa3E/Fiu/u6tFhG/FeI8B1btdXTt9VYwydVrJwj340fbYR7cPEVCgOTvMAgtndoieO92y/TJhhxt271mkZANROW6a54KHU32yYxwZmnoT15Wo3K1UyMZ7xYQOxntA/Eiy5WxHccQjtBXHkVmdGOYJhEb9SvY41QjInzEhN4R+p+8OzupsI3vKasLdC27o9BqD6oYS0Qt9lXGAl/0uE+0UuA1/uU1T2v92LiffN678zrPWLeI4RRo7oNzf+rECoKIu+gUfh/yF4zgiux/8ekrNfwKBK4lMBF95BLt3ENCZAACZAACZAACZBAgAQwEdkjOqlY73f6yFn1poRhqHmLJk3NMiaWgsFrETZDPW7dbdSv46TrM4+oyBXrvjrJ5eEaCgLn/XbcD2ZfCHeI04uh87BTp06bb+9/4jxVIVYkZpkzZZY6OukU4s0NGzvC7IrJ4JIy6wcLby1fdrmGIoAhVqzlht/w7unW+zF54o0XjJj7wy9jTTkHj/4Wm03sWIS/QIxgGOL0+jI7A/a/G9a4dkHYAsSLTbHFFw6es4Ha8/97zZQNE53BEBYDYr0VdW3ZrDe3e31ZfnOXLBDrfYs0MNnL/c/1lJ6v9dYH0vOyY0+cYFupbMUEcWvxcOpu8GCFwSMXjKxhGefwNLQ3xImG2brxNbmaPXarisBos71ef87EB8Z6CMut4yeOs+XFelcb0odqazZMRJXycXnFeojiW3deWp/p4lPwxmzGvNk2SfMNsRt98OsfhiZYzx8k4EmA13tPIm59ldf7S+G4reH13rnX+5+n/m7uXZ8O+8rUKF4eI5yRvee537vcqpyLJBB0AvTgDTpSJkgCJEACJEACJEACFwlgwq9cOXPJQRXCPhjY30zMdV69O/6cFyfkInQDrE2zVkbM/GnK73Lg0EEzsRgmqcKEK4gre52GQEiO1VXhFd6eM+bPlv8uXDDx4RDHd/aieUbIu+Lyqj6Tw8Rku/aeksFjvtMh+6UT9QBtqCIe0sQkZ4gdjOH9SRnSh3cqYhJjArVOOrGcp1UqW15qa7zgJRr24Y3P3hOc5+jxY8pjgfGUaRlzoxFz66jn6bQ5M+LKpedH+IEDOukZyo2HLDv5nGf6+I1Yf4j5OGnGNBUCT0lurSfUS6aMGY1o7e2YpNblzRU3qdv0uX/JCU0ToQoghKfEwBKTjQ0f+4Os37xJChUoYLxh0T6KqLep9YbNmzu3SX6G5h2eRFfXudLUd/2adYwg2/eT/8nVmg9MqgYxFoJ5iyatTXziUhrGAC0RD6gQgjG52HINcbF4xTKT5gb1wIXYi3YML99FGt/2jc/eNSEiNOKz4Yz27M1Qdkxctkdj10KERh0mZiXVwxeTsO09sE9DLfQ3bQlt6i9tXzD7cgLLebQNYXK772JHm0nkOqqXcsnLSsiajeuk/7cDTZzps2fPygwNz2BDL8zXeMCIfw2BHMxwnu9/wvHlTBu/SUNJTJsz03hHnzh1wjygb92xXfvlPDOhIMR1GgkkRoDX+0vp8Hp/KRNva3i9r23+D+HE6z3+r4K5ABAO68sRQ6Si3lMOHz0ikzQcFsxOyOqt3rmOBIJJgB68waTJtEiABEiABEiABEjAgwBi4T51/6NGKEXogO9/GiMj1ev0qE78dOuNN8tNOpEWDN6kr/Z8zghzszTGKkI4QDjFxB3Pdu+V7LANEMO63Han4PwQLYeM+d48gEBAe+K+R1zioEd2zc92zW/W0ADZZaWGdLAPKN72wzp4y9oYt9Xcln3tj/Vttdw5kL7ymDQz7gHI2/6P3NNNmmqIia07tws8dfEABRHy7rYdXWEXalSuqkPy7zFhISDqQjT+WcMOgGevrg8ZQc9b2lh347XXGdEQIRkQ4zV20i9GSEfs25TatToZGEIRHDh8UMMcTDEiYkrTQqgACPtHjx83oTxQh/OXLVLmVaX3Q4+7km1U7ypTToQXwDl374ubkO/BO7pK88bXm8nG0OZ+mTbRCNm3q6COCdxgCGtRv2ZdE4v3xwk/GX77Du4XxLvNqjFnEX5h5vw5Zt+H7upmhN1Dep6xE382EwIWyFdA7mjd3mz3/FOuVBkpWqiIWV25XAWX57HnfvY3Jll7+oEeUkW9t9dv3mj6CfoLQpegHJ1a3Wp3lTYaWzeXitEQn1Hm/3Rywfs63KXtuqiZ6Gb4uJGmzZQuVlLzd5s5Dv0JoSJgiM2LFy94MWGO13Am8JDu07O3Of+Cv5eYPogY1oULFjb5gjhMI4HECPB6fykdXu8vZeJtDa/3Y83/j5x4vS9fuqw8fNd9Zq4E3GeG6oim2Mm/mv/nPHJ3N7EjarzVO9eRQDAJpNMJBC4EM0GmRQIkQAIkQAIkQALBImCHnof6vyu1Hy9lijD0vQHBKopJB1688L7MpjMqI+ZgRvUU9Wbwbt29d496GeZJUhTzdrz7OgzD36dxTI+dOCbwLi2YjPi+yEemjJnUAzWTe5JBW8bEOmCQVPooA4bfp9fJ5+C56o0bwkRAmISXbx4tp40Z609m4WmDeile9LIUe9t6ngdCNPIE0TBQw/BOxKJFOAGUC1623uyMeqxiH8/J85APE75AvWjBD3XqaRBt9yuDAsa7Nc4LGfWP44oVvixBmjgHhF+0z6TiLT/7dh8j0GLiqSYNLsbF9Ty/52/UCTx0s2jbQ2xcX17QcW0og2s7rhWIEwxP5qKFChuRGmnDex3lKakeyzbOMNZ7Ho91MHh0Ix2wxgSH9loUtzWwv12eftgksOSjLYElxKNDSiC59wVe7xNWD6/3CXn4+sXrvXOv94i9u1/vW4ePHdEXkLn0/3kF/b538L7gq0dwfXIIUOBNDi3uSwIkQAIkQAIkEFICVlSJFIE3pPB4MhJIIwIQt/Ggu2j5UvlK49YixMhHL78lWXRCPpoIH+Sd2QqSK/A6s5TMNQkkjwCv98nj5Wtv3hd8keH65BDw7jaSnBS4LwmQAAmQAAmQAAmQAAmQAAnEE/h71Qqxk81gVfuWbSjusnWQAAmQQAQS4PU+AiuVRXIsAQq8jq06ZpwESIAESIAESIAESIAEwo9AIR2WelXtKyWThleoWaWGTpZWK/wyyRyRAAmQAAkETIDX+4ARMgESCBoBCrxBQ8mESIAESIAESIAESIAESIAEMBnZQzrhDI0ESIAESCCyCfB6H9n1y9I5i0B6Z2WXuSUBEiABEiABEiABEiABEiABEiABEiABEiABEiABErAEKPBaEvwmARIgARIgARIgARIgARIgARIgARIgARIgARIgAYcRoMDrsApjdkmABEiABEiABEiABEiABEiABEiABEiABEiABEjAEqDAa0nwmwRIgARIgARIgARIgARIgARIgARIgARIgARIgAQcRoACr8MqjNklARIgARIgARIgARIgARIgARIgARIgARIgARIgAUuAAq8lwW8SIAESIAESIAESIIGwIPB0v5ely9MPy5Yd28IiP8HKxMZtm025nn27T7CS9JnOrr27zbl6vtbb5z7cQAIkEL0EHn/9eXON2LF7Z6pDeOHdvuZc6zZvSPRcyEufj96S+3r3kEdfeVqOnTie6P6h2Ig8/7t+rZw5ezZFp7t4/JkUHR9pBx0+esS0hQee7+kq2qnTpwzjDVs2udZhod/n75t9l65cnmB9Yj+OHT9mjkEbsnb69GmT/nqP9N8a8IHZd8mKv+2u/CYBRxOgwOvo6mPmSYAESIAESIAESCDyCOTJlVvy5c4jGdJniLzCsUQkQAIkQAJeCXz/0xjZtG2LFC1URKpXrqr3gLSXKz7+5guBEHjw8EGveU5q5SdDvjTHHziUsuOTSt9p29OlS2fu7/ny5HVlfdfePYbRF98Pdq3DQq4cucy+mTJlSrA+sR/e0t+9f69J//NvByY4NCXpJ0iAP0ggzAhkDLP8MDskQAIkQAIkQAIkQAJRTuDlx56JcgIsPgmQAAlEHwE7aqPHPfdLsSKXRR+AKChx7py55KNX3varpI91edCv/dx3ypE9h9/p9+j8gPuhXCYBxxOgwOv4KmQBSIAESIAESIAESCCyCHw5YogcOnJY7m1/pxQuUMgUbsb8v+SPOTNl++5dkj59Oil5WQlpdd2NUqtqDZ+F37pzu8AjrFKZ8tKgVl0ZOnaErN20QV7u8YyULVlaVm9YK7/+MUnWb94ouXPlkqoVKku7FrdIjmzZXWmePnNGfpk2UeYvWyT7Dx6QzOpJVK5UGbnlhpZSqWx5135YWLFmlUyYMVU2qgfahf/+kzIlSsnN17eQKhUqJdgPPxBCYeQv4+RfzUP2rFnlqjr1pW2zVpIx48X/nmN48ujfYmXVujVy4tRJqVy2grRo0lQqanncbePWzZrWWHPeLJkzS70ateWaeg3dd+EyCZBAGhP4dOhXph8/fu/DMuKn0TJ36UK54eoYad+yjRw5dlRG/Rprrkmnz5zWa0sFaRnTzFxr3LM9Z8kCmfrXdHMdPHfurBQpWFiua3itNL2miftu6m16SEb/Pl7W6fXu4JFDUkSvozENG5l9M2RIODLi7Llz8l3sKFm88m85deqUVC5fUe5s3V4K5i/gSvPChQsyaeY0mafXQYRRKFWspDSoWfeS8x7Xa9aIn8fKP6tXyHG9ZlUqU0E6tmrrSsfXwryli2T6vFlyVIfXwwaP/k4KFSgo3e/oan4j3TG//ySrN67T6/B+I/7WqlJDr6/NxZYHXqC4xpfV626TBtfIkB9HyJoN6+SZB3vK5VomTztz9ozETvpNFi5frGkelOzZspn9bm3eWooVLmqu+X/MnSXHT54wh341Yqhk1utr7+69zO+de3bJz1MnyMq1/8oRzXfuHDmlpt6Pbr3xZsmrI1DmL1ssf8yd6Qoz8dUPQyVL5iyu45HI5FnTZa7W6fbdO8w9rd4VtaX5tdeb9O2fedpOJs/6Q7bu3KGrLpiy39TkBqmv/BMz1NP4yb/JynWr5cTJkwKPWdwHce/CfcLaSa2n0b+NN/sd1XaIttfs2uvM/dDu882Y72TP/n2mPqbOnmHYoM1WLFNO7mh9m1ymvKwt+HuxthXkd5v89x/yW1SaN24qV9W+0uyCuvxs+EDJpPe6J7s9qu3lR62ntWYb2u07X34s5fUe2/6mNnr/Hm3K3V7vyxkzZpAf9J6ZJVNm6XXvQwJPXWsT/pwiy/5dIY3qNpA61WvKJ9rX4P399AOPmXsj7rOww/r/CqRftkRp0y5xbrxUuK1Fa6lQupxNTvD/jVkL55pteNFQp9oV2h9v1P97pHfts3jFMpmo9/st27fJuf/OmzbT7JoYaXTlVa59uEACoSZw8X+QoT4zz0cCJEACJEACJEACJEACXgis3bhe9h7YJ6c0bh4MD1EQajNljBNXD6lgsUYf9NduWi8QS3yJvCf0wRwP3zCIBxCNYf+pWIGH6q9GDDG/S6sgcETjAk75608jpj6rD/B4QId9/M0AWaFp4MEOgu1ZjcO4fPVKjee3Rvr0ek4fyoub/aarEDDkx+8FQgjE48NHjsg/Kvji2F5dH5La+oBoDQ+4/T7/QLJlzWbEZJQVQgHO0U7FBdgBfdDt1/99wwEid8F8+WXRP0tl2arl8sjd95uHWOwHBm9pWudVUM6pnkuF8heUmQvnmDxiO40ESCA8COCagZc2Q/U68deieSZT/134T/aqcIbrwQENAYDQBBDiFi5fYvp6z67dpUblambfKSrsDh830iwXKVjIXKMQs3TYuB/ktIqVEIRhEPbeGvChEY0h0hYtWESFqq3mWIhZ93W42+xn/+A6iGsj9t13YL8sWr5U87RfXnv8OZegNeC7wQKhES+/ShQtLpu3bzViNES8ru3vMkkhRu1rn7wju/ftNaJrmeKlZNuu7WZofFLhdnBNxEsvXD9huCZaQ57e1Gsh+GTX8xcvUsyUB2VfrkLycw8/KRlVtD55+qS53p8/f87kdZ++kIPZNG169huC+98qCsKjFELlNuUGURbxdvs+8YLW1QmTp//02grbp8KyFZNNnrTOIIhm0xd0OB7lxn0A9683nnpJRVWP47Uc9nik97UKvhARUSYw3aYvJHFf26JsH7i9C3Yx27FfxgwZjdgPARzl7q8C6bnz5+VqfTHozVCfYIb2VrxoMfOiFHWGl5Xbdu2QJ+57xBwGkRb7gT3qv7CK6kv1HoP7zIMqrjeMF2XxEhQvTAeP/ta8JC2q7W/3vj263z+yc89u6ffMy+b+jBcQX2hbQTnLlyorqFe8gMQ63Dsb17/a5Bv3ZbwshSF0xf748BUoE/KSPz58A8J1rFaR/qiK3tUrVZFNmhZediI/FZS5tcnaN1AneJlwXtNA+pY1RGO8nIXhPon082oYKNgmjYuP+r6x0XXmN/58N360eZmRNUtWc3+HkA8BfOPWLfKoepbjPo17MUJvYBli9El9MQK+X48cJngp7PnCxZU4F0gglQlQ4E1lwEyeBEiABEiABEiABEggMAKzF883CWC4Zs0q1c0yxFR49MIDypfAa8+6Sj2YIJrAmwci7QUVVT4Y+Jl6BGWSFx99UkqrEAERYNjYH2TanBny05TfpXO7282DMARaeBq99Uwf41GGNCE2Q3Re/M8y8wCIh9gffvnRpAGPJOQR6cF7atykX2Tkr+MSCLx46G7dtIXxUMJ+8NKFJ/F89WKzAu8Y9b6DyAFvsLY3tjJFwUPr/776xAjJNS6vah6ov9eHUTy0NqhVTx66817zwIkH5jf7v2eLz28SIIEwIoDRAHfe0t54YGbNkkUGjfrWiJedWt0qLXVUAgzC2QeD+ss3Y76Xd5/ra8SqiTOmmW1d2t0h11/d2CxjFALEYYivVuCFJzCEu6ZXN5G723Y01wQIZa9+/Lb8Oe8vsx+EZGvwKn3vhTeMUAmP39c/e9cIqBDw4JkJT0WkD8/OJ7s9Yl5M4YVYPxWR4eHaoNaVZpQCPHwhcuJl1AuPPiUF8uY3Yhs8V/FCLTFDefB5+OWnjDD6ymPPSgFNBzZKr48Qd+tUq2kENoxywERd73zxkREb4dEMD1Fra1RgRRx3XIvxsg1CnadhIi6Iu7i2v/t8X7PPWfWIfvmDfqKFItkAAEAASURBVCpY7jLlbaFestdfda089uqzhucLjzxpPKaRFoRMiLvlS5eVlx592jDG8X0+fEu9cXeaewc8pvHBRJfIL4633PGSEOIuRoPgvgThHHl6W8uE9bieX3F5NZkTf+/r1ukel5g7RsXGn6dNMCKkL4EXZcN9pqZ6OaPOYJu3ow28I5iwbI/GpMWLw9hJvxrBE22no7Y/eMWiDfTTmMND9X5Yu+oVkkXbqDWI5uCFl4k7lNPz/3vNpLV521YjuM5ZHFfPXW+704i5OA73QJwH7QMCr6dBNEX7xOR6hVRk/p+2d2+Geq+ro1NmLphtBFYr8EKwhriL8sAzFxzd7aG77jOeuC9/8Kbkz5tP3te27ssgHCOfEMWf0xe9ubUdwcP53a8/NS9d0Hchetv2fFebDnKDeu3CftN7OO71E2dOpcBriPBPWhBInxYn5TlJgARIgARIgARIgARIwF8CECBgs9Qz1XriQOQY9M5nrofXxNKCiPrg7V3VE66qTtqSUx8Ol5mH35iG1xhxF8fiwbbTzbeaYZ14gMSs29j3WR3e+2KPp13iLva1E/8cOXYEP3XY8mLjwQMvXStAI72b9KEZIgEe1PHwbw2iAsIxwLCfHWprPc7wQDlbPfwgUtxyw032MKla8XKpW72WEQsW/L3EPMhuUI8m5McKOdgZD7EQCGgkQALhR6BJg0ZGkMRLJ3i9Ykg7PO9xvbCG6wiuG7jeLVFBDl6kXW+7w1yPEH7AmvWMhYAIw/cSDbWAUAIQjOFhCMOLrXvadjLnPXn6lFln/9zctLkRd/Eboln+PPnMJns9mqIv0WDwjsSoAxiErzbx16bJf/1h1v397z/mu41e2yDuwuBFeaNHyAGzwc8/8IyEuIxrXBctvw1hg2sjBEkYRme4G6738FIGQ3jnWk9R933AB9dehKfAi0JcczFCpN/TL5v7SlJ5rq2hGHBveFRHU1jG6SSdaxkCe2IGb2xYBw1DYEMC5dT7jb0vICQDzIZSgNAL8Rx22023mDy+pKGGfJm9Z8JDFWIy2g9eZA586xNzLNrbOS072GXXOr1N8wEeMLQBiJjwQP4rXmC250FoCIi7MISxsCNY4N0Ms/mFAIqQGTC8pMS9+tXHnze/A/lzVe24+xru4daWanuHIfxEoDZl9p8miXaaZ7RxGNo8QkTA8EIZZvnC4xse8zC8nEE5++nLYBoJpBUBevCmFXmelwRIgARIgARIgARIwC8CiLWLUAR4mMIHnjqIqYi4tYibm5ThAdY9Du6OXXEPZCvXrtYQDF8kOByCBESXQyqUYBg0HmbhDfXjPz+rZ9dOEw8QQzzdDZ5usNIal9Ld8LCL+ISelk8FFCtUYJv1VIMwAduhQ16xjKGmGEbsbvAOg+1VDyz7AI0YgRAy3A3DWeEVTCMBEggvAnVr1HJlaIfGFIed0ri7GPLtbvY6g74OEbGa9ml4YWL0ALwncS3AsHB3s9cixNx197zEPr6GjeN66m4F8uUzHrOu61H8NQcjGxAqwNqJU3GxaRFiAmavR5XLVbS7mG/ExEUYAgiGyTXLAJ6vNmyOTaNK+bjY5hA+bRgFbMMLNIjjiVlmjeOKl2+/T5+soy/GGi/hUsVKSDV9iQYBHbGNE7MSGponrwr0i3WoPmLjwut3k9YFvHr9MSsK/vrHZJdoiONOxYvvlilEf9x/8Hn27VeMdzT44gWefZno7Xy1VNxGeRCS4z31PoUXM2LM1qpaXRpfebVkVK9ccMM95kKmC9J/2NcJktm1L+4eh7bnbgjh4G64dyF0g20rYLpkxd8mNFHvd/qYextix0N8raXewIFaFb3f416Hdg6GuPctWbHcJBuMl5q2XiD02jAqSNy+oLWhQ/ACAP8XgQf98+/2NSOEUC9XXlFHX8LWDLSYPJ4EUkzg4hU6xUnwQBIgARIgARIgARIgARJIPQJ4kH3rmVdMfEOETMADJYaYzpg/W+BRdLsXEdU9N/BodTdM/gODB5OnN1t510QrF0xcXgx/3qmCbj6NyVu2ZBlpqA/WGC6Mc1s7rrEaYTlzxHk22fW+vq2nlK/tVgiBaOGZP5QFn1w5c5u4m0jDehO5p1fIQ7Rx38ZlEiCBtCNQwO16ZEVSTMro2dcL5CugAlkBM5IAAhrin+K6A+/TChrftJyGH7i6TgP5NnakqzAXr0U5XeuSWkgf77npaz97vcTkb2fTn3Ptli5den1xVtlcG7ESsUdhCDvhbhCnMfR+8/bkC7w2DjvK7Gl4SYZrKURKeOJag2d0UtdY7Hv7ze1MXFeEAFqt8ZERJgAfTNjVS2O7JyagYkLNDwcPMMIfvFhL6JD+WzWUDiYg264hA5IyTHoGA9PzOkGXu4Fprvh7CSbUfPvZV81kbYjpDsEWwiM+16pQe7+GbvBmEPdf6fmshjOYqwLoMhN24Z81KzUu/EozEWgfDYHhanvatjzbXp5ceXQESZ5LRHXUeWKGeLTvPKf5Va9oMMILCPDFB+EkumsYoUAMbQkjXuABDS9eeD2v37LRTORmvYkDSd/ee1EvnoZ6wcsDGMTzd3rH18vqVSrubzFhG+C5jElOe3R+wK826HkO/iaBQAlQ4A2UII8nARIgARIgARIgARJINQIQNjCpSm4VNK2Qi5i3U+fMkB91VvUJ6s3WpllL19BhbxmxQ2jttiLxXkjwAMaxvuzHCeq1q+IuhqtiNnebDjzZ3K1wwTivpj3qEeVuEDx+0Fm6L+i/u9t0dN+U6LL1qMujovJzDz3uc1+I3LDd+g0x2OYP66wnEpZpJEAC4UMgvZtIZvs6JrhKrK9DeIS4C/ESE4BZj33EH3U3m56n5yX2mfDnVPWy3aVxUK8xsV/dj0tsGd7AeKmGydQwLN+XQcTFfph0CyEUrOFFmg0vYNf5+120UJwnLY5HOu4jH3Btxv0BTGxoAKSblAiJfTCZF0S8ivpCD6MdYLiejvjpRxNzePyU3xIVeEfodR1enYh7jvuItVkL5tjFRL/hCYsYuffc2klDJyQc+eF+4HH1es6WLZt0aNnWfBBKYtbCeUbURyghiMp2BIj7cbj3nNPJ5hpfeZWJI4z7AyYrGzhqmIlXO1Pj/Daq19Ackj1r9kTbnnu6SS1DuIa38G0a0qC9hn1AiA2El8BEgBB5EU/eW0zkpNJ1336V3o8h8MJ7Gi9e0QYa1IwL3eC+X0qW0X/2qEd6x5a3Jhj145kWyomXDgg/gbj5COk0b9lCEzMbEySiH0AEppFAqAkk/gom1Lnh+UiABEiABEiABEiABEjAjQAe3p54/QWdfOdJWbVujdmSI3sOuaXpTeZBEdut55jbYYkuXh4/tBcPnHboJQ6AiNKt92Py1JsvGsEUw25hGHrpLp4iXIS7XV6ukvk5V2NF4qHd2l/6EI1J29Zv3pRAmLDbfX1DKMFDO86PCW+swVPtlQ/7SddnHjEzfxdU7z7EUsSwYEz6Yw0P8xjG7WmYIObnqRPUq8s/EcLzeP4mARIILgEImBBDce1B+AVruC69oEO/0dc3bNlkrgXYBk9RK+7it+e1CGFlEMoA8XMxUZu1/YcO6ARQY82kaO7iq92e2Le9Xs7QCdrcbdzEX0z+vtOJHmFVK1Y235NmTXMN2ccKTMRmQw+YHZLxB+ItJnqDZ6VnrF1MagVDWIXk2gb1+nxEJ3R7Uq/1EE1hEPduvr65Wbaew/hhvYHdvYQhYsPg1WkNLx63x4fcsOvw7e14F9P5CZni+ow6xySisBe1DSCfCzXmOgzxYJs1ijGhGvDb0/MW62BjJ/5sjvvi+2/Mb9y/EKbICqGoD7SDyzT0BUakwDvYGu4fb3z2nsmHexuy2xP7fvnDN815ETcZli1rVjN5nn3x4KsdWCdyd8a+zoOJ7TCRH+LPT5s70+zWMD42r69jbB3gJUFi5qtepmrIBtTL598OMoe/oRMRol4gssPgMY0XJ+ifMPf2Y1bwDwmEiAA9eEMEmqchARIgARIgARIgARJIPgE8mNbRycsgYA4cOVSurttAPbbyyXKNSYiHRUwe5BmbMamzQLDF7OLLVi03D7LwCMLkRDgHvJ5axtxoBF0M+cQESOP0YRkP75gMBxMYIR4ibM3GDTo8dJPOLl9eMMEaYg/26/++XKOeURAA4NEDa920hfn29w/KDI+tL74bLO8N/FRuuDpGsmfPrrOf/22GvGLYbuVyFYxwAA/kgSOHyaBRw2WjPvAWUs+wJTp0df3WTZecDrOz44EdzK5Vzy4aCZBA2hLAxF7wdkT4hXe++Fjj5MZINhWLMPwcMXYhXpbTYe+ZMmUyGYUQN2zsD1KqeAnZrrFfp+lQeBgm9bLD4OE5iWtC/+ED5YZrmpiXS+j7EO5wrfPm8WkS8fHnFr1+4aXQ7xq6ANdJ5GejCtLwzEQ4hqZXNzFH4roJMXfR8qXywaD+ZlJLjCSYrsIwvB3PxIdw8HEan6vvatNe48h+pl6ro4xnZHGNu4pQPUt18jmEp8EEYcm1MiVKm1A3Bw4dlPcH9jdxU+H5i4k8YXXc4sUiVAHKPVy9UHEc4qqXLFbcXG8/GfqlXKNhMk6fPSN/ajnt0P65SxYK8gmBGvenQ0cO6/EjNcxP3PGtVEjG/lP++lOOHj8uFcuU02v7Nq3DeTopXGattxiTj7o63B/eqsM1DMcGvabj+v6vvuiEgA8vYJzDm+GeiZd8uH99/cNQKa8hPQ5qHqbN+dPcN2z4iU4apuKjbwbIx0O+kGZ6Trw8wD0CLw7gWYyJSZNjCE+AEBff/zTG3KsQyxhxahEzF+2u5GUltLzHLkkSjGGoj4Ejh+tEb2UlRicj9GYQaxvUulJjzE/Ul6cbjacsYjQnZvalBurB8FDP7euvuvaSQxBbd6ryRl+CSIuXFvCSx6SnmNCweeOm5hjUC/rnqF9jjagPoXzd5g0mhAbOhfApNBJICwIUeNOCOs9JAiRAAiRAAiRAAiTgN4F7dWhwep38DIKCDY+AhzyIqvfptpRYj873C4bZ4iEb3nOwXBrP726dad5ORoQJbrBtscYwHPP7eLMPHtAfved+85C4ZcdWkyfEHXxEZ1NHOAZ4mY36dZzZF4LwHe1u05iBdczv5PyBEIOh3Iiv+fO0CeZQlBnrO7e7w+UVBqEWXswoi515HQ/pT3V7VN4a8GFyTsl9SYAE0oAAJvXKqNc3iGI/aWgAGF7yYAg9hvDD8LLpjtbt5ccJ4zXO659mHa5Xd7XtaMQnCHKjf4s1cU5xTcBkkd+rZ62daBHXjibqYXiniqXJtdwqWL3aq7d8raIxhC98YHhRhGuRDaMAIROxXeE1aicGy6Dl6NjqVhOP1d1LNDl5qFG5mjzbvZcMGfOdicNuj8WLLsSgza8ianItswrmT9//mPGUXbNxncsTGh6nLfW6365Fa1eSCIOAF2j/rl9rPhB47+94j3w67GsjMEJkhOHFHtijHuDZeVWdK43Ai5dwg1S0hNCJD2L/5tRRKH16PWeEeHi7Wo9XDOu/59bbXZ6gOBeEeYTncK/L6pWqyn0d7nLdB1yZjV/AS0yEFYIACXEfHxg8vO/v2NlMuIbfuIf2uvchGfbjiATpY7KwLrfdkWDkCvZPyvBi8px6n+O++ptOYGetqr6owL0a7dqboe0gnv6kmdMMuyPHjvgUeHE8PHYh8ML8mVwN90RM1oqQTmBx6MgRrwIvQn280rO3qRfc9/GBwYv8Hu1ruNfD0CbOqKg/TfsiBG1rmPwV/19xDyVit/GbBEJBIJ3+h/BCKE7Ec5AACZAACZAACZBAcgngoRQW6v+u1H68lDnv0PcGmG/+CQ8CGEq798B+MylNYQ1NgFANgRpiMSIUAoQIDCP19mB28PAhHcZ6SAqpBxLEDhhCMWCG9+JFiplhqDYfSA9ea0jHpKdCS6CG4dVHjh6VwvpwDtHYm6GPIIYkxAB4M9m+421frktbAl2efthkYMlHF4fkp22OeHZ/CITivrBPr29HTxyTIgUKS3aNveppiGmK6052vQ4glAsEMww7R8zP3LlySYG8+RMcgvRwrYKwh+H9gRpij+L8eXLnvuRc7mnDS3O/epkWUw9TiKnBsiPqSbtfvTxxjYMYGwyDVyfShLiHa7av/KLsuK7b7bjW7lLP1LMq9BUtWMQM00d+EC8Yo0sgyrsLmp7H27zjvmbjFvvyrkZ6uPehrhGvGeK+P4Y87ju433h4Q+S0oRK8HYt73GFlAS9hCNCBGGLS7j2wT0XQsya/OLc/hvwi5n42jeOLlxTBtuSkD+aoF7AAc2/3VISHQjnx7f7/g5Tkm/eFlFDjMZ4EKPB6EuFvEiABEiABEiCBsCFg/0NNgTdsqoQZIQESCJAAH+QDBJhGh4dC4E2jovG0JEACaUyA94U0roAIOb13H/kIKRyLQQIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAKRTIACbyTXLstGAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiQQ0QQo8EZ09bJwJEACJEACJEACJEACJEACJEACJEACJEACJEACkUyAAm8k1y7LRgIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkENEEKPBGdPWycCRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAApFMgAJvJNcuy0YCJEACJEACJEACJEACJEACJEACJEACJEACJBDRBCjwRnT1snAkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAKRTIACbyTXLstGAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiQQ0QQo8EZ09bJwJEACJEACJEACJEACJEACJEACJEACJEACJEACkUyAAm8k1y7LRgIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkENEEKPBGdPWycCRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAApFMgAJvJNcuy0YCJEACJEACJEACJEACJEACJEACJEACJEACJBDRBCjwRnT1snAkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAKRTIACbyTXLstGAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiQQ0QQo8EZ09bJwJEACJEACJEACJEACJEACJEACJEACJEACJEACkUyAAm8k1y7LRgIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkENEEMkZ06Vg4EiABEiABEiABEgiAQJenHw7gaB5KAiRAAiQQaQR4X4i0GmV5SIAESCAyCNCDNzLqkaUgARIgARIgARIggbAhsPTjrYIPjQSCSYDtKpg0mVakEWD/iLQaje7ysD1Hd/2z9CkjkO6CWsoO5VEkQAIkQAIkQAIkkLoE0qVLZ07A/66kLudgp856CzZRpgcCbFdsByTgmwD7h2823OI8AmzPzqsz5jjtCdCDN+3rgDkgARIgARIgARIgARIgARIgARIgARIgARIgARIggRQRoMCbImw8iARIgARIgARIgARIgARIgARIgARIgARIgARIgATSngAF3rSvA+aABEiABEiABEiABEiABEiABEiABEiABEiABEiABFJEgAJvirDxIBIgARIgARIgARIgARIgARIgARIgARIgARIgARJIewIUeNO+DpgDEiABEiABEiABEiABEiABEiABEiABEiABEiABEkgRAQq8KcLGg0iABEiABEiABEiABEiABEiABEiABEiABEiABEgg7QlQ4E37OmAOSIAESIAESIAESIAESIAESIAESIAESIAESIAESCBFBCjwpggbDyIBEiABEiABEiABEiABEiABEiABEiABEiABEiCBtCdAgTft64A5IAESIAESIAESIAESIAESIAESIAESIAESIAESIIEUEaDAmyJsPIgESIAESIAESIAESIAESIAESIAESIAESIAESIAE0p4ABd60rwPmgARIgARIgARIgARIgARIgARIgARIgARIgARIgARSRIACb4qw8SASIAESIAESIAESIAESIAESIAESIAESIAESIAESSHsCFHjTvg6YAxIgARIgARIgARIgARIgAR8ENmzYIH369HFtxTLW0UiABMT0BfYPtoRIIcDrfaTUJMuRFgTSXVBLixPznCRAAiRAAiRAAiSQFIF06dKZXfjflaRIhdd21lt41YcTc3Ps2DEZPXq0DBkyRGbMmOG1CI0bN5auXbtKhw4dJGfOnF734UoSiEQC7B+RWKvRWya25+ite5Y8uAQo8AaXJ1MjARIgARIgARIIIgEKhUGEGcKkWG8hhB1Bp8KLnOnTpxtRd8yYMXLixAlTumzZskmzZs3k1rZtze9xsbEyefJkOXnypPmdPXt2ad++vRF7Y2JixLa/CELDopCAsH+wEUQSAbbnSKpNliVcCFDgDZeaYD5IgARIgARIgAQuIWCFGnrwXoImrFew3sK6esIucxiSO3ToUBk2bJhs2rTJlb96detKWxV1mzdvLjly5HCtx8Lx48dl4sSJEqti78JFi1zbypQpI507d5YuXbpIuXLlXOu5QAJOJcD+4dSaY769EWB79kaF60ggOAQo8AaHI1MhARIgARIgARJIBQIUClMBagiSZL2FALLDT+FrSG6xYsWkTZs20lY/JUuW9KuUW7duldjx42W8fnbs2OE6hiEcXCi44DAC7B8OqzBmN1ECbM+J4uFGEggaAQq8QUPJhEiABEiABEiABIJNgEJhsImGJj3WW2g4O+0s/gzJrV+/fopDLCD9+fPnC0M4OK1lML8gwP7BdhBJBNieI6k2WRanEKDA65SaYj5JgARIgARIIAoJUCh0ZqWz3pxZb6mV65QMyQ00LwzhEChBHh8qAuwfoSLN84SCANtzKCjzHCTgnQAFXu9cuJYESIAESIAESCAMCFAoDINKSEEWWG8pgBZhhwRzSG6gaBjCIVCCPD7YBNg/gk2U6aUlAbbntKTPc5PARQIUeC+y4BIJkAAJkAAJkECYEaBQGGYV4md2WG9+goqw3VJ7SG6guBjCIVCCPD4QAuwfgdDjseFGgO053GqE+SEBEQq8bAUkQAIkQAIkQAJhS4BCYdhWTaIZY70liifiNqbFkNxAITKEQ6AEeby/BNg//CXF/ZxAgO3ZCbXEPEYrAQq80VrzLDcJkAAJkAAJOIAAhUIHVJKXLLLevECJsFXhNCQ3ULQM4RAoQR7vSYD9w5MIfzuZANuzk2uPeY8mAhR4o6m2WVYSIAESIAEScBgBCoUOq7D47LLenFlvSeU63IfkJpX/pLYzhENShLg9MQLsH10lJiZG7PU/MVbcFv4E2J7ZnsO/lTKHngQo8HoS4W8SIAESIAESIIGwIWAfFPGgQXMOAdabc+rKn5w6cUiuP+VKbB+GcEiMDre5E2D/WOTCUaZMGencubN06dJFypUr51rPBecQYHtme3ZOa2VOPQlQ4PUkwt8kQAIkQAIkQAJhQ4BCYdhURbIywnpLFq6w3DmShuQGCpghHAIlGHnHs39crFP2j4ssnLrE9nyx5tieL7LgkvMIUOB1Xp0xxyRAAiRAAiQQNQQoFDqzqllvzqy3SB+SG2itgM/8+fNlXGysTJ48WU6ePGmSzJ49u7Rv3166duWQ3kAZh/Px7B+J1w77R+J8wm0r23PiNcL2nDgfbg1PAhR4w7NemCsSIAESIAESIAElQKHQmc2A9easeovGIbmB1hBDOARK0DnHs38kv67YP5LPLFRHsD0nnzTbc/KZ8Yi0IUCBN22486wkQAIkQAIkQAJ+EKBQ6AekMNyF9RaGleKRJQ7J9QASwE8O6Q0AXpgeyv4RvIph/wgey5SmxPacUnKXHsf2fCkTrgkfAhR4w6cumBMSIAESIAESIAEPAhQKPYA45CfrLTwrikNyU7deOKQ3dfmmdursH6lLmP0jdfl6ps727EkkuL/ZnoPLk6kFhwAF3uBwZCokQAIkQAIkQAKpQIBCYSpADUGSrLcQQE7GKTgkNxmwgrQrh/QGCWQIkmH/CAFkj1Owf3gACeJPtucgwvQzKbZnP0Fxt1QnQIE31RHzBCRAAiRAAiRAAiklQKEwpeTS9jjWW9ryx9k5JDft68DmgEN6LYnw+Wb/CJ+6YP8IvC7YngNnGKwU2J6DRZLppIQABd6UUOMxJEACJEACJEACISFAoTAkmIN+EtZb0JH6lSCH5PqFKc124pDeNENvTsz+kbb8kzo7+0dShBJuZ3tOyCPcfrE9h1uNREd+KPBGRz2zlCRAAiRAAiTgSAIUCh1ZbcJ6C229cUhuaHkH42wc0hsMiv6lwf7hH6dw2ov9w3dtsD37ZhOuW9iew7VmIi9fFHgjr05ZIhIgARIgARKIGAIUCp1Zlay31K83DslNfcahOgOH9AafNPtH8JmmVYrsHwy5k1ZtLzXOy/acGlSZpiVAgdeS4DcJkAAJkAAJkEDYEaBQGHZV4leGWG9+YUr2ThySm2xkjjqAQ3oDqy72j8D4hfvR0dY/2J7DvUUGlr9oa8+B0eLR/hKgwOsvKe5HAiRAAiRAAiQQcgIUCkOOPCgnZL0FBaMrEScPye3cpYssXLjQVRb3hXr16smwoUPdV3ld3r5jhzRr1kyGDxsmdevWlX79+snSZctk1MiRXvf3d+VXX30lP2ga06ZO9feQkO3HIb3+o2b/YP+wraVMmTLSuXNn6aLXnXLlytnVjvoO9/b82GOPydp162TC778n4PrO//4nQ/V6/q5+t2rVyrXt1KlTUr9BA+n+4IPy6KOPutYnZ+GLL7+UMaNHy5QpU5JzmF/7Pvf887J3714ZNHCgX/unxk683qcG1ehMM2N0FpulJgESIAESIAESIAESIIHwJRBJQ8zLly8vvZ999hLYefLkuWSdtxXZsmY1Am++fPm8bY7IdTly5JB27dqZj/uQ3k2bNknfvn3Np3HjxtK1a1fp0KGD5MyZMyI5+CoU+8dFMuwfWyV2/HgZrx+n9g8ntWe8mJs6bZocPHhQ3K/J8+fNk/Tp08u8+fMTCLzL//lHzp07Jw0aNrzYaLmUgACv9wlw8EcABCjwBgCPh5IACZAACZAACZAACZBAsAhE6pDc3LlzS6NGjVKMKX/+/PLxRx+l+HinH1iyZEl5rEcP6aHeb/NVPBkXGyuTJ0+WGTNmmE8P3da+fXsj9sbExLgmOXR6uT3zz/7hSSTuN/uHM/uHU9vzlVdeaRre0qVL5brrrjPLhw4dkn9Xr5Y2bdrIAr1GuduSxYslS5YsckWNGu6rueyDAK/3PsBwtV8EKPD6hYk7kQAJkAAJkAAJkAAJkEDqEAj3IbmpU+qLqf7333/y1ddfy7hx42TXrl3GGxUhGV7QobOZM2c2w2cfUXGz72uvSZUqVS4e6Lb03XffyZgffzTH161TRx7U4cBXXHGFa4/NmzcLhhAvWbJEMmbMKG3btpXs2bK5tjthAaFPGuhQZ3xefuklmThxosSq2Ltw0SIZpuEr8ImEIeqedcH+wf7h2Sa8/XZK/3B6e65cubLA4xRhcqzAizA8eNFw1513mmvS7t27pUiRIqaaFus1t07t2uZajhUjRoyQsXqt37hxowmjgZEKt3fq5KrSrvfeKw8+8IAcPnJEvtfrOkRjT4M43u+tt2Sdhop4S0P2FC1a1HgJf/bZZzJx0iSBR3RD9Rju1bOnlChRwnX4YhWbP9V9li9fLnnz5jWhPFwbw2zBKe05zLBFfXYo8EZ9EyAAEiABEiABEiABEiCBUBNw0pDc1GYDcRcP5vdquIHq1asLBJDPBwyQEsWLy/333y9nzp6VFStWyIkTJ7xm5UP17oXAixiPl112mfz888/ygC5DHEB4CIgNt99xhxQuXFh69eolF1RQhsiwd98+yeYwkdcCiPQhvewftqbFvPxg/7jIw5+lcOsfkdSeM2TIIHiJBg9eawjLgBdPeAGHERsYadC6dWuBEIv97lXRFvb+Bx/IoEGD5A69HuN6D2EYIWf26DW6p4qxsJUrV8rMWbNktMbcRTiIMmXLyr79+802/EGar+rLvt9++02+1jjqEHdhTzz5pBFuIQ7juv7d999LN71//KDXeoSSWKaC9L333Se1atWSF194QQ6q1/FAjbt75swZqVq1qkkjXP+EW3sOV07MlwgFXrYCEiABEiABEiABEiABEggBAacOyQ0UDbylGjdpckkyf2gcR4gF0/T7pptukqeeesq1Dx788aCflG3fvl2GDBkiH334ocubDBP83HX33TL4m2/kzTfekG90+/nz52WofsNrC4Z9Wug5I8EiZUgv+0fC1sj+kZBHSn+lVf+I5PYM4XXAF1+Y6yqu4fM0/m7ne+4xMXiv1G1W4F23fr0cUU/cBvXryw6dLBOjDB555BETbgb12bJlSyMIDxo8WDqpF6/1+v1exVnsWzN+FIb7RJ3w3P1dJ3jDpGh2lMbcuXNl+vTpEquewXipB2vevLm0uvlm+XHsWLm/Wzf5/PPPpXSpUkYUxsgQ2HUa0qb1LbeYZaf8Sav27BQ+0Z5PCrzR3gJYfhIgARIgARIgARIggVQl4PQhuYHCKVyokHTs2PGSZDAEFTZq5EjXtv3qqYUwCitXrZJ6deu61vtaWLBggdlUsGBB4+Vr98ODP0I+QOCF2IAHeSvuYh94mbVo0cKIAvYYp387dUgv+wf7Ryj6Xqj6RzS0Z8Th/UBfqq1es0aK6MgIhEpASAQYPHmHf/utWUb83ezZs5uRGb+qx+1ZHY1xp3rvutudGtYBozgWaagZCL6wptdf7xJ37b4XdOHdd981ozVee/VVl7iL7bPnzJHiOuLj1KlTCe4DGBEyZcoUI/DO13tF9+7dXaEicFxZ9Q62MYXx20kWqvbsJCbMKz142QZIgARIgARIgARIgARIgARSkUARHUKLmLi+bNu2bdJfvav++usvMzN7hQoVjADra3/39Vu2bjWiQafbb3df7VrGAz/i+jZp3Ni1zi5AEKCRQFoTYP9I6xrg+ZNLACENsmbNKkv1ZVw+jb1brFgxV6zbBir0wst2586dgvi7COeAuOfw4IXYi1i97obQOZkyZTLb7fqKFSvaRdc30kPsXnjoDhk61MTmtZ64W/U+sGXLFung5UUiwvZgErjTp0+bfLoSjF8ornnfqfcIGglEAgF68EZCLbIMJEACJEACJEACJEACYUugXLly8prGDHxVvY4wjBQhBcaMGWMmx8IEWW/qJDGYVOxWnfirvg5ltZ6tYVugIGYMHl2YVAdDc/trHN7LL7/cPOz3RKxcjbWYlBUsUMCIBhMnTPC6K2Zvh6CACXs8DUOHI8nAC97K43TitcmTJ8vJkydN8SCqtG/fXrpqzMsY9WQOt/bF/uG7FbJ/+GaT3C2h6h/R0J4hyNaqWdNMtJZDry8N1WvXWkV9QYdrLjxmMRrDjt5AHFzEUcdLN4jD1o4fP25e0uXV7dYwwsLTcMwQDbtz7tw5wQs9eP320Mk3YQX0PlBF7x1faUxeT8P1LleuXEZkPnL4sOdmOXL06CXrnLAiVO3ZCSyYx4sE0l9c5BIJkAAJkAAJkAAJkAAJkEBqEcCDJmYdH6reR5j4a7DGHWysnqUQ4n766SczAUyzG280s3zDIykaDDOpw7PrUY3LWKNGDSPuotzw6vXH4EkG0QChHfCQbz8mRqPyBXPsM3PmTBMv0j3NP//80/2nY5fRVjAzPNoOJhFCW0KbQttCG0NbQ5tD2ws3cdcdOvuHO424ZfaPS5kkd01a9Y9Ib88IbYAJ1OZq/F0bnsHWDWLu/vbrrwL2WIZhAjaY53UXLz1hVeO3mx9e/uRXAbhy5cpSrVo1E+bhaxV412uMXxiO3awevPAUtvcAfH+jgvAvmg/ECa5UqZJM97jm4zqJ+MFOsrRqz05iFM15pcAbzbXPspMACZAACZAACZAACaQJgZw5c5qZxfGwi4fUV155RcqUKWPEzgEDBkhzjQ/buXNnGasTxMDDKVLNemrNUAEW5dyuYm8/9Wj+999/5bAOq8UM54kZZkTHEOCnn3nGzJJ+WD20EHMRs7Vb0eFe9VyFiPziSy8Z4RhDfd94801Zu3ZtYkmH9TawQttAG0FbQZtBGdGG0JbQptC2MHs92prTjP0jrsbYP1LWcsOtf0Rie8ZEa3gRt3nzZhN3172mEId35qxZ5tpjhV1MmHbVVVeZESt44XZUPWf/nDFD3nr7bbm2USPzIs49jcSWe+kID3gE99FRMfBkvVknU0NfefLJJ2WtxgPGC78fNLb7sOHDpfG115qkuulEa7Nnz5ZPPvlE9u7dK5s2bTL3jWPHjiV2qrDYFm7tOSygMBNeCaTTDpH02Cevh3IlCZAACZAACZAACaQuAettxv+upC7nYKfOeksZUbRz9xAO8EyFZcuWzbEhHDp36WI8Z7+Ln3THGxl4nw7UGdExHB1DfxFOoLyGtYAIe//995vZ1RHCYrjOql5XJ16DALx02TLX5GwHDx40oibEAgzfLV26tLRq1co1fBfnxLa+ffuauJD4DQGiunqCYeKfaVOnYlXYG9qHE0MwBAss+wf7R2JtyWn9w+ntGTFt6+t1tFSpUvKzjhpwt00q+mLCNISE+bx/f9cmiLqv68SXEydONNd7xNBt0by5vKQv3+yLKKTZq2dPueuuu1zHffHllzJm9Gjz8s6uRBiaXo8/Lq/26WPCQEBofuHFF41XMdhCWL69Uyfp0KGDPURGquj70ccfC14Epk+fXm7W+8S58+dN7PdBeg8KJ3Naew4ndtGcFwq80Vz7LDsJkAAJkAAJhDkBCoVhXkE+ssd68wEmGavhVTRaH2gRr3eGipPWMJlNmzZtpK1+SpYsaVc7/hseSvC6QvkwzBYGLyt4adnfSRUS3r4QexHP15chTQjmVkzwtV84rceQ3Njx42W8fuClaw0hGBBXFwKGk8pj8x/IN/sH+4dtP5HQP6KtPeNFHELH4Frt7/Xd1ndS33gxik/BggV97opRHLi3uMcC9rlziDdEQnsOMTKezo0ABV43GFwkARIgARIgARIILwIUCsOrPvzNDevNX1L+7bdhwwYTQ3WYerBiWKm1eurN2lYnZmuuHlA5cuSwq/kdAQQgeMPLLVYnTMNEfNYQggFhGbqoZzQmc6KJsH9EXyuI5P7B9sz2bAnwem9J8NtfAhR4/SXF/UiABEiABEiABEJOgEJhyJEH5YSst6BgvCQRpw/pvaRAXJGAAIfkJsCR7B/sH8lG5qgDoq1/sD07qnkmO7PR1p6TDYgHpIgABd4UYeNBJEACJEACJEACoSBAoTAUlIN/DtZb8Jl6phhtQ3o9yx9JvzkkN/i1yf4RfKZplSL7hwjbc1q1vuCfl+05+EyZ4kUCFHgvsuASCZAACZAACZBAmBGgUBhmFeJndlhvfoIK0m4c0hskkCFMJpKHmIcQo1+nYv/wC1NY7cT+4bs62J59swnXLWzP4VozkZcvCryRV6csEQmQAAmQAAlEDAEKhc6sStZb2tQbh/SmDXd/z8ohuf6SSp392D9Sh2uwUmX/SB5Jtufk8Qr13mzPoSbO84EABV62AxIgARIgARIggbAlQKEwbKsm0Yyx3hLFE5KNHNIbEsx+nYRDcv3CFNKd2D9CijvRk7F/JIrHr41sz35hCslObM8hwcyT+CBAgdcHGK4mARIgARIgARJIewIUCtO+DlKSA9ZbSqil3jEc0pt6bH2lzCG5vsiE33r2j9DXCftH6jFne049tr5SZnv2RYbrQ02AAm+oifN8JEACJEACJEACfhOgUOg3qrDakfUWVtXhygyH9LpQpMoCh+SmCtaQJcr+kbqo2T9Sl69n6mzPnkSC+5vtObg8mVpwCFDgDQ5HpkICJEACJEACJJAKBCgUpgLUECTJegsB5ABPwSG9AQJ0O5xDct1gRMgi+0fwKpL9I3gsU5oS23NKyV16HNvzpUy4JnwIUOANn7pgTkiABEiABEiABDwIUCj0AOKQn6w3h1RUfDY5pDf59cUhucln5tQj2D+SX3PsH8lnFqoj2J6TT5rtOfnMeETaEKDAmzbceVYSIAESIAESIAE/CFAo9ANSGO7CegvDSvEjSxzSmzgkDslNnE+kb2X/SLyG2T8S5xNuW9meE68RtufE+XBreBKgwBue9cJckQAJkAAJkAAJKAEKhc5sBqw3Z9abe645pPciDQ7JvciCS3EE2D8utgT2j4ssnLrE9nyx5tieL7LgkvMIUOB1Xp0xxyRAAiRAAiQQNQQoFDqzqllvzqw3X7mOxiG9HJLrqzVwvScB9o9FLiRlypSRzp07S5cuXaRcuXKu9VxwDgG2Z7Zn57RW5tSTAAVeTyL8TQIkQAIkQAIkEDYEKBSGTVUkKyOst2ThcszOkT6kl0NyHdMUwzKj7B9dJSYmxjXyJiwriZnymwDbM9uz342FO4YNAQq8YVMVzAgJkAAJkAAJkIAnAQqFnkSc8Zv15ox6CiSXkTSkl0NyA2kJPNYbAfYPb1S4zqkE2J6dWnPMd7QRoMAbbTXO8pIACZAACZCAgwhQKHRQZblllfXmBiMKFp04pJchGKKgYYZJEdk/wqQimI2gEGB7DgpGJkICqUKAAm+qYGWiJEACJEACJEACwSBAoTAYFEOfBust9MzD4YzhPqSXIRjCoZVEbx7YP6K37iOx5GzPkVirLJPTCVDgdXoNMv8kQAIkQAIkEMEEKBQ6s3JZb86st2DmOpyG9DIEQzBrlmkFgwD7RzAoMo1wIcD2HC41wXxEOwEKvNHeAlh+EiABEiABEghjAhQKw7hyEska6y0ROFG4KS2G9DIEQxQ2NIcWmf3DoRXHbHslwPbsFQtXkkBICFDgDQlmnoQESIAESIAESCAlBCgUpoRa2h/Dekv7OgjHHKT2kF6GYAjHWmee/CXA/uEvKe7nBAJsz06oJeYx0ghQ4I20GmV5SIAESIAESCCCCFAodGZlst6cWW+hzHUwh/QyBEMoa47nCgUB9o9QUOY5QkWA7TlUpHmeaCdAgTfaWwDLTwIkQAIkQAJhTIBCYRhXTiJZY70lAoebLiGQkiG9DMFwCUauiFAC7B8RWrFRWiy25yiteBY7JAQo8IYEM09CAiRAAiRAAiSQEgIUClNCLe2PYb2lfR04MQf+DOlFucbFxsrkyZPl5MmTppjZs2eX9u3bS9euXSUmJkZs+3MiA+aZBHwRYP/wRYbrnUiA7dmJtcY8hzsBCrzhXkPMHwmQAAmQAAlEMQEr1OBBgOYcAqw359RVuObU15Be9/w2btzYiLodOnSQnDlzum/iMglENAH2j4iu3qgrHNtz1FU5C5xKBCjwphJYJksCJEACJEACJBA4AQqFgTNMixRYb2lBPXLPaYf09u3b1xTylVdekS5duki5cuUit9AsGQn4SYD9w09Q3M0RBNieHVFNzGSYEqDAG6YVw2yRAAmQAAmQAAmIa6g1PXid1Roo8DqrvpySW7Yrp9QU85kWBNg/0oI6z5laBNieU4ss041kAukjuXAsGwmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAlEMgEKvJFcuywbCZAACZAACZAACZAACZAACZAACZAACZAACZBARBOgwBvR1cvCkQAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJRDIBCryRXLssGwmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQEQToMAb0dXLwpEACZAACZAACZAACZAACZAACZAACZAACZAACUQyAQq8kVy7LBsJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkEBEE6DAG9HVy8KRAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAlEMgEKvJFcuywbCZAACZAACZAACZAACZAACZAACZAACZAACZBARBOgwBvR1cvCkQAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJRDIBCryRXLssGwmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQEQToMAb0dXLwpEACZAACZAACZAACZAACZAACZAACZAACZAACUQyAQq8kVy7LBsJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkEBEE6DAG9HVy8KRAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAlEMoGMkVw4lo0ESIAESIAESIAESIAESMCZBAYNGiTz58+/JPPdu3d3ratfv75069bN9ZsLJBAtBNg/oqWmo6OcbM/RUc8sZeoSSHdBLXVPwdRJgARIgARIgARIIGUE0qVLZw7kf1dSxi+tjmK9pRX5yDrv9OnT5brrrku0UH/88YfExMQkug83kkAkEmD/iMRajd4ysT1Hb92z5MEjwBANwWPJlEiABEiABEiABEiABEiABIJEAMJtkyZNfKaGbRR3feLhhggnwP4R4RUcZcVje46yCmdxU4UABd5UwcpESYAESIAESIAESIAESIAEAiXw6quv+kwisW0+D+IGEoggAon1gcS2RRACFiWCCCTWZhPbFkEIWBQSCIgABd6A8PFgEiABEiABEiABEiABEiCB1CLgy6uL3rupRZzpOokA+4eTaot5TYoA23NShLidBBInQIE3cT7cSgIkQAIkQAIkQAIkQAIkkIYEvHlueVuXhlnkqUkgzQh46wve1qVZBnliEkgGAW9t19u6ZCTJXUkgaghQ4I2aqmZBSYAESIAESIAESIAESMB5BDy9uui967w6ZI5TjwD7R+qxZcqhJ8D2HHrmPGPkEKDAGzl1yZKQAAmQAAmQAAmQAAmQQEQScPfgcl+OyMKyUCSQTALufcJ9OZnJcHcSCAsC7m3YfTksMsdMkEAYE0h3QS2M88eskQAJkAAJkAAJRDGBdOnSmdLzvyvOagSsN2fVl1NyC88u2PTp0803/5AACVwkwP5xkQWXnE+A7dn5dcgShJ4ABd7QM+cZSYAESIAESIAE/CRAodBPUGG2G+stvCqk9uOlwitDKczN0W2nzJG5SmRNYQo8jARIwCkElny0xSlZDSifkXJ9DghCFBwcLe05CqoyrIuYMaxzx8yRAAmQAAmQAAmQAAmQAAmQgBKgsMtmQAIkQAIkQAIkQALeCVDg9c6Fa0mABEiABEiABEiABEggoggMfW9ARJWHhSEBEog8Al2efjjyCuVHiejh6QckB+5CD20HVpqDs8xJ1hxcecw6CZAACZAACZAACZAACZAACZAACZAACZAACZBAdBOgwBvd9c/SkwAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJOJgABV4HVx6zTgIkQAIkQAIkQALhRGDDhg3Sp08fV5awjHU0EiABEiABEiABEiABEiCB1CNAgTf12DJlEiABEiABEiABEoh4AseOHZNvvvlGmjRpIuXLl5e+ffu6yoxlrMM27IN9aSRAAiRAAiRAAiRAAiRAAsElwEnWgsuTqZEACZAACZAACZBAxBO4cOGCTJ8+XYYMGSJjxoyREydOmDJny5ZNmjVrJre2bWt+j4uNlcmTJ8uMGTPMp0ePHtK+fXvp2rWrxMTESLp06SKeFQtIAiRAAiRAAiRAAiRAAqlNgAJvahNm+iRAAiRAAiRAAiQQIQQQbmHo0KEybNgw2bRpk6tU9erWlbYq6jZv3lxy5MjhWt+gQQN5+aWXZOLEiRKrYu/CRYvMsTi+TJky0rlzZ+nSpYuUK1fOdQwXSIAESIAESIAESIAESIAEkkeAAm/yeHFvEiABEiABEiABEogqAgirMHr0aOOtC09ca8WKFZM2bdpIW/2ULFnSrr7kG4Jvu3btzGfr1q0SO368jNcPBGKEcMCncePGxqu3Q4cOkjNnzkvS4AoSIAESIAESIAESIAESIAHfBCjw+mbDLSRAAiRAAiRAAiQQlQT8CcFQv379ZIdYgBD8mIZp6PHoozJ//nxhCIeobF4sNAmQAAmQAAmQAAmQQJAJUOANMlAmRwIkQAIkQAIkQAJOJZDcEAwpLSdi7yJ8A0M4pJQgjyMBEiABEiABEiABEiCBiwQo8F5kwSUSIAESIAESIAESiDoCgYZgCBQYQzgESpDHkwAJkAAJkAAJkAAJRDsBCrzR3gJYfhIgARIgARIggagjkFohGAIFyRAOgRLk8SRAAiRAAiRAAiRAAtFIgAJvNNY6y0wCJEACJEACJBCVBEIVgiFQuAzhEChBHk8CJEACJEACJEACJBBNBCjwRlNts6wkQAIkQAIkQAJRRyCtQzAECpwhHAIlyONJgARIgARIgARIgAQinQAF3kivYZaPBEiABEiABEgg6giEawiGQCuCIRwCJcjjSYAESIAESCCOwMvfPSG/LPjxEhzp06WXInkvk6olr5AHWzwulYpVuWSfpFZs2r1e9h/dJyULlZbCeYomtTu3kwAJBIEABd4gQGQSJEACJEACJEACJBAOBJwSgiFQVgzhEChBHk8CJEACJEACcQTyZM8rl+Uv4cJx7vxZ2bZ/i0z9+3eZtWqaDH18vFQuXtW13Z+FwVP6y88Lxkjv2/rK7dd29ecQ7kMCJBAgAQq8AQLk4SRAAiRAAiRAAiSQlgScHoIhUHYM4RAoQR5PAikjcOzEcdm9d4+cPXdWCuUvKPnz5hO8fKGRAAk4i0CT6s3ktTvfT5Dpk6dPSLdPO8iqbctl5Mwh8srt/0uwnT9IgATCjwAF3vCrE+aIBEiABEiABEiABBIlEKkhGBIttB8bGcLBD0h+7vLViCHy16J5l+wNAQ9CXtkSpaVNs5ZSqthFr69Ldg5gBcTDbTt3SPZs2YJ+jjUb18t///0nFUqXlYwZfT8OzVo4V77+YagpRc+u3aVu9VoJSnT46BHp+Vpvs+6LNz6UbFmzJtieWj/8zX9qnf/QkcMy4qcxMm/ZIsG1yBraQoeWbeWKy6vZVX5/79i9U55/t6/ky5NXPnr5Lb+PS60d0T4Gj/5WFvy9WP7TMt7VpoPENGiUWqdzbLp79++T/YcOSsF8+aVg/gKOLQczfimBbFmyS+3y9Y3Ae+DY/gQ7LFw7R4ZO+0KWb14iBXIXloaVGsnDLZ+SnFlzyXb1/H195HOyftcac8wPKg5PXz5JHru5t2TKmFk+iH1dShYsIy927OdKc9+RPfLSt49Ljqw55f37vjLrnx7cXY6dOiof3j9I3o/tKxMX/ySdGnWRZrVayYc/vSk1y9aVG2u3ls9++Z8sXD9X4IXcpn5Hua/Zo5IhfQZX2lwggWgi4Pt/NNFEgWUlARIgARIgARIgAQcQiJYQDIFWBUM4BErw4vE5s+eQAireWDt//rzsObBPFi5fIstW/SOv9Hw26AIszrV+80b5YFB/qVS2grz46FP29EH5fn/gp3Lq9GkjJEJQ9Me+HTdKqlesIlmyZPFn91TdJyX5D1aGTp46Jf/78mPZroJs4QIFpVqlKnLmzBlZu2m9bNmxzdTZ4/c+LLWq1gjWKdMknblLF8rMBXMke9ZsUrNKNcmbK3ea5CPcTzp1zgz5ffpkueWGlnJbi9bhnl3mL5kE5q6eaY4oX7SS60jE7H11xNPqrZ9eqpSoLnsP75bvZwyWhevmyIBHvjce/Zv3bDDiLA46cHS/nD5zSk7p5+SZkzJvzSw5fOKQKz0snDl72qyHSGttkYq2h44flH6jX3DFCT5/4bwcOXnY7IttY+eMkNx6TK54Yfnz39+TLJmzSufrHrTJ8JsEoooABd6oqm4WlgRIgARIgARIwGkEoj0EQ6D1xRAOgRGsXe0Kub9T5wSJnFZxtN+AD2TTti0yZdZ0ua/j3Qm2R+KPA4dVTJj0i9zR+rZILJ7fZVqy8m8j7hYpWFjefPol9cjL5Dr2HRV+V679V8b8Pt7xAu+W7VtNuZpe3UTat2zjKiMXSCASCew+tFP+/Geyq2gQT6f9PUE2qBduzmy5pdO1Xcy2IyrM/m/sq5I1Uzb5ptdYqVgiKEwhAABAAElEQVTscjMa4o1Rz8m4uT/I4Mn95elbX5HfX50rr3z3pInB+4h69toYvAvXzXWdw9+FSUt+kafbviLNat8s2bPkkFVbl5tDV29fIb1aPy9dmz5s8vDOjy/LqL+Gy6QlP1Pg9Rcu94s4AhR4I65KWSASIAESIAESIAGnE2AIhtSpQYZwCA5XeLHCsxYC75FjRxMkumrdGvlt+iTZsGWT5FGvx2oVL5d26tmXTT0hrW3evkV+mjJBVm9YK/AIhYfwNXXrS6vrW0jGDBlk4Mjhgn1g23ZuFwiHV1SuKjfFNDPr5ixZIFP/mq5C4y45p/FfITZe1/BaaXpNE7Mdf/oPHygI89CzS3cZ/VuszFk8XyqUKSfn1AP5tHqcwj7/dpDJ15PdHjG/ff0pUbSYSWvSzGmazwZJeiyj/074c4oO718iO/bslNLFS0qDmvXk+qsbm1PAO3nMhJ8kb+480v2Orq7TIp8btm6Wq2rXk8b1rzHrkdePvhkgmNW+Qa06MmfJQp/5x3knz/pD5i9bLFuVG9JHGIr2N7UxoQ/siQZouY8cPyaPdX5Qxk/5TRYtX6r1cFIql68od7Zun+hQ+117d5tkTp0+dckwaIQxmK1hPeBBjxAH6dOnN/uiHiD6IrTE/oP7pXiRYlKrWg25+brmrn1s3uz3+Mm/yb/aPq6sUdvFDdtQfx8N/lzOa/qP3t1NcubIaQ5B3cDrFqEeECriyivqSLNG19nk5M95f5ntLRo3VW/BM6ZNoO19+mrCuKLHlEt/5bNrT1w55y1bKOu3bpK723TUutkks7Ud3ajp4vyjfh0nx7Vs/fu+Z87zx9yZ2s4WyFb1ZM6VM6eUK1lGblP2hdxCFwwaNVz2HTwgXW+707Bf8s8yyaqhPZBfvDz4d/1a+Wnq77JZ+1blchWlYe0rtd7rusrhuYD+N+C7wVIoXwHtHzfIt7GjTT7R9y7X+uzY8lYT5sT9OPSt2Em/mf4LFmVKlBII2XWq13TfTdvRIpk08w/Ztmu71ucFrbei0lz5IU/HT56Qz4Z9Lbv37THHzF48T9Zt3qB1eqPx6k6QEH+EPQF41eLjaRB3+3cfJoXzFDWbflsUK0fVgxaiKsRdGPr5E21ekvHzRqnIO0JDMTwrWTIFL1xNu6vukLti7jfncv+TO3seuSfeUxd5aFbrZiPw7jyw3X03LpNAVBHIGFWlZWFJgARIgARIgARIIIwJMARDaCqHIRwC57xizSqTSPGil7kS+0tj1g5UAQt8yxQvJQePHJJJKjiuWr9Gnu3eS3LnzCW7dFKuN/t/oCLlaRXiSkqhAhlky/ZtMnbiL7Jb43k+eHsXFcD2y8HDcUN4z5w9q8fsNiIpTjRFhd3h40aacxYpWMiImBCTh437QU6rWNUyXgRes3GdIFbscF1vYwlDLN2r4SVs3Ni9+/dK1ixJCxHY5+brm8sX338jQ38cIS/1wPBk35OJ9R/+tRF3Ed6iRNHiRkiDcLdt1w7p3O52uaxwURXy1hgRFKIeuMCmz51lhOT0mrYVeFEOeMVCUIcgCRa+8v/xkC9kyYq/VXhNb3jtVSERcYSXrlwuvR963CVMr9Y0wfeL7webUBiInQouEHr37t8vrz3+nE/htULpciaviD/89hcfSeumLYyQCE9eCOEdW91qtts/iNH65ufvm/PlyJbdiLtbdmyV9Vs2yj+rV0rv7o9LBhX1PQ15WjnxZ8F5rDCOfVYrt+V6HERzK+5+qfUC4TW7pg/eCBWxesM6892t4z0m6d379hqOCLWAFwRgiPrxNAi3YAwBE3ZUBV+IyphIbo+2F9RFHq0viMlIw8ZdtnmA0IS8HdC4tDjP0lXL5ekHHlOhPY4bRNAd+mLi06FfmpcjCBGCcBcTZ0w1x6CucqlonSd3blm8Ypn54By+4hojX8gT2tCyf//RFx7npJi2LzD+Y84u+VdfuLysYVTAHgbxH/WOUCsIsZFDh7f/o30Zn7Y3tpJbb7zZ7AeeKBPqpnypstouj5mXDxCTcY6aGoIDnE7Eczp2/Lhpz2ijNOcRqFS8qsToRGvW9h3ZK7NWTpM9h3fJc0MfldG9J5v4uBt2rTW7zPl3hmzas97ubr4zZsgkJ04fl4PHDkjRfMUSbAvkx/VXtPB6eLH8JRO8ZLLnvHDhP6/7cyUJRAMBCrzRUMssIwmQAAmQAAmQQNgSYAiGtK0ahnBInD8mUIJoaA2C16J/lhpRCvFJb7gmxmyCJ+O340dL5kyZjQBa8rLiRvAZMuZ7+XP+X/LLtAly5y0dNK1lRtyFJ+yD8d6r8Pp9+4sPjfcnBM/nVIxEfF/E4C1XSifjcYvBO3HGNHO+Lu3ucAl/8ATu9/kHMk9FNyvw2vzOW7pIOt3czngdZs2cxXgzdn/xcRODt0+v5xJ4ttpjvH1fVae+TJszU71Q1xlv0JiG3ifcWqheu/Dchffk4/c+YgRAiJTI39TZf2o+6hmxtrIKthC+kXd4b8LzFJ6uEAjXqYev9YBdtW61yU5tFdTgPYmPt/yj7Kin/HnyyfOPPKHiXSEjQH4z5juT329jR8kLjzyZoGgQ5d574Q2Tx3WbNsjrn71rhEF4ZUKE9mYQGlF3EM2Rd3wyZ84sVcpXkhqVq8nVda5U0fCicDry17FG3L3yitry0F3djIc2hPe3B3xoRFgwbdYo5pJT1alW04R/2K6iOMRZiPmwJSqAwhrUqme+0U4gRkJAfer+HqZ+0Ubf0vRnzJ8tDXU/xAm2BtG1uv6+XdtEbi9xdeH5+uFL/cxLBLxMaKkeqbc0vckcjnYPg7hbtUJlueOW9sZL3eYBIutzDz0h9qXH9zoRHYRbvJB4Vdua+0sB9JN3n39d44Vmll//mGS8gTGhGwRziKwQVj9RwX6Revj+s2alT4HXZEj/wJO3eqWq0uveh7QPZjK/IcCD32T1woV4C6/rb2NHGnEXLxrgtQtbqW3sg4H91av+d/U0ryvFilxmPN6x7b72d0mjK6/Cor6E+VngWT1R08M6cPrhl7EmBu+N117PGLyGkjP/XF68mjx801MJMn/g6D5p82YT2Xlwu0xe+qu0bdjJeO9ipzPnTsvxU8cS7I9Jz2D//Xc+wfpAfxTJ610sxqgGGgmQQEIC7BUJefAXCZAACZAACZAACaQ6AXh+/fHHH9KlSxcpUqSI3HfffTJjxgzJli2b3HLLLfLN4MEyeZLOOt2jhyCsAC00BGwIB7BHHaAuUCeoG9QR6gp1hrqzXpShyVnanQXegQgRYD8YYg4vQ4i7Tz3QwyWQztah6fDma6phCCDuwiBW3q6CLYQtDJGHN24WFVlhEAbh1Qohs0qFSjLonc9k4NufevWqNAfoH+zb9bY75NkHe0qTBnEhDLDNzpgOIdXTrr2yoRF986unZHaty0Dsnls7mbJgaL5naAqbLkRBWMdW7VzenRANIdzBEEIBVrNKdfMNBjB41cIgJEOIg1cnDOIbLKlJy+D9C2tzY0sj7mIZ3O9SUR11Bd7wnna3m5s2d+UR4SsgDsMQQiAxe0C9rJ/s9qjU1SH98G7GJGsQOSEePtXvJfWwXWEOh+gPsRtiZedbbzfiLjYgdIT19P1zXly+Pc8Hr1Vb5sXxwir2QQxgGIRImOXdoWVbV/3CA7aNTvoFmzxruvm2f+C1i9AUJbSNWs9pu83fb3jDPqahP9DOkYYtQysVg624i7RQRtQ9Qpls2r4lQfLNG19vxF2sdPfOvVaFU+vRXKXC5eaYg4cPJzjW148brmlixF1sR746xXtTw4sbhn6LPoKXJlbcxXqI1Y20n6B/YWI5mO2nCAli20275q1NP+3Tq7fZx9cfhH2Ah7j7x1vf9HU814cHgfy5Cso1VWJMZrbs3Wi+SxQsbb5vqd9Bvnr0B6+fYgV8/58lY/o4b/0jJxK26aOnjpp0vf3BiAQaCZCAfwTowesfJ+5FAiRAAiRAAiRAAgETYAiGgBGGJAEIYw0aNDCfl196SSZOnCixsbGycNEiGTZsmPmUKVNGOnfubATfcuXKhSRfaXESxDPFRGvWINRAzIN4gxi2bz71shEJ4YEKW756leyMj19qj0Fc3VM6MdvR40dNPNEJM6YYr8y3dKI2iGUQF2tVvUIa1WvoEgHtse7fEIzhjYkYovCM3LFnlxFCN8dPiOW+r12uW6OWXQz4Gyyuv6qx8cSF56IV0NwTtsLs+Mm/uoRnbLdD/vdoyAIYxEukgVANMMSnRYiBppo+Ql2s1d8F8uY34iCG0sOrMjHbqSxg8KR1N8RLLluytKxQoR77FC1U2LUZXr7uViBfPsFkckm9vED/gECND4b6r1XvX4QTQL7hhfzZsIHGu3OnDuGHIWSAp7csRH0YhvlDWPRmiPUKr1Z4sSL+MkJc7Duw34QMQAgHmOUND3G0CWuIKQzbo6En3A3tB0wCsaoVK7uEcaSzI769X+7BHu2+YpnysnD5EtMnypaIE8dwDOrWmg2fAE9oxJO2Bk9cWFL1gX1QJ/AadzebH4Q8QT3ZfunZRnBMlfKVNaTDTNc+NzW5wQjC8B7u/U4fEycbMYEhrFvh3f1c7ssQ9b8aMcR9lTn+gxffTLCOP8KfQKH42LsHjsX1o3oVrpKBkz6VXxb8KHc16aZe9plNIf7ZvFTu/eQ2uUxDM4x/cYZpj/rHbDtz7oyroDaW744DW2XXwR2uUA6zV0137RPMhV8XjjXnQTiHm+pyssRgsmVa4UmAAm941gtzRQIkQAIkQAIkECEEGILB2RUZ7SEcEE8UnnvudkRF3mdV9Nmvnp4L/l5k4sXaWJyICXpSPVDdrYKKXDBM1ITh+68/8aIJ2wCPQsRihWCMzxT1bn2pxzMuT0z3NLAMoWvw6G/N0HuIYRU0Nmg5FS+vrtPAeI967o/f+fNcFNK8bU/uutt0wjiEQ4CYWfPyOC9c9zSssAhBG4K0NSxXUU/J/HnjvGQRAgECK0RLTOy1Rj1sIQZiwiuUba3Gas2bJ48pM8TvpOyUxjSGYei/p9l1dh+7HbF+k2vwiEWMy3oaVgJe0fA2hbCIT7NrYuTpt142Hsjw4rUxblEeT0PMXhji2573MaS7ZpVqxkMYcWvR5pZa710Nc2HNtjvEV0ZaLtOygTfi5bpbgXj+7uuSu5zfTZzFsae1rmHeymlFWrQHd4Mg62meQ8697OJ5iOs3vJbdJzLEBpwb7Q4COrxqbf3b9uA6OH5f/Lb7lNfJ+d7p/aoRff9Zu0rjZG81IVQwiZ57eBX3NOwyhO2sHiI6QlHQnEcgZ9a4/rPvSJz3f4NKjaRh5cYyd/UMI+i2qHOL7NVtvy+M1f53Vrpe/3CcuKtFLZQ77mXFyJlDZd/h3Rri4XYpU7i8lFQv4K37NkuvgfdJq3rtVIDdLhBiU8P+z955wEdVbGH8AKGF3juE3ouCASwQUKQXMahYKNanItgr0lT0WbAi0pTyFBEUEBEwlNB7kyK999B7CfrON8ldNyEbks1u9u7ud36/zd7cMnfmPzNRvnvuNxMW/U/W7Vop4RVvo8DrDcAs03YEKPDarktYIRIgARIgARIgAX8nACEqOjpaRo0aJRMnTpQLF+IW7MHr/s2aNZN7OnSQ8PBwxz+E/L29wVJ/y8Khx7PPyvLly2WSZvVGRUUZCwfYOPRQS43IyEjp1q2bREREBGz/IhuzloqbEDoPx8SY7i8c75GKV8zxqrqrgBgWq4JeU/X/hG8nMguRXTpi/BiTjblcBeOI+kn72yJTF76qWJhqwAtvOl6xh0jqKjJmvF5Ic3VuSvZDoIYdALxtf/h1wnWXFNJsWyyi9dh9DyfIxrzuRN1RRzNgsQgdfGFhiwAmEEzhJ4sM3pzxC2PdKGMSZRctVER27dtjGIKPc1hZrs7Zu87HU7MNSwRk3eIVfmebDJSBtiOzFlm2EBVRJ8QRtYZAP1vWA9iH7GsEBFdL7DU7nH5gfz3NwIbFALx312xcb+ZUuIrLVkAkx7joqp6ysF24USQWUW90flLHEwvj4IrMZ/jdIlvZOTzJ3rncxNuwDEGWuJUNjOPIFkc/wO4C4q/V/weOXD9fEtcTZWXT6+5t2U4iW7U3C/wtXr1MxvwSt2ghPH0TZ4BbdYI/suWRbO3jt38SKFe0gqn4im1L5PT5U5InR14Z9Ogw+XjyAPl12U+yce86czxfzgLyVqeB0vHWBx0N7diws8zbECU7Dm+VsdHDpWGVRlKuaEXp/+An8saY52TrgU3mUyx/Sfmo2zfy1NedHddygwRIwD0C/z5Wdu96XkUCJEACJEACJEACJBBPABYMffv2Fbyy37RpU/MqP8TdenXryrvvvCPz582TD95/37z6n1QGl7dBPvfcc9KiZdyCQc73+u+HH0q16tVl2rRpzrvlkq6IXqt2bRk8eHCC/an55ZuhQ+Wuu+5KzSUpPvf1N96Qxx5/PMXne+pE9B0sHNCX6FP0LfoYfQ0LB/Q9xgDGAsZEIAZ8VBGWF631OjgW34qNjXU0ecfe3fLoaz3klff7mGzUserT+szbL8n/Jv1ozoHoBw9Sywbi0qWEmY6xmhFshWVDULJocYe4i2Pbdu+wTknhd5zo61zPFF5oTmsUfqvJtMViYYnD4jBv2eIEhyZOnyLdXnlGfpz6s2O/JdxikS1EpbJxmc5YgC1GrQVgTwBxDq/GJ4zr61+9YhVzyvToWUbUs87Hom9Hj8cYL9gSRYpbu93+rqh2Goips2cYP1fngrBQG7K6EcgARbYyLAdg2zBPhXnnsNpcvWJV593XbcOmAQEPZ2R7V1I2zgK2g3ei8mGRAd5j48fZdQV7cEf1SnHssQCgcxbxxq1/GfEZ1hthJUp78I5JFzVj3r8WFTjjjwVxv1cpV8lcAGsGZPSu3vCnEemtUi5cvChzly4wv1rj6O1B75l5unzdarMf4xC+vZaoa2UkW49PnOepVS6/7U/gnYc+lTWf7TWia1K1bVanjTm+7ONtRtzFOdmzhsrb938giz/cLONfnSm/vDFHZvZfLpG3PZygiBIFSsvE12fpeVtkwQcbVeBtbI7fVC5cfnt7kUx+a545/nufxRJe6TZzn+iBcR7bOHHue+vMPpTjHLdUvNXs//6l35x3C/yB0ZY578UthoiDo3r9YvYNfXZcgnP5CwkEKgFm8AZqz7JdJEACJEACJEAC6ULAnywY6tWrJ7PnzJGTJ09KPvXbtGL5smXmH/7LNCu1devW1m5Zv2GDEevqN2jg2MeNhASC1cIBC3chTp+NEzkhDNVQf9MNKmq9N/hjzeC7RU7psSWrl5vsTWT1QhivW6OOWcgJmbh/a6Y7/GFjNNMQr37Hib3VTLmWgLxbszNH/zxORc4KjgxN3AOZhKVLlJQDhw7KHPUORUBsXqz3u1UXKksuUPbhmEvyrWbhwuIBGbmpCYhkWHDtnS8/uu4yLO6FtkybO1NOnTll2ofMWtQruy5I1kQ9dq2AcItX2eFnjGxVy6PVEnRPqoAcXvvm63yJk6p/m6bNDVd4pn449HMjmCOT1mJzn7bRsguw7u/Od2TL9vLn5o1GgIZoD5EaNggx6vMKmw28vYBX+C0h8KH2nWTQyMHaX+P0Nf+9xksY/YdzsUBbR7W8SC6wABjsByDuIurXiVtczboGi9ct0LH0x4I5pv8rqLCMjF70AWwB7rwtwjrVa99333GnsTLAg4YP1Fe6Xs2b5aT2/Zwl8809OzZv49J2xFOVwtyaOnu6ZoIfN2Mans7L160yc65VfEY9Mqoh0mKhv4FfDzIZ2MjEBiuMFYjnt8RnRyNzGoL191N+Uh/oPYIM/S26ICAeFhTMl1/wkAVhzVM82Lmm2cINNHsXi7gxAp8A/HcrFU/+AQ0oZM8S998KZyIhmUKkTKGyzru4TQIk4AECFHg9AJFFkAAJkAAJkAAJBBcBf7VguOWWuGy4tWvXSpMmTUynnTp1SjZv2SLt27eXFSrwOsea1avNgkS1atZ03s1tFwSCycKheJG4V9H/2r7FZGjCb7Vn16fkh6kTjeC2U0VNRC4V/7re+6BENIizXUCmLn6fNHOqycpEZiaihC4i1rldpGMxMXj/QiiEMAqhLPZarCCbs3PbSPl5xhSz0Bmug/j3UIf7jEgFgW3C75NvKPBCcBulovEmtYaAv2tqBV7cFzYKWBQO9gHOAcGrb8/XZLhaTkD0wgcBIbtrx86a0VrIcXpISIiK4tXMIlwQxfA7onyZMCN2w9YgKf/dpOqPV/D79XrdWEes37JJ/opfvA31eaj9fUYodtw4DRso742nX9A+mGrqDZsOK9AXTW9tJBC5rcBCbC8/8ZwR6ecuXWjtNoL9o50ecQiEjgOJNiD636Ii95zFcQs3WQKkdRru2VfbPWL8aFmqVhf4IEoXL2VsGxJbJljXefIbwjn6fNTPP+hic3+aRedQPsZ+N+3z23SceDvw8KDLvZ1lrD74gGCLwJx87L5HHJnh2PegzjFkQP8663f9TMcufYAQIk10fmJuWXFf6476cO+aWqIskt+jo6zdggc53Ts97PCXbqgPU8Ac8x2L3GHeUuB14OIGCZAACaQrgQz6D5R/0vWOvBkJkAAJkAAJkAAJpJCAZWNgl/9dwev2o0ePNq/h796929EKvJ7fQX11mzdvLsjotGtAMGrQsKE8+OCD8sLzz5tqzpo1S/oPGCDfDBkine67T+Zqhm+RInHemf95+mm5qosXjRw50pw7btw4+WXSJNm1a5exIOjYsaM8cP/9juZ2695dnnziCTl95oz88P33RjQ+dvy4TJwwQXAfBPpyoFobbN++Xd4fOFCKFi1qsoS/+uormfnHH4KM6AaaMdyrZ08pWbKko+zVKjZ/qeesX79e8ubNK127dpWNGzWTUD1gR44Y4TjPbhvnz5+XmTNnymT16125apWjemFhYdKlSxfTDtg5eDNuej7uFdfRHw/x5m0cZcP6AB6rECyRyYlFlxIHXmVH1uC5C+ckb648xrs18Tn4HR6iFy5dFGQMI3MWcVGtQ+ADi1ffC6nnK/bjnvsOHZDcuXKpr2vKFlaDzygyZz2R2WoqlugHyof/bJ7cuVNcp0RFJPurq/pjwTHYWeRRr2RnO4NkC3PjIO6P7GtYMOTLndeI15ZInVRxWCjtuHrVFtNMUmTvejqwwN2ho0dMuwtolqkv4srVq1qHQ5JTheeUjsO01PP4qRPy4rtvmfkx5N1BxiLiwOEDklkX2wNn67+hie+Bv8PIxr2q9cWCf87+yM7nwjP7qNqF4Dx4LENQTyrQbszBUPWZT2t0fflpUwRetw+GsP4+B0t7g6FPndvI/nWmwW1vE2AGr7cJs3wSIAESIAESIAG/JuBPFgw3Ao1/xNe9+WZBBq8VsGWAn2zVqlUltwpRWDysbdu2RojFed1VtEV8MmiQEXo7d+4s3bt1k5UrV8oAFYaPHjkiPVWMRWzatEkWLFwoE1TQhR1EWNmyAoHXCogK/fr3l99//12GDxtmxF0ce+HFF41wC3EYC9F9/8MPxlv3RxWUYSWxbt066f7oo1KnTh1568035aRmHY9QUfeKClnVqsW90m/dw27fwWjhAJGvdPF/xfmk+gSib9yiT3ErrSd1DvZBvEUmonPADxQZsc6Beybe53w8qW3nBamSOp7WfSjfm9mMruoPa4Kwkgl9K9PalqSux/1zpOI+WJwPH28Fspi9yTsl9cbDgjLp4Lfrqi6YVym5P4Rf+CPfKLKqhUipFCxeh3Z760HJjerI4yRAAiRAAnEEKPByJJAACZAACZAACZBAIgIQIqOjo2XUqFEyceJEs3gWToH42KxZM7lHs3XDw8NdZkclKs5Wv0J4HfLNN45V7Zep/26XRx4xQtoteswSeLfv2CFnNBO3vrbz4MGDJmv5mWeekR7PPmva06pVKyMIj/z2W7lfs3itrN8fVJzFQmO1a9Uy50EItgKZu9OnTzcZt7Xijy9dutSwnqyZweXLlzenIhO6dZs28vMvv8jjjz0mX3/9tZQpXdqIwllUvEI0iYiQtu3amW1/+RFMFg7+0iesJwmQAAmQAAmQAAkEAoG495wCoSVsAwmQAAmQAAmQAAmkkQAsGPr27WvsB5o2bWqEygsXLggsGN595x2ZP2+efKAiJTJeXb36msYqeP1y+PBe1FXTt2zdKsc1uxZWCbBEQKBdy1fEeVjCfzc0NFRq1KghK1SkxSu6D2r2rnPA6gH7VzlZD9yp3Cxx1zoXfmAfffSRfK+2Da+8/LJY4i6OL16yREqUKCGX9LV7WC7gAwsI3NeydUCdWunib5a4i+vKanaw5SmM3/0pMHbAGmMJYwpjC2MMYw3iOMYebBswFjEmGSRAAiSQFAFkUcNX1x0f6aTK4z4SIAESIAH/JcAMXv/tO9acBEiABEiABEiABFJNAJYG2fQV97Vr1ki+/PmlePHiDq/b+ir0Isv20KFDslqPw84Br74jgxdib3493zkKFy6sXo+ZzXFrf8WKFa1NxzfKg3cvMnRHqYcxFnSzxNp9+/bJ3r17jf+v44L4jWLFigkWgYMPJOqZOErovkOHDyfezd9JgARIICgIwMu4eaM7g6KtbCQJkAAJkEDyBCjwJs+HR0mABEiABEiABIKIALIm+6tHbL9+/RJYNGBxLHze00XB/N2iAYJsndq1Za362uZQ0baBZpJaUbFCBSPiImN2jQq89+miawj44CK7FFm2EIetwAJiyODNq8etgI9v4sA1o777zizCc/8DD8iw4cMdVg8FChSQqlWqyDD15E0cyHTNpYtmQWQ+c/p04sNy5uzZ6/b5ww5YgMAKY5IuvBYVFWUyqlFviOiRkZHSTT2OI9SCwl+zxP2hD1hHEiABEiABEiABEggkArRoCKTeZFtIgARIgARIgAQ8QgDCWpMmTWS0Zpse0UXEvlWf2UaNGhkh7tdffzULfjW7+2758quvBBmo/hawNsACakvVf9eyZ7DaAM/d36dNM+3CNgILsCHmqZ2Ac8CnGFEt/rj5JYkf+VUArly5slSvXt3YPAxXgXeHevwicO0ezeCFiAux1/p8p4Lwb1oPLAxXqVIliU50b9hMwD/YnwJjBWMGYweLxmEsoR0YWxhjGGsYcxh7FHf9qWdZVxIgARIgARIgARLwLQEKvL7lz7uTAAmQAAmQAAnYnEDOnDmle/fuRtyEKNmnTx8JCwsztgRDhgyR5i1aSJcuXeQXXRAMGa3+EFhobf/+/bJnzx7jBetcZ3jDLli4UNBuS9iFp27Dhg1NBvOCBQvkrGbOzps/X97/4AO54/bbBbYPKY1evXqZjOC+miWNTNY2upgasn5ffPFF2aZ+wPAF/nH8eBkzdqw0uuMOU+xjutDa4sWL5YsvvpCYmBjZvXu3vPzKK3Lu3LmU3tZn52FMYGxgjGCsYMzA8gJjCGMJYwrCOcYYmDNIgARIgARIgARIgARIILUEaNGQWmI8nwRIgARIgARIIGgJBIqFAxY5g1VD6dKlpVChQgn6MzzesgEiMLJnrfjs00/lnXfflR7PPWdsGeCh26J5c+ndu7d1Soq+c+TIIW+9+ab0ev55mTBhgrGB+E6zV9986y3p0KGDEX0hLL+t5UIERbRUYRQWDZ99/rl8M3SoZMyYUdroomstW7aUkydPmnPs9IMWDHbqDdaFBEiABOxP4KbnS9u/kqwhCZCArQlk0P8BxcLGDBIgARIgARIgARKwHQHrNXU7/+8KskghVI4aNUrma1arFVgUDIuJddBPqVKlrN1+/x0bG2usBIoUKWJsFTzZIPj84lOwYEGXxWLBNngCO3sBuzw5nQ/AgmHylCkyRT/I0rUCFgzw1e3UqZNPsnQt4WD0x0OsKvGbBEiABGxJoOvLT5t6rflsry3r5+lKWX+fPV0uy7MXgWAZz/aiHny1ocAbfH3OFpMACZAACZCA3xDwB4HXGebOnTuNh+qYMWOMjYB1rF7duiY7tblmvCKDlRE4BGDBMHPmTJmsC6ZhIT4rkH0MW4auXbsKMr99GZaAQIHXs73w07TJMm3uTGnbtIVEtmrv2cKTKW3Pgb3S59P3pXCBQvLRGwOSOfP6Q+cunJf9hw5KaPbsUrp4SccJr7zfR44ej5EBL7whZUrYL5PwcMwROXXmjBQuWEjy58nrqHdKNw7HHNXrT7t9fUrvw/PSTiDYBN60E2MJJEACJBBHICNBkAAJkAAJkAAJkAAJeIaAZeEAoXfOnDlG4AsNDTXCX++335ZGjRvL62+8YRYHs3NWsmdoBG4p6Dss8Ia+RJ+ibyHuoq8h6qLvMQb69+/vc3E3cHvB9y0LzZ5N8uXOY8tscld0duzZJe8PGSRjJ41PcEqeXLlNWzJl/NeWJcEJPv5l2tw/TL1XrPv3IUpqqvR7dNz1y9euTM1lPJcESIAESIAE/IYAPXj9pqtYURIgARIgARIgAX8hgMzjJk2amM/gwYMTWDj8+uuvgk+gWjj4Sx+5U0+7WjC40xZek3YCbTRzF59AiN49Xg6EZrANJEACJEACJBC0BCjwBm3Xs+EkQAIkQAIkQALpQSBnzpzSvXt380ls4TBkyBDBhxYO6dET7t3DHywY3GsZr0qOwMVLF2XSH7/Jqg3r5JQu8JdDs7OrV6oqHe9uI4UKxHlEz1u2SJZqRmjDm+pJo/DbZN+hA/LDrxOlfOkwqV6xqvz4289y8MghKaVWCB2bt5VqFSprmdNk5frVcvnKFalX8yZp0uB2KVa4qKlK1MK5snrjnxJR/zapX6eeo3rL9B7Req+bqtWUu+9o6tifeGPJ6uUya9E8c8/Ya7FStFARLf8OaXprI3PqiPFjBfYOiP1a1/8O/VxqVa4mLSOaybBxo+SkWhh0u7ezFClY2JyDTPU/FsyRFX+u1rYdNBm+FcLKSWTL9pJXM5etGDx2hMD6oWfXJ037Visz8KtSvpI82C5SCuTLb52a5PfClUtl9uK4eotkkFLFikurJnfLzdVry/GTJ2TET2NNm3Dx7MXzZe1fGySyRTspX6asXL58WX5Tm4xla1fJiVMnJYsuHllO+bdv1koqhpU3+4aPH+O4fs6S+bJu80a5t0VbqVCmnKnPlp3b1GrjD0F2c+5cuUw/ddTyc2QPTbK+3EkCJEACJEACdiRAgdeOvcI6kQAJkAAJkAAJBCQBy8KhX79+Eh0dbRZmmzhxonm9H6/4vzdwoDRr1kzu6dBBwsPDxfIgDkgYNm4UhK3ly5fLJPXVjYqKkosXL5rawoIhMjLSLJgWERHB/rFxH6a1ah8N/9IIfrBgqKiiJsTbxauWCcTAd154UwXfHHLkWIxs2rZZypcKM7e7cPGC+R2i5Mz5s6V4kWISkinElPPl6KEq+lYxgnFYydLGTxbnrFFB94NX+0qmTJnk4NHD5nqc5xzHtDzcp2i88Op8zNqGOPy/yT+ZX4uoTy0E2B17dsvoX8bJlatXpEXju+TYyeNy8vQpc86Vq1cFvrZlSsQtALlt907jwXvp8iVzHHPg02+/lnUqpqJuOC/mxHFZsGKJrN20Xl7/z/NSslgJc+7WXduNv+2Q77+VnXt3G0E35sQxFbLXmHv27fmaZMyY0Zyb+MdsFaTHTPpRMoeEqDBbVk6fPSOoy+fffSM9uz0lJYsWN/W8oIIx4uz5c3I19qoK5JfN7599N0Q2bd9iygfXq9qu9Vs2yeYd26Rfr9ckS5Ys5vqLl+LadVYXxbyqC0VCYEcsXbPCiNvYLqPXn9H7QyT/a/tWefWpXgmEbJzDIAESIAESIAG7EqDAa9eeYb1IgARIgARIgAQClgAtHOzZtbRgsGe/pHetYo4fM6JsThVxP3rzHRUfMwuEzzc+GmAySldtWGsydl3V68ixo9LlngfkztsaGyGx/xf/lQOHDxrh8b2XehthFNmmLw/sbURViKHItk1LzJw/x1zeLfJBk7WLXzbv2Kq+tZ+aLGMIvBBlIdgOGjnYZLm+9exLLm+5RIVPnIvs2zeeflEK5S8gf//9t3w74XsVeRfL91MmyGtannMgi/dj5ZUtazbZumuHvDf4Y9m9f6+2Ee2Lywp2Ph/bizXrGPHMw4/LzTVqm20I1RCsoxbMldeffkE+7T1QRmoW7/zli6WDZuY2b3SnOQ+iO8RdiMMfvNpPCmodEagbMo9Xb/pT2t3Z0lz/7YT/CTKukdkLFghkGcOLOET7961nXzSLy0HYHvPLj4JM319nTZcuHR8w5/IHCZAACZAACdidAAVeu/cQ60cCJEACJEACJBDQBGjh4NvupQWDb/nb8e5ZNesTAcFywYqlctvN4Ua0/OTNd+VvFQAzqsd2chGqr/Zbtggoq3K5CkbghSWAlfWaP28+I+oeUAuHk2oBkRaBF8JrdxV2EVXVBsKKjPELpiErNrURvXShueQeWFLEC6fIwn2ofSdj2QBhFUK4ZVeBk9vd2cJwwnalsuWNpQNsH45r5rArgddivXDlEmNlgXvhHg+0vRfFJBu5cuSUV5/sabKpLXEXF2SKzxY+c/ZsstfDXgN93LxRUyPu4mQ8fLu/zT0qBi80Qvb9re+RrFmzJlsOD5IACZAACZCAHQhQ4LVDL7AOJEACJEACJEACJKAEaOGQPsOAFgzpw9lf75I7V25prD64yPgc/fMPan0w3lgU1FAP3oj6t9/QU7aAirfO9iqWl2vpeDsEi0tm9YtF/PPP39Yut74hvMIfGNmyM+bNEojGsHvYo7+7G4f0egR8dJ0je7ZsUlatDP7S7GDcw1ngLVygkPOpkl+zfyHwQhR3Fa3VaxeZxvA6xqew+htXLldRfY1vMW1ydR32w4YCIu+f6qmLaw8dPWS8gmE9kZI4ePiQOW3Tti3GEsL5GthSwMbilIrjRbImbJfzedwmARIgARIgAbsQoMBrl55gPUiABEiABEiABEggngAtHLwzFGjB4B2ugVjqo50e1kW+aqlH60rZrL678JbFZ3p0lLz8RE8VPiu6bLazuOt8UuLMX1fnOV+Tkm08sICFAfxx4TlbQb1sy5UqI7dq5rHly5uScpzPuRTvcZs1XoR2PmYJ05YPrnXMnfZAmH5fPYjnasbwxq2bVaDdbywd0JZmtzeRhzvcZxV/3Tf8ct/7epDx2IVXcln1Qm5Qp54cV/sL2EjcKM7H+/rGqifvxXjvYeua8vELsKn8bu3iNwmQAAmQAAnYmgAFXlt3DytHAiRAAiRAAiQQ7ARo4ZC2EUALhrTxC8arIfhd1oXJqlaoInWq1TIIkNEKsXTD1r9k2tyZyQq87jLLFG+pgMXanMNa5M95n/M2MnchiObPk08GvPimyWrFcXjUuhtFCxaRvQf3yX7NBq6mGc1WQExG5i4iLbYSVnnnta05NQv3gTYdzS78Pk/F3vHTJhkfXnju4nhS8Yf69CJbF0L2Ew90dSzkNiVqWlKnX7eviGYLIxrq9fDmZZAACZAACZCAPxNIejlTf24R604CJEACJEACJEACAUrAsnDYuXOnzJkzR7p06SKhoaGyctUq6f3229KocWN5/Y03ZNmyZfrad/BmnqHtYAAWYAI2YARWYAZ2YNi/f39jixGgw4XNcpPAhq2b5Jm3X5LX/ttXrsZeNaUUK1xUF+eKW9zr4qVLbpac/GX58uQ1J2zesc1xIsbyeq1PcmEJriWLFXeIuzh/my505ipi49vl6nj1SlXMIVg+wOPXiuXrVsuxE8eNv26xwmlbGA5te/m93ob1+i1xbYSdRSu1bcACd4hLly+b7wwS53t8VcV3Kw4djbNigKUDbCqs2Lprp7Xp+Layi52vt+wnsNCb1c+4AIL5Y689Jy+995aj7Zu2bZaps2eYDG5HobqxMX4/ODnHRn0QgPNnzJvtvJvbJEACJEACJOA1Aszg9RpaFkwCJEACJEACJEAC3iEAsaJJkybmM3jwYJkwYYKMGjVK5s/Xld9//dV8ihcvLu3bt5cO+ilVqpR3KmKzUmnBYLMO8dPqVAwrL7ly5tLFz07JoBGDNYu3plxTkROevAhYN3gjqsUvkLZz324ZPHa4oB5rN603WarJ3a9UsRLmMETSsZN+NIuV7T90UOYuWWD2Y7GxJSpiIlMVvrWI3Qf2qb/wOLMAXAP1u00cbXXBtIUrl8q6vzbIR8O+kDraZiyqNmfJfHPqfZpxmzkkc+LLUvU7/o7VrVnHZB9/O+F/uphdfePbC3EUi5+hXdbiaXni6437nz1/Tu64paE5vnL9Gvll5lSzD+Lwmk1/apZ1nFi8ddd22bF3t5QvHSZ5c8W1e+7SBabsO+o1MF6/tavW1Daul3e/+tj4/mJBuiVrVkjstVhpFXG3Qzhepz6/EHGzZskqLSOaOdqJa2fOn2MWl2vR+C7HfvQbMozhWWw9GHAc5AYJkAAJkAAJeIEABV4vQGWRJEACJEACJEACJJBeBILdwoEWDOk10oLnPjk0e/Slx5+VMSqAbtq+xXzQegiI99zdJoHA50kqZdU3996W7WTyzN8EmbL4QABt36y1jP/tF5e3Kl28pLE4gNA5a9E8cx4WH3v4nvtkkYq023bvlInTpxiBt4wu9HZb3fqCrFWIpRAykxJ40db+z78u3/70vWap/uVggCzjhzvcL/W0Xp6ILh0f0GIyyOJVS2XqnBmmSAi/EF4f7fSQ4xaNw2+VNRvXGdsJCK0Qw1s1aaZC9V7d/6dpH06G9/Czjzwuw8aNlj0qYi9VsRYCb6P6t+pCbGsd11dVD+WSKiD36PK4jJv6sxHvkbmLMOy0jXfe1tj8zh8kQAIkQAIk4A8EMuirMcH7/p4/9BDrSAIkQAIkQAJBTMB6rZb/u5K6QQBe0dHRJqt34sSJcuFCnKdn9uzZpVmzZnJPhw4SHh4uFt/Ule77s9G+5cuXy6TJkyUqKkosj1JYMERGRkq3bt0kIiLCb9vnacI3PV/aFDn64yGeLjrgy0MW7wldtAuZmIULFJKQEO/nx8AC4ujxo2qDkFdyO/nf3gj2RV007HDMUQlVcbZQ/gIm+xR+wvDizaPl5M+bz1EEbBcu6Pmh2bI7slQdBxNtXL5yReBBjOxfKwM40Slp/hVtjjlxTDOlr2ndCzosGhIXfEW9ka9du6b9kd1x6IT2EfqpUL78Dl7IAD6iLIoXKWb6zjo5qetxLFbLRBszqdVDevWzVSd+JyTQ9eWnzY41n8UJ7gmP8jcSIAESIAFXBCjwuiLD/SRAAiRAAiRAAj4nYAmQFHjd74pz584lsHCwSvJHCwdaMFi9l7pvCryp48WzSYAEfEeAAq/v2PPOJEAC/k2AAq9/9x9rTwIkQAIkQAIBTYACr2e7FwuLjR49WsaMGSO7d+92FF6vbl3poFm9zZs3lxw54hY3chz08QYtGNLeARR4086QJZAACaQPAQq86cOZdyEBEgg8AhR4A69P2SISIAESIAESCBgCFHi905V2t3CgBYNn+50Cr2d5sjQSIAHvEaDA6z22LJkESCCwCVDgDez+ZetIgARIgARIwK8JUOD1fvfZycKBFgze6W8KvN7hylJJgAQ8T4ACr+eZskQSIIHgIECBNzj6ma0kARIgARIgAb8kQIE3fbvNFxYOtGDwfh9T4PU+Y96BBEjAMwQo8HqGI0shARIIPgIUeIOvz9liEiABEiABEvAbAhR4fdNV3rZwoAVD+vYrBd705c27kQAJuE+AAq/77HglCZBAcBOgwBvc/c/WkwAJkAAJkICtCVDg9X33eNLCgRYMvulPCry+4c67kgAJpJ4ABd7UM+MVJEACJAACFHg5DkiABEiABEiABGxLgAKvvbrGHQsHWjD4vg8p8Pq+D1gDEiCBlBGgwJsyTjyLBEiABBIToMCbmAh/JwESIAESIAESsA0BCry26YoEFUmJhQMumDR5skRFRcnFixfN9aGhoRIZGSndunWTiIgIsfo3QeH8xeMEKPB6HCkLJAES8BIBCrxeAstiSYAEAp4ABd6A72I2kARIgARIgAT8l4AlAEJQZNiTgCsLB+faNmrUyIi6nTp1kpw5czof4nY6EKDAmw6QeQsSIAGPEKDA6xGMLIQESCAICWQMwjazySRAAiRAAiRAAiRAAh4iAMG2e/fuMm/ePNmxY4f06dPHUTK2sQ/HcA7FXQcabpAACZAACZAACZAACZCAxwhQ4PUYShZEAiRAAiRAAiRAAsFNoFy5ctK/f38HBGxjH4MESIAESIAESIAESIAESMB7BCjweo8tSyYBEiABEiABEiABEiABEiABEiABEiABEiABEiABrxKgwOtVvCycBEiABEiABEiABEiABEiABEiABEiABEiABEiABLxHIMR7RbNkEiABEiABEiABEiABEiABuxCwFi+yS31YDxIgARIgARIgARIgAc8QYAavZziyFBIgARIgARIgARIgARIgAS8SWPv5PsGHQQIkcD0Bzo/rmXAPCZAACQQTgQz/aARTg9lWEiABEiABEiAB/yGQIUMGU1n+74r/9Blqyn7zr/7yl9pyXPlLT7GeviDA+eEL6rwnCZAACdiHADN47dMXrAkJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJpIoABd5U4eLJJEACJEACJEACJEACJEACJEACJEACJEACJEACJGAfAhR47dMXrAkJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJpIoABd5U4eLJJEACJEACJEACJEACJEACJEACJEACJEACJEACJGAfAhR47dMXrAkJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJpIoABd5U4eLJJEACJEACJEACJEACJEACJEACJEACJEACJEACJGAfAhR47dMXrAkJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJpIoABd5U4eLJJEACJEACJEACJEACJEACJEACJEACJEACJEAC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EiABEiABEiABEiABEiABtwlQ4HUbHS8kARIgARIgARIgARIgARIgARIgARIgARIgARIgAd8SoMDrW/68OwmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAm4TYACr9voeCEJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJ+JYABV7f8ufdSYAESIAESIAESIAESIAESIAESIAESIAESIAESMBtAhR43UbHC0mABEiABEiABEiABEiABEiABEiABEiABEiABEjAtwQo8PqWP+9OAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAm4ToMDrNjpeSAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAK+JUCB17f8eXcSIAESIAESIAESIAESIAESIAESIAESIAESIAEScJsABV630fFCEiABEiABEiABEiABEiABEiABEiABEiABEiABEvAtAQq8vuXPu5MACZAACZAACZAACZAACZAACZAACZAACZAACZCA2wQo8LqNjheSAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQgG8JUOD1LX/enQRIgARIgARIgARIgARIgARIgARIgARIgARIgATcJhDi9pW8kARIgARIgARIgARIgARIgARIgARI4IYEDr/7qpydMeX68zJmlJBCRSVblRqSv/uzkrVClevPSWbP5W2bZW/39hJSvKSU/Wl2MmfyEAmQAAmQQCAToMAbyL3LtpEACZAACZAACZAACZAACZAACdiGQMbceSVz0eKO+vwTGytXD+6Tc/P+kPNL5kmpoT9J1oqpEHlDQiRTwcISkr+Qo0xukAAJkAAJBB8BCrzB1+dsMQmQAAmQAAmQAAmQAAmQAAmQgA8I5Ly9qRR58/0Ed/774gXZ3+Nhubxlo5z6+X9S5PV3ExxP7pesZStIuckLkjuFx0iABEiABIKAAAXeIOhkNpEESIAESCDwCbzyfh85ejzmhg1t0fgu6dz23huel5oTDscckVNnzkjhgoUkf568qbk06M89r/+o33fwgGTPlk3KlCgV8Dz6fva+7N6/V177z/NSrUJl097te3ZKbOw1KVe6jGTJnMXs+33uHzJ+2iRp0vAO6XbvgynmMuCLD2XH3l3yypM9pUalqua6HXt2yVXNkCtbqoxkzRJX/vToKPnxt18kosHt0j3yoRSX7+0T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lm1KMHhiyOkkAlkKcD3IkoYFCCCAAAIIIIBArgUI8OaajA0QQAABBBBAIK8CJ3LLNiUY8qrO9gi4U4DrgTvHhV4hgAACCCCAgHcECPB6Z6zoKQIIIIAAAmEnkJNbtvWkR44aJePHj5fU1FRrkJCQIF26dJFevXpJu3btJCoqKuxsOCEEIk2A60GkjTjniwACCCCAAAL5JUCAN78k2Q8CCCCAAAII5Ekgq1u2/Xfapk0bG9Tt2rWrJCUl+S9iGgEEwkiA60EYDSanggACCCCAAAIFLkCAt8CJOQACCCCAAAII5FbAuWW7X79+dtPHH39cevbsKbVr187trlgfAQQ8LsD1wOMDSPcRQAABBBBAoMAFCPAWODEHQAABBBBAAIETFXBKL+it2zQEEIhsAa4HkT3+nD0CCCCAAAIIZC0QnfUiliCAAAIIIIAAAggggAACCCCAAAIIIIAAAgi4WYAAr5tHh74hgAACCCCAAAIIIIAAAggggAACCCCAAAJBBAjwBsFhEQIIIIAAAggggAACCCCAAAIIIIAAAggg4GYBArxuHh36hgACCCCAAAIIIIAAAggggAACCCCAAAIIBBEgwBsEh0UIIIAAAggggAACCCCAAAIIIIAAAggggICbBQjwunl06BsCCCCAAAIIIIAAAggggAACCCCAAAIIIBBEgABvEBwWIYAAAggggAACCCCAAAIIIIAAAggggAACbhYgwOvm0aFvCCCAAAIIIIAAAggggAACCCCAAAIIIIBAEAECvEFwWIQAAggggAACCCCAAAIIIIAAAggggAACCLhZgACvm0eHviGAAAIIIIAAAggggAACCCCAAAIIIIAAAkEECPAGwWERAggggAACCCCAAAIIIIAAAggggAACCCDgZgECvG4eHfqGAAIIIIAAAggggAACCCCAAAIIIIAAAggEESDAGwSHRQgggAACCCCAAAIIIIAAAggggAACCCCAgJsFYt3cOfqGAAIIIIAAApElMGjQIJkxY8ZxJ927d2/fvFatWsnNN9/s+8wEAgiEpwDXg/AcV84KAQQQQAABBPJfIOqIafm/W/aIAAIIIIAAAgjkXmDSpEnSvn37oBv+/PPP0q5du6DrsBABBLwvwPXA+2PIGSCAAAIIIIBA4QhQoqFwnDkKAggggAACCORAQAO3bdu2zXJNXUZwN0seFiAQVgJcD8Jq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i9fNlwGjn5ZJf4+Xl3q969uOCQQQ8I5A0ZPq2M5qAPfQrh1S5obekmBKLGigduu7r8iWV54Uzb6t9OQA81C0Iram7p6JY447wRgTCK7y8gcS1/gUSZ3zuySbTNzkt16QQ9uSpUyvO6T0DbfabWJNELj6B8OkWJNmsnvsaNny6tM24BtXt5FUffUjKVotvYzMcQdgBgIIIIAAAggg4DGBKHMb1NF7Iz3Wc7qLAAIIIIBABAq0uLeGPes5r6721NlriYYVm5dJkZgiorV59T1QSz2QKodMANjJBtZ10g6lyToT+NWsXw0Ch3Pz6viG85i4+dyWtG5gu1dv6iI3dzPbvh3cvFEOmQeuxVauJrGly9j1D+3cbmr1rpaiteqajNrELPeRlrzJPLhto0SZdYpUrSHRRYsGXPeQeeDawTUrTOZveSlSsXLAddw2M1zG122u9AcBBBBAAIFwFMh4v1M4niHnhAACCCCAAAIhFygSW1TqV2mUbT/ii8Yft06suT37pPI8IOk4GGYgECYCRSpUEn35t5iSpUVf2TWt6+vU9g22bkxScYlpdEqwVViGAAIIIIAAAgh4VoASDZ4dOjqOAAIIIIAAAggggAACCCCAAAIIIIAAApEuQIA30r8BnD8CCCCAAAIIIIAAAggggAACCCCAAAIIeFaAAK9nh46OI4AAAggggAACCCCAAAIIIIAAAggggECkCxDgjfRvAOePAAIIIIAAAggggAACCCCAAAIIIIAAAp4VIMDr2aGj4wgggAACCCCAAAIIIIAAAggggAACCCAQ6QIEeCP9G8D5I4AAAggggAACCCCAAAIIIIAAAggggIBnBQjwenbo6DgCCCCAAAIIIIAAAggggAACCCCAAAIIRLoAAd5I/wZw/ggggAACCCCAAAIIIIAAAggggAACCCDgWQECvJ4dOjqOAAIIIIAAAggggAACCCCAAAIIIIAAApEuEBvpAJw/AggggAACXhRocW8NL3abPiOAQAEILGndoAD2yi4RQAABBBBAAAEEvCJABq9XRop+IoAAAggggAACCCCAAAIIIIAAAggggAACmQSijpiWaR4fEUAAAQQQQAABBBBAAAEEEEAKLVoQAAADlElEQVQAAQQQQAABBDwgQAavBwaJLiKAAAIIIIAAAggggAACCCCAAAIIIIAAAoEECPAGUmEeAggggAACCCCAAAIIIIAAAggggAACCCDgAQECvB4YJLqIAAIIIIAAAggggAACCCCAAAIIIIAAAggEEiDAG0iFeQgggAACCCCAAAIIIIAAAggggAACCCCAgAcECPB6YJDoIgIIIIAAAggggAACCCCAAAIIIIAAAgggEEiAAG8gFeYhgAACCCCAAAIIIIAAAggggAACCCCAAAIeECDA64FBoosIIIAAAggggAACCCCAAAIIIIAAAggggEAgAQK8gVSYhwACCCCAAAIIIIAAAggggAACCCCAAAIIeECAAK8HBokuIoAAAggggAACCCCAAAIIIIAAAggggAACgQQI8AZSYR4CCCCAAAIIIIAAAggggAACCCCAAAIIIOABAQK8HhgkuogAAggggAACCCCAAAIIIIAAAggggAACCAQSIMAbSIV5CCCAAAIIIIAAAggggAACCCCAAAIIIICABwQI8HpgkOgiAggggAACCCCAAAIIIIAAAggggAACCCAQSIAAbyAV5iGAAAIIIIAAAggggAACCCCAAAIIIIAAAh4QIMDrgUGiiwgggAACCCCAAAIIIIAAAggggAACCCCAQCABAryBVJiHAAIIIIAAAggggAACCCCAAAIIIIAAAgh4QIAArwcGiS4igAACCCCAAAIIIIAAAggggAACCCCAAAKBBAjwBlJhHgIIIIAAAggggAACCCCAAAIIIIAAAggg4AEBArweGCS6iAACCCCAAAIIIIAAAggggAACCCCAAAIIBBIgwBtIhXkIIIAAAggggAACCCCAAAIIIIAAAggggIAHBAjwemCQ6CICCCCAAAIIIIAAAggggAACCCCAAAIIIBBIgABvIBXmIYAAAggggAACCCCAAAIIIIAAAggggAACHhAgwOuBQaKLCCCAAAIIIIAAAggggAACCCCAAAIIIIBAIAECvIFUmIcAAggggAACCCCAAAIIIIAAAggggAACCHhAgACvBwaJLiKAAAIIIIAAAggggAACCCCAAAIIIIAAAoEECPAGUmEeAggggAACCCCAAAIIIIAAAggggAACCCDgAQECvB4YJLqIAAIIIIAAAggggAACCCCAAAIIIIAAAggEEiDAG0iFeQgggAACCCCAAAIIIIAAAggggAACCCCAgAcE/h9KCZQgHF+w+wAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "fig = Image(filename=('../../../documentation/gfx/steadystate_solver_workflow.png'))\n", + "fig" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The example model\n", + "\n", + "We will use the example model `model_constant_species.xml`, which has conserved species. Those are automatically removed in the SBML import of AMICI, but they can also be kept in the model to demonstrate the failure of Newton's method due to a singular right hand side Jacobian." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Species: ['substrate', 'enzyme', 'complex', 'product']\n", + "\n", + "Reactions:\n", + "creation: -> substrate\t\t[compartment * (synthesis_substrate + k_create)]\n", + "binding: substrate + enzyme <-> complex\t\t[compartment * (k_bind * substrate * enzyme - k_unbind * complex)]\n", + "conversion: complex -> enzyme + product\t\t[compartment * k_convert * complex]\n", + "decay: product -> \t\t[compartment * k_decay * product]\n" + ] + } + ], + "source": [ + "import libsbml\n", + "import importlib\n", + "import amici\n", + "import os\n", + "import sys\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# SBML model we want to import\n", + "sbml_file = 'model_constant_species.xml'\n", + "\n", + "# Name of the models that will also be the name of the python module\n", + "model_name = 'model_constant_species'\n", + "model_reduced_name = model_name + '_reduced'\n", + "\n", + "# Directories to which the generated model code is written\n", + "model_output_dir = model_name\n", + "model_reduced_output_dir = model_reduced_name\n", + "\n", + "# Read the model and give some output\n", + "sbml_reader = libsbml.SBMLReader()\n", + "sbml_doc = sbml_reader.readSBML(sbml_file)\n", + "sbml_model = sbml_doc.getModel()\n", + "dir(sbml_doc)\n", + "\n", + "print('Species: ', [s.getId() for s in sbml_model.getListOfSpecies()])\n", + "\n", + "print('\\nReactions:')\n", + "for reaction in sbml_model.getListOfReactions():\n", + " reactants = ' + '.join(['%s %s'%(int(r.getStoichiometry()) if r.getStoichiometry() > 1 else '', r.getSpecies()) for r in reaction.getListOfReactants()])\n", + " products = ' + '.join(['%s %s'%(int(r.getStoichiometry()) if r.getStoichiometry() > 1 else '', r.getSpecies()) for r in reaction.getListOfProducts()])\n", + " reversible = '<' if reaction.getReversible() else ''\n", + " print('%3s: %10s %1s->%10s\\t\\t[%s]' % (reaction.getId(), \n", + " reactants,\n", + " reversible,\n", + " products,\n", + " libsbml.formulaToL3String(reaction.getKineticLaw().getMath())))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Create an SbmlImporter instance for our SBML model\n", + "sbml_importer = amici.SbmlImporter(sbml_file)\n", + "\n", + "# specify observables and constant parameters\n", + "constantParameters = ['synthesis_substrate', 'init_enzyme']\n", + "observables = {\n", + " 'observable_product': {'name': '', 'formula': 'product'},\n", + " 'observable_substrate': {'name': '', 'formula': 'substrate'},\n", + "}\n", + "sigmas = {'observable_product': 1.0, 'observable_substrate': 1.0}\n", + "\n", + "# import the model\n", + "sbml_importer.sbml2amici(model_reduced_name,\n", + " model_reduced_output_dir,\n", + " observables=observables,\n", + " constantParameters=constantParameters,\n", + " sigmas=sigmas)\n", + "sbml_importer.sbml2amici(model_name,\n", + " model_output_dir,\n", + " observables=observables,\n", + " constantParameters=constantParameters,\n", + " sigmas=sigmas,\n", + " compute_conservation_laws=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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pKSEEydOsGTJEgYPHsz+/fuJjY3ljjvu4Je//CUbNmwAwGw243ZXPyU8Ly8Ph8NBeHg4x44dY968eZXbQkNDyc/PByAlJYUVK1awe/duwHvNYdeuXX5570FXWsEhF22FEGexZcsWHnnkEQwGA2azmX/9618UFxdz++238+STT55ywRYgMTGRkSNHcvz4cZ588kni4uJ47733ePHFFzGbzTidTt5//30A7rzzThITExk4cCDPPvvsKefp378/AwYMoGfPnrRv375yyKbiuHHjxhEXF8fixYt59913ufHGG3G5vNPLn3nmGbp3797g995s17RNTk7W9V0ApeeT8/jFsAR+d1kvP0clhGio7du306uX/LfpD9X9LZVS62sqWxN0Qzrg7eUXyJCOEEKcIjgTvtUkF22FEOI0QZnw7RajXLQVQojTBGXClx6+EEKcKWgTvozhCyHEqYIz4VuMUjxNCCFOE5QJ324xyTx8IYQ4TVAmfKfVKLV0hBDiNEGZ8O1WE0XSwxdC1OCDDz5gyJAhJCUl8atf/Yry8nKcTidPPPEE/fv3JyUlhWPHjgGQlJRU+QgJCWHp0qV069atcj1Zj8dD165dycrKYvLkydx9992kpKTQuXNnlixZwm233UavXr2YPHlyZfuBKn98LkFXWgG8Y/il5R5KyzxYTEH5mSZEcJj3OBzd4t9ztukH45+vcfP27dv56KOPWLFiBWazmV//+tdMnz6dwsJCUlJSePbZZ3n00Ud56623+MMf/lBZ7vjLL7/kb3/7GxdccAE333wz06dP5/7772fBggX079+fikWbTp48ycqVK5k9ezZXXnklK1as4O2332bw4MFs3LiR+Pj4gJU/PpfgTPhVVr2ymCxNHI0QojlZuHAh69evZ/DgwQAUFxcTExODxWJhwoQJAAwaNIhvv/228pi0tDQeeeQRFi9ejNls5rbbbmPixIncf//9vPPOO0yZMqVy3yuuuAKlFP369SM2NpZ+/foB0KdPH9LT08nIyAhY+eNzCc6EX1FArbScCHsTByOEqNlZeuKBorXmF7/4BX/9619PeX3q1KmVpZCNRiNlZd7rgAUFBVx//fW89dZbtG3bFoD27dsTGxvLokWLWLNmDdOnT688j9VqBcBgMFQ+r/i9rKwMo9EYsPLH5xKU4x0VJZKLZC6+EOI0o0ePZubMmWRmZgKQ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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAEZCAYAAACU3p4jAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAgAElEQVR4nO3deXyU1b348c83+77vJBD2VdawCSgRBRQqLlypS61V67X32msXa2td6a2ttv7UWq293tbtWhFcQFtXUMSNLSD7vgTIQlayE7Kd3x/PJAwhCZMwM0lmvu/Xa16ZPNv55mH4PmfOc55zxBiDUkopz+fT3QEopZRyD034SinlJTThK6WUl9CEr5RSXkITvlJKeQlN+Eop5SU04SuPICKPiMhr3R1HR84Vo4hki8il7oxJeRdN+KrXEJFbRGS7iNSIyHEReV5Eoro7LqV6C034qlcQkZ8DjwO/ACKBKUA/YKWIBLgpBj93lKOUq2jCVz2eiEQAi4EfG2M+MsbUG2OygeuAdOAm26ZBIrJURCpFZLOIjLE7xi9FJNe2bq+IzLIt9xGRX4nIQREpEZFlIhJjW5cuIkZEbhORo8BnIvKhiNzVKr6tInKN7f2fROSYiFSIyCYRmdHqz2k3xlbH7CiuIBF5zba8TEQ2ikji+Z1l5Q004ave4EIgCHjHfqExpgr4ALjMtmgB8CYQA7wOrBARfxEZCtwFTDTGhANzgGzbPj8GrgIuBlKAE8Bzrcq/GBhu228JcH3zChEZgfVN433boo3AWLsY3hSRILtjtRljG39zR3F9H+tbThoQC9wJnGzjGEqdQRO+6g3igGJjTEMb6/Jt6wE2GWPeMsbUA09iXSSmAI1AIDBCRPyNMdnGmIO2fe4E7jfG5BhjTgGPAAtbNd88YoypNsacBJYDY0Wkn23djcA7tn0xxrxmjCkxxjQYY/6frdyhdsdqL8bWOoqrHivRDzLGNBpjNhljKs59GpW304SveoNiIK6dNvRk23qAY80LjTFNQA6QYow5APwEK2kWisgbIpJi27QfsNzWNFIG7Ma6QNg3kdgftxKrNv9d26LrgX80rxeRe0Rkt4iU244XyekLUrsxtvF3dRTX/wEfA2+ISJ6I/KGdbwlKnUETvuoN1gKngGvsF4pIGHA58KltUZrdOh8gFcgDMMa8boyZjpVIDdYNYLAS8OXGmCi7V5AxJteuqNZDyi4BrheRqVg19NW2MmcA92LdW4g2xkQB5YDY7dtujK20G5ftHsZiY8wIrOau+cDNbZ86pU7ThK96PGNMOdZN2z+LyFxbu3w6sAyrhvx/tk0niMg1tm8CP8G6SKwTkaEicomIBAK1WO3dTbZ9/go82txEIyLxIrLgHCF9gHXh+A2w1FZTBwgHGoAiwE9EHgIiWu3bZoxtlNFuXCKSKSIXiIgvUIHVxNPUxjGUOoMmfNUrGGP+APwaeAIrya3HqgXPam4/B94FFmHd4PwecI2trTwQeAyr6ec4kADcZ9vnT8B7wCciUomVfCefI5ZTWDeQL8W68drsY+AjYB9wBOvicqzV7u3F2FpHcSUBb9nOw25gDacvekq1S3QCFKWU8g5aw1dKKS+hCV8ppbyEJnyllPISmvCVUspL9OjBoOLi4kx6enp3h6GUUr3Gpk2bio0x8W2t69EJPz09naysrO4OQymleg0ROdLeOm3SUUopL6EJXymlvIQmfKWU8hI9ug1fKW9QX19PTk4OtbW13R2K6kWCgoJITU3F39/xgVI14SvVzXJycggPDyc9PR0ROfcOyusZYygpKSEnJ4f+/fs7vJ9bE76IZAOVWON6NxhjMtxZvlI9UW1trSZ71SkiQmxsLEVFRZ3arztq+JnGmOJzb6aU99BkrzqrK58Zz7xpu+YPcGBVd0ehlFI9irsTvsEa33uTiNzR1gYicoeIZIlIVme/rrT4+k9w4NNzb6eUUl7E3Ql/ujFmPNa0dP8pIhe13sAY84IxJsMYkxEf3+bTwecWEAZ1VecXqVJeLjs7m1GjRnV3GLz88svcddddba4LCwtzczRn6yg+R/bNy2trhkvXcGvCb54n1BhTCCwHJrmkoIBQqKt2yaGVUl3X0NDQ3SE4rLGx0eVluDvhu+2mrYiEAj7GmErb+9lYc4I6X0AonNIavup9Fv9zJ7vyKpx6zBEpETz8nZHn3O7JJ5/kxRdfBOD222/nqquuoqGhgRtvvJHNmzczcuRIXn31VUJCQvjVr37Fe++9h5+fH7Nnz+aJJ56gqKiIO++8k6NHjwLw9NNPM23aNB555BEOHjzIoUOH6Nu3L4cPH+bvf/87I0daMc2cOZMnnniCpqYm7r77bmprawkODuall15i6NChABw7doyZM2eSm5vLTTfdxMMPP3xW/H/84x9ZtmwZp06d4uqrr2bx4sVt/p3Z2dnMnTuXCRMmnPV3paens2jRIlauXMm9996LMYbf/e53GGOYN28ejz/+OAAvvfQSv//974mKimLMmDEEBgYCcMsttzB//nwWLlwIWN9AqqqsXPT444/z2muv4ePjw+WXX05GRgZZWVnceOONBAcHs3btWoKDgx3+d+0Kd/bSSQSW2+4s+wGvG2M+cklJgeFaw1eqEzZt2sRLL73E+vXrMcYwefJkLr74Yvbu3cvf//53pk2bxq233spf/vIXfvCDH7B8+XL27NmDiFBWVgbA3XffzU9/+lOmT5/O0aNHmTNnDrt37wZg165dfPXVVwQHB/PUU0+xbNkyFi9eTH5+Pvn5+WRkZFBRUcGXX36Jn58fq1at4te//jVvv/02ABs2bGDHjh2EhIQwceJE5s2bR0bG6V7dn3zyCfv372fDhg0YY7jyyiv54osvuOiis1qNAdr8u+655x4AYmNj2bx5M3l5eUyZMoVNmzYRHR3N7NmzWbFiBZMnT+bhhx9m06ZNREZGkpmZybhx4zo8vx9++CHvvvsu69evJyQkhNLSUmJiYnj22Wd54oknzvhbXMltCd8YcwgY45bCAkKhqtAtRSnlTI7UxF3hq6++4uqrryY0NBSAa665hi+//JK0tDSmTZsGwE033cQzzzzDT37yE4KCgrjtttuYP38+8+fPB2DVqlXs2rWr5ZgVFRUttdsrr7yypfZ63XXXMXv2bBYvXsyyZctaasPl5eV8//vfZ//+/YgI9fWn53a/7LLLiI2NbYntq6++Oivhf/LJJy2Jt6qqiv3797eb8Nv6u5oT/qJFiwDYuHEjM2fOpPle4o033sgXX3wBcMbyRYsWsW/fvg7P76pVq/jBD35ASEgIADExMR1u7yqe+aRtQKjetFXKCVr39RYR/Pz82LBhA59++ilvvfUWzz77LJ999hlNTU2sW7eOoKCgs47TfCEB6NOnD7GxsWzbto2lS5fy17/+FYAHH3yQzMxMli9fTnZ2NjNnzuwwDnvGGO677z7+/d//vct/V1uxdpafnx9NTU0ANDU1UVdX1+VjuYJn9sMPCNMmHaU6YcaMGaxYsYKamhqqq6tZvnw5M2bM4OjRo6xduxaA119/nenTp1NVVUV5eTlXXHEFTz31FFu3bgVg9uzZ/PnPf2455pYtW9otb9GiRfzhD3+gvLyc0aNHA1YNv0+fPoB1M9PeypUrKS0t5eTJk6xYsaKldt5szpw5vPjiiy3fKHJzcyksbP9bflt/V2uTJk1izZo1FBcX09jYyJIlS7j44ouZPHkya9asoaSkhPr6et58882WfdLT09m0aRMA7733Xsu3lMsuu4yXXnqJmpoaAEpLSwEIDw+nsrKy3TidTRO+Uorx48dzyy23MGnSJCZPnsztt99OdHQ0Q4cO5bnnnmP48OGcOHGCH/3oR1RWVjJ//nxGjx7N9OnTefLJJwF45plnyMrKYvTo0YwYMaKl5t6WhQsX8sYbb3Dddde1LLv33nu57777GDdu3Fm9eSZNmsS1117L6NGjufbaa89q8549ezY33HADU6dO5YILLmDhwoUdJtK2/q7WkpOTeeyxx8jMzGTMmDFMmDCBBQsWkJyczCOPPMLUqVOZNm0aw4cPb9nnhz/8IWvWrGHMmDGsXbu25dvC3LlzufLKK8nIyGDs2LE88cQTgHWT984772Ts2LGcPHmy3XidRYwxLi+kqzIyMkyXZrz69L/hqyfhoVLQR9ZVD7d79+4zkoZyrezsbObPn8+OHTu6O5Tz1tZnR0Q2tTdOmWfW8APDwDRBveuvmEop1Vt46E1b29N3ddUQENK9sSilukVJSQmzZs06a/mnn37qEbX7rvDQhG+7y15XBXRxeAalVK8WGxvb4Y1jb+SZTTotNXztmqmUUs08NOE31/C1p45SSjXz0ISvNXyllGrNMxN+oC3h6wBqSinVwjMTvjbpKHXedDx8yyOPPNLyoJQjfve733WpnKeffrrlSVxX8dCEb9ctUynVY/Sm8fC7qr2Eb4xpGWenLe5I+B7aLbM54btvjAqlnOLDX8Hx7c49ZtIFcPlj59zMW8bDr66u5rrrriMnJ4fGxkYefPBBFi1aRHp6OllZWcTFxZGVlcU999zD559/DsDWrVuZOnUqxcXF3Hvvvfzwhz8kPz+fRYsWUVFRQUNDA88//zzvv/8+J0+eZOzYsYwcOZJHH32UOXPmMHnyZDZt2sQHH3zAY489xsaNGzl58iQLFy5k8eLFPPPMM+Tl5ZGZmUlcXByrV6/mk08+4eGHH+bUqVMMHDiQl1566by/0XhmwvcLBPHVGr5SDvKm8fA/+ugjUlJSeP/99wFr0LZz2bZtG+vWraO6uppx48Yxb948lixZwpw5c7j//vtpbGykpqaGGTNm8Oyzz7b0/8/Ozmb//v288sorTJkyBYBHH32UmJgYGhsbmTVrFtu2beO//uu/ePLJJ1m9ejVxcXEUFxfz29/+llWrVhEaGsrjjz/Ok08+yUMPPXQe/8qemvBFdAA11Ts5UBN3BW8aD/+CCy7g5z//Ob/85S+ZP38+M2bMOOf5WbBgAcHBwQQHB5OZmcmGDRuYOHEit956K/X19Vx11VWMHTu2zX379evXkuwBli1bxgsvvEBDQwP5+fns2rWrZcTQZuvWrWPXrl0t576uro6pU6eeM85z8cyEDzrNoVJO4Inj4Q8ZMoTNmzfzwQcf8MADDzBr1iweeuihM8ayr62tPed5uOiii/jiiy94//33ueWWW/jZz37GzTff3OHffvjwYZ544gk2btxIdHQ0t9xyy1llNf89l112GUuWLDnn39MZnnnTFqyumdoPXymHeNN4+Hl5eYSEhHDTTTfxi1/8gs2bNwNnjmXf3JTU7N1336W2tpaSkhI+//xzJk6cyJEjR0hMTOSHP/wht99+e8tx/P39z/h2Yq+iooLQ0FAiIyMpKCjgww8/bFlnPzb+lClT+Prrrzlw4ABg3Xc416xajvDchB8Qqk06SjnIm8bD3759O5MmTWLs2LEsXryYBx54AICHH36Yu+++m4yMDHx9fc/YZ/To0WRmZjJlyhQefPBBUlJS+PzzzxkzZgzjxo1j6dKl3H333QDccccdjB49mhtvvPGsspu3HzZsGDfccMMZF6477riDuXPnkpmZSXx8PC+//DLXX389o0ePZurUqezZs6fd8+kozxwPH+Dl+dDUALe6Zp50pZxFx8NXXaXj4TcL0CYdpZSy59k3bbVJRymv1dF4+M09fryNZyd87aWjegljzFk9QdT58fTx8LvSHO+5TTqB4VrDV71CUFAQJSUlXfoPrLyTMYaSkpI2u8B2xLNr+PXV0NQEPp57XVO9X2pqKjk5ORQVFXV3KKoXCQoKIjU1tVP7eHbCByvpB4Z3byxKdcDf35/+/ft3dxjKC3hu1VdHzFRKqTN4cA3fsxO+MYaK2gaqTzXg7+tDgJ8Pwf6+BPh57jVcKXV+PDjh25p0TvX+IZJLqk6x/nApW4+VseVYGYeKqzlRXUdD09k3+eLCAkiKDCI1KoShSeEMTw5nRHIkaTHB2gtEKS/nuQk/sHfX8E81NPLZ7kLe3pzL53sLaWgyBPj6MDwlgsyh8cSFBRITGkBYoB/1jU3UNRqqahs4XnGS/PJa9hVU8vGu4zR3/IgPD2RS/xgm949hxuB4+seFdhyAUsrjeG7C76VNOk1NhhVbcvnjx3vJL68lITyQ26b3Z+6oJEakRBDo53vug9icrGtkb0El23PLycouZePhUt7flg9Av9gQMocmcNmIRCb3j8HPV5uClPJ0bk/4IuILZAG5xpj5LiuoZV7b3tOkszG7lMX/3MmO3ApGp0byu2su4KLB8fj6dK0pJjjAl7FpUYxNi+J7U/oBcKSkmjX7ivh8bxFvbDzKy99kEx3iz2UjEpk/OoULB8Zq8lfKQ3VHDf9uYDcQ4dJSelEN3xjDX9cc4o8f7yEpIoinF43lyjEp+HQx0XekX2woN08N5eap6Zysa2TNviI+2pHPh9uPsywrh7iwAOZdkMzV41MZkxqp7f5KeRC3JnwRSQXmAY8CP3NpYS01/J6d8Ctr6/nFm9v4aOdx5l2QzB8WjiY00D3/LMEBvswdlcTcUUnU1jfy+d4i3tuayxsbj/HK2iMMjA9l4YQ0rhnfh8SIzj3Rp5Tqedxdw38auBdo90koEbkDuAOgb9++XS+puYbfg8fTKa2u4/oX1nGgqIr7rxjO7TP6d1uNOsj/dPKvqK3ng235vLUph8c/2sMTn+wlc2gCiyamkTk0Xpt8lOql3JbwRWQ+UGiM2SQiM9vbzhjzAvACWOPhd7lAvwDwDeixQyRX1NZz84vryS6p5uUfTGTG4PjuDqlFRJA/353Ul+9O6svh4mqWZR3jzawcVu0uIDEikEUZaSya1Jc+UcHdHapSqhPcWcOfBlwpIlcAQUCEiLxmjLnJZSX20CGST9Y1ctvLG9mTX8n/3pzRo5J9a/3jQvnl3GH87LIhfLankCUbjvLn1Qd4dvUBMocmcNOUflw0pOs3lpVS7uO2hG+MuQ+4D8BWw7/HpckeeuQkKI1Nhjtf28SmIyd45vpxZA5L6O6QHOLv68OckUnMGZnEsdIalm48xhsbj/HpyxtJiwnmhkn9WDQxjZjQgO4OVSnVDs9ujO2BCf+51QdYs6+I3ywYxfzRKd0dTpekxYRwz5yhfPOrS3j2hnGkRAbz+Ed7mPL7T/nZsi1sPVbW3SEqpdrQLQ9eGWM+Bz53eUE9rEln05FS/vTpfhaMTeHGyedxQ7qHCPDzYf7oFOaPTmHv8UpeW3eEdzbn8M7mXMakRnLz1HTmjU4myN/xh8WUUq7juZOYA7xyJdSfhNtXOi+oLio/Wc8Vf/oSHx/44L9mEB7k390huURlbT3Lv83llW+yOVhUTUxoAIsmpnHj5L6kRod0d3hKebyOJjH33KEVwBoHv7q4u6MA4IEVOzheUcubd0712GQPEB7kz81T0/nelH6sPVjCq2uP8D9rDvI/aw4ya3gi35+azrRBsfpAl1LdwLMTfkBoj2jDX723kH9uzePnlw1hfN/o7g7HLUSECwfFceGgOHLLTvKPdUd4Y+MxVu4qYGC89aTvNeP7ePTFT6mexsNv2nZ/wq9vbOLR93fTPy6Uf794YLfG0l36RAVz79xhfPOrS3jyujGEBfrx8Hs7mfK7T3lwxQ72F/Se8Y6U6s08vIYf1u03bZdsOMqBwipe+N4Er5+cJMjfl2vGp3LN+FS2HCvj1bXZLM06xv+tO8KUATHcPDWdy0Yk4q9P8irlEp6f8BtqobEBfN3/p5bX1PPkyn1cODCWy0Ykur38nswaxXMsD8wbwdKNx3ht3RH+4x+bSQgP5PpJfbl+Ul+SInX8HqWcycMTfvMAalUQHOX24p/5bD/lJ+t5YN4IvUnZjpjQAH40cyB3XDSAz/cW8uraIzzz2X6eXX2Ay4YnctOUflw4MNYlI4cq5W08O+Hbz3rl5oSfc6KGV9dmsygjjREprh0J2hP4+gizhicya3giR0tq+MeGIyzbeIyPdh6nf1woN0zqy8IJqUTrk7xKdZlnN5Z245j4L36VjTFw96WD3V52b9c3NoT7Lh/O2vtm8dSiMcSEBvDoB7uZ/PtP+enSLWzMLqUnPz+iVE/l2TX8bpr1qrymnjc2HuXKMSkkR+qIkl0V5O/L1eNSuXpcKnuOV/D6+qMs35zL8m9zGZwQxvWT+nLN+D5EhWitXylHaA3fBV7fcJSaukZunzHAreV6smFJEfxmwSjW3z+Lx6+9gJBAP37zr11M+t2n3P3Gt6w9WKK1fqXOwUtq+O5L+HUNTbz09WFmDI7TtnsXCAnwY9HEviya2JddeRUs2XCUFVtyeXdLHumxIVw3MY2F41NJ0Bm6lDqLd9Tw3Tjr1Xtb8yisPMUPtXbvciNSIvjvq0ax4deX8uR1Y0gID+IPH+1l6mOfcfsrG/l453HqG5u6O0ylegzPruG39NJxT8I3xvC3Lw8xLCmcGYPj3FKmsubmbX6g61BRFcuycnh7cw6rdhcSGxrAVeP68G8ZqQxL0m9cyrt5dsJ3c5POukOl7DleyRP/Nkb73XeTAfFh/OryYdwzewhr9hXxZlYOr3yTzd+/OsyoPhEsHJ/KlWP76EQtyit5dsL3t3vwyg3e3pxDeKAf80cnu6U81T4/X5+Wfv0lVad4d0seb2/O4ZF/7uLRD3aTOTSBa8ankjksnkA/Ha9feQfPTvi+fuAX7JaEX1PXwIfb8/nOmBSd8KOHiQ0L5Nbp/bl1en9251fwzuYcln+bxye7CogK8WfeBclcPa4PE/pF6zcz5dE8O+GD22a9+njncarrGrlmfKrLy1JdNzw5gvvnjeCXc4fx5YFilm/O5e3NOfxj/VHSYoJZMKYPV41LYVBCeHeHqpTTeX7CD4qA2nKXF/PO5lzSYoLJ6Ocd4933dn6+PmQOTSBzaAJVpxr4aMdx3t2Sy18+P8Czqw8wMiWCK8ekMH9MCn2i9OE55Rk8P+EHR0NNqUuLOF5ey1cHivnxJYN1kK9eKCzQj4UTUlk4IZXCylr+tTWfd7fm8fsP9/D7D/eQ0S+a74xJ4YoLkokPD+zucJXqMi9I+DFQXejSIlZsycUYuGZcH5eWo1wvITyopb3/SEk1/9yax3tb83j4vZ0s/udOpgyIZf7oFOaMTCQ2TJO/6l08P+GHxEDxXpcd3hjD25tymNAvmvS4UJeVo9yvX2wod10ymLsuGcy+gkr+tTWPf23L59fLt/PguzuYOiCWKy5IZvbIROI0+atewPMTfnAM1Jxw2eF35lWwv7CKR68e5bIyVPcbkhjOz2YP5aeXDWHP8Ure35bP+9ut5P/Aiu1M6h/D5aOSmTMySSduUT2W5yf8kBhrtMyGOvBz/sM2H+88jo/A5aO07703EBGGJ0cwPDmCn8+2kv+H2/P5YMdxHn5vJw+/t5PxfaOYMzKJOSOT9Fuf6lE8P+EH23rNnDwB4c6fZnDV7kIy+sXok5teyD75/2z2UA4UVvLRjuN8tPN4yw3foYnhzB6ZyOwRSYzqE6H9/FW30oR/HnJO1LA7v4JfXzHMqcdVvdOghHDuuiScuy4ZTM6JGj7ZWcDHO4/z3OoD/PmzAyRHBnHp8EQuHZHIlAEx+oSvcjvPT/ghMdbPk87vmvnpbqv3z6XDdYJydabU6JCW3j6l1XV8tqeQT3Ye561NOfzfuiOEBvhy0ZB4LhmWQOawBL3pq9zC8xN+sC3hu6Av/qrdBQyIC2VAfJjTj608R0xoQEs//9r6RtYeLGHl7gI+213IhzuOIwJjUqO4ZFgClwxLYERyhD7PoVzCCxJ+c5OOcxN+ZW096w6V8INp/Z16XOXZgvx9ybTV6s1Vhp15FXy6u5DVewt5atU+nly5j/jwQC4eEk/m0ASmD44jMti/u8NWHsLzE35Lk45zu2Z+ub+Y+kajzTmqy0SEUX0iGdUnkrsvHUxx1SnW7C3i831FrNxVwFubcvD1EcamRXHxkHguGhLPBX0i8dXav+oityV8EQkCvgACbeW+ZYx52OUFB4SBj7/Tm3RW2UZaHN83yqnHVd4rLiyQayekcu2EVBoam9hyrIw1+4r4Yl9RS+0/OsSfaYPiuGhwPNMHx5Gi4/yoTnBnDf8UcIkxpkpE/IGvRORDY8w6l5YqYtXyndik09DYxGd7C7lkaAJ+vp49S6TqHn6+PmSkx5CRHsPPZw+lpOoUXx0o5ot9xXy5v4h/bcsHYGB8KNMHxTF9cDyTB8QQEaTNP6p9nU74IhIK1BpjGjuznzHGAM0D0/vbXqaz5XdJcIxTa/ibj5ZRVlPPpSO0OUe5R2xYIAvG9mHB2D4YY9hbUMlX+4v5cn8xS7OO8craI/j6CKNTI5k2MI4LB8Yyvl+0zs2gznDOhC8iPsB3gRuBiVg19UARKQbeB/7HGHPAkcJExBfYBAwCnjPGrG9jmzuAOwD69u3r4J9xDsHRcLLMOccCvtxfhI/AdJ23VnUDEWFYUgTDkiK4fcYATjU08u3RMr4+UMzXB4p5fs1Bnl19gAA/H8b3jWLqgDimDoxlTFqk9v33cmJVvDvYQGQNsAp4F9hhjGmyLY8BMoEbgOXGmNccLlQkClgO/NgYs6O97TIyMkxWVpajh23fGzdC6SH4j7Xnfyxg4fPfUN9kePc/pznleEo5U2VtPRuzS/nmQAlrD5WwK78CYyDQz4cJ/aKZMiCWSf1jGJsWpd8APJCIbDLGZLS1zpEmnUuNMfWtFxpjSoG3gbdtbfIOM8aUichqYC7QbsJ3GieOiV9T18DWnDJumz7AKcdTytnCg/y5ZFgilwyzmhzLaupYf7iUdYdKWH+olKdW7cMYCPDzYWxaFJPSY5jYP4YJ/aIJC/T8jnvezJF/3R+3Gv/DAMXAV8aYwwBtXRBaE5F4oN6W7IOBy4DHOx9yFzTftDXGuol7HrKyT1DfaJg6MNZJwSnlWlEhAS2DuYF1AcjKPsH6wyWsP1za0gTk6yMMTw4no18ME9NjmJgeTUKEjvzpSRxJ+G1N7pkO3C8ijxhj3nCwrGTgFVs7vg+wzBjzLwf3PT/BMdBYZ81tG3h+T8WuPVSCn4/oVIaq14oKCeDSEYktnQ6qTzWw+egJNhwuJSv7BG9sPMrL3wuU50gAABuaSURBVGQDkBptTds5IT2GCX2jGZoUrs8B9GLnTPjGmMVtLbe14a8CHEr4xphtwLhORecs9gOonW/CP1jCmLQoQvWrr/IQoYF+zBgcz4zB8QDUNzaxM6+CrOxSNh05wdcHS1ixJc/aNsCXMWlRjO8bzbi+UYxNi9KZv3qRLmctY0yp9JaxXu0HUItK6/Jhqk41sD23nB9dPNBJgSnV8/j7Wm37Y9OiuH2GNatbzomTbD56gqzsE3x77ATPrzlIY5PV4aNvTEhL8h+TFsWI5Ai9GdxDdTnhi0gm4LqppJzJSQOobTxcSmOTtt8r7yIipMWEkBYTwoKx1rzNJ+sa2ZZTxpZjZXx7tIx1h0p41/YtwN/XmidgdGoko1OjGJMaxaCEMG0K6gEc6Ye/nbMfkIoB8oDvuyIop3PSEMlrD5UQ4Gt1bVPKmwUH+DJ5QCyTB5yu/Bwvr2XLMesisPVYGSu+zeO1dUet7f19GZkSwQWpkVzQJ5LRqZH0j9OLgLs5UsOf3+p3A5QYY6pdEI9rBDtnALVvDhYztq/2XVaqLUmRQcyNTGLuKKs3UFOT4VBxNdtyytiWU8723HKWbDjKS/VNAIQE+DIiOYJRfSIZmRLByJRIBieG4a/DlbiMIzdtj7S1XESmA9cbY/7T6VE5W/NN2/OYzLy8pp6deRX81yWDnRSUUp7Nx0cYlBDGoIQwrhmfCljjUB0sqmZ7bjk7bK9lWceoqbNGagnw9WFIUhgjkq0LwIiUCIYlhROuYwQ5Rafa8EVkHNaTtf8GHAbecUVQTucXYI2aeR5NOusPl2AM2n6v1Hnw8/VhaFI4Q5PCWTjBugg0NhkOF1ezM6+cXXkV7MyrYOWuApZl5bTslxYTzPCkCNscwuEMT44gLTpEJ4rpJEfa8IcA19texcBSrCEZMl0cm3Od5wBqm46cIMDWe0Ep5Ty+dt8Emm8KG2MoqDjFzrxydudXsDu/kt35FazcXUDzaDAhAb4MTgxnWKJ1ARmWFM6QpHCdLrIDjtTw9wBfAvObB0kTkZ+6NCpXCIk+rzb8b4+WMSJFu5sp5Q4iQlJkEEmRQcyym2ToZF0j+wqs5L/neCV7j1eycncBS7OOtWwTGxrA4MQwhiSGMzgxnCEJ1vvo0IDu+FN6FEcS/jVYo2WuFpGPsB606n3fo4Kju9yk09DYxLbcMq6f5KTRO5VSXRJse/BrjN03bWMMxVV17CuoZM/xSvYXVLK3oJJ3NudSdaqhZbu4sAAGJYQxOCG85RvFoIQwEsID6S2PFJ0vR27argBW2MbBXwD8BEgQkeexRsn8xMUxOkdwDJQdO/d2bdhzvJLa+iZtzlGqBxIR4sMDiQ8PZNqg00OWG2PIK69lf0El+wuq2F9YyYHCKlZsyaWy9vSFIDzQjwEJYQyMD2Vg/OmffWNDPG44aYdv2tq6Yb4OvC4i0Vg3bn8J9I6Efx6zXn17zBpLf3xf7X+vVG8hIvSJCqZPVDAzhya0LDfGUFh5ioOFVRwoquJAYRUHi6r45kAJ72zObdnORyAtJoT+caEMiAujf1wI/ePC6B8fSnJEUK+8YezITVsxrQbNN8acAF6wvdrcpscJjrEmQWlqAp/O9fPdcrSMuLAAUqN1/lClejsRITEiiMSIIC4cdOYkRlWnGjhcVM2h4ioOFlZxqLiaQ0XVrD9Uysn605P8Bfj50C8mhPS4UPrHhdIvNoT+saH0iwslKSKoxz5Q5kgNf7WIvA28a4w52rxQRAKA6VhP264GXnZJhM4SEgMYqC07/eStg749doKxaVFe086nlLcKC/SzngZOjTxjeXOvoUPFVRwuruZISQ2Hi6vJLq5mzb4i6hqaWrYN8PUhNSaYfjEh9IsNJS0mhH4xIfSNDSEtOoTggO5rJnIk4c8FbgWWiEh/oAwIAnyxmnOeNsZ867oQncR+xMxOJPzymnoOFVVzre3BEaWU97HvNXThwDO/FTQ1GY5X1JJdXM2R0hqyS6o5UlzD0dIaNmafOOPGMUB8eCBp0cH0tY1PlBYdQmpMMGnRISRHBuHnwieNHblpWwv8BfiLbWarOOCkMcZ5k8S6g/0AarGOj3a5Jcf6M8fpDVulVBt8fISUqGBSooK5sNU6Ywyl1XUcLbUuAEdLajh24vTF4L2teTTZNYb7+ghJEUEMTAjj1VsnOT3WTj1pa5vZKt/pUbhDSNfG09lytAwRzvqKp5RS5yIixIYFEhsWyLg2On3UNzZxvLyWY6U15Jw4Sc4J62eji26Jes8sHi1NOp3rqfPtsRMMSdCxPJRSzufv69My9LQ7eM+wdCGdHxPfGMOWY2Xa/14p5RE6nfBFJNQ2L23vEhgJ4tOpGn52SQ1lNfWM66sJXynV+50z4YuIj4jcICLvi0gh1tg6+SKyS0T+KCKDXB+mE/j4QFBUp9rwvz1qbdtW25tSSvU2jtTwVwMDgfuAJGNMmjEmAasP/jrgcRG5yYUxOk9I50bM3JZTTkiAL4MSzm/ic6WU6gkcuWl7qTGmXkTSjTEtTxcYY0qBt4G3bd01e77QBKgqcHjznXnlDE+O6LFPzSmlVGecs4Zv64oJbUx2IiJTWm3Ts0X2gYrcc2+H9TDF7vxKRqZEuDgopZRyD0fa8K8TkceAcBEZLiL2+7zgutBcICIFKvLAgT6uR0trqDrVwIhkTfhKKc/gSJPO11hDKdwOPAkMFZEyIA846cLYnC8iFRrroLoYwuI73HRXfgUAI1P0gSullGdwZGiFXOBVETlojPkaQERigXSsHju9R0SK9bMi95wJf2deOX4+wuBEvWGrlPIMjjTpCEBzsre9LzHGbLKNkd+yTY9nn/DPYWdeBYMSwnRKQ6WUx3CoW6aI/FhEzpjfT0QCROQSEXkFa4jkni/SNuJlRd45N92VV8EIvWGrlPIgXR0eORjrYtF7hkcGCIkDH38oz+lws6LKUxRWntL2e6WUR/Ge4ZHBetq2uadOB3bmlQNoDx2llEfp9PDIIvIjwE9EtgBbjDH7XBOai0T0OWfCb+6ho006SilP0unB04wxDwF/AsqBq0Xkfx3ZT0TSRGS1bQyenSJyd2fLdorIPlDRcZPOzrwKUqODiQzuHQ8QK6WUIxyu4YvISuAeY8xWY0wB8LHt5agG4OfGmM0iEg5sEpGVxphdnQv5PNk/fNVO56JdeRX6hK1SyuN0pob/S+BpEXlJRJI7W5AxJt8Ys9n2vhLYDfTp7HHOW0Sf0w9ftaHqVAPZJdV6w1Yp5XEcTvjGmM3GmEzgX8BHIvKwiAR3pVARSQfGAevbWHeHiGSJSFZRUVFXDt+xCNs1pp2++HvyKzBGb9gqpTxPp9rwbQ9Y7QWeB34M7BeR73XyGGFYo2z+xBhT0Xq9MeYFY0yGMSYjPr7jp2G75BwPX+3Msw2p0EcTvlLKszic8EXkayAXeAqrKeYWYCYwSUQcGkTN1q3zbeAfxpizRt90i3M8fLU7v4LoEH+SIoLcGJRSSrleZ7pl3gHsMuasoSZ/LCK7z7Wz7dvB34HdxpgnO1GuczU/fNVODX9vQSVDk8LpLaNFKKWUozrThr+zjWTfbJ4Dh5gGfA+4RES22F5XOFq+0/j4QEQylJ+d8I0x7DteydDEcLeHpZRSrtapB6/aY4w55MA2XwE9o9ockdpmk05u2Umq6xoZkqQJXynleTr94JVHiEhp8+GrfQWVAFrDV0p5JO9M+JF92pz5au/xKgAGa8JXSnkg70z47Tx8ta+gkuTIIB1SQSnlkbw34cNZPXX2Hq9kiNbulVIeyksTfvPDV6dv3DY2GQ4UVTFUb9gqpTyUlyb8s2v4R0qqqWto0hq+UspjeWfCD40/6+Er7aGjlPJ03pnw23j4au/xKkRgUEJYNwamlFKu450JH6yHr+zmtt1XUEnfmBCCA3y7MSillHId7034cYOg+PTsjHsLtIeOUsqzeW/Cjx8GNcVQXcyphkYOF1dr+71SyqN5d8IHKNzNoaJqGpuMjqGjlPJo3pvwE4ZbP4v2aA8dpZRX8N6EH54MgZFQtIe9xyvx8xH6x4V2d1RKKeUyThkeuVcSgfihULiHfT5V9I8LJcDPe69/SinP590ZLmEYFO3mQKH20FFKeT7vTvjxw6GmhKrS4wzUB66UUh7OuxN+gtVTZ5DkMFgTvlLKw3l3wrd1zRwsOQxO1ISvlPJs3p3ww5Op9Q1jqE+O9tBRSnk87+2lAyBCrn8/RpnjBPrpGDpKKc/m3TV8YG9jHwZyrLvDUEopl/PqhF/f2MTmk4mEN5VDVVF3h6OUUi7l1Qn/SEk1e5pSrV+KdndvMEop5WJenfD3F1SxryXh7+3eYJRSysW8OuEfKKyikChMYAQUag1fKeXZvLqXzv7CKlKjQ5C44VC0p7vDUUopl/LqGv7+wiprDtuk0ZC3BRrruzskpZRyGa9N+I1NhkNFVdaQCunTob7aSvpKKeWhvDbh55yo4VRDE4MTwqHfNGvhka+6NyillHIhtyV8EXlRRApFZIe7yuzI/oIqAGuUzLB4a1ydbE34SinP5c4a/svAXDeW16H9hVbCH9Q8Smb6dDi6TtvxlVIey20J3xjzBVDqrvLO5UBhFYkRgUQG+1sL0qdDXRXkb+3ewJRSykV6XBu+iNwhIlkiklVU5LrhDvYXVp6u3QP0m279zP7SZWUqpVR36nEJ3xjzgjEmwxiTER8f75IympoM+wuqzpzWsKUd/2uXlKmUUt2txyV8d8gtO8nJ+saz57HtNw2OroXGhu4JTCmlXMgrE/6+gkoAhrSe5Urb8ZVSHsyd3TKXAGuBoSKSIyK3uavs1vYVNPfQaVXDT9d2fKWU53JnL53rjTHJxhh/Y0yqMebv7iq7tf0FlSRFBJ3uodMsLAHihsIRbcdXSnker2zS2VtQ2f6k5f1nWA9gnapyb1BKKeViXpfwG5sMBwqrzr5h22zUtVBfA3v+5d7AlFLKxbwu4R8rtcbQOeuGbbO+UyGqH2xd4t7AlFLKxbwu4Tf30BncXg1fBMZcD4fWQHmuGyNTSinX8rqE3zyGzuCEdmr4AGMWAQa2LXVPUEop5QZel/D3FVSSEhlEeJB/+xvFDIC0KbD1DTDGfcEppZQLeWHCr2q/OcfemO9C8V7I+9b1QSmllBt4VcJvbDIcLKpq/4atvZFXg2+gVctXSikP4FUJ/0hJNXUNTe13ybQXHAXDroDtb2qffKWUR/CqhN88pIJDCR9gyn/AyVJY97wLo1JKKffwqoS/39Ylc1BHPXTspU2CYfPh6z9BdbELI1NKKdfzqoS/t6CS1OhgQgP9HN9p1kNQXw1f/j/XBaaUUm7gXQn/eKXjzTnN4ofC2Bth49/gxBHXBKaUUm7gNQm/+lQDB4uqGNUnsvM7z7wPxAdW/875gSmllJt4TcLfkVtOk4ExqV1I+JF9YPKd1pO3+1c5PzillHIDr0n423LKARidGtW1A1z8S0gcCe/crk07SqleyWsS/tacMlIig4gPD+zaAQJC4LpXoakJlt0M9bXODVAppVzMaxL+9tzyrtfum8UOhKufh/wt8OG9Os6OUqpX8YqEX1ZTx5GSGkandaH9vrVh82D6T2HzK/DJA1aNXymleoFOdEjvvZrb78ecbw2/2SUPQV0NrH0WqgphwXPgF+CcYyullIt4ScIvA+hal8y2+PjA5Y9bk55/9t9QUwLX/g1CYpxzfKWUcgGvaNLZmlPOgLhQIoM7GAO/s0Tgonvgyj/D4TXw3CTYuVzb9ZVSPZZXJPxtOWWM7kr/e0eMvxnu+Bwi+sCbt8DSm6B4v2vKUkqp8+DxCb+gopaCilPn30OnI0kXwO2fwmW/gQOfwrMTYen3IHez68pUSqlO8vg2/K3HrPb7Mc7oodMRXz+YdjeMuQHW/xU2/C/sfg+SRsMFC2HkNRCV5toYlFKqAx6f8LfllOPrI4xIdnHCbxYWD7MetJL/ltdh+zJY+ZD1ShwF/S+G/hdZQy/rTV6llBt5fsLPLWdIYjjBAb7uLTgoAqbcab1KD8HOFXDoc2vUzXXPWdtE9YXksZAwAuIGW6/o/ta+SinlZB6d8E9U17HxcCnXTujTvYHEDIAZP7Ne9bWQs8Fq38/fAvlbYfc/AbvePUGREJkGESlW18+wRAhNsL4RhMRAcDQERlrbBYaDX6DVa0gppTrg0Qn/1bVHOFnfyPempHd3KKf5B1lNOv0vOr2svtb6FlC8D8qOQNkxKD8GlflwfLv1cJdpbP+YPn4QEGZ7hYB/MPiHgF+Q7RVovXwDTv/08bP76Qc+/uDrb/0uPuDjC+Lb6qfPmS8fX0Dslontd7F732p5y086fg+nt+fMxWf9csbFrp0LX4cXxPO4WOqFVrmCjx8kDHf6YT024dfUNfDyN4e5dHgCQ5M6OemJu/kHQeII69WWpkY4WWbNr1tTav2srYBTFVBbDnVVUFdtTbZeXwP1J62fddXWQ2ENtdBwChrrrJ9NDdb7xjowOjSEUj1OaAL8wvnduz024S/deIwTNfX8aOag7g7l/Pn4Qmis9XK2pibrAtBUb/vZaL1M4+nfTaP1QFlTo3WBME22ZU12L2N76Myc/v2s97af0MH75sBMq4fY7N47tJy2tzlr1fk8KKcP2SkX8e3iqL7n4NaELyJzgT8BvsDfjDGPuaKcuoYm/veLQ0zqH8OEftGuKMJz+PiATwCgYwEp5enc9uCViPgCzwGXAyOA60WknTaM8/Pe1jzyymv50cyBrji8Ukr1Su580nYScMAYc8gYUwe8ASxwdiFNTYa/rjnI8OQIZg6Jd/bhlVKq13Jnk04f4Jjd7znA5NYbicgdwB0Affv27XQhNfWNZPSLZsbgeER7UCilVIsed9PWGPMC8AJARkZGp++KhQX68di1o50el1JK9XbubNLJBewHk0m1LVNKKeUG7kz4G4HBItJfRAKA7wLvubF8pZTyam5r0jHGNIjIXcDHWN0yXzTG7HRX+Uop5e3c2oZvjPkA+MCdZSqllLJ4/AQoSimlLJrwlVLKS2jCV0opL6EJXymlvISY8xot0LVEpAg40sXd44BiJ4bjLBpX52hcnaNxdY4nxtXPGNPmuDI9OuGfDxHJMsZkdHccrWlcnaNxdY7G1TneFpc26SillJfQhK+UUl7CkxP+C90dQDs0rs7RuDpH4+ocr4rLY9vwlVJKncmTa/hKKaXsaMJXSikv0esSvojMFZG9InJARH7VxvpAEVlqW79eRNLt1t1nW75XROa4Oa6ficguEdkmIp+KSD+7dY0issX2cuqQ0Q7EdYuIFNmVf7vduu+LyH7b6/tujuspu5j2iUiZ3TpXnq8XRaRQRHa0s15E5Blb3NtEZLzdOleer3PFdaMtnu0i8o2IjLFbl21bvkVEstwc10wRKbf793rIbl2HnwEXx/ULu5h22D5TMbZ1rjxfaSKy2pYLdorI3W1s47rPmDGm17ywhlU+CAwAAoCtwIhW2/wH8Ffb++8CS23vR9i2DwT6247j68a4MoEQ2/sfNcdl+72qG8/XLcCzbewbAxyy/Yy2vY92V1yttv8x1nDaLj1ftmNfBIwHdrSz/grgQ0CAKcB6V58vB+O6sLk84PLmuGy/ZwNx3XS+ZgL/Ot/PgLPjarXtd4DP3HS+koHxtvfhwL42/k+67DPW22r4jkyEvgB4xfb+LWCWiIht+RvGmFPGmMPAAdvx3BKXMWa1MabG9us6rBm/XO18Jo6fA6w0xpQaY04AK4G53RTX9cASJ5XdIWPMF0BpB5ssAF41lnVAlIgk49rzdc64jDHf2MoF932+HDlf7Tmfz6az43Ln5yvfGLPZ9r4S2I0137c9l33GelvCb2si9NYnq2UbY0wDUA7EOrivK+OydxvWFbxZkIhkicg6EbnKSTF1Jq5rbV8d3xKR5mkoe8T5sjV99Qc+s1vsqvPliPZid+X56qzWny8DfCIim0Tkjm6IZ6qIbBWRD0VkpG1ZjzhfIhKClTTftlvslvMlVnPzOGB9q1Uu+4z1uEnMPZ2I3ARkABfbLe5njMkVkQHAZyKy3Rhz0E0h/RNYYow5JSL/jvXt6BI3le2I7wJvGWMa7ZZ15/nq0UQkEyvhT7dbPN12vhKAlSKyx1YDdofNWP9eVSJyBbACGOymsh3xHeBrY4z9twGXny8RCcO6yPzEGFPhzGN3pLfV8B2ZCL1lGxHxAyKBEgf3dWVciMilwP3AlcaYU83LjTG5tp+HgM+xrvpuicsYU2IXy9+ACY7u68q47HyXVl+3XXi+HNFe7K48Xw4RkdFY/4YLjDElzcvtzlchsBznNWWekzGmwhhTZXv/AeAvInH0gPNl09HnyyXnS0T8sZL9P4wx77Sxies+Y664MeGqF9Y3kkNYX/Gbb/SMbLXNf3LmTdtltvcjOfOm7SGcd9PWkbjGYd2kGtxqeTQQaHsfB+zHSTevHIwr2e791cA6c/oG0WFbfNG29zHuisu23TCsG2jijvNlV0Y67d+EnMeZN9Q2uPp8ORhXX6z7Uhe2Wh4KhNu9/waY68a4kpr//bAS51HbuXPoM+CquGzrI7Ha+UPddb5sf/urwNMdbOOyz5jTTq67Xlh3sPdhJc/7bct+g1VrBggC3rR9+DcAA+z2vd+2317gcjfHtQooALbYXu/Zll8IbLd94LcDt7k5rt8DO23lrwaG2e17q+08HgB+4M64bL8/AjzWaj9Xn68lQD5Qj9VGehtwJ3Cnbb0Az9ni3g5kuOl8nSuuvwEn7D5fWbblA2znaqvt3/l+N8d1l93nax12F6S2PgPuisu2zS1YHTns93P1+ZqOdY9gm92/1RXu+ozp0ApKKeUlelsbvlJKqS7ShK+UUl5CE75SSnkJTfhKKeUlNOErpZSX0ISvlFJeQhO+Ukp5CU34SrUiIqkisqiddcEiskZEfNtZHyAiX9iG9VCqR9GEr9TZZmGNpd6WW4F3zJmDubUw1lC/nwJtXjCU6k6a8JWyIyLTgSeBhbYZjwa02uRG4F3btqEi8r5t6N8ddt8KVti2U6pH0a+dStkxxnwlIhuBe4wxZ0yPJyIBWGMzZdsWzQXyjDHzbOsjbct3ABPdFLJSDtMavlJnGwrsaWN5HFBm9/t24DIReVxEZhhjygFszT11IhLu+lCVcpwmfKXs2MZqLzfWbGmtncQajRUAY8w+rLb+7cBv7SfoxhqGu9aVsSrVWdqko9SZ0oG8tlYYY06IiK+IBBljakUkBSg1xrwmImXA7QAiEgsUG2Pq3Ra1Ug7QGr5SZ9oDxNluwl7YxvpPOD194AXABhHZAjwM/Na2PBN43+WRKtVJOh6+Up0gIuOBnxpjvtfBNu8Av7I1+SjVY2gNX6lOMMZsBlZ39OAVsEKTveqJtIavlFJeQmv4SinlJTThK6WUl9CEr5RSXkITvlJKeQlN+Eop5SU04SullJf4/51KvALGzHh7AAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAEZCAYAAACU3p4jAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAgAElEQVR4nOzdeXyU1dXA8d+dPTOTjZAEQoCw7yFAgGBUNkFQFDe01qWg1Wqt1l1ba7WtWq24tFrbqhX1leKCCyggyi7IjmyyhSVA2BII2ZPJJHPfP2YSAySQZSbLcL7vO59M5lnumRTP3LnPfc5VWmuEEEIEP0NTByCEEKJxSMIXQojzhCR8IYQ4T0jCF0KI84QkfCGEOE9IwhdCiPOEJHwh6kkp9aNSakQziOPfSqknmzoO0fxJwheNQil1oVLqe6VUrlIqWym1Qik12LdtslJqeR3OlaCU0kopUz1jadDxFbTWfbTWSxpyDqXUu0qpZxoYx11a67805Bzi/NCgf/BC1IZSKgz4Crgb+BiwABcBrqaM62yUUiatdVlTx3EuSimj1rq8qeMQLYP08EVj6A6gtZ6htS7XWhdrrb/RWm9WSvUC/g0MU0oVKKVyAJRSlyulflBK5SmlDiqlnq5yvmW+nzm+Y4b5jrlNKbVdKXVSKTVfKdWxhnjOON73LWOFUuoVpdQJ4GmlVBel1CKl1Aml1HGl1HSlVETFSZRS6UqpS3zPDUqpx5VSe3z7f6yUalVl34pvODm+9zNZKXUncBPwqC+OL3379lJKLfHt+6NS6soq53lXKfUvpdRcpVQhMPL0bwlKqQlKqY2+479XSiVW2faYUuqQUipfKbVTKTW6Dv87ipZOay0PeQT0AYQBJ4D3gPFA5GnbJwPLT3ttBNAPb6ckETgGXOXblgBowFRl/4nAbqAX3m+ufwC+ryGe6o6fDJQB9/qODwG6AmMAKxCN94Pi1SrHpAOX+J7/FlgFxPv2/w8ww7etI5AP3AiYgSggybftXeCZKuc0+97H7/F+ExrlO7ZHlf1zgVTf38ZW9RzAACATGAoYgV/44rQCPYCDQFyVv0OXpv73IY/Ge0gPXwSc1joPuBBvkn0LyFJKzVZKxZ7lmCVa6y1aa4/WejMwAxh+lmbuAv6qtd6uvUMxzwFJZ+nlV+ew1vo1rXWZ9n4L2a21/lZr7dJaZwEvnyWGu4AntNYZWmsX8DRwne86wc+BBdr7DcettT6htd5Yw3lSACfwvNa6VGu9CO9w2I1V9pmltV7h+9uUnHb8ncB/tNartffb1Ht4h85SgHK8ib+3UsqstU7XWu+pw99HtHCS8EWj8CXiyVrreKAvEAe8WtP+SqmhSqnFSqkspVQu3oTa+ixNdAT+7hvGyAGyAQW0q0OYB0+LIVYp9aFvCCQP+OAsMXQEPq/S/na8CTYWaA/UNrHGAQe11p4qr+0/7X0cpGYdgYcq4vDF0h5vr343cD/eD6NM33uLq2VcIghIwheNTmu9A+8wRN+Kl6rZ7X/AbKC91joc7zi/Osv+B4Ffaa0jqjxCtNbfVxdCTaGd9vtzvtf6aa3DgJurxFBd++NPa9+mtT7k29allm0eBtorpar+t9kBOFSL+CviePa0OOxa6xkAWuv/aa0vxPvBoIEXznIuEWQk4YuAU0r1VEo9pJSK9/3eHu8QxSrfLseAeKWUpcphoUC21rpEKTUE77BIhSzAA3Su8tq/gd8ppfr42ghXSk2qIaTqjq9OKFAA5Cql2gGPnGXffwPPVgwhKaWilVITfdumA5copa5XSpmUUlFKqSTftmOnxbEaKMJ7Idfsm+d/BfDhOWKt8BZwl+8bklJKOXwXwEOVUj2UUqOUUlagBCj2/R3EeUISvmgM+XgvIq72zSxZBWwFHvJtXwT8CBxVSh33vfZr4M9KqXzgj3incwKgtS4CngVW+IYtUrTWn+PtrX7oG37ZivcC8RmqO76GuP8EDMR7kXQO8NlZ3uPf8X4j+cYX8yrfe0ZrfQC4zPd+s4GNQH/fcf/FO6aeo5T6QmtdijfBjweOA28At/q+FZ2T1nodcAfwOnAS7wXgyb7NVuB533mPAjHA72pzXhEclNayAIoQ9aGUOgDcrLVeds6dhWgGpIcvRD0opaLxTtVMb+JQhKg1SfhC1JHyloRIA17zDdcI0SLIkI4QQpwnpIcvhBDniWZbPK1169Y6ISGhqcMQQogWZf369ce11tHVbWu2CT8hIYF169Y1dRhCCNGiKKX217RNhnSEEOI8IQlfCCHOE5LwhRDiPNFsx/CFEMHJ7XaTkZFBScnplZ1FXdhsNuLj4zGbzbU+RhK+EKJRZWRkEBoaSkJCAkrVVHxUnI3WmhMnTpCRkUGnTp1qfVyjJnylVDreQlrlQJnWOrkx2xdCNL2SkhJJ9g2klCIqKoqsrKw6HdcUPfyRWuvj595NCBGsJNk3XH3+hkF30Xbb4Tymzt9JbpG7qUMRQohmpbETvsZbL3y9UurO0zcqpe5USq1TSq2r61eVCmmZ+by+eDdZBa6GxiqEOM89/fTTTJ06tdb7P/fcc/Vq59VXX6WoqKhex9ZFYyf8C7XWA/Eu7nCPUuriqhu11m9qrZO11snR0dXeGXxOTqt3lKqotKyhsQohRJ3UlPC11ng8NS8uFpQJ37e+J1rrTOBzYIi/27BbvAm/0FXu71MLIYJAYWEhl19+Of3796dv37589NFHJCQkcPy499LiunXrGDFiROX+mzZtYtiwYXTr1o233noLgCNHjnDxxReTlJRE3759+e6773j88ccpLi4mKSmJm266ifT0dHr06MGtt95K3759OXjwIHfffTfJycn06dOHp556CoB//OMfHD58mJEjRzJy5EgAvvnmG4YNG8bAgQOZNGkSBQUFfnnvjXbRVinlAAxa63zf87HAn/3djsNqBKDQJT18IZq7P335I9sO5/n1nL3jwnjqij41bv/666+Ji4tjzpw5AOTm5vLYY4/VuP/mzZtZtWoVhYWFDBgwgMsvv5wZM2Zw6aWX8sQTT1BeXk5RUREXXXQRr7/+Ohs3bgQgPT2dtLQ03nvvPVJSvKtoPvvss7Rq1Yry8nJGjx7N5s2bue+++3j55ZdZvHgxrVu35vjx4zzzzDMsWLAAh8PBCy+8wMsvv8wf//jHBv9tGnOWTizwue/Ksgn4n9b6a3834vAN6RTKkI4Qohr9+vXjoYce4rHHHmPChAlcdNFFZ91/4sSJhISEEBISwsiRI1mzZg2DBw/mtttuw+12c9VVV5GUlFTtsR07dqxM9gAff/wxb775JmVlZRw5coRt27aRmJh4yjGrVq1i27ZtpKamAlBaWsqwYcMa+K69Gi3ha6338tPCzQHjsFSM4cuQjhDN3dl64oHSvXt3NmzYwNy5c/nDH/7A6NGjMZlMlWPsp98BfPr0R6UUF198McuWLWPOnDlMnjyZBx98kFtvvfWMthwOR+Xzffv2MXXqVNauXUtkZCSTJ0+u9m5jrTVjxoxhxowZ/ni7pwi6aZl2GdIRQpzF4cOHsdvt3HzzzTzyyCNs2LCBhIQE1q9fD8Cnn356yv6zZs2ipKSEEydOsGTJEgYPHsz+/fuJjY3ljjvu4Je//CUbNmwAwGw243ZXPyU8Ly8Ph8NBeHg4x44dY968eZXbQkNDyc/PByAlJYUVK1awe/duwHvNYdeuXX5570FXWsEhF22FEGexZcsWHnnkEQwGA2azmX/9618UFxdz++238+STT55ywRYgMTGRkSNHcvz4cZ588kni4uJ47733ePHFFzGbzTidTt5//30A7rzzThITExk4cCDPPvvsKefp378/AwYMoGfPnrRv375yyKbiuHHjxhEXF8fixYt59913ufHGG3G5vNPLn3nmGbp3797g995s17RNTk7W9V0ApeeT8/jFsAR+d1kvP0clhGio7du306uX/LfpD9X9LZVS62sqWxN0Qzrg7eUXyJCOEEKcIjgTvtUkF22FEOI0QZnw7RajXLQVQojTBGXClx6+EEKcKWgTvozhCyHEqYIz4VuMUjxNCCFOE5QJ324xyTx8IYQ4TVAmfKfVKLV0hBDiNEGZ8O1WE0XSwxdC1OCDDz5gyJAhJCUl8atf/Yry8nKcTidPPPEE/fv3JyUlhWPHjgGQlJRU+QgJCWHp0qV069atcj1Zj8dD165dycrKYvLkydx9992kpKTQuXNnlixZwm233UavXr2YPHlyZfuBKn98LkFXWgG8Y/il5R5KyzxYTEH5mSZEcJj3OBzd4t9ztukH45+vcfP27dv56KOPWLFiBWazmV//+tdMnz6dwsJCUlJSePbZZ3n00Ud56623+MMf/lBZ7vjLL7/kb3/7GxdccAE333wz06dP5/7772fBggX079+fikWbTp48ycqVK5k9ezZXXnklK1as4O2332bw4MFs3LiR+Pj4gJU/PpfgTPhVVr2ymCxNHI0QojlZuHAh69evZ/DgwQAUFxcTExODxWJhwoQJAAwaNIhvv/228pi0tDQeeeQRFi9ejNls5rbbbmPixIncf//9vPPOO0yZMqVy3yuuuAKlFP369SM2NpZ+/foB0KdPH9LT08nIyAhY+eNzCc6EX1FArbScCHsTByOEqNlZeuKBorXmF7/4BX/9619PeX3q1KmVpZCNRiNlZd7rgAUFBVx//fW89dZbtG3bFoD27dsTGxvLokWLWLNmDdOnT688j9VqBcBgMFQ+r/i9rKwMo9EYsPLH5xKU4x0VJZKLZC6+EOI0o0ePZubMmWRmZgKQ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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# import the models and run some test simulations\n", + "model_reduced_module = amici.import_model_module(model_reduced_name, os.path.abspath(model_reduced_output_dir))\n", + "model_reduced = model_reduced_module.getModel()\n", + "\n", + "model_module = amici.import_model_module(model_name, os.path.abspath(model_output_dir))\n", + "model = model_module.getModel()\n", + "\n", + "\n", + "# simulate model with conservation laws\n", + "model_reduced.setTimepoints(np.linspace(0, 2, 100))\n", + "solver_reduced = model_reduced.getSolver()\n", + "rdata_reduced = amici.runAmiciSimulation(model_reduced, solver_reduced)\n", + "\n", + "# simulate model without conservation laws\n", + "model.setTimepoints(np.linspace(0, 2, 100))\n", + "solver = model.getSolver()\n", + "rdata = amici.runAmiciSimulation(model, solver)\n", + "\n", + "# plot trajectories\n", + "import amici.plotting\n", + "amici.plotting.plotStateTrajectories(rdata_reduced, model=model_reduced)\n", + "amici.plotting.plotObservableTrajectories(rdata_reduced, model=model_reduced)\n", + "\n", + "amici.plotting.plotStateTrajectories(rdata, model=model)\n", + "amici.plotting.plotObservableTrajectories(rdata, model=model)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inferring the steady state of the system (postequilibration)\n", + "\n", + "First, we want to demonstrate that Newton's method will fail with the unreduced model due to a singular right hand side Jacobian." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " ts: [inf]\n", + " x: [[0.11 2. 0.2 2.00000002]]\n", + " x0: [5. 2. 0. 0.]\n", + " x_ss: [nan nan nan nan]\n", + " sx: None\n", + " sx0: None\n", + " sx_ss: None\n", + " y: [[2.00000002 0.11 ]]\n", + " sigmay: [[1. 1.]]\n", + " sy: None\n", + " ssigmay: None\n", + " z: None\n", + " rz: None\n", + " sigmaz: None\n", + " sz: None\n", + " srz: None\n", + " ssigmaz: None\n", + " sllh: None\n", + " s2llh: None\n", + " J: [[-20. 0. 20. 0. ]\n", + " [ -1.1 0. 1.1 0. ]\n", + " [ 1. 0. -11. 10. ]\n", + " [ 0. 0. 0. -1. ]]\n", + " xdot: [ 0.00000000e+00 0.00000000e+00 2.22044605e-16 -2.24170307e-08]\n", + " status: 0.0\n", + " llh: nan\n", + " chi2: nan\n", + " res: [0. 0.]\n", + " sres: None\n", + " FIM: None\n", + " w: [[2. 2. 2. 2.00000002]]\n", + " preeq_wrms: nan\n", + " preeq_t: nan\n", + "preeq_numlinsteps: None\n", + "preeq_numsteps: [[0 0 0]]\n", + "preeq_numstepsB: 12.0\n", + "preeq_status: [[0 0 0]]\n", + "preeq_cpu_time: 0.0\n", + "preeq_cpu_timeB: 0.0\n", + " posteq_wrms: 0.5604257578208488\n", + " posteq_t: 19.2252094591474\n", + "posteq_numlinsteps: None\n", + "posteq_numsteps: [[ 0 417 0]]\n", + "posteq_numstepsB: 0.0\n", + "posteq_status: [[-3 1 0]]\n", + "posteq_cpu_time: 2.315\n", + "posteq_cpu_timeB: 0.0\n", + " numsteps: None\n", + " numrhsevals: None\n", + "numerrtestfails: None\n", + "numnonlinsolvconvfails: None\n", + " order: None\n", + " cpu_time: 0.0\n", + " numstepsB: None\n", + "numrhsevalsB: None\n", + "numerrtestfailsB: None\n", + "numnonlinsolvconvfailsB: None\n", + " cpu_timeB: 0.0\n" + ] + } + ], + "source": [ + "# Call postequilibration by setting an infinity timepoint\n", + "model.setTimepoints(np.full(1, np.inf))\n", + "\n", + "# set the solver \n", + "solver = model.getSolver()\n", + "solver.setNewtonMaxSteps(10)\n", + "solver.setMaxSteps(1000)\n", + "rdata = amici.runAmiciSimulation(model, solver)\n", + "\n", + "#np.set_printoptions(threshold=8, edgeitems=2)\n", + "for key, value in rdata.items():\n", + " print('%12s: ' % key, value)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The fields `posteq_status` and `posteq_numsteps` in rdata tells us how postequilibration worked:\n", + " * the first entry informs us about the status/number of steps in Newton's method (here 0, as Newton's method did not work)\n", + " * the second entry tells us, the status/how many integration steps were taken until steady state was reached\n", + " * the third entry informs us about the status/number of Newton steps in the second launch, after simulation\n", + "\n", + "The status is encoded as an Integer flag with the following meanings:\n", + " * ` 1`: Successful run\n", + " * ` 0`: Did not run\n", + " * `-1`: Error: No further specification is given, the error message should give more information.\n", + " * `-2`: Error: The method did not converge to a steady state within the maximum number of steps (Newton's method or simulation).\n", + " * `-3`: Error: The Jacobian of the right hand side is singular (only Newton's method)\n", + " * `-4`: Error: The damping factor in Newton's method was reduced until it met the lower bound without success (Newton's method only)\n", + " * `-5`: Error: The model was simulated past the timepoint `t=1e100` without finding a steady state. Therefore, it is likely that the model has not steady state for the given parameter vector.\n", + " \n", + "Here, only the second entry of `posteq_status` contains a positive integer: The first run of Newton's method failed due to a Jacobian, which oculd not be factorized, but the second run (simulation) contains the entry 1 (success). The third entry is 0, thus Newton's method was not launched for a second time.\n", + "More information can be found in`posteq_numsteps`: Also here, only the second entry contains a positive integer, which is smaller than the maximum number of steps taken (<1000). Hence steady state was reached via simulation, which corresponds to the simulated time written to `posteq_time`.\n", + "\n", + "We want to demonstrate a complete failure if inferring the steady state by reducing the number of integration steps to a lower value:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Status of postequilibration: [[-3 -2 -3]]\n", + "Number of steps employed in postequilibration: [[ 0 100 0]]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Warning] AMICI:simulation: AMICI simulation failed:\n", + "Steady state computation failed. First run of Newton solver failed: RHS could not be factorized. Simulation to steady state failed: No convergence was achieved. Second run of Newton solver failed: RHS could not be factorized.\n", + "Error occured in:\n", + "0 0x1060f7913 amici::SteadystateProblem::handleSteadyStateFailure(amici::Solver const*, amici::Model*) + 531\n", + "1 0x1060f6b3c amici::SteadystateProblem::findSteadyState(amici::Solver*, amici::NewtonSolver*, amici::Model*, int) + 332\n", + "2 0x1060f6882 amici::SteadystateProblem::workSteadyStateProblem(amici::Solver*, amici::Model*, int) + 322\n", + "3 0x1060a4615 amici::AmiciApplication::runAmiciSimulation(amici::Solver&, amici::ExpData const*, amici::Model&, bool) + 405\n", + "4 \n" + ] + } + ], + "source": [ + "# reduce maxsteps for integration\n", + "solver.setMaxSteps(100)\n", + "rdata = amici.runAmiciSimulation(model, solver)\n", + "print('Status of postequilibration:', rdata['posteq_status'])\n", + "print('Number of steps employed in postequilibration:', rdata['posteq_numsteps'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, the same logic works, if we use the reduced model.\n", + "For sufficiently many Newton steps, postequilibration is achieved by Newton's method in the first run. In this specific example, the steady state is found within one step." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Status of postequilibration: [[1 0 0]]\n", + "Number of steps employed in postequilibration: [[2 0 0]]\n" + ] + } + ], + "source": [ + "# Call postequilibration by setting an infinity timepoint\n", + "model_reduced.setTimepoints(np.full(1, np.inf))\n", + "\n", + "# set the solver \n", + "solver_reduced = model_reduced.getSolver()\n", + "solver_reduced.setNewtonMaxSteps(10)\n", + "solver_reduced.setMaxSteps(100)\n", + "rdata_reduced = amici.runAmiciSimulation(model_reduced, solver_reduced)\n", + "\n", + "print('Status of postequilibration:', rdata_reduced['posteq_status'])\n", + "print('Number of steps employed in postequilibration:', rdata_reduced['posteq_numsteps'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Postequilibration with sensitivities\n", + "\n", + "Equilibration is possible with forward and adjoint sensitivity analysis. As for the main simulation part, adjoint sensitivity analysis yields less information than forward sensitivity analysis, since no state sensitivities are computed. However, it has a better scaling behavior towards large model sizes.\n", + "\n", + "### Postequilibration with forward sensitivities\n", + "\n", + "If forward sensitivity analysis is used, then state sensitivities at the timepoint `np.inf` will be computed. This can be done in (currently) two different ways:\n", + " 1. If the Jacobian $\\nabla_x f$ of the right hand side $f$ is not (close to) singular, the most efficient approach will be solving the linear system of equations, which defines the steady state sensitivities:\n", + " $$ \n", + " 0 = \\dot{s}^x = (\\nabla_x f) s^x + \\frac{\\partial f}{\\partial \\theta} \n", + " \\qquad \\Rightarrow \\qquad\n", + " (\\nabla_x f) s^x = - \\frac{\\partial f}{\\partial \\theta} \n", + " $$\n", + " This approach will always be chosen by AMICI, if the option `model.SteadyStateSensitivityMode` is set to `SteadyStateSensitivityMode.newtonOnly`. Furthermore, it will also be chosen, if the steady state was found by Newton's method, as in this case, the Jacobian is at least not singular (but may still be poorly conditioned). A check for the condition number of the Jacobian is currently missing, but will soon be implemented.\n", + " 2. If the Jacobian is poorly conditioned or singular, then the only way to obtain a reliable result will be integrating the state variables with state sensitivities until the norm of the right hand side becomes small. This approach will be chosen by AMICI, if the steady state was found by simulation and the option `model.SteadyStateSensitivityMode` is set to `SteadyStateSensitivityMode.simulationFSA`. This approach is numerically more stable, but the computation time for large models may be substantial.\n", + "\n", + "Side remark:\n", + "\n", + "A possible third way may consist in a (relaxed) Richardson iteration type approach, which interprets the entries of the right hand side $f$ as residuals and minimizes the squared residuals $\\Vert f \\Vert^2$ by a Levenberg-Marquart-type algorithm. This approach would also work for poorly conditioned (and even for singular Jacobians if additional constraints are implemented as Lagrange multipliers) while being faster than a long forward simulation." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We want to demonstrate both possibilities to find the steady state sensitivities, as well as the failure of their computation if the Jacobian is singular and the `newtonOnly` setting was used." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Status of postequilibration: [[-3 1 0]]\n", + "Number of steps employed in postequilibration: [[ 0 1026 0]]\n", + "Computed state sensitivities:\n", + "[[-1.10000000e-02 0.00000000e+00 -6.70507402e-18 -1.20114408e-11]\n", + " [ 1.00000000e-02 0.00000000e+00 -8.22965063e-19 1.20114329e-11]\n", + " [-1.00000000e-03 0.00000000e+00 -2.00000000e-02 -2.40228711e-11]\n", + " [ 5.50000000e-02 0.00000000e+00 1.00000000e-01 9.99999999e-01]\n", + " [ 0.00000000e+00 0.00000000e+00 0.00000000e+00 -2.00000004e+00]]\n" + ] + } + ], + "source": [ + "# Call simulation with singular Jacobian and simulationFSA mode\n", + "model.setTimepoints(np.full(1, np.inf))\n", + "model.setSteadyStateSensitivityMode(amici.SteadyStateSensitivityMode.simulationFSA)\n", + "solver = model.getSolver()\n", + "solver.setNewtonMaxSteps(10)\n", + "solver.setSensitivityMethod(amici.SensitivityMethod.forward)\n", + "solver.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "solver.setMaxSteps(10000)\n", + "rdata = amici.runAmiciSimulation(model, solver)\n", + "\n", + "print('Status of postequilibration:', rdata['posteq_status'])\n", + "print('Number of steps employed in postequilibration:', rdata['posteq_numsteps'])\n", + "print('Computed state sensitivities:')\n", + "print(rdata['sx'][0,:,:])" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Status of postequilibration: [[-2 -1 1]]\n", + "Number of steps employed in postequilibration: [[ 0 543 0]]\n", + "Computed state sensitivities:\n", + "[[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Warning] AMICI:simulation: AMICI simulation failed:\n", + "Steady state sensitvitiy computation failed due to unsuccessful factorization of RHS Jacobian\n", + "Error occured in:\n", + "0 0x1060f698b amici::SteadystateProblem::workSteadyStateProblem(amici::Solver*, amici::Model*, int) + 587\n", + "1 0x1060a4615 amici::AmiciApplication::runAmiciSimulation(amici::Solver&, amici::ExpData const*, amici::Model&, bool) + 405\n", + "2 0x1060a4474 amici::runAmiciSimulation(amici::Solver&, amici::ExpData const*, amici::Model&, bool) + 36\n", + "3 0x106061005 _wrap_runAmiciSimulation(_object*, _object*) + 549\n", + "4 0x1021b2309 cfunction_call_varargs + 320\n", + "5 \n" + ] + } + ], + "source": [ + "# Call simulation with singular Jacobian and newtonOnly mode (will fail)\n", + "model.setTimepoints(np.full(1, np.inf))\n", + "model.setSteadyStateSensitivityMode(amici.SteadyStateSensitivityMode.newtonOnly)\n", + "solver = model.getSolver()\n", + "solver.setSensitivityMethod(amici.SensitivityMethod.forward)\n", + "solver.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "solver.setMaxSteps(10000)\n", + "rdata = amici.runAmiciSimulation(model, solver)\n", + "\n", + "print('Status of postequilibration:', rdata['posteq_status'])\n", + "print('Number of steps employed in postequilibration:', rdata['posteq_numsteps'])\n", + "print('Computed state sensitivities:')\n", + "print(rdata['sx'][0,:,:])" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Status of postequilibration: [[1 0 0]]\n", + "Number of steps employed in postequilibration: [[2 0 0]]\n", + "Computed state sensitivities:\n", + "[[-1.1e-02 0.0e+00 -0.0e+00 -0.0e+00]\n", + " [ 1.0e-02 0.0e+00 -0.0e+00 -0.0e+00]\n", + " [-1.0e-03 0.0e+00 -2.0e-02 -0.0e+00]\n", + " [ 5.5e-02 0.0e+00 1.0e-01 1.0e+00]\n", + " [-0.0e+00 0.0e+00 -0.0e+00 -2.0e+00]]\n" + ] + } + ], + "source": [ + "# Call postequilibration by setting an infinity timepoint\n", + "model_reduced.setTimepoints(np.full(1, np.inf))\n", + "model.setSteadyStateSensitivityMode(amici.SteadyStateSensitivityMode.newtonOnly)\n", + "solver_reduced = model_reduced.getSolver()\n", + "solver_reduced.setNewtonMaxSteps(10)\n", + "solver_reduced.setSensitivityMethod(amici.SensitivityMethod.forward)\n", + "solver_reduced.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "solver_reduced.setMaxSteps(1000)\n", + "rdata_reduced = amici.runAmiciSimulation(model_reduced, solver_reduced)\n", + "\n", + "print('Status of postequilibration:', rdata_reduced['posteq_status'])\n", + "print('Number of steps employed in postequilibration:', rdata_reduced['posteq_numsteps'])\n", + "print('Computed state sensitivities:')\n", + "print(rdata_reduced['sx'][0,:,:])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Postequilibration with adjoint sensitivities\n", + "\n", + "Postequilibration also works with adjoint sensitivities. In this case, it is exploited that the ODE of the adjoint state $p$ will always have the steady state 0, since it's a linear ODE: \n", + "$$ \\frac{d}{dt} p(t) = J(x^*, \\theta)^T p(t), $$\n", + "where $x^*$ denotes the steady state of the system state. \n", + "Since the Eigenvalues of the Jacobian are negative and since the Jacobian at steady state is a fixed matrix, this system has a simple algebraic solution:\n", + "$$ p(t) = e^{t J(x^*, \\theta)^T} p_{\\text{end}}$$\n", + "As a consequence, the quadratures in adjoint computation also reduce to a matrix-vector product:\n", + "$$Q(x, \\theta) = Q(x^*, \\theta) = p_{\\text{integral}} * \\frac{\\partial f}{\\partial \\theta}$$\n", + "with\n", + "$$ p_{\\text{integral}} = \\int_0^\\infty p(s) ds = (J(x^*, \\theta)^T)^{-1} p_{\\text{end}}$$\n", + "However, this solution is given in terms of a linear system of equations defined by the transposed Jacobian of the right hand side. Hence, if the (transposed) Jacobian is singular, it is not applicable. \n", + "In this case, standard integration must be carried out." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Status of postequilibration: [[1 0 0]]\n", + "Number of steps employed in postequilibration: [[2 0 0]]\n", + "Number of backward steps employed in postequilibration: 0.0\n", + "Computed gradient: [-1.85900e-02 1.69000e-02 -1.69000e-03 -3.16282e+00 1.60000e+01]\n" + ] + } + ], + "source": [ + "# Call adjoint postequilibration by setting an infinity timepoint \n", + "# and create an edata object, which is needed for adjoint computation\n", + "edata = amici.ExpData(2, 0, 0, np.array([float('inf')]))\n", + "edata.setObservedData([1.8] * 2)\n", + "edata.fixedParameters = np.array([3., 5.])\n", + "\n", + "model_reduced.setSteadyStateSensitivityMode(amici.SteadyStateSensitivityMode.newtonOnly)\n", + "solver_reduced = model_reduced.getSolver()\n", + "solver_reduced.setNewtonMaxSteps(10)\n", + "solver_reduced.setSensitivityMethod(amici.SensitivityMethod.adjoint)\n", + "solver_reduced.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "solver_reduced.setMaxSteps(1000)\n", + "rdata_reduced = amici.runAmiciSimulation(model_reduced, solver_reduced, edata)\n", + "\n", + "print('Status of postequilibration:', rdata_reduced['posteq_status'])\n", + "print('Number of steps employed in postequilibration:', rdata_reduced['posteq_numsteps'])\n", + "print('Number of backward steps employed in postequilibration:', rdata_reduced['posteq_numstepsB'])\n", + "print('Computed gradient:', rdata_reduced['sllh'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we carry out the same computation with a system that has a singular Jacobian, then `posteq_numstepsB` will not be `0` any more (which indicates that the linear system solve was used to compute backward postequilibration). \n", + "Now, integration is carried out and hence `posteq_numstepsB > 0`" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Status of postequilibration: [[-3 -1 1]]\n", + "Number of steps employed in postequilibration: [[ 0 479 0]]\n", + "Number of backward steps employed in postequilibration: 3076.0\n", + "Computed gradient: [-1.85899987e-02 1.68999988e-02 -1.69000055e-03 -3.16282001e+00\n", + " 1.60000000e+01]\n" + ] + } + ], + "source": [ + "# Call adjoint postequilibration with model with singular Jacobian\n", + "model.setSteadyStateSensitivityMode(amici.SteadyStateSensitivityMode.newtonOnly)\n", + "solver = model.getSolver()\n", + "solver.setNewtonMaxSteps(10)\n", + "solver.setSensitivityMethod(amici.SensitivityMethod.adjoint)\n", + "solver.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "rdata = amici.runAmiciSimulation(model, solver, edata)\n", + "\n", + "print('Status of postequilibration:', rdata['posteq_status'])\n", + "print('Number of steps employed in postequilibration:', rdata['posteq_numsteps'])\n", + "print('Number of backward steps employed in postequilibration:', rdata['posteq_numstepsB'])\n", + "print('Computed gradient:', rdata['sllh'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Preequilibrating the model\n", + "\n", + "Sometimes, we want to launch a solver run from a steady state which was inferred numerically, i.e., the system was preequilibrated. In order to do this with AMICI, we need to pass an ExpData object, which contains fixed parameter for the acutal simulation and for preequilibration of the model." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "# create edat, with 3 timepoints and 2 observables:\n", + "edata = amici.ExpData(2, 0, 0,\n", + " np.array([0., 0.1, 1.]))\n", + "edata.setObservedData([1.8] * 6)\n", + "edata.fixedParameters = np.array([3., 5.])\n", + "edata.fixedParametersPreequilibration = np.array([0., 2.])\n", + "edata.reinitializeFixedParameterInitialStates = True" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAEZCAYAAACU3p4jAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAgAElEQVR4nO3deXyU9bn38c+VDRJ2CIvIWlsRUNYEsK6IKFQq7TnW5REVUDzaHpfautVatUULpz7WWpdWLaKPFG3VKq3LUSvqKYIkARQUcTmCIij7mkC26/njvrMayAzJzCSZ7/v1ysvM3Nt1J/jNb35zz3WbuyMiIi1fSqILEBGR+FDgi4gkCQW+iEiSUOCLiCQJBb6ISJJQ4IuIJAkFvsghMrP3zOzkJlDHH8zs5kTXIU2fAl/iwsyON7O3zGynmW0zs0Vmlhsum2pm/4piX/3MzM0s7RBradD2Fdx9sLu/3pB9mNlcM5vZwDouc/dfNWQfkhwa9A9eJBJm1h74B3A58BcgAzgB2J/Iug7GzNLcvTTRddTHzFLdvSzRdUjzoBG+xMORAO4+393L3L3I3V9293fNbCDwB+BYM9tjZjsAzOwMM1tuZrvM7HMzu7Xa/t4M/7sj3ObYcJvpZrbazLab2X+bWd8D1PO17cNXGYvM7LdmthW41cyOMLPXzGyrmW0xs3lm1rFiJ2a21sxODb9PMbMbzOyTcP2/mFnnautWvMLZEZ7PVDO7FDgfuC6s4+/hugPN7PVw3ffM7Mxq+5lrZg+Y2QtmthcYW/tVgplNMrMV4fZvmdmQasuuN7MvzGy3ma0xs3FR/B6luXN3fekrpl9Ae2Ar8CgwEehUa/lU4F+1njsZOIZgUDIE+Ar4XrisH+BAWrX1JwMfAwMJXrn+HHjrAPXUtf1UoBS4Itw+E/gmMB5oBXQl+ENxd7Vt1gKnht9fBSwBeoXr/xGYHy7rC+wGzgPSgS7AsHDZXGBmtX2mh+fxM4JXQqeE2w6otv5O4LjwZ9O6+j6A4cAmYDSQClwU1tkKGAB8DvSs9nM4ItH/PvQVvy+N8CXm3H0XcDxByD4EbDazBWbW/SDbvO7uK9293N3fBeYDJx3kMJcBv3b31R5MxdwBDDvIKL8uG9z99+5e6sGrkI/d/RV33+/um4G7DlLDZcBN7r7e3fcDtwJnhe8T/B/gVQ9e4ZS4+1Z3X3GA/YwB2gKz3L3Y3V8jmA47r9o6z7n7ovBns6/W9pcCf3T3tz14NfUowdTZGKCMIPgHmVm6u69190+i+PlIM6fAl7gIg3iqu/cCjgZ6AncfaH0zG21mC81ss5ntJAjU7IMcoi/wu3AaYwewDTDg8CjK/LxWDd3N7IlwCmQX8PhBaugL/K3a8VcTBGx3oDcQabD2BD539/Jqz62rdR6fc2B9gZ9U1BHW0ptgVP8xcDXBH6NN4bn1jLAuaQEU+BJ37v4BwTTE0RVP1bHan4EFQG9370Awz28HWf9z4D/cvWO1r0x3f6uuEg5UWq3Hd4TPHePu7YEp1Wqo6/gTax2/tbt/ES47IsJjbgB6m1n1/zf7AF9EUH9FHbfXqiPL3ecDuPuf3f14gj8MDsw+yL6khVHgS8yZ2VFm9hMz6xU+7k0wRbEkXOUroJeZZVTbrB2wzd33mdkogmmRCpuBcuAb1Z77A3CjmQ0Oj9HBzH5wgJLq2r4u7YA9wE4zOxy49iDr/gG4vWIKycy6mtnkcNk84FQzO9vM0sysi5kNC5d9VauOt4FCgjdy08Pr/L8LPFFPrRUeAi4LXyGZmbUJ3wBvZ2YDzOwUM2sF7AOKwp+DJAkFvsTDboI3Ed8OryxZAqwCfhIufw14D/jSzLaEz/0Q+KWZ7QZ+QXA5JwDuXgjcDiwKpy3GuPvfCEarT4TTL6sI3iD+mrq2P0DdtwEjCN4kfR545iDn+DuCVyQvhzUvCc8Zd/8M+E54vtuAFcDQcLs/Ecyp7zCzZ929mCDgJwJbgPuBC8NXRfVy93xgBnAvsJ3gDeCp4eJWwKxwv18C3YAbI9mvtAzmrhugiBwKM/sMmOLub9a7skgToBG+yCEws64El2quTXApIhFT4ItEyYKWEB8Bvw+na0SaBU3piIgkCY3wRUSSRJNtnpadne39+vVLdBkiIs1KQUHBFnfvWteyJhv4/fr1Iz8/P9FliIg0K2a27kDLNKUjIpIkFPgiIklCgS8ikiQU+CIiSUKBLyKSJOJ6lY6ZrSVopFUGlLp7TjyPLyKSzBJxWeZYd99S/2oiItKYmux1+IfsxRvgy5WJrkJE5ND1OAYmzmr03cZ7Dt8J+oUXmNmltRea2aVmlm9m+Zs3b45zaSIiLVtcm6eZ2eHu/oWZdQNeAa44UC/xnJwc1ydtRUSiY2YFB3p/NK4j/PD+nrj7JuBvwKh4Hl9EJJnFLfDDe2u2q/geOI3gNnQiIhIH8XzTtjvwNzOrOO6f3f2lOB5fRCSpxS3w3f1/qbpxs4iIxJk+aSsikiQU+CIiSUKBLyKSJBT4IiJJQoEvIpIkFPgiIklCgS8ikiQU+CIiSUKBLyKSJBT4IiJJQoEvIpIkFPgiIklCgS8ikiQU+CIiSUKBLyKSJBT4IiJJQoEvIpIkFPgiIklCgS8ikiQU+CIiSUKBLyKSJBT4IiJJQoEvIpIkFPgiIklCgS8ikiQU+CIiSUKBLyKSJBT4IiJJQoEvIpIkFPgiIklCgS8ikiTiGvhmlmpmy83sH/E8roiIxH+EfxWwOs7HFBER4hj4ZtYLOAN4OF7HFBGRKvEc4d8NXAeUx/GYIiISikvgm9kkYJO7F9Sz3qVmlm9m+Zs3b45HaSIiSSNeI/zjgDPNbC3wBHCKmT1eeyV3f9Ddc9w9p2vXrnEqTUQkOcQl8N39Rnfv5e79gHOB19x9SjyOLSIiAV2HLyKSJNLifUB3fx14Pd7HFRFJdhrhi4gkCQW+iEiSUOCLiDQh7k55cXFM9h33OXwREani5eXs/+gjCpfmUZiXR2F+Pl0uvpguF09v9GMp8EVE4sjLytj3wQdBuOflU5SfT9nOnQCk9TyMticcT6ujBsTk2Ap8EZEY8pIS9r3/PoV5eezNy6OoYBnle/YAkN6nD21PHUdWTi5Zublk9Do8prUo8EVEGlF5cTH7Vq2qmqJZvhwvLAQgo39/2n/nO2Tl5pKVm0N6jx5xrU2BLyLSAOX79lH0zrvhFE0eRStW4Pv3A9DqW9+i4/e+R1ZuDlk5OaQluGWMAl9EJArlhYUULl9OYX4+hXl57HvnXbykBMxoddRRdDzn7GAEn5NDWqdOiS63BgW+iMhBlO3ZQ9GyZcEIfmkeRe+9B6WlkJpK60GD6HTBBcEIfsQIUjt0SHS5B6XAFxGppmznTgoLllVO0ex7/30oL4e0NDKPPpou06aRNSqXzOEjSG3bJtHlRkWBLyJJrXT79spLJAvz8ti/Zg24YxkZZA4ZQvZl/0FWbi6ZQ4eSkpWV6HIbRIEvIkmldPPmyg84Feblsf+jjwGw1q3JHDaM7P/8UVXAt2qV4GoblwJfRFq0ki+/rJx/L8zLo3jtWgBSsrLIHDGC9pO+GwT80YOxjIzEFhtjCnwRaTHcnZIvvgjCPRzBl3z+OQAp7dqRNWIEHX9wFlm5ubQeNAhLS64ITK6zFZEWxd0pWbeOveEbrIV5+ZRu3AhAaocOZObm0HnK+WTl5tJqwAAsNTXBFSeWAl9Emg13p/iTTyqvoCnMy6d082YAUrt0ISsnh6yLLw4C/lvfxFLUELi6qAPfzNoA+9y9LAb1iIhUqquTZNm2bQCkdetG1qhRwYecRuWS0b8/Zpbgipu2egPfzFIIbjx+PpAL7AdamdkW4Hngj+7+cUyrFJGk4GVl7Fv9QdUIvqCA8rCTZHrPnrQ94YTgQ065uaT36aOAj1IkI/yFwKvAjcAqdy8HMLPOwFhgtpn9zd0fj12ZItIS1ddJst2p48jKzaVNbi7ph8e2k2QyiCTwT3X3ktpPuvs24GngaTNLb/TKRKTFKS8uZt/KlVWXSa5YUdVJ8hvfoP0ZZwTz8KNySe/ePcHVtjz1Bn5dYX8o64hI8omok+SosNFYdnaCq235IpnD3w14XYsAd/f2jV6ViDRLlZ0kwyto9r1brZPkwKPodO45ZIwaxfbevdlfVsZ+YDvA5s3Bl0SsdevW9OrVi/T0yCdYIhnht2tQVSLSYkXcSXLkSFLbB2PDTz/9lPbt2tGlSxe96XqI3J2tW7eyfv16+vfvH/F2ug5fRCIWdJIsqLxMct/q1UEnyfT0oJPk9OlBm4Lhww/YSXLfvn3069dPYd8AZkaXLl3YHOWroogD38xygJuAvuF2FVM6Q6I6oog0G6XbtgVdJPPr6SQ5bBgpmZkR71dh33CH8jOMZoQ/D7gWWAmUR30kEWnyKjpJVrQqKP74EyDsJDl8GNlX/CdtcnNpPWRIi+skWZdbb72Vtm3b8tOf/jSi9e+44w5+9rOfRX2cu+++m0svvZSsGLdfjibwN7v7gphVIiJxV7JxYzB6P0AnyQ7fPTNpOkk2hgMFvrvj7qQcoNXD3XffzZQpU5pU4N9iZg8D/yT4tC0A7v5Mo1clIo2uRifJcARfsn49EHaSHDmSjj/4AVmjcmk9cGCL7SS5d+9ezj77bNavX09ZWRk333wz119/Pfn5+WRnZ5Ofn89Pf/pTXn/9dQDeeecdjj32WLZs2cJ1113HjBkz2LhxI+eccw67du2itLSUBx54gOeff56ioiKGDRvG4MGDuf322zn99NMZPXo0BQUFvPDCC8yaNYu8vDyKioo466yzuO2227jnnnvYsGEDY8eOJTs7m4ULF/Lyyy9zyy23sH//fo444ggeeeQR2rZt2+Bzj+Y3Og04CkinakrHAQW+SBPk7hSvXVvtZh/VOkl27EhWbg6dL5iS0E6St/39Pd7fsKtR9zmoZ3tu+e7gAy5/6aWX6NmzJ88//zwAO3fu5Prrrz/g+u+++y5Llixh7969DB8+nDPOOIP58+dz+umnc9NNN1FWVkZhYSEnnHAC9957LytWrABg7dq1fPTRRzz66KOMGTMGgNtvv53OnTtTVlbGuHHjePfdd7nyyiu56667WLhwIdnZ2WzZsoWZM2fy6quv0qZNG2bPns1dd93FL37xiwb/bKIJ/Fx3H9DgI4pITNTbSTI3l6xLwk6S30zeTpLHHHMMP/nJT7j++uuZNGkSJ5xwwkHXnzx5MpmZmWRmZjJ27FiWLl1Kbm4u06dPp6SkhO9973sMGzaszm379u1bGfYAf/nLX3jwwQcpLS1l48aNvP/++wwZUvO6lyVLlvD+++9z3HHHAVBcXMyxxx7bwLMORBP4b5nZIHd/v1GOLCIN4uXl7P/ww6qbfVTvJNm9O1mjR1e2KWiqnSQPNhKPlSOPPJJly5bxwgsv8POf/5xx48aRlpZGeXkwcbFv374a69f+uZkZJ554Im+++SbPP/88U6dO5ZprruHCCy/82rHatKm6NPXTTz/lzjvvJC8vj06dOjF16tSvHQuCP9zjx49n/vz5jXG6NUQT+GOAFWb2KcEcflSXZZpZa+BNoFV43Kfc/ZYo6xVJWhF1khyVG3SS7N27SQZ8U7BhwwY6d+7MlClT6NixIw8//DD9+vWjoKCAiRMn8vTTT9dY/7nnnuPGG29k7969vP7668yaNYt169bRq1cvZsyYwf79+1m2bBkXXngh6enplJSU1Pnp1127dtGmTRs6dOjAV199xYsvvsjJJ58MQLt27di9ezfZ2dmMGTOGH/3oR3z88cd885vfZO/evXzxxRcceeSRDT73SForHAssASY08Fj7gVPcfU/YbO1fZvaiuy9p4H5FWiQvKWHfe+9VXiJZtGx5VSfJvn1oN/5UsnJy1EkySitXruTaa68lJSWF9PR0HnjgAYqKirj44ou5+eabK0O4wpAhQxg7dixbtmzh5ptvpmfPnjz66KP85je/IT09nbZt2/LYY48BcOmllzJkyBBGjBjB7bffXmM/Q4cOZfjw4Rx11FH07t27csqmYrsJEybQs2dPFi5cyNy5cznvvPPYH/YdmjlzZqMEvrnX1San2gpmDwCjgQ+Bl4CX3P3LBh3ULAv4F3C5u79d1zo5OTmen5/fkMOINCv1dZLMys0Nv3KadSfJ1atXM3DgwESX0SLU9bM0swJ3z6lr/Uh66Vwe7uQoYCIw18w6EPTJfwlYFOndr8wsFSgAvgncVzvszexS4FKAPn36RLJLkWarfN8+ila8U9VJ8p13qjpJHnkkHb///SDgc0aqk6Q0iojn8N39A+AD4Ldmlklw85MfAHcBdf41qWMfZcAwM+sI/M3Mjnb3VdWWPwg8CMEIP+KzEGkGyvfupXDFioN2kszKzSVz5EjSOnVKdLnSAh3SJyvcvQh4Ifw6lO13mNlCgvcFVtW3vkhzVLZnD0UFBZWtCva9935VJ8nBg+l04QXBCH7EiMpOkiKxFG0//Npv+0fcD9/MugIlYdhnAuOB2dEUK9KUNUYnSZFYimc//MOAR8N5/BTgL+7+j0bat0jcVXaSDOfg93/4YVUnyaFDyb7sMrJG5ZI5dGhUnSRFYiWqKR0zGwpUfCztTXd/N9Jtw3WHR3M8kaakZNMmivLz1UlSmq1o+uFfBcygqnfOPDN70N1/H5PKRBKsZOPGqg85Lc2jeN06IOwkOXIkHc6cTFZuDpmD1UlSmodoRvgXA6PdfS+Amc0GFgMKfGn23J2S9eur2hTU1Uny7LNbfCdJadmi+VdrQPXr7cv4+pu4Is1CjU6S4Tx86ZfB5wkrO0mGV9G0OvLIhHSSlNh5/PHHueeeeyguLmb06NHcf//9dOjQgauuuop//OMfZGZm8txzz9G9e/cajdHWrFnDSy+9xCWXXMJbb71F165dKS8v58gjj2Tx4sVce+21ZGZmsnz5cjZt2sScOXN47LHHWLx4MaNHj2bu3LkAMWt/XJ9oAv8R4G0z+1v4+HvAnxq/JJHG5+4Uf/xx5fx7YX4+ZZu3AJCanR3caDsnJ+k7ScbdizfAlysbd589joGJsw64ePXq1Tz55JMsWrSI9PR0fvjDHzJv3jz27t3LmDFjuP3227nuuut46KGH+PnPf17Z7vjvf/87//Vf/8W3v/1tpkyZwrx587j66qt59dVXGTp0KF27dgVg+/btLF68mAULFnDmmWeyaNEiHn74YXJzc1mxYgW9evWKWfvj+kTzwau7zOwNoKIBxDR3Xx6bskQapkYnyYqA374dCDpJthk9prJVQUZ/3VA7mfzzn/+koKCA3NxcAIqKiujWrRsZGRlMmjQJgJEjR/LKK69UbvPRRx9x7bXXsnDhQtLT05k+fTqTJ0/m6quvZs6cOUybNq1y3e9+97uYGccccwzdu3fnmGOOAWDw4MGsXbuW9evXx6z9cX2imoh09wKC1ggiTYqXllZ1kszPr9lJ8vDDaXvSSVV9aNRJsuk4yEg8Vtydiy66iF//+tc1nr/zzjsr/12kpqZSWloKwJ49ezj77LN56KGHOOywwwDo3bs33bt357XXXmPp0qXMmzevcj+twiu0UlJSKr+veFxaWkpqamrM2h/XJ5qrdHKAm4C+4XZRtUcWaUxf6yRZsIzyvXuBqk6SbcIRfHrPngmuVpqScePGMXnyZH784x/TrVs3tm3bxu7duw+4/vTp05k2bdrXbpRyySWXMGXKFC644AJSo3iPJ5btj+sTzQh/HnAtsJKqWxyKxEV5cTH73n236k3W6p0kjziC9t+dFDYayyW9e7cEVytN2aBBg5g5cyannXYa5eXlpKenc99999W57rp163jqqaf48MMPmTNnDgAPP/wwOTk5nHnmmUybNq3GdE4kunbtGrP2x/Wptz1y5Ypm/3L342NcTyW1R05u9XWSrN4qOK1LlwRXK9FoKe2R8/Pz+fGPf8z//M//JKyGRm+PXM0tZvYw8E+Cm5kA4O66ibk0WPnevRQuX1EV8CtXQkkJpKTQ+qij6HTuuUGbghEj1ElSEm7WrFk88MADNebum4NoAn8acBSQTtWUjlP1yVuRiJXt3k3RsmUH7CRZcQ181siRpLZrrHZOIo3jhhtu4IYbbkh0GVGLJvBz3X1AzCqRFq1sx46anSQ/+KCqk+Qxx9Dl4ouDTpLDhqmTpEiMRBP4b5nZIHd/P2bVSItRunUrhfkF6iQp0oREE/hjgHfM7H8J5vB1WaZUKtm0qarRWF4+xZ+EnSQzM8kaPoz2V15BVkUnSTUaE0mIaAJ/Qh3P6TaESapkw4bKJmM1Okm2aUPmyBF0mKxOkiJNTTSB35WaH7yqoBF+C1ejk2Q4ii/54gsAUtq3DzpJnhPcj7X1wKPUSVIkNHXqVCZNmsRZZ52V6FIAffBK6uDuFH+6lsL8OjpJdupEVk4OnS+6UJ0kRZqZaAJ/s7sviFklkjARdZLMzaVNbi4ZRxyhTpLS7D322GOVvXOGDBnCr371K6ZPn86WLVvo2rUrjzzyCH369GHq1KkRtTtu27YtM2bM4OWXX6ZHjx488cQTld0zKxQUFHDNNdewZ88esrOzmTt3LllZWYwaNYoFCxYwYMAAzjvvPE455RRmzJgRk/PWB6+SkJeXs3/Nmqo2BdU7SfboQZsxx1a2ClYnSYml2Utn88G2Dxp1n0d1PorrR11/wOXvvfceM2fO5K233iI7O5tt27Zx0UUXVX7NmTOHK6+8kmeffRaov93xsGHD2Lt3Lzk5Ofz2t7/ll7/8Jbfddhv33ntv5TFLSkq44ooreO655+jatStPPvkkN910E3PmzOHee+9l6tSpXHXVVWzfvj1mYQ/64FVSqNFJMi8v6CS5axdQq5PkqFzSe/VSwEuL9tprr/GDH/yA7OxsADp37szixYt55pkgyi644AKuu+66yvXra3c8bNgwUlJSOOeccwCYMmUK//Zv/1bjmGvWrGHVqlWMHz8egLKyssrOm+PHj+evf/0rP/rRj3jnnXdieu764FUL5CUlFK1aVTn/XrSsqpNkRt++tD/9tLDRWI46SUpCHWwk3lTU1+64LrUHTe7O4MGDWbx48dfWLS8vZ/Xq1WRlZbF9+3Z69erViNXXpA9etQA1O0nmUbh8BV5UBKiTpEhtp5xyCt///ve55ppr6NKlC9u2bePb3/42TzzxBBdccAHz5s37Wivk+pSXl/PUU09x7rnn8uc//5njj6/ZZ3LAgAFs3ryZxYsXc+yxx1JSUsKHH37I4MGD+e1vf8vAgQO54447mDZtGosXLyY9Pb0xT7lStB+8WmFmn6IPXiVUeVERRe+8U3nD7RqdJAcMoOO//3sY8CPVSVKklsGDB3PTTTdx0kknkZqayvDhw/n973/PtGnT+M1vflP5pm002rRpw9KlS5k5cybdunXjySefrLE8IyODp556iiuvvJKdO3dSWlrK1VdfTVpaGg8//DBLly6lXbt2nHjiicycOZPbbrutMU+5UjTtkfvW9by7r2vUikJqj1ylvk6SFfPvWSNHktqxY6LLFTmoltIeubq2bduyZ8+euB+30dsjm5l54IDBXrFO1NVKncp27w4ajYWXSO5b9R6UlQWdJI8eTJfwGvjMESPUSVJEIhbJlM5CM3saeM7dP6t40swygOOBi4CFwNyYVJgE6u0kecklwSh++DBS2qiTpEhTk4jR/aGIJPAnANOB+WbWH9gBtAZSgZeBu919eexKbHlKt26tvIKmspMkYK1aBZ0kL788bBU8lJTWrRNcrYi0FPUGvrvvA+4H7jezdCAbKHL3HbEurqUo+WpT2Kagrk6Sw2k/cYI6SYpIzEXV5crdS4CNMaqlxSjZsKHyTk6FeXmUrAtmwio7SX5vMm1yc2k9eDAWo8uvRERqU1vDBijbsYPideso/uwziteuo3jtWopWrKjqJNmhA1kjR9LpnHPVSVJEEk7pU4+yXbuCUF+7juLP1gXfr1tHydp1lO3cWbWiGek9e9J60CA6X3QRWaPCTpJqNCbSos2dO5f8/PwavXOi2fa0006jZ5w+8R514JtZG2Cfu5dFuV1v4DGgO0EPngfd/XfRHj8WyvbsCQJ93dogzNeto3jdZxSvW1fZVAwAM9IO60FG3760mziBjL79yOjbh4y+fUnv3Vvz7yItSFlZGakxbv09d+5cjj766KYT+GaWApwLnA/kEnzKtpWZbQGeB/7o7h9HcKxS4CfuvszM2gEFZvZKvFo1lO3ZS0m1EXoQ8MF0TNnWrTXWTesRhvr48WT07UtGv75k9OlDep8+pFTrpSEizdPatWuZMGECI0eOZNmyZQwePJjHHnuMQYMGcc455/DKK69w3XXX4e7ccccduDtnnHEGs2fPBuCRRx7h17/+NR07dmTo0KGVPXZq3/Ck+geyZs+ezeOPP05KSgoTJ04kJyeH/Px8zj//fDIzM1m8eDGZMb6/c0TX4QOvAjcCq9y9HMDMOgNjgdlm9jd3f/xgO3H3jYRv+Lr7bjNbDRwONGrgl3y1iaLly6uCPfwq27Klxnpp3boFoX7K2GCE3rcvGX36ktGnt26qLRInX95xB/tXN2575FYDj6LHz35W73pr1qzhT3/6E8cddxzTp0/n/vvvB6BLly4sW7aMDRs2MGbMGAoKCujUqROnnXYazz77LKNHj+aWW26hoKCADh06MHbsWIYPH37QY7344os899xzvP3222RlZbFt2zY6d+7Mvffey5133klOTp0fjG10kQT+qe5eYmb9KsIewN23AU8DT4eXa0bMzPoBw4G3az1/KXApQJ8+faLZZaXCt5ew4bqgA19q12wy+val7UknhtMvfYMpmD59SMnKOqT9i0jL0Lt3b4477jggaGl8zz33AFS2Oc7Ly+Pkk0+uvJHJ+eefz5tvvglQ4/lzzjmHD8PP0hzIq6++yrRp08gKc6dz586Nf0IRiOQ6/JLw22eAEdWXmdkYd19SbZ16mVlbgj8UV7v7rlrHehB4EIJeOpHus7o2J5xA/2eeJr1PX1Lb6lOpIk1ZJCPxWKndwrjicZsGfJo9LS2N8vJgXFxeXk5xcfGhFxgD9V5CYmZnm9ksoJ2ZDQzn9Cs8GM3BwlcCTwPzYnWnrLROnV2IUSEAAA3OSURBVGg9aJDCXkQO6rPPPqvsT19XS+NRo0bxxhtvsGXLFsrKypg/fz4nnXQSo0eP5o033mDr1q2UlJTw17/+tXKbfv36UVBQAMCCBQsoKQnGwuPHj+eRRx6hsLAQgG3btgHQrl07du/eHfNzrRDJNYOLCObZOwF3AR+b2TIz+wdQFOmBLPjz+SdgtbvfdSjFiog0lgEDBnDfffcxcOBAtm/fzuWXX15j+WGHHcasWbMYO3YsQ4cOZeTIkUyePJnDDjuMW2+9lWOPPZbjjjuuRrfKGTNm8MYbbzB06FAWL15c+WphwoQJnHnmmeTk5DBs2DDuvPNOIHiT97LLLmPYsGEUFUUcp4csmvbIx7n7ovD7LkA/4AN33xvh9scD/wOspOoWiT9z9xfqWl/tkUVapqbQHnnt2rVMmjSJVatWJbSOhople+RFFc+5+1Zga+11DrYfd/8XwU1TREQkASKZ0lloZleYWY3LZswsw8xOMbNHCVoki4g0C/369Wv2o/tDcajtkTMJ/lioPbKISDOh9sgiEnfu/rXLIiU6h3KTwajbI5vZ5UCama0AVrj7wT9xICJSTevWrdm6dStdunRR6B8id2fr1q20jvIGSVE3T3P3X5hZd2AY8H0z+6a7z4h2PyKSnHr16sX69evZvHlzoktp1lq3bk2vXr2i2ibiwDez3xF8Otbd/Svgv8MvEZGIpaen079//0SXkZSiada+G1gQtkfGzE43s0X1bCMiIk1ExCN8d/+5mf0f4HUzKwb2ADfErDIREWlU0UzpjANmAHuBw4Dp7r4mVoWJiEjjimZK5ybgZnc/GTgLeNLMTolJVSIi0uiimdI5pdr3K81sIkHny2/HojAREWlch3yH7fAOVuMasRYREYmhQw58AHePfT9PERFpFA0KfBERaT4U+CIiSUKBLyKSJBT4IiJJQoEvIpIkFPgiIklCgS8ikiQU+CIiSUKBLyKSJBT4IiJJQoEvIpIkFPgiIklCgS8ikiQU+CIiSUKBLyKSJBT4IiJJQoEvIpIkFPgiIklCgS8ikiTiFvhmNsfMNpnZqngdU0REqsRzhD8XmBDH44mISDVxC3x3fxPYFq/jiYhITU1qDt/MLjWzfDPL37x5c6LLERFpUZpU4Lv7g+6e4+45Xbt2TXQ5IiItSpMKfBERiR0FvohIkojnZZnzgcXAADNbb2YXx+vYIiICafE6kLufF69jiYjI12lKR0QkSSjwRUSShAJfRCRJKPBFRJKEAl9EJEko8EVEkoQCX0QkSSjwRUSShAJfRCRJKPBFRJKEAl9EJEko8EVEkoQCX0QkScStW6aISKK4O2VeRml5aY3/lpWXVT4+6DIvrfG4Ynmph9sdbFm1x3Udr/aysvIyTu9/OpO+ManRfw4KfJEkUhF80YbQQZcdJPTKvIyS8pKDL6sVrpXHiCRo69i2opYaIeplCf25p1kaqSmppFoqqSmpNR6npaSRlpJWY1lhSWFs6ojJXkWaOHen3MujGpWVldcMqK8t85Iajw8pTOsJverbVgZcHaFYZ+iFjxMp1SILvYrnav+3lbWqsW3tdWrsr9b+qx83LaWeZREGcyTLUi0VM0voz72CAl+C4KsVDtVHZXUG1IFGXlGMyg4WiHW9/K5r24a8DE+kFEuJPqiqLUtPS68Klor16gihiJYdqI4DLEtPSa8zmFNTDr4szdKaTPAlKwV+IyktL2XN9jXs2LcjqkCsb1R20GW1Qi+iUWUdL7UdT+jPrq6QiyT0Ui2VVmmtqkZ7Fl3oNfqILsIRZGpKKimm6yUk/hT4h6isvIwPtn9A3sY88r7KY9lXy9hTsqdB+6wdRvWNlqo/zkjJIDUtupfHtUPooMvqCNPa4XYoYargE4kfBX6Eyr2cD7d/yNKNS8n7Mo+CrwrYXbIbgH7t+zGx/0Rye+RyWJvDDmm+MMVS9HJXRGJKgX8A5V7OR9s/Iv+rfJZuXEr+V/nsKt4FQJ92fTit32nk9sglt0cu3bK6JbhaEZH6KfBD7s4nOz5h6ZdBuOd9mceO/TsAOLzt4YzrM64y4Hu06ZHgakVEope0ge/ufLrrU/I25lWG/LZ92wA4rM1hnNjrREb1GEVuj1x6tu2Z4GpFRBouaQLf3Vm3ax15X+VVvtG6pWgLAN2zunNcz+MqR/CHtz1c8+ki0uK02MB3d9bvXs/SL5dWhvymok0AdM3syqgeoypH8L3b9VbAi0iL1+ICf+Xmlcz/YD55X+Xx5d4vAejSugujeowip0cOo3qMom/7vgp4EUk6LS7wt+7byqINi8jpnsMlR19Cbo9c+nfor4AXkaTX4gL/hMNP4PWzX1fAi4jU0uICPzUlNdEliIg0SS0u8P/+zgZufGYlBmBgUDnat2qPLXwMVu15sBqPq14lmNW9vK7j1Mc9st41EXe4iXDFSFZr7Noi3F3E/Xwi2V+kx4xUIn4mjfnzCPYX4XqN/I8usnON8IiJ+rcZwYqN/f/qf5z0Df7zlG9FuteItbjA79sli7NzeuN4jV+oe/C/kDuVyyoeU/G4zmXh/3yVz1XfT9Vjwm3DPwH1a9zVIv5jE8lakc6GJaK2SFeM9PfQ+Oca6f7qXzHifTXmDy6a40Z61Cb9+2q8qd/G/N0PPrxDA6upW1wD38wmAL8DUoGH3X1WYx9jSK+ODOnVsbF3KyLS7MWtVaGZpQL3AROBQcB5ZjYoXscXEUl28exNOwr42N3/192LgSeAyXE8vohIUotn4B8OfF7t8frwuUpmdqmZ5ZtZ/ubNm+NYmohIy9ek7j7h7g+6e46753Tt2jXR5YiItCjxDPwvgN7VHvcKnxMRkTiIZ+DnAd8ys/5mlgGcCyyI4/FFRJJa3C7LdPdSM/tP4L8JLsuc4+7vxev4IiLJLq7X4bv7C8AL8TymiIgELNKPK8ebmW0G1h3i5tnAlkYspznQOScHnXNyaMg593X3Oq96abKB3xBmlu/uOYmuI550zslB55wcYnXOTeqyTBERiR0FvohIkmipgf9gogtIAJ1zctA5J4eYnHOLnMMXEZGva6kjfBERqUWBLyKSJJp14JvZBDNbY2Yfm9kNdSxvZWZPhsvfNrN+8a+ycUVwzteY2ftm9q6Z/dPM+iaizsZU3zlXW+/fzczNrNlfwhfJOZvZ2eHv+j0z+3O8a2xsEfzb7mNmC81sefjv+zuJqLOxmNkcM9tkZqsOsNzM7J7w5/GumY1o8EHdvVl+EbRn+AT4BpABvAMMqrXOD4E/hN+fCzyZ6LrjcM5jgazw+8uT4ZzD9doBbwJLgJxE1x2H3/O3gOVAp/Bxt0TXHYdzfhC4PPx+ELA20XU38JxPBEYAqw6w/DvAiwR3bBwDvN3QYzbnEX4kN1SZDDwafv8UMM4a8yaW8VfvObv7QncvDB8uIehK2pxFeuOcXwGzgX3xLC5GIjnnGcB97r4dwN03xbnGxhbJOTvQPvy+A7AhjvU1Ond/E9h2kFUmA495YAnQ0cwOa8gxm3Pg13tDlerruHspsBPoEpfqYiOSc67uYoIRQnMWyY1zRgC93f35eBYWQ5H8no8EjjSzRWa2JLxfdHMWyTnfCkwxs/UEPbmuiE9pCRPt/+/1imvzNIkfM5sC5AAnJbqWWDKzFOAuYGqCS4m3NIJpnZMJXsW9aWbHuPuOhFYVW+cBc939/5rZscD/M7Oj3b080YU1F815hB/JDVUq1zGzNIKXgVvjUl1sRHQTGTM7FbgJONPd98eptlip75zbAUcDr5vZWoK5zgXN/I3bSH7P64EF7l7i7p8CHxL8AWiuIjnni4G/ALj7YqA1QZOxlqrRbxrVnAM/khuqLAAuCr8/C3jNw3dDmql6z9nMhgN/JAj75j6vC/Wcs7vvdPdsd+/n7v0I3rc4093zE1Nuo4jk3/azBKN7zCybYIrnf+NZZCOL5Jw/A8YBmNlAgsBvyTe/XgBcGF6tMwbY6e4bG7LDZjul4we4oYqZ/RLId/cFwJ8IXvZ9TPDmyLmJq7jhIjzn3wBtgb+G709/5u5nJqzoBorwnFuUCM/5v4HTzOx9oAy41t2b7avXCM/5J8BDZvZjgjdwpzbnAZyZzSf4o50dvi9xC5AO4O5/IHif4jvAx0AhMK3Bx2zGPy8REYlCc57SERGRKCjwRUSShAJfRCRJKPBFRJKEAl9EJEko8EVEkoQCX0QkSSjwRWoxs15mds4BlmWa2RtmlnqA5Rlm9mbYykOkSVHgi3zdOII+5XWZDjzj7mV1LQxb+/4TqPMPhkgiKfBFqjGz4wm6b55lZivM7Bu1VjkfeC5ct42ZPW9m75jZqmqvCp4N1xNpUvSyU6Qad/+XmeUBP3X3GreeC5t6fcPd14ZPTQA2uPsZ4fIO4fOrgNw4lSwSMY3wRb5uAPBBHc9nA9X7za8ExpvZbDM7wd13AoTTPcVm1i72pYpEToEvUk3YanhneIe02ooIWvIC4O4fEsz1rwRmmtkvqq3bipZxu0VpQTSlI1JTPw5wr1R3325mqWbW2t33mVlPYJu7P25mO4BLAMysC7DF3UviVrVIBDTCF6npA4L+5KvM7Nt1LH8ZOD78/hhgqZmtIOhlPjN8fizQUu6vKy2I+uGLRCG8YfqP3f2Cg6zzDHBDOOUj0mRohC8SBXdfBiw82AevgGcV9tIUaYQvIpIkNMIXEUkSCnwRkSShwBcRSRIKfBGRJKHAFxFJEgp8EZEk8f8Buvh9/JxQIFUAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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8NJLL1FaWsr3vvc97rrrrlqPc8OGDaSmpnLKKad857iSkpKYPXs2ixYt4uabb8bduffee3F3zjnnHO6//34Ann76af7t3/6Nbt26ceKJJ9KuXTsA5s6dy8yZMzn//POB4Ixm9+7dANx///08//zzREVFkZaWRkpKCitWrODiiy+mffv2fPjhh7Rv3/D/E4kcDXdn9ZadZGTlkZmdz/qCPUQZjBsUx4/GD2TGqAR6d4mNaE0tPhgay8qVK3n66af56KOPcHfGjRvHpEmT+OKLL3jyySeZMGECl112GX/84x+59NJLeeWVV/j8888xM3bs2AHA9ddfz89+9jPOOOMMNm7cyIwZM1izZg0AOTk5LF26lPbt2/O73/2Ol156ibvuuou8vDzy8vJISUlh586dvP/++0RHR/PWW29x66238re//Q2Ajz/+mOzsbDp06MCpp57KOeecQ0pKSlX9CxcuZO3atXz88ce4O+eeey5LlizhzDPPrPV4azuuG2+8EYC4uDhWrVrFli1bOO2001i5ciXdu3dn+vTpvPrqq4wbN4558+axcuVKunbtypQpUxgzZswhf76ZmZm89tprfPTRR3To0IGioiJ69OjBo48+yoMPPhh2LCJNjbvzaW5x6Mwgj01F+2gTZZw+OI4rJx7H9FG9ie/UrtHqa/HBUJ+/7BvC0qVL+d73vkfHjh0B+P73v8/7779P//79mTBhAgBz5szhkUce4YYbbiA2NpbLL7+cmTNnMnPmTADeeustcnJyql5z586dVX8tn3vuuVV/DV9wwQVMnz6du+66i5deeqnqr+vi4mIuueQS1q5di5lRVvbPXvLTpk0jLi6uqralS5d+JxgWLlxY9Qa9e/du1q5de9BgqO24DgTD7NmzAVi+fDmTJ0+mZ89gpt+LL76YJUuWAIQtnz17Nl9++eUhf75vvfUWl156KR06dACgR48eh9xepLFVVjqrNn4bDCBn5bGluISYNsaEIfFcN2Uo00b2pnvHto1dJtAKgqGpqXmvvJkRHR3Nxx9/zNtvv83LL7/Mo48+yjvvvENlZSXLli0jNva7p5EHAgegb9++xMXF8dlnn/Hiiy/yxBNPAHD77bczZcoUXnnlFTZs2MDkyZMPWUd17s6vfvUrfvzjHx/xcdVW6+GKjo6msrISgMrKSvbv33/EryUSaRWVzvINRWRm5fHG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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# create the solver object and run the simulation\n", + "solver_reduced = model_reduced.getSolver()\n", + "solver_reduced.setNewtonMaxSteps(10)\n", + "rdata_reduced = amici.runAmiciSimulation(model_reduced, solver_reduced, edata)\n", + "\n", + "amici.plotting.plotStateTrajectories(rdata_reduced, model = model_reduced)\n", + "amici.plotting.plotObservableTrajectories(rdata_reduced, model = model_reduced)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also combine pre- and postequilibration." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "# Change the last timepoint to an infinity timepoint.\n", + "edata.setTimepoints(np.array([0., 0.1, float('inf')]))\n", + "\n", + "# run the simulation\n", + "rdata_reduced = amici.runAmiciSimulation(model_reduced, solver_reduced, edata)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prequilibration with sensitivities\n", + "\n", + "Beyond the need for an ExpData object, the steady state solver logic in preequilibration is the same as in postequilibration, also if sensitivties are requested. The computation will fail for singular Jacobians, if `SteadyStateSensitivityMode` is set to `newtonOnly`, or if not enough steps can be taken.\n", + "However, if forward simulation with steady state sensitivities is allowed, or if the Jacobian is not singular, it will work." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Prequilibration with forward sensitivities" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " preeq_wrms: 0.5604257578208488\n", + " preeq_t: 19.2252094591474\n", + " preeq_numlinsteps: None\n", + " preeq_numsteps: [[ 0 417 0]]\n", + " preeq_numstepsB: 0.0\n", + " preeq_status: [[-3 1 0]]\n", + " preeq_cpu_time: 1.723\n", + " preeq_cpu_timeB: 0.0\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Warning] AMICI:simulation: AMICI simulation failed:\n", + "Steady state sensitvitiy computation failed due to unsuccessful factorization of RHS Jacobian\n", + "Error occured in:\n", + "0 0x1060f698b amici::SteadystateProblem::workSteadyStateProblem(amici::Solver*, amici::Model*, int) + 587\n", + "1 0x1060a456f amici::AmiciApplication::runAmiciSimulation(amici::Solver&, amici::ExpData const*, amici::Model&, bool) + 239\n", + "2 0x1060a4474 amici::runAmiciSimulation(amici::Solver&, amici::ExpData const*, amici::Model&, bool) + 36\n", + "3 0x106061005 _wrap_runAmiciSimulation(_object*, _object*) + 549\n", + "4 0x1021b2309 cfunction_call_varargs + 320\n", + "5 \n" + ] + } + ], + "source": [ + "# No postquilibration this time.\n", + "edata.setTimepoints(np.array([0., 0.1, 1.]))\n", + "\n", + "# create the solver object and run the simulation, singular Jacobian, enforce Newton solver for sensitivities\n", + "model.setSteadyStateSensitivityMode(amici.SteadyStateSensitivityMode.newtonOnly)\n", + "solver = model.getSolver()\n", + "solver.setNewtonMaxSteps(10)\n", + "solver.setSensitivityMethod(amici.SensitivityMethod.forward)\n", + "solver.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "rdata = amici.runAmiciSimulation(model, solver, edata)\n", + "\n", + "for key, value in rdata.items():\n", + " if key[0:6] == 'preeq_':\n", + " print('%20s: ' % key, value)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " preeq_wrms: 0.9920376238481097\n", + " preeq_t: 21.270502326483026\n", + " preeq_numlinsteps: None\n", + " preeq_numsteps: [[ 0 1026 0]]\n", + " preeq_numstepsB: 0.0\n", + " preeq_status: [[-3 1 0]]\n", + " preeq_cpu_time: 12.439\n", + " preeq_cpu_timeB: 0.0\n" + ] + } + ], + "source": [ + "# Singluar Jacobian, use simulation\n", + "model.setSteadyStateSensitivityMode(amici.SteadyStateSensitivityMode.simulationFSA)\n", + "solver = model.getSolver()\n", + "solver.setNewtonMaxSteps(10)\n", + "solver.setSensitivityMethod(amici.SensitivityMethod.forward)\n", + "solver.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "rdata = amici.runAmiciSimulation(model, solver, edata)\n", + "\n", + "for key, value in rdata.items():\n", + " if key[0:6] == 'preeq_':\n", + " print('%20s: ' % key, value)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " preeq_wrms: 0.0\n", + " preeq_t: nan\n", + " preeq_numlinsteps: None\n", + " preeq_numsteps: [[2 0 0]]\n", + " preeq_numstepsB: 0.0\n", + " preeq_status: [[1 0 0]]\n", + " preeq_cpu_time: 0.036\n", + " preeq_cpu_timeB: 0.0\n" + ] + } + ], + "source": [ + "# Non-singular Jacobian, use Newton solver\n", + "solver_reduced = model_reduced.getSolver()\n", + "solver_reduced.setNewtonMaxSteps(10)\n", + "solver_reduced.setSensitivityMethod(amici.SensitivityMethod.forward)\n", + "solver_reduced.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "rdata_reduced = amici.runAmiciSimulation(model_reduced, solver_reduced, edata)\n", + "\n", + "for key, value in rdata_reduced.items():\n", + " if key[0:6] == 'preeq_':\n", + " print('%20s: ' % key, value)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Prequilibration with adjoint sensitivities\n", + "\n", + "\n", + "When using preequilibration, adjoint sensitivity analysis can be used for simulation. This is a particularly interesting case: Standard adjoint sensitivity analysis requires the intial state sensitivities `sx0` to work, at least if data is given for finite (i.e., not exclusively postequilibration) timepoints: \n", + "For each parameter, a contribution to the gradient is given by the scalar product of the corresponding state sensitivity vector at timepoint $t=0$, (column in `sx0`), with the adjoint state ($p(t=0)$). Hence, the matrix `sx0` is needed. This scalar product \"closes the loop\" from forward to adjoint simulation.\n", + "\n", + "By default, if adjoint sensitivity analysis is called with preequilibration, the initial state sensitivities are computed in just the same way as if this way done for forward sensitivity analysis. The only difference in the internal logic is that, if the steady state gets inferred via simulation, a separate solver object is used in order to ensure that the steady state simulation does not interefere with the snapshotting of the forward trajectory from the actual time course.\n", + "\n", + "However, also an adjoint version of preequilibration is possible: In this case, the \"loop\" from forward to adjoint simulation needs no closure: The simulation time is extended by preequilibration: forward from $t = -\\infty$ to $t=0$, and after adjoint simulation also backward from $t=0$ to $t = -\\infty$. Similar to adjoint postequilibration, the steady state of the adjoint state (at $t=-\\infty$) is $p=0$, hence the scalar product (at $t=-\\infty$) for the initial state sensitivities of preequilibration with the adjoint state vanishes. Instead, this gradient contribution is covered by additional quadratures $\\int_{-\\infty}^0 p(s) ds \\cdot \\frac{\\partial f}{\\partial \\theta}$. In order to compute these quadratures correctly, the adjoint state from the main adjoint simulation must be passed on to the initial adjoint state of backward preequilibration.\n", + "\n", + "However, as the adjoint state must be passed on from backward computation to preequilibration, it is currently not allowed to alter (reinitialize) states of the model at $t=0$, unless these states are constant, as otherwise this alteration would lead to a discontinuity in the adjoints state as well and hence to an incorrect gradient." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " preeq_wrms: 0.0\n", + " preeq_t: nan\n", + " preeq_numlinsteps: None\n", + " preeq_numsteps: [[2 0 0]]\n", + " preeq_numstepsB: 0.0\n", + " preeq_status: [[1 0 0]]\n", + " preeq_cpu_time: 0.039\n", + " preeq_cpu_timeB: 0.0\n", + "Gradient: [-0.05528395 0.0461776 -0.03354519 -2.34602219 6.314481 ]\n" + ] + } + ], + "source": [ + "# Non-singular Jacobian, use Newton solver and adjoints with initial state sensitivities\n", + "solver_reduced = model_reduced.getSolver()\n", + "solver_reduced.setNewtonMaxSteps(10)\n", + "solver_reduced.setSensitivityMethod(amici.SensitivityMethod.adjoint)\n", + "solver_reduced.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "rdata_reduced = amici.runAmiciSimulation(model_reduced, solver_reduced, edata)\n", + "\n", + "for key, value in rdata_reduced.items():\n", + " if key[0:6] == 'preeq_':\n", + " print('%20s: ' % key, value)\n", + "print('Gradient:', rdata_reduced['sllh'])" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " preeq_wrms: 0.8470065245264354\n", + " preeq_t: 19.213162474372176\n", + " preeq_numlinsteps: None\n", + " preeq_numsteps: [[ 0 426 0]]\n", + " preeq_numstepsB: 0.0\n", + " preeq_status: [[-2 1 0]]\n", + " preeq_cpu_time: 1.753\n", + " preeq_cpu_timeB: 0.0\n", + "Gradient: [-0.05528395 0.0461776 -0.03354519 -2.34602226 6.3144812 ]\n" + ] + } + ], + "source": [ + "# Non-singular Jacobian, use simulation solver and adjoints with initial state sensitivities\n", + "solver_reduced = model_reduced.getSolver()\n", + "solver_reduced.setNewtonMaxSteps(0)\n", + "solver_reduced.setSensitivityMethod(amici.SensitivityMethod.adjoint)\n", + "solver_reduced.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "rdata_reduced = amici.runAmiciSimulation(model_reduced, solver_reduced, edata)\n", + "\n", + "for key, value in rdata_reduced.items():\n", + " if key[0:6] == 'preeq_':\n", + " print('%20s: ' % key, value)\n", + "print('Gradient:', rdata_reduced['sllh'])" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " preeq_wrms: 0.0\n", + " preeq_t: nan\n", + " preeq_numlinsteps: None\n", + " preeq_numsteps: [[2 0 0]]\n", + " preeq_numstepsB: 0.0\n", + " preeq_status: [[1 0 0]]\n", + " preeq_cpu_time: 0.042\n", + " preeq_cpu_timeB: 0.009\n", + "Gradient: [-0.05528395 0.0461776 -0.03354519 -2.34602219 6.314481 ]\n" + ] + } + ], + "source": [ + "# Non-singular Jacobian, use Newton solver and adjoints with fully adjoint preequilibration\n", + "solver_reduced = model_reduced.getSolver()\n", + "solver_reduced.setNewtonMaxSteps(10)\n", + "solver_reduced.setSensitivityMethod(amici.SensitivityMethod.adjoint)\n", + "solver_reduced.setSensitivityMethodPreequilibration(amici.SensitivityMethod.adjoint)\n", + "solver_reduced.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "rdata_reduced = amici.runAmiciSimulation(model_reduced, solver_reduced, edata)\n", + "\n", + "for key, value in rdata_reduced.items():\n", + " if key[0:6] == 'preeq_':\n", + " print('%20s: ' % key, value)\n", + "print('Gradient:', rdata_reduced['sllh'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As for postquilibration, adjoint preequilibration has an analytic solution (via the linear system), which will be preferred. If used for models with singular Jacobian, numerical integration will be carried out, which is indicated by `preeq_numstepsB`." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " preeq_wrms: 0.9986067660342685\n", + " preeq_t: 36.94272314329062\n", + " preeq_numlinsteps: None\n", + " preeq_numsteps: [[ 0 417 0]]\n", + " preeq_numstepsB: 1371.0\n", + " preeq_status: [[-3 1 0]]\n", + " preeq_cpu_time: 2.488\n", + " preeq_cpu_timeB: 5.016\n", + "Gradient: [-0.05528395 0.04617759 -0.03354518 -2.34602224 6.3144811 ]\n" + ] + } + ], + "source": [ + "# Non-singular Jacobian, use Newton solver and adjoints with fully adjoint preequilibration\n", + "solver = model.getSolver()\n", + "solver.setNewtonMaxSteps(10)\n", + "solver.setSensitivityMethod(amici.SensitivityMethod.adjoint)\n", + "solver.setSensitivityMethodPreequilibration(amici.SensitivityMethod.adjoint)\n", + "solver.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "rdata = amici.runAmiciSimulation(model, solver, edata)\n", + "\n", + "for key, value in rdata.items():\n", + " if key[0:6] == 'preeq_':\n", + " print('%20s: ' % key, value)\n", + "print('Gradient:', rdata['sllh'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Controlling the error tolerances in pre- and postequilibration\n", + "\n", + "When solving ODEs or DAEs, AMICI uses the default logic of CVODES and IDAS to control error tolerances. This means that error weights are computed based on the absolute error tolerances and the product of current state variables of the system and their respective relative error tolerances. If this error combination is then controlled.\n", + "\n", + "The respective tolerances for equilibrating a system with AMICI can be controlled by the user via the getter/setter functions `[get|set][Absolute|Relative]ToleranceSteadyState[Sensi]`:" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "ODE solver steps, which were necessary to reach steady state:\n", + "lax tolerances: [[ 0 733 0]]\n", + "strict tolerances: [[ 0 1031 0]]\n", + "\n", + "simulation time correpsonding to steady state:\n", + "6.002011407974004\n", + "31.0689293433781\n", + "\n", + "computation time to reach steady state:\n", + "7.646\n", + "7.837\n" + ] + } + ], + "source": [ + "# Non-singular Jacobian, use simulaiton\n", + "model_reduced.setSteadyStateSensitivityMode(amici.SteadyStateSensitivityMode.simulationFSA)\n", + "solver_reduced = model_reduced.getSolver()\n", + "solver_reduced.setNewtonMaxSteps(0)\n", + "solver_reduced.setSensitivityMethod(amici.SensitivityMethod.forward)\n", + "solver_reduced.setSensitivityOrder(amici.SensitivityOrder.first)\n", + "\n", + "# run with lax tolerances\n", + "solver_reduced.setRelativeToleranceSteadyState(1e-2)\n", + "solver_reduced.setAbsoluteToleranceSteadyState(1e-3)\n", + "solver_reduced.setRelativeToleranceSteadyStateSensi(1e-2)\n", + "solver_reduced.setAbsoluteToleranceSteadyStateSensi(1e-3)\n", + "rdata_reduced_lax = amici.runAmiciSimulation(model_reduced, solver_reduced, edata)\n", + "\n", + "# run with strict tolerances\n", + "solver_reduced.setRelativeToleranceSteadyState(1e-12)\n", + "solver_reduced.setAbsoluteToleranceSteadyState(1e-16)\n", + "solver_reduced.setRelativeToleranceSteadyStateSensi(1e-12)\n", + "solver_reduced.setAbsoluteToleranceSteadyStateSensi(1e-16)\n", + "rdata_reduced_strict = amici.runAmiciSimulation(model_reduced, solver_reduced, edata)\n", + "\n", + "# compare ODE outputs\n", + "print('\\nODE solver steps, which were necessary to reach steady state:')\n", + "print('lax tolerances: ', rdata_reduced_lax['preeq_numsteps'])\n", + "print('strict tolerances: ', rdata_reduced_strict['preeq_numsteps'])\n", + "\n", + "print('\\nsimulation time correpsonding to steady state:')\n", + "print(rdata_reduced_lax['preeq_t'])\n", + "print(rdata_reduced_strict['preeq_t'])\n", + "\n", + "print('\\ncomputation time to reach steady state:')\n", + "print(rdata_reduced_lax['preeq_cpu_time'])\n", + "print(rdata_reduced_strict['preeq_cpu_time'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.2" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/deps/AMICI/python/examples/example_constant_species/model_constant_species.xml b/deps/AMICI/python/examples/example_constant_species/model_constant_species.xml new file mode 100644 index 000000000..7a8ddaa02 --- /dev/null +++ b/deps/AMICI/python/examples/example_constant_species/model_constant_species.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + init_enzyme + + + + + + + + + complex + product + substrate + + + + + + + + + + + + + + compartment + + + synthesis_substrate + k_create + + + + + + + + + + + + + + + + + + compartment + + + + + k_bind + substrate + enzyme + + + + k_unbind + complex + + + + + + + + + + + + + + + + + + + compartment + k_convert + complex + + + + + + + + + + + + + compartment + k_decay + product + + + + + + + diff --git a/deps/AMICI/python/examples/example_presimulation/model_presimulation.ipynb b/deps/AMICI/python/examples/example_presimulation/model_presimulation.ipynb index 4db09a65c..d55c5ee3f 100644 --- a/deps/AMICI/python/examples/example_presimulation/model_presimulation.ipynb +++ b/deps/AMICI/python/examples/example_presimulation/model_presimulation.ipynb @@ -52,11 +52,11 @@ "Species: [('__s0', \"PROT(kin=None, drug=None, phospho='u')\"), ('__s1', 'DRUG(bound=None)'), ('__s2', 'KIN(bound=None)'), ('__s3', \"DRUG(bound=1) ._br_PROT(kin=None, drug=1, phospho='u')\"), ('__s4', \"KIN(bound=1) ._br_PROT(kin=1, drug=None, phospho='u')\"), ('__s5', \"PROT(kin=None, drug=None, phospho='p')\")]\n", "\n", "Reactions:\n", - " r0: __s0 + __s1 <-> __s3\t\t[__s0 * __s1 * kon_prot_drug - __s3 * koff_prot_drug]\n", - " r1: __s0 + __s2 -> __s4\t\t[__s0 * __s2 * kon_prot_kin]\n", - " r2: __s4 -> __s2 + __s5\t\t[__s4 * kphospho_prot_kin]\n", - " r3: __s5 -> __s0\t\t[__s5 * kdephospho_prot]\n", - "Parameters: [('PROT_0', 'PROT_0'), ('DRUG_0', 'DRUG_0'), ('kon_prot_drug', 'kon_prot_drug'), ('koff_prot_drug', 'koff_prot_drug'), ('KIN_0', 'KIN_0'), ('kon_prot_kin', 'kon_prot_kin'), ('kphospho_prot_kin', 'kphospho_prot_kin'), ('kdephospho_prot', 'kdephospho_prot'), ('__obs0', 'pPROT')]\n" + "PROT_DRUG_bind: __s0 + __s1 <-> __s3\t\t[__s0 * __s1 * kon_prot_drug - __s3 * koff_prot_drug]\n", + "PROT_KIN_bind: __s0 + __s2 -> __s4\t\t[__s0 * __s2 * kon_prot_kin]\n", + "PROT_KIN_phospho: __s4 -> __s2 + __s5\t\t[__s4 * kphospho_prot_kin]\n", + "PROT_dephospho: __s5 -> __s0\t\t[__s5 * kdephospho_prot]\n", + "Parameters: [('initProt', 'initProt'), ('initDrug', 'initDrug'), ('initKin', 'initKin'), ('pPROT_obs', 'pPROT_obs'), ('PROT_0', 'PROT_0'), ('DRUG_0', 'DRUG_0'), ('KIN_0', 'KIN_0'), ('kon_prot_drug', 'kon_prot_drug'), ('koff_prot_drug', 'koff_prot_drug'), ('kon_prot_kin', 'kon_prot_kin'), ('kphospho_prot_kin', 'kphospho_prot_kin'), ('kdephospho_prot', 'kdephospho_prot'), ('__obs0', 'pPROT'), ('__obs1', 'tPROT')]\n" ] } ], @@ -88,15 +88,7 @@ "metadata": { "scrolled": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - } - ], + "outputs": [], "source": [ "# Create an SbmlImporter instance for our SBML model\n", "sbml_importer = amici.SbmlImporter(sbml_file)" @@ -136,7 +128,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Observables: {'__obs0': {'name': 'pPROT', 'formula': '__s5 / (__s0 + __s3 + __s4 + __s5)'}}\n" + "Observables: {'__obs0': {'name': 'pPROT', 'formula': '__s5'}}\n" ] } ], @@ -166,7 +158,7 @@ " model_output_dir, \n", " verbose=False,\n", " observables=observables,\n", - " constantParameters=fixedParameters)\n", + " constant_parameters=fixedParameters)\n", "sys.path.insert(0, os.path.abspath(model_output_dir))\n", "# load the compiled module\n", "model_module = importlib.import_module(model_name)" @@ -208,7 +200,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -240,7 +232,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -272,7 +264,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -321,7 +313,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -360,7 +352,7 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -406,15 +398,15 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.0" + "version": "3.7.7" }, "pycharm": { "stem_cell": { "cell_type": "raw", - "source": [], "metadata": { "collapsed": false - } + }, + "source": [] } } }, diff --git a/deps/AMICI/python/examples/example_steadystate/ExampleSteadystate.ipynb b/deps/AMICI/python/examples/example_steadystate/ExampleSteadystate.ipynb index fb5ab0624..fa95d29dd 100644 --- a/deps/AMICI/python/examples/example_steadystate/ExampleSteadystate.ipynb +++ b/deps/AMICI/python/examples/example_steadystate/ExampleSteadystate.ipynb @@ -191,40 +191,40 @@ "name": "stderr", "output_type": "stream", "text": [ - "2020-01-16 11:54:47.121 - amici.sbml_import - INFO - Finished processing SBML parameters (6.30E-04s)\n", - "2020-01-16 11:54:47.125 - amici.sbml_import - INFO - Finished processing SBML species (2.22E-03s)\n", - "2020-01-16 11:54:47.139 - amici.sbml_import - INFO - Finished processing SBML reactions (1.32E-02s)\n", - "2020-01-16 11:54:47.140 - amici.sbml_import - INFO - Finished processing SBML compartments (2.36E-04s)\n", - "2020-01-16 11:54:47.219 - amici.sbml_import - INFO - Finished processing SBML rules (7.89E-02s)\n", - "2020-01-16 11:54:47.300 - amici.sbml_import - INFO - Finished processing SBML observables (6.63E-02s)\n", - "2020-01-16 11:54:47.353 - amici.ode_export - INFO - Finished writing J.cpp (3.82E-02s)\n", - "2020-01-16 11:54:47.362 - amici.ode_export - INFO - Finished writing JB.cpp (8.50E-03s)\n", - "2020-01-16 11:54:47.366 - amici.ode_export - INFO - Finished writing JDiag.cpp (3.08E-03s)\n", - "2020-01-16 11:54:47.375 - amici.ode_export - INFO - Finished writing JSparse.cpp (7.90E-03s)\n", - "2020-01-16 11:54:47.384 - amici.ode_export - INFO - Finished writing JSparseB.cpp (7.47E-03s)\n", - "2020-01-16 11:54:47.399 - amici.ode_export - INFO - Finished writing Jy.cpp (1.41E-02s)\n", - "2020-01-16 11:54:47.498 - amici.ode_export - INFO - Finished writing dJydsigmay.cpp (9.77E-02s)\n", - "2020-01-16 11:54:47.535 - amici.ode_export - INFO - Finished writing dJydy.cpp (3.71E-02s)\n", - "2020-01-16 11:54:47.546 - amici.ode_export - INFO - Finished writing dwdp.cpp (9.46E-03s)\n", - "2020-01-16 11:54:47.549 - amici.ode_export - INFO - Finished writing dwdx.cpp (1.88E-03s)\n", - "2020-01-16 11:54:47.556 - amici.ode_export - INFO - Finished writing dxdotdw.cpp (5.38E-03s)\n", - "2020-01-16 11:54:47.569 - amici.ode_export - INFO - Finished writing dxdotdp_explicit.cpp (1.13E-02s)\n", - "2020-01-16 11:54:47.589 - amici.ode_export - INFO - Finished writing dydx.cpp (1.53E-02s)\n", - "2020-01-16 11:54:47.601 - amici.ode_export - INFO - Finished writing dydp.cpp (1.05E-02s)\n", - "2020-01-16 11:54:47.605 - amici.ode_export - INFO - Finished writing dsigmaydp.cpp (3.87E-03s)\n", - "2020-01-16 11:54:47.609 - amici.ode_export - INFO - Finished writing sigmay.cpp (2.44E-03s)\n", - "2020-01-16 11:54:47.612 - amici.ode_export - INFO - Finished writing w.cpp (2.75E-03s)\n", - "2020-01-16 11:54:47.615 - amici.ode_export - INFO - Finished writing x0.cpp (1.83E-03s)\n", - "2020-01-16 11:54:47.616 - amici.ode_export - INFO - Finished writing x0_fixedParameters.cpp (5.91E-04s)\n", - "2020-01-16 11:54:47.619 - amici.ode_export - INFO - Finished writing sx0.cpp (2.14E-03s)\n", - "2020-01-16 11:54:47.623 - amici.ode_export - INFO - Finished writing sx0_fixedParameters.cpp (2.99E-03s)\n", - "2020-01-16 11:54:47.629 - amici.ode_export - INFO - Finished writing xdot.cpp (5.83E-03s)\n", - "2020-01-16 11:54:47.635 - amici.ode_export - INFO - Finished writing y.cpp (4.59E-03s)\n", - "2020-01-16 11:54:47.638 - amici.ode_export - INFO - Finished writing x_rdata.cpp (1.87E-03s)\n", - "2020-01-16 11:54:47.640 - amici.ode_export - INFO - Finished writing total_cl.cpp (9.08E-04s)\n", - "2020-01-16 11:54:47.643 - amici.ode_export - INFO - Finished writing x_solver.cpp (1.97E-03s)\n", - "2020-01-16 11:54:47.657 - amici.ode_export - INFO - Finished generating cpp code (3.50E-01s)\n", - "2020-01-16 11:54:57.708 - amici.ode_export - INFO - Finished compiling cpp code (1.00E+01s)\n" + "2020-04-24 12:00:42.746 - amici.sbml_import - INFO - Finished processing SBML parameters (5.40E-04s)\n", + "2020-04-24 12:00:42.748 - amici.sbml_import - INFO - Finished processing SBML compartments (4.23E-04s)\n", + "2020-04-24 12:00:42.809 - amici.sbml_import - INFO - Finished processing SBML species (6.01E-02s)\n", + "2020-04-24 12:00:42.819 - amici.sbml_import - INFO - Finished processing SBML reactions (1.00E-02s)\n", + "2020-04-24 12:00:42.847 - amici.sbml_import - INFO - Finished processing SBML rules (2.74E-02s)\n", + "2020-04-24 12:00:42.928 - amici.sbml_import - INFO - Finished processing SBML observables (7.94E-02s)\n", + "2020-04-24 12:00:43.022 - amici.ode_export - INFO - Finished writing J.cpp (4.21E-02s)\n", + "2020-04-24 12:00:43.032 - amici.ode_export - INFO - Finished writing JB.cpp (8.60E-03s)\n", + "2020-04-24 12:00:43.036 - amici.ode_export - INFO - Finished writing JDiag.cpp (3.54E-03s)\n", + "2020-04-24 12:00:43.045 - amici.ode_export - INFO - Finished writing JSparse.cpp (9.11E-03s)\n", + "2020-04-24 12:00:43.056 - amici.ode_export - INFO - Finished writing JSparseB.cpp (8.67E-03s)\n", + "2020-04-24 12:00:43.079 - amici.ode_export - INFO - Finished writing Jy.cpp (2.16E-02s)\n", + "2020-04-24 12:00:43.231 - amici.ode_export - INFO - Finished writing dJydsigmay.cpp (1.51E-01s)\n", + "2020-04-24 12:00:43.281 - amici.ode_export - INFO - Finished writing dJydy.cpp (4.83E-02s)\n", + "2020-04-24 12:00:43.292 - amici.ode_export - INFO - Finished writing dwdp.cpp (9.91E-03s)\n", + "2020-04-24 12:00:43.296 - amici.ode_export - INFO - Finished writing dwdx.cpp (2.48E-03s)\n", + "2020-04-24 12:00:43.305 - amici.ode_export - INFO - Finished writing dxdotdw.cpp (7.81E-03s)\n", + "2020-04-24 12:00:43.315 - amici.ode_export - INFO - Finished writing dxdotdp_explicit.cpp (7.82E-03s)\n", + "2020-04-24 12:00:43.344 - amici.ode_export - INFO - Finished writing dydx.cpp (1.94E-02s)\n", + "2020-04-24 12:00:43.358 - amici.ode_export - INFO - Finished writing dydp.cpp (1.23E-02s)\n", + "2020-04-24 12:00:43.364 - amici.ode_export - INFO - Finished writing dsigmaydp.cpp (5.51E-03s)\n", + "2020-04-24 12:00:43.368 - amici.ode_export - INFO - Finished writing sigmay.cpp (3.35E-03s)\n", + "2020-04-24 12:00:43.373 - amici.ode_export - INFO - Finished writing w.cpp (3.53E-03s)\n", + "2020-04-24 12:00:43.376 - amici.ode_export - INFO - Finished writing x0.cpp (2.23E-03s)\n", + "2020-04-24 12:00:43.378 - amici.ode_export - INFO - Finished writing x0_fixedParameters.cpp (1.14E-03s)\n", + "2020-04-24 12:00:43.382 - amici.ode_export - INFO - Finished writing sx0.cpp (3.75E-03s)\n", + "2020-04-24 12:00:43.387 - amici.ode_export - INFO - Finished writing sx0_fixedParameters.cpp (4.08E-03s)\n", + "2020-04-24 12:00:43.397 - amici.ode_export - INFO - Finished writing xdot.cpp (9.57E-03s)\n", + "2020-04-24 12:00:43.401 - amici.ode_export - INFO - Finished writing y.cpp (3.07E-03s)\n", + "2020-04-24 12:00:43.405 - amici.ode_export - INFO - Finished writing x_rdata.cpp (2.53E-03s)\n", + "2020-04-24 12:00:43.407 - amici.ode_export - INFO - Finished writing total_cl.cpp (1.34E-03s)\n", + "2020-04-24 12:00:43.412 - amici.ode_export - INFO - Finished writing x_solver.cpp (2.74E-03s)\n", + "2020-04-24 12:00:43.437 - amici.ode_export - INFO - Finished generating cpp code (4.67E-01s)\n", + "2020-04-24 12:00:58.500 - amici.ode_export - INFO - Finished compiling cpp code (1.51E+01s)\n" ] } ], @@ -234,7 +234,7 @@ " model_output_dir, \n", " verbose=logging.INFO,\n", " observables=observables,\n", - " constantParameters=constantParameters,\n", + " constant_parameters=constantParameters,\n", " sigmas=sigmas)" ] }, @@ -273,6 +273,7 @@ "name": "stdout", "output_type": "stream", "text": [ + "Model name: model_steadystate_scaled\n", "Model parameters: ('p1', 'p2', 'p3', 'p4', 'p5', 'scaling_x1', 'offset_x2', 'observable_x1withsigma_sigma')\n", "Model outputs: ('observable_x1', 'observable_x2', 'observable_x3', 'observable_x1_scaled', 'observable_x2_offsetted', 'observable_x1withsigma')\n", "Model states: ('x1', 'x2', 'x3')\n" @@ -639,26 +640,87 @@ " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n", " sres: None\n", " FIM: None\n", - "wrms_steadystate: nan\n", - "t_steadystate: nan\n", - "newton_numlinsteps: None\n", - "newton_numsteps: [[0 0 0]]\n", - "newton_cpu_time: 0.0\n", - " numsteps: [ 0 100 144 165 181 191 200 208 216 221 225 228 232 236 240 245 252 257\n", - " 262 267 271 274 278 281 284 287 290 293 296 299 301 304 307 310 314 316\n", - " 318 321 323 326 329 332 334 336 340 343 346 349 352 355 358 362 365 369\n", - " 372 375 378 381 384 387]\n", - " numrhsevals: [ 0 114 160 193 212 227 237 247 256 261 265 268 272 276 281 287 298 304\n", - " 309 315 319 322 326 329 332 335 338 341 345 348 351 354 358 361 365 368\n", - " 372 375 378 381 384 387 389 392 396 399 403 407 410 413 416 420 423 427\n", - " 431 435 438 442 445 448]\n", - "numerrtestfails: [0 1 1 3 3 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5\n", - " 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5]\n", + " w: [[0.01 0.02 0.16 1.4 0.7 0.1 ]\n", + " [0.3363426 0.21274269 0.29346324 0.1903178 0.0951589 0.1 ]\n", + " [0.31356076 0.20010373 0.28588036 0.13882541 0.0694127 0.1 ]\n", + " [0.29842785 0.18582001 0.27212146 0.12698788 0.06349394 0.1 ]\n", + " [0.28688753 0.17390856 0.25974973 0.1184711 0.05923555 0.1 ]\n", + " [0.27705998 0.16385625 0.24903827 0.11137372 0.05568686 0.1 ]\n", + " [0.26855211 0.15531924 0.23977338 0.10536158 0.05268079 0.1 ]\n", + " [0.26115949 0.14803652 0.23174264 0.10024074 0.05012037 0.1 ]\n", + " [0.25472239 0.14179957 0.22476637 0.09586103 0.04793052 0.1 ]\n", + " [0.24910745 0.13643958 0.21869407 0.0921016 0.0460508 0.1 ]\n", + " [0.2442021 0.13181887 0.21339925 0.08886411 0.04443205 0.1 ]\n", + " [0.23991078 0.12782433 0.20877507 0.08606799 0.04303399 0.1 ]\n", + " [0.23615203 0.12436246 0.20473093 0.08364678 0.04182339 0.1 ]\n", + " [0.23285621 0.12135553 0.20118965 0.08154533 0.04077267 0.1 ]\n", + " [0.22996352 0.11873854 0.19808528 0.07971764 0.03985882 0.1 ]\n", + " [0.22742249 0.11645686 0.19536122 0.07812508 0.03906254 0.1 ]\n", + " [0.22518868 0.11446439 0.1929688 0.07673512 0.03836756 0.1 ]\n", + " [0.22322363 0.112722 0.19086601 0.0755202 0.0377601 0.1 ]\n", + " [0.22149398 0.1111964 0.18901651 0.07445689 0.03722844 0.1 ]\n", + " [0.21997073 0.10985912 0.18738881 0.07352518 0.03676259 0.1 ]\n", + " [0.21862862 0.10868575 0.18595553 0.07270795 0.03635397 0.1 ]\n", + " [0.21744563 0.10765529 0.18469283 0.07199046 0.03599523 0.1 ]\n", + " [0.2164025 0.10674963 0.18357995 0.07136003 0.03568002 0.1 ]\n", + " [0.21548241 0.10595311 0.18259874 0.0708057 0.03540285 0.1 ]\n", + " [0.21467061 0.10525213 0.18173333 0.07031797 0.03515899 0.1 ]\n", + " [0.21395417 0.1046349 0.18096983 0.06988859 0.03494429 0.1 ]\n", + " [0.21332175 0.10409116 0.18029606 0.06951039 0.03475519 0.1 ]\n", + " [0.21276339 0.10361194 0.17970135 0.06917712 0.03458856 0.1 ]\n", + " [0.21227033 0.10318943 0.1791763 0.06888332 0.03444166 0.1 ]\n", + " [0.21183485 0.1028168 0.17871267 0.06862424 0.03431212 0.1 ]\n", + " [0.21145019 0.10248805 0.17830322 0.06839569 0.03419784 0.1 ]\n", + " [0.21111037 0.10219794 0.17794155 0.06819402 0.03409701 0.1 ]\n", + " [0.21081014 0.10194188 0.17762205 0.06801603 0.03400802 0.1 ]\n", + " [0.21054485 0.10171582 0.17733978 0.06785891 0.03392945 0.1 ]\n", + " [0.21031042 0.1015162 0.17709038 0.06772017 0.03386009 0.1 ]\n", + " [0.21010324 0.10133991 0.17686998 0.06759766 0.03379883 0.1 ]\n", + " [0.20992014 0.1011842 0.17667522 0.06748945 0.03374472 0.1 ]\n", + " [0.20975831 0.10104665 0.17650309 0.06739386 0.03369693 0.1 ]\n", + " [0.20961526 0.10092512 0.17635095 0.06730941 0.03365471 0.1 ]\n", + " [0.20948882 0.10081774 0.17621648 0.0672348 0.0336174 0.1 ]\n", + " [0.20937705 0.10072285 0.17609762 0.06716887 0.03358444 0.1 ]\n", + " [0.20927824 0.100639 0.17599255 0.06711061 0.0335553 0.1 ]\n", + " [0.20919089 0.1005649 0.17589966 0.06705912 0.03352956 0.1 ]\n", + " [0.20911367 0.1004994 0.17581755 0.06701361 0.03350681 0.1 ]\n", + " [0.2090454 0.1004415 0.17574496 0.06697339 0.0334867 0.1 ]\n", + " [0.20898504 0.10039033 0.17568079 0.06693784 0.03346892 0.1 ]\n", + " [0.20893168 0.1003451 0.17562405 0.06690641 0.03345321 0.1 ]\n", + " [0.2088845 0.10030511 0.17557389 0.06687863 0.03343931 0.1 ]\n", + " [0.20884279 0.10026976 0.17552954 0.06685407 0.03342704 0.1 ]\n", + " [0.2088059 0.10023851 0.17549033 0.06683236 0.03341618 0.1 ]\n", + " [0.2087733 0.10021088 0.17545567 0.06681317 0.03340658 0.1 ]\n", + " [0.20874446 0.10018646 0.17542501 0.0667962 0.0333981 0.1 ]\n", + " [0.20871897 0.10016486 0.17539791 0.0667812 0.0333906 0.1 ]\n", + " [0.20869643 0.10014577 0.17537395 0.06676793 0.03338397 0.1 ]\n", + " [0.2086765 0.10012889 0.17535276 0.0667562 0.0333781 0.1 ]\n", + " [0.20865888 0.10011396 0.17533403 0.06674584 0.03337292 0.1 ]\n", + " [0.2086433 0.10010077 0.17531746 0.06673667 0.03336833 0.1 ]\n", + " [0.20862952 0.1000891 0.17530282 0.06672856 0.03336428 0.1 ]\n", + " [0.20861734 0.10007878 0.17528987 0.0667214 0.0333607 0.1 ]\n", + " [0.20860656 0.10006966 0.17527842 0.06671506 0.03335753 0.1 ]]\n", + " preeq_wrms: nan\n", + " preeq_t: nan\n", + "preeq_numlinsteps: None\n", + "preeq_numsteps: [[0 0 0]]\n", + "preeq_cpu_time: 0.0\n", + " posteq_wrms: nan\n", + " posteq_t: nan\n", + "posteq_numlinsteps: None\n", + "posteq_numsteps: [[0 0 0]]\n", + "posteq_cpu_time: 0.0\n", + " numsteps: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\n", + " numrhsevals: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\n", + "numerrtestfails: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\n", "numnonlinsolvconvfails: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\n", - " order: [0 5 5 5 5 5 4 4 5 5 5 5 5 5 5 4 5 4 4 4 4 4 4 4 4 5 5 4 4 4 4 4 4 5 5 5 5\n", - " 5 5 5 4 4 4 5 5 5 5 5 4 4 5 5 5 4 4 3 3 3 3 4]\n", - " cpu_time: 1.147\n", + " order: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\n", + " cpu_time: 0.0\n", " numstepsB: None\n", "numrhsevalsB: None\n", "numerrtestfailsB: None\n", @@ -715,7 +777,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -727,7 +789,7 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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NhljjGnIvnw2xhgTxwKDMcaYOBYYjDHGxLHAYIwxJo4FBmOMMXGS+bqqMZ1WIBBgx44d+P3+tm6K6WR8Ph99+/bF6/U2eRsLDMYkwY4dO8jKymLAgAFYv5AmWVSV4uJiduzYwcCBA5u8nd1KMiYJ/H4/+fn5FhRMUokI+fn5zb5StcBgTJJYUDBt4XB+7iwwGGOMiWOBwRhjTBwLDMZ0Ylu2bGHkyMMaFqVFPfnkk/z4xz9OmJeZmdmi+5o2bRq5ubmce+65LVrv0cTeSjImyW7/1xrW7ipr0TqH987m1v83okXrPFzBYBCPp/3+arnxxhuprKzk0UcfbeumtFt2xWBMJ3L33XczcuRIRo4cyT333AM4v8i//e1vM2zYMKZPn05lZSUAN910E8OHD6egoICf//znABQVFXHxxRczduxYxo4dy4cffgjAbbfdxhVXXMHEiRO54oorGD9+PGvWrInud/LkySxdupTFixczYcIETjzxRL7yla+wYcOGaJnt27czefJkBg8ezO23356w/XfeeSdjx46loKCAW2+9tdHjXLJkCQUFBfj9fg4cOMCIESNYvXo1AFOmTCErK+sIzmInoKodejr55JPVmPZu7dq1bd0EXbp0qY4cOVIrKiq0vLxchw8frsuXL1dAFy5cqKqqV199td555526d+9eHTJkiIbDYVVVLSkpUVXVSy+9VBcsWKCqqlu3btXjjz9eVVVvvfVWPemkk7SyslJVVe+++2695ZZbVFV1165dOmTIEFVVLS0t1UAgoKqqb7/9tl500UWqqvrEE09oz549de/evVpZWakjRozQJUuWqKpqRkaGqqrOnTtX/+d//kfD4bCGQiE955xz9P3332/0eH/1q1/pDTfcoD/84Q/197//fVzeu+++q+ecc86RnM4OJdHPH844OAl/r7bf6z1jTItauHAhF154IRkZGQBcdNFFLFiwgH79+jFx4kQALr/8cu677z6uv/56fD4f3/3udzn33HOj9+Pfeecd1q5dG62zrKyMiooKAM477zzS0tIAuOSSSzj77LO5/fbbefHFF5k+fToApaWlXHXVVWzcuBERIRAIROs666yzyM/Pj7Zt4cKFjBkzJpr/1ltv8dZbb3Hiic6wLhUVFWzcuJHTTjst4fHecsstjB07Fp/Px3333XfkJ7ATscBgTCdX/z13EcHj8bB4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3nmHF154gW9+85u8+OKLAHHjMRx//PEsWLCATz75hDvuuIObb745uv3ixYt55ZVXWLVqFS+99FKDoSpjx2NYsWIFy5Yt44MPPkh4rLHjMfziF79IOB5DrBNPPDH6PcSCBQsYOXIkS5Ys4eOPP2bcuHFxZX/605/Su3dv3n333WhQOHDgAOPHj2flypWcdtpp/PWvfwWcq4y5c+eycuVKXnvttQb7vf322znjjDNYs2YN06dPjwZcgE2bNnHDDTewfv161q9fz/PPP8/ChQu56667+P3vfw9w0PN5JOyKIUawyOmpccDf/07N55soef4FCu+8k6J77yVj4kQyT5tExqRJpPTt28YtNR1ZU/6ybw02HkPjPB4Pxx13HOvWrWPx4sX87//+b3TktUmTJh3y3KakpETP0cknn8zbb78NJB6bIdbChQujH9dNmzaNvLy8aN7AgQMZNWoUACNGjGDKlCmICKNGjWLLli3Awc/nkbDAECMY6cLX26cPvqFDyP761/F/9hn7X3yJinffpSLy10HKwIFkTDqVjPHjSTvhBDzN+PTemPams43H0JjTTjuNN998E6/Xy5lnnsmMGTMIhUJNGsfZ6/VG2+t2u6PjXicam6GpUlNTo8sulyu67nK5ovUf7HweCbuVFCNYWIgrPR13Zt0PkG/IEHr++lcc987bHPvmG/S4eSbevn3ZP/tFdvzwR2yceCqbzjqbnTf+gn3PPkfVp58Srq5uw6MwJjEbj+HQ5+eee+5hwoQJdOvWjeLiYjZs2JDwFlT9cRMak2hshlgTJ06M3nJ76623KGnmbeuDnc8jYVcMMYJFRXi6dUuYJyKkDhxI6sCBdLnySsJ+P/41a6hasZKqFSuoXLSIsn/9yynsdpN67LH4hg8jddgwfMcPI3XwILuyMG3KxmOYzxlnnMGkSZNYv349FRUV9O3bl1mzZjF16lTGjRvHnj17oremCgoK+PLLLxtcuQBcc801TJs2LfqsoTGJxmZ4//33o/m33norl156Kc888wwTJkygZ8+eZGVlRYPfoRzsfB6JpI3HICKPA+cCharaIASLc/bvBb4OVAIzVHX5oeptyfEYtlx+OSIujnnm6WZvq6oEd++mavVq/OvW4V+7luq16wgWFUXLuPPySB00iNTBg0gZNIjUgQNJGTAAT48e9vbTUc7GYzCJVFdX43a78Xg8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\n", "text/plain": [ "
" ] @@ -762,7 +824,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Log-likelihood -100.615231\n" + "Log-likelihood -86.872839\n" ] } ], @@ -801,7 +863,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -815,7 +877,7 @@ "source": [ "solver.setRelativeTolerance(1e-16)\n", "solver.setAbsoluteTolerance(1e-16)\n", - "solver.setSensitivityOrder(amici.SensitivityOrder_none)\n", + "solver.setSensitivityOrder(amici.SensitivityOrder.none)\n", "rdata_ref = amici.runAmiciSimulation(model, solver, edata)\n", "\n", "def get_simulation_error(solver):\n", @@ -1377,11 +1439,11 @@ "model.requireSensitivitiesForAllParameters() # sensitivities w.r.t. all parameters\n", "# model.setParameterList([1, 2]) # sensitivities \n", "# w.r.t. the specified parameters\n", - "model.setParameterScale(amici.ParameterScaling_none) # parameters are used as-is (not log-transformed)\n", + "model.setParameterScale(amici.ParameterScaling.none) # parameters are used as-is (not log-transformed)\n", "\n", "solver = model.getSolver()\n", - "solver.setSensitivityMethod(amici.SensitivityMethod_forward) # forward sensitivity analysis\n", - "solver.setSensitivityOrder(amici.SensitivityOrder_first) # first-order sensitivities\n", + "solver.setSensitivityMethod(amici.SensitivityMethod.forward) # forward sensitivity analysis\n", + "solver.setSensitivityOrder(amici.SensitivityOrder.first) # first-order sensitivities\n", "\n", "rdata = amici.runAmiciSimulation(model, solver)\n", "\n", @@ -1409,9 +1471,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "Log-likelihood: -1088.566890\n", - "Gradient: [-5.70730678e+01 -7.76339486e+01 1.27121046e+02 1.42311847e+01\n", - " 2.71899987e+02 -1.64169706e+00 3.56056940e+00 1.91288570e+04]\n" + "Log-likelihood: -1782.069948\n", + "Gradient: [ 1.88753631e+01 2.34371294e+01 -4.34446460e+01 -5.65142354e+00\n", + " -1.05291555e+02 5.87696815e-01 -2.16000777e+00 3.30558521e+04]\n" ] } ], @@ -1421,7 +1483,7 @@ "p_orig = np.array(model.getParameters())\n", "p_orig[list(model.getParameterIds()).index('observable_x1withsigma_sigma')] = 0.1 # Change default parameter\n", "model.setParameters(p_orig.flatten())\n", - "model.setParameterScale(amici.ParameterScaling_none)\n", + "model.setParameterScale(amici.ParameterScaling.none)\n", "model.setTimepoints(np.linspace(0, 10, 21)) \n", "\n", "solver = model.getSolver()\n", @@ -1437,8 +1499,8 @@ " list(model.getObservableIds()).index('observable_x1withsigma'))\n", "\n", "# enable sensitivities\n", - "solver.setSensitivityOrder(amici.SensitivityOrder_first) # First-order ...\n", - "solver.setSensitivityMethod(amici.SensitivityMethod_adjoint) # ... adjoint sensitivities\n", + "solver.setSensitivityOrder(amici.SensitivityOrder.first) # First-order ...\n", + "solver.setSensitivityMethod(amici.SensitivityMethod.adjoint) # ... adjoint sensitivities\n", "model.requireSensitivitiesForAllParameters() # ... w.r.t. all parameters\n", "\n", "# compute adjoint sensitivities\n", @@ -1465,16 +1527,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "sllh: |error|_2: 28.864869\n", + "sllh: |error|_2: 49.727388\n", "\n", - "sllh: p[0]: |error|_2: 0.001781\n", - "sllh: p[1]: |error|_2: 0.002541\n", - "sllh: p[2]: |error|_2: 0.026482\n", - "sllh: p[3]: |error|_2: 0.003422\n", - "sllh: p[4]: |error|_2: 0.085271\n", + "sllh: p[0]: |error|_2: 0.015277\n", + "sllh: p[1]: |error|_2: 0.013750\n", + "sllh: p[2]: |error|_2: 0.012565\n", + "sllh: p[3]: |error|_2: 0.015211\n", + "sllh: p[4]: |error|_2: 0.047226\n", "sllh: p[5]: |error|_2: 0.000280\n", "sllh: p[6]: |error|_2: 0.001050\n", - "sllh: p[7]: |error|_2: 28.864726\n", + "sllh: p[7]: |error|_2: 49.727399\n", "\n", "sy: p[0]: |error|_2: 0.002974\n", "sy: p[1]: |error|_2: 0.002717\n", @@ -1516,7 +1578,7 @@ " verbose and print('f: p=%s' % p)\n", " \n", " old_parameters = model.getParameters()\n", - " solver.setSensitivityOrder(amici.SensitivityOrder_none)\n", + " solver.setSensitivityOrder(amici.SensitivityOrder.none)\n", " model.setParameters(p)\n", " rdata = amici.runAmiciSimulation(model, solver, edata)\n", " \n", @@ -1537,8 +1599,8 @@ " verbose and print('g: p=%s' % p)\n", " \n", " old_parameters = model.getParameters()\n", - " solver.setSensitivityMethod(amici.SensitivityMethod_forward)\n", - " solver.setSensitivityOrder(amici.SensitivityOrder_first)\n", + " solver.setSensitivityMethod(amici.SensitivityMethod.forward)\n", + " solver.setSensitivityOrder(amici.SensitivityOrder.first)\n", " model.setParameters(p)\n", " rdata = amici.runAmiciSimulation(model, solver, edata)\n", " \n", @@ -1597,8 +1659,8 @@ "op=model.getParameters()\n", "\n", "\n", - "solver.setSensitivityMethod(amici.SensitivityMethod_forward) # forward sensitivity analysis\n", - "solver.setSensitivityOrder(amici.SensitivityOrder_first) # first-order sensitivities\n", + "solver.setSensitivityMethod(amici.SensitivityMethod.forward) # forward sensitivity analysis\n", + "solver.setSensitivityOrder(amici.SensitivityOrder.first) # first-order sensitivities\n", "model.requireSensitivitiesForAllParameters()\n", "solver.setRelativeTolerance(1e-12)\n", "rdata = amici.runAmiciSimulation(model, solver, edata)\n", @@ -1606,7 +1668,7 @@ "def fd(x0, ip, eps, symbol='llh'):\n", " p = list(x0[:])\n", " old_parameters = model.getParameters()\n", - " solver.setSensitivityOrder(amici.SensitivityOrder_none)\n", + " solver.setSensitivityOrder(amici.SensitivityOrder.none)\n", " p[ip]+=eps\n", " model.setParameters(p)\n", " rdata_f = amici.runAmiciSimulation(model, solver, edata)\n", @@ -1644,7 +1706,7 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABDAAAALICAYAAACJhQBYAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAgAElEQVR4nOzdd1hUxxoG8Pdsp4sIIiCgFLtir7EmGo16NfYeSzQaSxITY9cba6xJbLG3GBKDiS3FRI29Y4nBXlFEQUSQuuye9/4B7hUBXZBlUef3PPMAp8yZQ9E535n5RiIJQRAEQRAEQRAEQRCEwkxh7QYIgiAIgiAIgiAIgiA8jwhgCIIgCIIgCIIgCIJQ6IkAhiAIgiAIgiAIgiAIhZ4IYAiCIAiCIAiCIAiCUOiJAIYgCIIgCIIgCIIgCIWeytoNKEjFihWjr6+vtZshCIIgCK+c0NDQ+yRdrd2OgiT6FYIgCIJgGTn1K16rAIavry9OnDhh7WYIgiAIwitHkqSb1m5DQZEkqQ2ANv7+/qJfIQiCIAgWkFO/QkwhEQRBEARByAWS20gOdHJysnZTBEEQBOG1IgIYgiAIgiAIgiAIgiAUeiKAIQiCIAiCIAiCIAhCofda5cAQBEEQ8gdl2VRkgwGywQClQgGVUgnZYEBSYmLmY4xG2Op00Go0SNPrERsbm2k/ZRlFHB1hq9UiJTkZ96KjQRIgTR+Lu7jA1sYGiYmJiIyKAknTuQBQ0t0dtjY2iIuPx51799L3ZxwDAH5eXrDRahHz8CEioqKeuiEi0McHOq0W0Q8e4E50dPq1nzikQunSUKtUiIyOxt2YmCzfk8oBAVAqlYiIikJ0bCwgSZn2VylTBpIk4fa9e3gQF5e+MeMYhSShYkAAIEkIj4xE3KNH6bsV6e8ZVCoVypYuDUgSbkVGIiE5+f/7JQlajQalSpYEANy+dw/JKSmAJEHKKFqNBl4eHunXVCoBH5+8/eAFwcKio6Ph4uIChUK8YxMEQRCyEgEMQRBeG0a9HkoSSEtDUnw8kh49QlpyMgypqTCkpkLW6+Hn4QEYDLh24waio6Nh0Oth0OuRlpoKJYkmFSoAaWnYf/YsbkVFpe9PS4PRaIS9SoVu1aoBRiN+PHECN2NiYDQaYTQYYDAa4W5riw+qVAGMRsw7dgw3Hz6EUZZhMBphNBoR4OCAUeXKAUYjPj5xArcTE2EkIcsyjCRqOjpiop8fYDSi85kziNbrYZRlyCSMJN50dMQUDw/AaES9ixfxyGhMPx+AkURnOztMK1IENBpR8s4dMGOfDEAmMVinwxc6HRKMRnjEx4OP92WU8QoFJkgS7hiN8Mzm+zsbwKcALgMom83+bwEMAvAPgBrZ7N8AoDuAIwCaZLN/K4A2AHYDaJvN/r8BNAbwW0Y9TzsBoDqATRnteNoFAGUArMu4j6dFAPAAsAzA5Gz2xwNwADAfwNxs9j8OhkzJqONJdgASMj4fDSD4qf3uACIzPh8CYPtT+wMAXMr4vCeAvU/trwYg9PEXRYsC2QRgBPM9mcRTyD/nzp1DUFAQ3nzzTaxfvx4uLi7WbpIgCIJQyIgAhiAIL4SyDH1CAlLj45H66BEctVpoAcTdv4/r169Dn5SE1MREpCYlQZ+cjHp+fiiiVuPijRvYFxYGfUoKUlNToU9NRWpqKj6sUgXFVCrsvnoVGy9eRJrBAL3BkP7RaMTyihXhIklYGx6OFRERSDMaoZdlpMky0kic8PCAvcGAybGxWJCUBD2JNAB6pD9AGpE+d+5jZH2ItAWQmPH5eGR9iCwO4G7G57MBbHtqvx+AbqtXA0h/WN/z1P5qAD7YuRNQKrFFr8cZWYZKkqAEoJQk1NVqgfv3AaUSFyIjcdNggFKSoJAkKCUJfiTw4AGgUCDNYIAsy1AqFNBkHGNrZwe4uQEKBXyjopBKpp+rUEChUKB0iRJAQAAkpRItDh6EQpKgyNgnSRKqlCwJ+PtDLcvof/hw+r4njqnr6wv4+cEhLQ2Tjh6FlLHv8ccGfn6Ary9ck5Mx6/hx09t/hVIJSZJQLzAQ8PREyYQELDx9GlLGuY9LzXLlAHd3lImLw8p//03fnvEWVpIkBJUvDxQrhqoPHmD9hQum7Y+PK1ehAlCkCOpFR+OHK1cyjUCQJAmlK1UCHBzwVlQUNl2/nuV32SMoCLCxQds7d1A6PBwZF4CUMUrCOSgI0GrRJSICQRERWc7XVa8OqFR47+ZNNIiMzLSPsgzUqQMAGHT1KlpkjPB4TKlQADVrAgA+unwZHWJiTCNHAECrUgHVqwMARp07h56xsf8foQLAXqsFqlUDSIw7exbvx8WBQPoxAIra2gJBQenX1GiytF3IHZLbAGyrUaPG+9Zuy6tkyZIlAIBdu3ahWrVq2LhxI2rXrm3lVgmCIAiFiUTy+Ue9ImrUqEGx3JnwqpINBqTExkKRmgqdLCP14UOcCwtD0sOHSI6PR1J8PJITElDVwwOBRYogKjoaqw8eREpKClJSUpCckoKU1FT09vVFPUdHhEVFYeQ//yDFYEgvRiNSZBnfFCmC5pKEPx89QtukJKQ+1Y6/ALwJYCOALtm08zCAOgBWAeifzf6zSiUqarVYSmJiSgo0CgXUkgS1JEGjUODPgACUsLPDugcPsCY6GmqlEhqlEmqVCmqlEivr1YO9nR1+uX0bu+/ehUathlqlgkajgVqtxthmzaDUaLD7+nWci46GSq2GWq2GSq2GRqtFt4YNAZUKJ8PDcTc+HmqNBiqNBiqtFja2tqhRqRKgVuNWdDSS0tKg1umgzNiv0engWrw4oFIhKTUVVCigytiv1GhMD+OC8CqSJCmUZHaDa15Zol+RfxITE+Hh4YE2bdrgo48+QqdOnRAREYE5c+Zg2LBhpkCiIAiC8HrIqV8hRmAIQgExpKYiMSoKSEyEk1IJJCTg4OHDePTgARJiY5EYF4eE+HiUdXJCM3d3GBISMOzPP5Gcmoqk1FQk6/VISktDpyJF8IGDAx4mJKDSzZtIkmUkkUjJuM40AGORPlKgWjbt+BpAIIBopA9VBwANAB0AnSShUVQU6rm4gAAepqRAp1KhiE4HnVoNnVoNp0qVgJIl4ZucjI8uXoRWq/1/0ekQWL06UKIE6iUk4OfwcGhsbKC1tYXWxgYaW1tUKFcOKFIEnQ0GNE9NhcbWFloHB2gcHKCxs4My4+3wIGQ/zP+x3hklJ+0zSk6aZpScZPe9e1LJ5+y3fc5+QRAE4f9++OEHxMfH4+bNmzhz5gxCQ0Px3nvvYcSIEThw4ABWrFgBR0dHazdTEARBsDIRwBCEnJBIuHsXD2/fRnxkJOKjohAXFQWbtDQ09PIC4uLw9Z9/4mZ0NBKTkpCQnIyE1FRU0enwRfHiQEICal6+jBtpaUh4IsDQDcD3GZ+/jf/Pe39sAIBmkgSljQ1+Tk6GjUIBG6UStkolbNVqUKsFSpWCjUaD5kolbHU62Oh0sLW1ha2tLd4oWxaoUAHFVSpsvnABNo6OsHVygo2jI2wcHeHh4wO4uaGcRoNkhQIaBwcoVFn/KaiI9FwEOQkEMPMZ+70ySk7sM4ogCIIgLF26FO7u7jhw4AAOHDiAH374AUuXLkWDBg0wduxYnD59GiEhIahcubK1myoIgiBYkQhgCK8uWcbDGzdw9+JF3L9+Hfdv3ULc/ftAcjL6lC0LxMdj/v79OHrnDuKTkxGXkoJ4vR6ekoQ/tFrg0SO8Kcs4+lS1dZA+DQIAVgO4CsBeoYCdUgl7pRK+zs5AkSKApycakagpSbC3tYW9vT3s7OxQoVQpoHZtwM4O269ehdbJCXbOzrB3dYVdsWJwdHcHnJ0hSRLuPeP2tABWPmO/DsB/nrFfkXGMIAiCIFhTaGgojh8/Djc3N9SpUwe9e/fGqFGjULlyZcycORM7d+5E9+7dUbt2bSxatAj9+vWzdpMFQRAEKxEBDOGlQFlGwt27uH/lCu5fv44axYpBionBHwcOYN+//+J+bCzux8XhfmIikvV6HLe3Bx48wGBZxg9P1eUGoA8A2NjgHxInjUY4qtVw0mrhZm8P/6JFgWbNAEdHjLxxA7EkHF1c4OTiAkc3N7iVLAlUrgw4OuKUvT0kpTLHds95zn01erFviyAIgpBPJEnyBvANgAcALpF81iAzIR8tXboUWq0WUVFRmDdvHnr06IFWrVph4MCBGDZsGN544w2EhIRgwoQJ6N+/Pw4cOICFCxfC1lZM1hMEQXjdiCSegtXJBgMiQkNx5eBBXD55ElcuXcJkb2/YxsbimwsX8OXdu7gvy9A/cU4C0pcdHIn03mYxhQLF1GoUs7GBq709fmjdGgpXV+yJjcUdWUYxLy8U8/ZGEU9POHl6wsXHR2TiFwRByEfWTOIpSdIqAK0BRJGs+MT2t5Ge+kcJYMWzghKSJL0DwJnkd5Ik/UgyuzzEmYh+xYuLi4uDp6cnXFxckJKSgvDwcGi1WgDpq+isWbMGn3zyCVJSUjB58mQ8evQI06ZNQ6VKlRASEoLAwEAr34EgCIJgCSKJp2BVssGAiBMncPngQVw5dQrtHB3hducO1p04gUEREab8EEB6QskBUVEI9PSEj6cn3razQ7GiReFarBiKubujmIcHVG++CXh4YIaTE+a4uOS4ukPjgrg5QRAEwdrWAFgIYN3jDZIkKQEsAvAWgNsAjkuStBXpwYwZT53fD+lpf0IkSeoHYH0BtFkAsGHDBiQmJiIpKQnjxo0zBS+A9GWS+/btixYtWmDIkCEYPXo0atasiSVLlmD8+PGoUaMGVq5ciU6dOlnxDgRBEISCJEZgCPlGNhhw+/hxXD5wAGWNRnjev4/Dx45hwLFjuJqammm5zd9UKrQMDMSJYsUQnJiIgMBA+AcFIaB+fXjVrGlaiUIQBEF4OVh7GVVJknwBbH88AkOSpLoAJpNskfH1GAAg+XTw4vH5nwI4RnKfJEkhJDvmcNxAAAMBwNvbu/rNmzfz+1ZeGyRRpUoVREVF4f79+7hx4wa8vLJP/0wSGzduxNChQxEXF4dhw4bhwIEDOHbsGIYNG4Y5c+ZAI/oOgiAIrwwxAkPIXyRw8iRur1mDD0NCcCU2NlOQYhmA97VaFC1ZEgHOzmjp5ZUepKha1RSkgEqFGgCs1tsVBEEQXmWeAG498fVtALWfcfwfACZLktQdwI2cDiK5TJKkSABtNBpN9fxo6Ovq8OHDOHv2LOzt7dGuXbscgxdA+miMLl26oGnTphg+fDjmzZuHSpUqoVu3bliwYAGOHj2KjRs3wsfHpwDvQBAEQShoIoAh5Mq5rVsRPHs2Sl26hH5RUbBTKnFVpUKAszNaeXkhoEwZ+FetiipvvQVUrIgyCgU2W7vRgiAIgvAcJP8FkO2oi2yO3QZgW40aNd63bKtebd9++y10Oh0SEhIwdOhQs85xdXVFcHAwunbtisGDB2Pjxo1o3749du7ciWrVquG7775Dy5YtLdxyQRAEwVpEAEN4rqu7d+PHmTPxw/79OJuSAgWAD7y80G/FCji3b49/ixa1dhMFQRAE4WkRAEo+8bVXxrYXJklSGwBt/P3986O611JMTAx+/PFHODk5wc/PD40a5W5drv/85z9o2LAhPv30U6xatQqlS5eGQqFAq1atMHbsWPz3v/+FSiW6uYIgCK+a7DMfCq+9+//8A8ybB9SqhWHNmmHcX3/BUa3Ggk6dEPHPP1h06xbQvz8ggheCIAhC4XQcQIAkSaUkSdIA6Apgq5XbJGRYu3Yt9Ho9oqOj8eGHH0KSpFzX4ezsjJUrV2LHjh0wGAy4evUqKlSogOnTp+Ott97C3bt3LdByQRAEwZpEAEMwiQoLw+KuXdHQyQnuVaogYuRIQJYxa+RI3Dx0CAfi4zF040a4V6pk7aYKgiAIgokkScEADgMoI0nSbUmS+pM0ABgKYAeA8wA2kgzLj+uR3EZyoJOTU35U99ohiW+//Raurq5wcHBAz549TfuuXLkCvV7/jLOzat68Of79918MGTIEYWFhcHV1xaFDh1C1alXs3bs3v5svCIIgWJEYW/e6e/gQYQsW4OOvvsKuBw8gAyiv1WJys2bQTJsG1K6NitZuoyAIgiA8A8luOWz/DcBv+X09MYXkxfz999+4fPkyVCoVBg8eDAcHBwDA6dOnUa1aNQQEBGD27Nlo06aN2SMzHBwcsHDhQnTu3Bn9+/dHdHQ0kpOT0aRJE0ybNg2ff/45FDksuS4IwosxGo2m5ZATExPN+vxZ+2VZxoQJE/Duu+9a+9aEQkgso/oaSrh7F1unToX7yZNoeuIE7qSlobFajc61aqHryJGo2L69tZsoCIIgvGSsvYyqNYh+Rd507twZ27dvR3JyMs6fP4+yZcsCAD744AOsW7cOPj4+uHDhApo2bYq5c+ciKCgoV/UnJSVh0qRJmDdvHrRaLZKTk/HOO+9g7dq1cHFxscQtCcJrafTo0fjqq6+Qmpr6/IOfIEkS7OzsYGtrm+nj489v3LiBc+fOYfbs2fjkk0/yNMVMePnl1K8QAYzXhD4hAb9OmYIfgoOx7dYtJAPobmODDYMHA127gtWrQxJvJgRBEIQ8EgEMwRx3796Fl5cXbGxsUKdOHfz1118AgEePHsHDwwMdO3bEsmXLsGzZMkyaNAkPHjxA3759MXXqVJQoUSJX1zp27Bj69euHsLAwKBQKuLu748cff0SDBg0scWuC8Fr59ddf0bp1a7Rt2xY1atTIEoTILjDx+KNOp3tmUCI5ORm9e/dGSEgIBg8ejG+++UYk5X0N5divIPnalOrVq/O1dPcuWzo5EQBdJYlDKlbk/oULaUxLs3bLBEEQhFcEgBMsBP/XF0QB0AbAMn9///z69r02pk2bRgAEwM2bN5u2L126lAB4+PBh07YHDx5w5MiRVKvVtLOz45QpU5iUlJSr66WkpHD8+PFUKBRUqVRUKBScNm0ajUZjvt2TILxuoqOjWbx4cVaqVIkpKSkWuYbRaOSoUaMIgK1atWJ8fLxFriMUXjn1K8QIjFfduXPAO+9g9507uNOvH7rOnw+VTmftVgmCIAivGDECQ3geo9EIPz8/xMfHw8HBAdeuXYNSqXz8kglGoxGnT5/O8mb26tWrGDVqFH7++WeULFkSM2bMQLdu3XKV0+LQoUPo3r07wsPDQRLNmjXDhg0bULx48fy+TUF4pZFE586dsWXLFhw/fhxVqlSx6PWWLl2KDz/8EJUqVcL27dvh6elp0esJhUdO/QoxZ+AVtmvWLHxdvTqQnIymBw6g55IlInghCIIgCIJV7NixAzdv3kRsbCwGDx4MpVIJADhx4gROnTqFQYMGZTus3M/PD5s2bcLevXvh6uqKnj17om7dujh48KDZ165Xrx7++ecf9OrVCwCwe/duVKhQAbt27cqfmxOE10RwcDBCQkLwxRdfWDx4AQCDBg3C9u3bceXKFdSuXRtnzpyx+DWFwq1QjsCQJOltAF8DUAJYQXLmU/sbAvgKQGUAXUmGmFPv6/SmZFXfvhi0Zg3KabU4/s8/0AYGWrtJgiAIwivsdRqB8cQqJO9fvnzZ2s15abRt2xY7d+6ELMu4desWXF1dAQADBgxAcHAw7ty5g+ctTSvLMr777juMGTMGd+7cQefOnTFz5kyUKlXK7Hb8+OOPeP/995GYmAhZljF+/HhMmjRJzLF/RcXExGDAgAH4888/4ejoCEdHRzg5OZk+Pvn58/bZ29u/1gklb9++jUqVKqF8+fLYt2+fKQhZEM6cOYN33nkHcXFx2LhxI1q2bFlg1xas46VJ4ilJkhLAJQBvAbgN4DiAbiTPPXGMLwBHAJ8C2CoCGP8nGwwY37AhZhw+jOYuLth48iScvL2t3SxBEAThFfc6BTAeex36FfklPDwcvr6+UKvV6Nq1K9auXQsAiIuLg4eHB7p164YVK1aYXV9iYiLmzJmDWbNmwWAw4KOPPsLYsWOfGwB5sj3du3c3jeKoW7cufvrpJzE8/RVz6NAhdOnSBVFRUXjvvfcgyzLi4+MRFxeX5eOjR4+eW59CoYCDg4MpoOHi4oI+ffqgd+/eBfowbw2yLKNFixY4fPgwzpw5Az8/vwJvQ0REBFq3bo2zZ89i0aJFGDRoUIG3QSg4OfUrCmOouRaAKySvAYAkST8A+A8AUwCD5I2MfbI1GlhYMSkJPcuWRfCtWxhUrhwWnDgBta2ttZslCIIgCMJrbsWKFSAJvV6PoUOHmrZv2LABSUlJuX4QsbOzw6RJkzBgwACMGzcOs2bNwurVq/HFF19gwIABzx1N4e3tjb1792L27NkYP348jhw5gvLlyyM4OBitWrXK0z2+Lh48eIDz58/j/PnzcHV1Rdu2bQvdqARZljF37lyMGTMG3t7e2LNnD7y9veHu7p5joEGWZTx69CjHAEd2265cuYJ+/fph3rx5mDlzJlq1alXovhf5ZcmSJdi5cye+/fZbqwQvAMDT0xP79u1D165d8cEHH+DatWuYMWNGrvLhCC+/wjgCoyOAt0kOyPi6F4DaJIdmc+waANvFCAwAUVFA27ZYdPQoklu3xsgtW8SyqIIgCEKBeZ1GYIgpJLmTlpYGb29vPHr0CBUqVMDRo0cBpCcDDAoKglKpRGho6As9+IWGhuKTTz7Bvn37UKFCBcydOxctWrQw69wTJ06gY8eOuHnzJgDgk08+wcyZM6FWq/PcnpcdSURERJgCFU+WqKioTMe+/fbbWLp0KbwLyYjfmJgYvPfee9i+fTs6dOiAHj16YOTIkbh+/TpUKhVKliwJX19f+Pj4wNfXN9PnXl5euZpKRBIhISEYO3Ysrly5gkaNGmHWrFmoVauWBe+w4F26dAlBQUFo1KgRfvvtN6sHaQwGA4YPH44lS5agY8eOWLduHWxsbKzaJiH/vUxTSPI1gCFJ0kAAAwHA29u7+uP/nF4l57dtw63330fz+HhgwwagfXtrN0kQBEF4zZgTwJAkqeiz9pN8kL+tsqxX+sVIPvrll1/w7rvvAgDWrl2L3r17AwCOHDmCunXr4ttvv82XoeAksXnzZnz22We4evUqWrZsiTlz5qB8+fLPPTcxMRHDhg3D6tWrAQBVqlTB5s2b4evr+8LtKswMBgOuXbuWJUhx4cKFTFMq7O3t4ebmBnt7eyiVSiQnJyM2NhYqlQoxMTFQqVSYOXMmBg8ebNW34UeOHEHnzp1x9+5d/Pe//8X58+exfv16BAYGYsiQIbh37x5u3LiBmzdv4saNG7hz506m8xUKBby8vHIMcJQsWRIajSbLddPS0rB8+XJMnjwZ0dHR6NSpE6ZPnw5/f/+CunWLMRgMaNCgAS5fvoyzZ8/Cw8PD2k0CkP73Pm/ePHz22WeoXbs2tm7dasqrI2SVlpaG2NhYuLm5WbspZnuZAhh1AUwm2SLj6zEAQHJGNseuwWs+AmPX7NnoMGoUXJVKnNu/H+q6da3dJEEQBOE1ZGYA4zoAApAAeAOIzfi8CIBwkuZnYiwEXsV+hSW0aNEC+/fvh52dHW7dugVdxopoffv2RUhICO7cuQMHB4d8u15qaioWLlyIKVOmICEhAYMGDcLkyZPNerjZvHkzevfujUePHsHGxgYbNmxA+1fgxVBycjIuXryYJVBx+fJl6PV603H29vawtbWFJElISkrKkhfi8QgGHx8f+Pj44NChQ7h8+TJcXFwQExODBg0aYOXKlQgs4OTxjx9mR48eDS8vL7z33ntYsGAB4uLiMHr0aIwbN870e/ek1NRU3Lp1K1NQ48nPIyIiIMv/n7EuSRI8PDxMQY3SpUujT58+pkDFo0ePMHfuXMyZMwepqakYNGgQJkyY8FIv1zt16lRMmDABP/74Izp37mzt5mSxadMm9OzZEx4eHvjtt99QpkwZazfJKkgiJiYG165dy7bcunULsixj4MCBWLRo0UuRtDjHfgXJQlWQnpfjGoBSADQAzgCokMOxawB0NLfu6tWr81Wyok8fqgBW1Gp548ABazdHEARBeI0BOEHz/69fDqDVE1+3BLDU3PMLS3nV+hWWcOXKFQKgJEkcM2aMaXtsbCxtbGw4cOBAi107OjqaQ4cOpVKppKurK/fv32/WeREREaxfvz6RHmzj+++/z5SUFIu109KOHz9OOzs70/0AoFarpVqtzrQNADUaDf39/fnmm29ywIABnDJlCtevX899+/YxPDycBoMhU92pqamcP38+nZycKEkSNRoNtVotZ86cybS0tAK5v5iYGLZp04YA2Lx5czZp0oQAWLduXZ49e/aF6tbr9bx27Rp3797N1atXc9KkSezTpw8bN25MX19fKpVKqlQqDhkyhHfv3jWdFxkZycGDB1OpVNLe3p6TJ0/mo0ePXvRWC1xoaChVKhW7detWYNeMiYnh999/z4cPH5p9zpEjR+jq6kpnZ2fu2bPHgq2zrpSUFF68eJG///47Fy1axJEjR7J9+/asUqUKHRwcsvw9Fy9enHXr1mWPHj04YcIEDh48mADYpk0bJiYmWvt2niunfoXV//PPtlFAK6SvRHIVwLiMbV8AaJvxeU2kr1CSCCAGQJg59b4qHQ3ZYOCYunXT/6F2ceHDmzet3SRBEAThNZfLAMZZc7YV9vKq9CssadSoUZQkiQqFgjef6K988803BMDQ0FCLt+Hs2bMMDAykWq3msmXLzDrHaDRy1qxZVCqVBEB/f39evnzZwi3Nf/fu3cv0YKPVahkYGMi3336bgwYN4owZM/j999/z0KFDjIiIoNFozNN17t+/z+HDh5se6AGwatWqPH36dD7fUWZHjhyhj48PVSoV27ZtSxsbGzo4OHDhwoV5vpfceDJQYWdnx0mTJjE+Pt60/+LFi+zQoYPpYXLx4sXU6/UWb1d+SE5OZvny5enh4cGYmBiLXkuWZe7bt489e/akVqslAFauXJkRERFm13H16lWWLVuWarWa69evt2BrLS8qKoobNmzglClT2LdvXzZq1IglS5akJEmZAhQ6nY7lypVjy5YtOWjQIE6dOpWrV6/m77//ztDQUJ45c4bHjh3j/v37uXPnTu7YsYNffPEFJUlinTp1GB0dbe1bfaaXKoBhqfJKdDSSkih37MgBAAeWK0f9SxA9EwRBEF59udf2ZcAAACAASURBVAxg7AAwHoBvRhkHYIe55xeW8kr0KywoJSWFLi4u1Gg0bNeunWm7LMusUKECa9SoUWBtefDgAVu0aEEAHDp0qNkPkadPn6a3tzcBUK1Wc+3atRZuaf6Ji4ujq6srAbBXr168d+8eZVl+4XrT0tL422+/sUePHuzSpQvPnTtn2nfhwgXTaAiFQkGlUslx48bl+wgWWZY5f/58qtVqlihRgmXKlCEAtm3blrdu3crXa5nj4sWL7NSpEwHQ1dWVCxYsYGpqqmn/4cOH+cYbbxAAAwMDGRISki8/C0saOXIkAfCPP/6w2DXu37/PefPmsWzZsgRAR0dHDhkyhKtWraK9vT29vb0z/X49z4MHD9i4cWMC4BdffFHov8c5qVGjhilIoVaraWtrS0dHRxYpUoTOzs50cnKinZ0dNRpNllEX5hQnJycqFAq6uLhw9erVvH//vrVvOVs59SsKXQ4MS3rZ56pGhYXhYY8eCPznHxi//BKKkSPFSiOCIAhCoZCbVUgyknlOAtAQ6R2qfQC+4EuSxFOsQmKe4OBgdO/eHQDw119/4c033wQAHDx4EA0aNMDy5csxYMCAAmuPwWDA559/jnnz5qFp06bYuHEjXFxcnntecnIyhgwZgjVr1gDAS7HqwZ07d1CjRg1ERkaiW7du+P7771+oPpI4deoU1q9fj+DgYNy7dw/Ozs4wGo1ISkrChx9+iEmTJsHZ2RkAsGvXLgwfPhznzp0DAPj6+uL7779H3XzI1RYbG4u+fftiy5Yt8PPzw/Xr1+Hm5oaFCxfi3XffteoKGceOHcOoUaOwd+9e+Pn5Ydq0aejUqRMUCgVI4tdff8Xo0aMRFhaGOnXqYNasWXjjjTes1t6c7N27F02aNMEHH3yAxYsX52vdJLFv3z4sW7YMISEh0Ov1qFOnDgYOHIjOnTvDzs4OAHDy5Em0atUKer0e27ZtQ/369c2qX6/XY8CAAVi/fj369OmDZcuWZZt4tbD66aef0LlzZzg4OCAoKAi2trbQarXQaDTQarWm8qyvc9oHAP/++y+OHTuGPXv2IDw83HTd0qVLo1atWqhZsyZq1aqFqlWrmn4W1vLS5MCwZHmZ35SEbdlCX5WKFSSJhp9+snZzBEEQBCETmDECA8D6jI8jnnfsy1Be5n5FQWjYsCG1Wi3LlCmT6U1or1696ODgYLWcAGvWrKFGo2Hp0qX577//mn3eli1baGtrSwAsUaIEw8LCLNjKvDt79qxp5EWTJk1e6C10eHg4Z8yYwfLly5veBrdv354///wzU1JSeO/ePQ4cOJCSJNHFxYWLFi0y5b4wGAxcvnw5ixQpYnrz269fPyYkJOS5PUePHqWvry8VCgWLFi1KABw4cCBjY2PzXGd+k2WZv/32GytVqkQArF69Onfu3GnabzAYuHLlSnp6epryERSm36W4uDj6+PjQ39//hX5WT4uOjuacOXNMo2WcnJw4dOhQnjlzJsdzrl69yoCAAOp0Ov7yyy9mX0uWZU6ePNn0N1CYfj+e5ejRo6ZRFRs3brT49Y4cOUI3NzdqNBrWr1+fJUuWNP2tKhQKVq5cmQMGDODSpUt56tSpAp/+lFO/wur/+RdkeVk7GjtnzaITwOIKBY+tWWPt5giCIAhCFmYGMM4B8EB6gm5nAEWfLM87v7CVl7VfURDCwsJMHeEFCxaYtsfExFCr1XLw4MFWbF36kH53d3fa29tz69atZp9379491qpVy9TBnz17doHkWjDXzp07aW9vT0mS8vwAGhcXx1WrVrFJkyamOff16tXjkiVLcsyFcPr0adPQ/YoVK2Z6YI+Pj+fIkSOpUCgIgEWKFMnV95xMfyD96quvqFKpTEGkMmXKcO/evc89NyUlhRs2bODEiRO5fPly7tixg+fPn7d4EkODwcB169aZpiC1aNGCp06dMu1PTEzkjBkz6OjoSIVCwX79+lll+svT+vXrR4VCwUOHDr1wXbIsc/fu3ezatavpwbxevXpcs2aN2d//6Oho1q5dmwqFgkuWLMnV9deuXUu1Ws1y5crx+vXrebiDgnP16lW6urrS0dGRGo2mwAK8t2/fZuXKlalSqbh+/XpGRkZy69atHD9+PFu0aEFnZ+dMOTfq1avHESNGcMOGDbx06ZJFp+mIAMZL2tFY+d57VAGsIFYaEQRBEAoxMwMYwwGcB5CK9BXHrj9Rrj3v/MJWXsZ+RUEZPnw4FQoF7ezsGBcXZ9o+f/58ArB4ckdz3Lp1i9WrV6ckSZw+fbrZHXFZljl9+nTTw32jRo149epVC7f2+dasWUOlUkkbGxva29vz4sWLZp+r1+u5fft2dunShTqdjgDo5+fHyZMn88qVK2bVIcsyQ0JC6OvrSwBs165dpnNv3LjBpk2bmh6G3njjDbOSQ8bGxrJdu3amESBqtZoTJ058bl6N27dvc8KECXRzc8sxF0CxYsVYrVo1tmvXjiNGjODcuXP5008/8dixY7x7926+PJwlJydz7ty5phEjPXr04LVr10z779+/z48//pgajYY6nY6jR4+22oiBLVu2EADHjh37QvVERUVx1qxZDAgIMAWthg8fnudVYRISEvjOO+8QAMePH5+rn8vff//NIkWK0M3NjUePHs3T9S0tJiaGZcqUobOzMwMCAtisWbMCvf7Dhw9Nq/d8+eWXmb6/sizzypUr/P777/nxxx+zfv36tLGxMf0NOTs7s3379hZpV74HMAD0f+prJYBJea2vIMpL1dEwGmkYNYoNxEojgiAIwkvAnADG4wJgibnHFubyUvUrClBiYiIdHByoUCg4ZMgQ03ZZllm2bFnWrl3biq3LLCkpid26dSMAdu3aNVdv5VevXp0pyd4333xjldEYsixz0qRJBEAvLy8C4KZNm8w67/jx4xw+fLhpyknRokU5ZMgQHj58OM8P78nJyZw+fbopyeCoUaMyBbH+/vtvenh4EABVKhWnTJmSY13Hjx+nl5dXppEgz5pu8Xg1i86dO1OlUlGSJLZp04Y7duxgamoqb968yX379vG7777j9OnTOWjQILZs2ZIVKlSgvb19lgCHVqulv78/mzVrxr59+3LSpElctWoVd+7cyUuXLjE5Odns70tsbCzHjBlDGxsbqtVqjhgxItMqENevX2ePHj1MiUDXr19foEkoo6Ki6ObmxipVqmRKQPosy5YtY48ePXjo0CEajUbu2rWLXbp0MS3R26BBA65bt45JSUkv3L60tDT279/fNBUpN9MZzp07x1KlStHW1pZ//fXXC7clP6WkpLBhw4bUaDT86aefCIBz5syxSju6du1KABw2bFiWJZOflJaWxtOnT3P58uUcOHAgBwwYYJE2WSKA8T2A3wCUAFABwHEAc/JaX0GUl6WjkRQTw9j//IcEGPvee2KlEUEQBKHQy00AozAWAOUBbASwBEBHc855WfoVBW3VqlWmB8AnHzb37t1LAFy1apUVW5eVLMucOXMmJUlitWrVGB4ebva5I0aMIABTvoOGDRsW6HKrqamp7N27t2lEAwB++umnzzznxo0bnDZtmmnlB41Gww4dOnDz5s1mP7iaIyIign369CEylhBduXKlKcAjyzKnTZtmetD19PTk4cOHTec+XmVEoVBQkiTa2tpy8eLFOQaIEhMTuWzZMlauXNn0VvjTTz/N1cgYWZb54MEDnj59mlu2bOGCBQv42WefsXPnzqxTpw49PDyyLGOpVqv5/fff5+r7cvv2bQ4YMIAKhYIODg6cOnVqpqk+oaGhrF27NgGwWbNmuRpJk1eyLLN9+/bUaDRmj5LYt28fFQqFaWrQ4+VPixQpwo8++sgieT1kWebEiRMJgK1atcrVFKnIyEhWqlSJGo2Gmzdvzve25YXRaDQFUIODg7l06dIs/24WdHs++eQTAmDHjh1zFaCzBItMIQHQBcB9ADcB1H+RugqivAwdjXv//ss69vZsClCePZt8SZf/EQRBEF4v1gxgAFgFIArAv09tfxvARQBXAIx+Th0jAbyR8flWc677MvQrrKFmzZpUq9Vs0qRJpu3du3enk5OTxXMP5NW2bdvo4ODA4sWL8+DBg2ado9fr2aRJE2q1Wk6cOJFOTk60sbHh/Pnzn/kGMz/ExsaapmR8+OGHtLW1ZcOGDU1JNJ/08OFDrlixgo0aNTI9fDdo0IBLly7lgwcPLNrOo0ePsm7dugTAatWqcf/+/Zna9eabb5ra9Pbbb/PatWum4eyPH1Rv376dbd1Xr17lyJEjTYlCK1euzOXLl1vsdyw1NZVXr17l33//zbVr17JOnTq0tbXN1VKfj507d840Ncbd3Z3ffvut6WdnNBq5ZMkSOjk5UaPRcPLkyfm+FO2T1q5dSwCcPXu2WcdHRUWxePHidHR0pEqlMuVHAMCSJUtyzpw5fPjwocXa++2331KhULBmzZqMiooy+7yYmBjWrl2bSqWS69evt1j7zDVmzBgC4IwZM0iS7dq1o7e3t9WXf507d64pKGrpfx+exRIjMAIAHAKwFOnLn30LwDav9RVEKewdjccrjdgA3PTZZ9ZujiAIgiCYzcoBjIYAqj0ZwMiY2noVQGkAGqQnDi0PoBKA7U8Vt4yyCMBsAAfNuW5h71dYQ2hoqOnB88lpDNHR0dRoNBw6dKgVW/d8YWFh9PPzo0ajMXukSFRUFH18fOjl5cVTp06xdevWpukOFy5csEg7b9y4wfLly1OtVnPZsmUMDAyku7s779y5k+XYvXv30sHBgQAYEBDAL774IlMOhoIgyzI3bNhgmuLSpUsX3nxievSePXuy5KpwdHTMdiqM0Wjkjh072Lp1a0qSRKVSyc6dO3Pfvn0F/uAXERFBV1dXVqhQIc9Bk4MHD7J+/foEwMDAQG7atMl0H5GRkaZh/YGBgdy9e3d+Np8kefPmTTo6OvKNN94wK+j28OFDli5d2jQFaNiwYTx//jwNBgO3bNliCpLZ29tzxIgRFvtd27x5M3U6Hf39/XM10iY+Pt4UIFu0aJFF2maOZcuWERmr6MiyzNTUVNrb23PQoEFWa9OTgoODqdFoWL58+VyNSstPlghgXADQLONzKePNRVhe6yuIUpg7Gn/OmEFHgO5ipRFBEAThJZTbAAaA4gBaZxS33JybQ32+TwUw6gLY8cTXYwCMMaMeJYAt5lyzMPcrrGXgwIFUKBT08PDINBJgzpw5BJDnJH4FKSYmhs2aNSMAfvzxx9mOaHjaqVOnaGNjwwYNGjAlJYXr16+ns7MzdTodZ8+ena+jMU6cOEF3d3c6OTlx165d7NChA5VKZbYrchw6dIj29vYsW7Ysjxw5YvU3uwkJCZw4cSJ1Oh11Oh0nTpxomgZgMBj46aefUqPRsF27dlne4D98+JBff/01AwMDCYBubm6cMGFCjqMzCsqOHTsoSRL79euX5zpkWeaWLVtMy9XWqFGDISEhpt+bP/74wxQ06N27d65GHTyL0Whk06ZNaW9v/9wgQFpaGpcsWUI7OzsCYM2aNXNc2SM0NJQ9e/akSqWiQqFghw4dePDgwXz//Tt48CCLFi1KNzc3njhxwuzzkpOT2aZNm0yjHwrS77//TqVSybffftv078vu3bsJoNBMbyHT2+To6EhPT0/+888/BX59SwQwHLPZFpjX+gqiFNaORuqiRSwNsJJOx5v5sGSRIAiCIBS03AQwAHTOmH66FsA6pK9CYlbeiWfU+XQAoyOAFU983QvAwuecvwzABgANnnHcQAAnAJzw9va22PfzZRQXF2fKTj916lTTdlmWGRgYyHr16lmxdbmTlpbG4cOHEwDfeusts4ZRBwcHE4Bpidg7d+6YpgjUrl07T9MMnrZt2zba2trSx8eHYWFhpqHe2SX9O3HiBJ2cnOjv78+IiIgXvnZ+unHjBrt06WLKf/Hdd9+ZHm6ffsgNCwvjkCFDTEk269Spw++++86iUypya/z48QTAtWvXvlA9aWlpXLlyJf38/EyjLpYtW8bk5GQmJSVx3LhxVKvVLFq0KFesWPHCSWO//vprAuDy5ctzPEaWZW7bto3lypUzjY5p3ry5WcGI27dvc/To0aalOGvVqsUffvjBrKCguc6fP08fHx/a2dnxjz/+MPs8vV5vyj8xevToAgvunTp1ivb29gwKCmJ8fLxp+2effUa1Wp1pW2Fw5swZenh40MnJiX///XeBXjvfAxgvYylsAQxDairTPv6YBHixYUPGFYK1nwVBEAQhL3IZwDjz5KgLAK4Azph7fg51vlAAI5fXagNgmb+/f/5/I19iixcvNiU2vHfvnmn74zeLL/pwZw0rVqygWq2mv7+/WQGIUaNGEQCXLVtGMv3hLzg4mC4uLtRqtZwxY0aeH94WLVpEhULB6tWrMzIykvv27aNSqeS7776b5eHrzJkzLFq0KH18fDJN1Shs9u/fz2rVqhEA69aty2PHjpFMH43xyy+/mEbCaLVa9unTh8ePH7dyi7OXlpbGRo0a5TkfxtMMBgM3btzI6tWrm3JkzJgxg7GxsQwLCzMlbG3QoEGeEz6eO3eOOp2OrVu3zvHhPTQ01DTdolSpUixatCgDAgJy/ZCdkJDARYsWmZZV9fb25uzZs/NtudiIiAhWqVKFKpWK69atM/s8g8HAgQMHEgCHDBli8VWEwsPD6eHhQS8vryxBxYoVK2bJG1RY3Lx5k+XKlaNGo+GPP/5YYNcVAYxCFsBIuHeP7UqU4GCA8ocfkvkYiRQEQRCEgpbLAMbZp75WPL0ttyW/ppCYeS0RwHiKLMssX748FQoFe/TokWlfly5d6OzsnC9LKVrDgQMH6ObmRkdHR/7666/PPNZgMLB58+ZUq9WZEoHevXuXHTt2NE0PyM1UGqPRyE8//ZQA2KZNGyYkJDAyMpLu7u4MCAjItEQpmf5g6urqSk9Pz1zlBrAWo9HIlStXsnjx4gRgSmSIjISQ06dPz7cpE5aUH/kwnibLMnft2sUWLVoQAB0cHPjpp58yPDycK1euZNGiRalWqzl27Nhc/X3p9XrWqFGDLi4ujIyMzLI/PDycvXr1IgAWK1aMX3/9Nd966y1qtVqePn06z/djNBq5detWNm7cOFOejPz4PX348KEpqe3MmTPNHlEhyzI/++wzAmCvXr3ydXTI0+2rVKkSHRwcskzHCA8PJwDOmjXLItfODzExMaxfvz4lSeJXX31VINcUAYxCFMCICA1lNVtbKgB+3aGD1ecjCoIgCMKLymUAYzaAHQDeyyi/A5hl7vk51Pl0AEMF4BqAUvh/Es8KL3KNp0th6VcUBocOHTINL39yOcx79+5RrVZzxIgRVmzdi7t58yaDgoIoSRK//PLLZ/bdYmJi6OfnR3d39yz5GTZu3EhXV1eq1WpOnTqVer3+mddNSkoyBT6GDh1Kg8HAtLQ0NmzYkLa2tlkCIZcvX2aJEiVYvHjxAll+Mz/FxcXx888/p62tLZs0acJNmzZZ7GHSUvIjH0ZOTp06xW7dulGhUFCtVrNv3748cOCAaRnd0qVLmz2FYvLkyQTAkJCQTNvj4uI4ZswY6nQ6arVajh49mg8fPuS0adMIgEuXLs23+zl58iR79eplypPx7rvv8sCBAy/0XJSSkmKaFvL478Ucsixz6tSppgBafk9P0uv1fOutt6hSqfjnn39m2f84oWdhzxGUlJTEd999l8hYrtnSI1byPYAB4GcA7wBQ5LWOgi6FoaNx6ocf6KlU0g7gtokTrd0cQRAEQcgXuQlgpB+OdwHMyyjtc3NuNnUFA4gEkAbgNoD+GdtbAbiE9NVIxr3INZ66nhiB8ZRevXpRoVAwKCgo0wPIl19+SQD5Mqze2hISEtipUycCYI8ePZ75xvvs2bO0s7NjrVq1mJycnGlfVFSUKf9D1apVeebMmWzriIqKYt26dSlJEufOnWv6vj5+W/zdd99lOv769essWbIkixUrxn///fcF71bIq/zKh5GTa9eucejQoaZ8M23btuU333xjSm7atWvXbEdVPHb8+HEqlUr27NnTtE2v13PRokV0dXUlAPbs2ZM3btwgmb6KjUKhYLdu3Szy0jUiIoJjx4415cmoWbMmg4OD8/xwbDQaOXLkSAJgx44ds/z9Pcs333xDAHzzzTdNyWVflCzL7NevHwHkuLJR+/bt6eXl9VK81DYYDBwyZAgBsHv37kxNTbXYtSwRwHgT6YmurgKYCaBMXusqqGLtAEZiSAjdAHoqlTz1ww9WbYsgCIIg5KdcjsD40pxthb1Yu19RWMTExFCtVmfpoBuNRvr5+fGNN96wYuvy15NvamvWrPnMN6abNm0iAPbt2zfbB5NNmzbRzc2NKpWKkydPzvQgcOnSJfr7+1On02V6S/64ziFDhmSq69atWyxdujSLFCnCU6dO5cOdCnmV3/kwchIdHc1JkyaxaNGiphwi3bp1o1qtppOTExcvXpwlCJCUlMSyZcvS09OTsbGxptVPypQpQwBs1KhRpjwj9+7do4eHBwMDAy2eXDIhIYGLFy82BWJGjRr1QvU9TnDbsGFDs5LwPrZmzRoqFArWq1cvX3J0TJkyhQA4YcKEbPfr9Xo6ODjw/ffff+FrFRRZljl9+nQCYLNmzbJMY8svFptCAsAJwAcAbgE4BKAvAPWL1muJYtWOxtdfkwoF/woIYERoqPXaIQiCIAgWkMsAxslstv1j7vnWLmIERmbz588nADo5OWUalfDXX39lO1LgVfDLL7/QwcGBAPif//yHR48ezfa4CRMmEAAXLFiQ7f779++zR48eBMDKlSvz5MmTPHDgAF1cXFisWDEeemJ1uosXL9LBwYG1atXKNMQ9MjKSgYGBdHBwMCXBFKzLEvkwcpKQkMBvvvmGPj4+BEB/f3/TiiG1a9fOlLNixIgRBMC//vqLx48fZ6NGjQiAZcqU4datWzMF2oxGI5s3b06dTpfjKCFLMBqNpsSaL7qkaHBwMNVqNStUqMBbuVgsISQkhGq1mkFBQZkSEufW+vXrTbk1chpdsWfPHgLgzz//nOfrWMuaNWuoUqkYFBRkkVWBLBLAAOACYATSlxPbCqALgAUA9rxIvZYq1ghgpCUnc2ilSlwKkO3akfk0HEkQBEEQChNzAhgABgM4CyARwD9PlOsAvnve+YWtiBEY6W/iSpcuTQD87LPPMu3r2LEjXVxccjWE+2Vy//59Tpw4kUWKFDENO9+9e3eWh8DWrVtTqVQ+cwnCLVu2sESJElQqldRqtQwICOCVK1dM+xMSElixYkW6uLhkWlUkOjqaFSpUoJ2dHQ8cOGCR+xTy5s8//6QkSezbt2+BXE+v13PDhg2sXLkyAdDZ2Zl2dnZUKBQcOXIkt2zZQgDs06cPu3fvTgB0dXXl4sWLs83F8nik0eMVdQpScnIyq1evTicnp0x/B3mxa9cuOjg40MvLK1c5Jv744w/a2NiwTJkyDA8Pz/V1d+/eTbVazcaNGz9zmsXnn39OlUplsVEMlvbHH39w3rx5FqnbElNIfgFwDulZvUs8tS9X82ALqhR0RyPu1i22zJhL9nmtWqSFE50IgiAIgrWYGcBwQnqyzWAAPk+Uos87tzAWEcAg//77bwKgJEm8du2aaXtkZCRVKhU/+eQTK7auYMTHx3PWrFmmVTTq1KmT6W32w4cPWaZMGRYrVuyZS5o+ePCA/fv35zvvvMP79++btsuyzJ49e1KSJO7YsSPT8UFBQdTpdNy9e7flblDIs8cjcNasWVNg15Rlmb///rtp+VONRmNKsOvs7EytVkudTsexY8fm+NC8Z88eKhQKdu/e3Wp5Ga5fv05nZ2cGBQW98ApGp0+fZokSJViqVKlc5dbYv38/HR0d6e3tzUuXLpl9XlhYGJ2cnFiuXLnnTl+pXLkyGzdubHbdrxNLBDBaZbNNm9f6CqIUZEfj5qFDrKTTUQlw6VPLiQmCIAjCq6awvrywRBFTSP6vY8eOlCSJrVq1yrT98fzoCxcuWKllBS85OZmLFy82DeWvXLkyg4ODaTAYeOHCBTo6OrJq1aq5nlKwZMkSAuB///tf07a4uDjWqlWLGo2Gv//+e37fipBPDAYDGzduTFtbW4aFhRX49Y8dO2b6G30caOzdu/czRxTcu3ePJUqUKJC8F8+zfft2AmD//v1fuK7g4GAC4M6dO3N1XmhoKIsVK8bixYtnWf40O5GRkfTx8WHx4sV5/fr1Zx57+/ZtAuCXX36Zqza9LiwRwMhu/mqWbYWpFFQA4+Hu3SyhUNAR4J8zZhTINQVBEATBml6nAMbj8rqPwLh79y6VSiUBZFq+0Wg0slSpUmzSpIkVW2c9er2ea9euZdmyZU05CVasWMFffvmFkiTl6q320aNHqdFo2LJlS9Ob40ePHrF+/fpUqVTcsmWLJW9FyAd37tyhm5sby5cvn28rW+TWpUuXOH36dIY+Jw+f0WjkW2+9VeB5L55l3Lhxz1zBw1xJSUl0cnLKtPqKuc6dO0dPT086OzvnmO+GTJ/qVb16ddra2mZKhpqTFStWEIBZgZEXJcvyS7HKyZPyLYABwB1AdQDnAVQFUC2jNAZwIbf1FWQpkI7Gpk2kjQ0XFi3KMPGfiiAIgvCaeJ0CGGIERroZM2YQAH18fDINy/7jjz8IgD+85iuuGY1Gbtq0idWqVSMAenl5sVWrVgTAOXPmPPf86Ohoent708fHxzSlJCkpiU2aNKFCoeDGjRstfQtCPinofBh5Zc28FzkxGAxs2rQpdTrdC6+wM2jQINrY2OQp38S1a9dYunRp2tvbZztly2AwsE2bNlQoFNy6datZdXbo0IGenp6ZAgsGg4EDBgygvb09bW1taWtrSxsbG+p0Oup0Omq1Wmo0Gmo0GqrVaqpUKqpUKiqVSioUCioUCtOIm6eLSqXir7/+mut7t5ac+hVS+j7zSZLUB8B7AGogPXnnY48ArCH5c64qLEA1atTgiRMnnn9gHlCWg/vpYQAAIABJREFUMbdNG9T67Tc0rFMH2LIFcHOzyLUEQRAEobCRJCmUZI1cHO8DIIDkTkmSbACoSD6yXAvznyX7FYWdLMvw8vJCZGQk5s+fj48++si0r3379jh48CBu374NjUZjxVYWDiTx559/Yvr06di3bx80Gg3S0tKwadMmtG/fPttzjEYjWrVqhT179uDgwYOoUaMGUlNT0a5dO+zYsQPr1q1Dz549C/hOhBcxceJETJkyBWvWrEGfPn2s3Zws9u7di6ZNm6Jbt25Yv349JEmydpNMoqKiULVqVdjY2CA0NBROTk55qufIkSOoW7cuVq5ciX79+uX6/Dt37qB58+a4cuUKQkJC0Lp1awDpf+PDhg3DokWLsHDhQnz44YfPrSstLQ3FihVDp06dsGLFCgDpf/d9+/bF+vXr0bNnT7i7uwMAJEky/Tyy+2jutrVr16JIkSI4efJkofr55iTHfkV2UQ1zCoAOeT3XzPrfBnARwBUAo7PZrwXwY8b+owB8n1enpUZg6BMTOSBj/eRBfn7kCyaaEQRBEISXDXK3jOr7AI4DuJrxdQCAXeaeX1jK6zyF5PfffycAav/H3n2HR1WlDxz/nqmZTHpCiUDooBQFDSqCrAgKFqQoKioSF5CyiLog2BZFFhTLsv6QVcFlAQvrSglFAuIiCCiCgiyI0qUHQnoyyWTK+/tjBgyRmjaZcD7Pc565c8+9576ZtDtnznmP1SqZmZmn9x85ckSMRqOMGTMmgNFVXWvXrpXbbrvt9CeiQ4cOPesyjS+99JIA8v7774uIb1rKPffcI4DMmDGjssPWykGg82GcT2pqqsTHx0vz5s0lNzc30OGc1bp168RkMkmvXr1KPRXC6/VK8+bN5eabby51HCdPnpTExEQxmUwyd+5cERF56623BJBRo0ZddDtr1qwRQObNmycivhFbSUlJAsjEiRNLHd/5zJo1S4CgmXp2rvuK0nQsPOJ/HAX8uWS51PbOcQ0jsBdoBFiArUCLEscMB97zbz8IfHqhdiviRiNz/37pEh0tgLzQoYN4XK5yv4amaZqmVXWX2IHxo///+5Zi+7Zd7PlVpVyOHRher1c++ugjiYmJEUAGDRp0Rv0rr7wigOzevTtAEQaHRYsWidlsFkBCQkJk5MiRpxMrLlu2TJRSMmDAAPF6veJyuaRv374CyDvvvBPgyLWyqAr5MEpyu93StWvXKpX34lz+9re/CSBvvPFGqds4NfWtLH+jsrOzpVOnTqKUkkGDBolSSu69995LWuHk2WefFZPJJFlZWeLxeGTgwIG/S9Zb3lwulzRu3FiuvfbaoMiHUZ4dGEP8jy+drVxqe+e4RntgRbHnzwHPlThmBdDev20CToJvSsy5SnnfaJyYOFHqKCVGkCeuuUZWTJok6/7xD/ll4UKRnTtFDh+WnAMHxJmbKxIEPySapmlaEPN6xet2i9vpFFdBgRTl54szN1ecOTkiBQUiDoc4MzPFU0Gfrl1iB8Z3/sct8tv/8f9d7PmBLlymOTD27dsn3bp1E0ASEhJ+l3zO7XZLvXr1pGvXrgGMMnisWLFCDAaD1K9fX4xGo5jNZhkwYIDExMTI1VdfLfn5+eJ2u+WRRx656LwZWtW3cuXKKpUPY8KECUEzssfr9cq9994rRqNR1qxZU6o2Dh8+LAaDQf7yl7+UKRaHw3E6p0379u0veanXNm3aSKdOncTj8cjjjz8ugIwbN65MMV2MmTNnCiBLliyp8GuV1bnuKy45B8YpSqkaIpJWqpMv3PZ9QHcRGeR/3h+4QURGFDtmu/+Yw/7ne/3HnCzR1uPA4wAJCQnXHThwoNzi/DkyktY5OXhK7L8F+Mq/3QzYje/OLBSwGwzcZbczo0EDsNt5YN8+CpTCbrUSarVit9loX78+/Tp1gtq1WZuWRkzDhtRu0YKYxo1RRmO5xa9pWtmJ14vH5cLrcmExmcDrpdDhwOlw4PV48LrdeF0uxOulZkwMeL2knThBXl6er87txuN2Y1SKpvXqgcfD3gMHyMrJ+e18jwerycS1TZuC18vmX34h81S9v0TYbHS48krwelm1dSuZubm/1Xu91AwLo0uLFuD1Mn/jRrIdDrxeL16PBxEhISqKO666CkSYsX49+YWFvnp/aVGjBnc3bw4ivLZ6NUVu92/1IrSrXZueTZrg9XoZ+9VXp//JeP2PnevUoWeDBhS4XPx53boz6rxeLz3r1eOeevXIKChg5MaNvvPxzbMXoH9CAnfXrs3h/Hye2Lr1jPMFeCIhgW5xcezMy+OJHTt85xaLYVxCArdGRfFDTg4j9+37rX3/45S6dekQFsbqnByePnz4d/Wzr7iC60JCWJKTwzNpab+rX1yrFi3NZj7KzeX5rCzf2HB/nQDrY2JoaDQyLT+f8fn5vnP5LbPWzrAwairFXwsLmVxUdEY9wEmzGTsw2u3m7WLtCqDg9P+hQcA/S/yMRgDZ/u0HgBcjImidnU15u5QcGEqp14Es4FHgCXyjKneIyAvlHlgFulxyYLjdbt5++23GjRuHwWDg1Vdf5V//+hdms5kNGzacPu7zzz/n7rvv5rPPPuO+++4LYMTB48033+SZZ55h9OjRFBYW8sEHH2CxWPjhhx9o1KgRQ4YM4YMPPmDChAm8+OKLgQ5XKycvvfQSr7zySsDzYaxevZouXbpUybwX55KTk0NiYiK5ubls2bLldJ6IS9G9e3d+/vln9u/fj8FgKHUsRUVFfPzxx/Ts2ZOYmJiLPu/YsWNcccUVTJo0iUOHDvHuu+/y/PPP89e//rXCvwcul4vmzZsTGxvLxo0bq/T3/Fz3FaYytLleKfUrvjwUC0QkswxtVRgRmQ5MB9+NRnm2Hb9mDbFt2xJtNjNn+nSKHA4c2dmEKwX16kF+PmNXrSI1PR2Hw0G+w0F+QQGtw8Kgbl1wOMgpKiLV6cThdpPv8eAQwbl9O/2WLMELdOa3G1MzUMtoZHitWjzXti2emjV5adcuasfHUzshgdqNG1O7eXOuaN2aUJ1AVDsP8XhwFRTgcTpx+4vH6STEbCbMasVdWMiBgwd9+10u3EVFuJ1OroiJoXZUFI68PDZu3477VF1RER63m2sSEmgQG0t6ZibLt2zB7X9z7nG7cbvddG3alKaxsRxMS+PTU/Uej+8Yj4eHW7SgeVQU21NT+eB//8Pjf/Pt8ZdnWrakWVgY648dY9rOnaf3e7xePCJMufJKGoeEsCQ1lSkHDuAVwSNyuv6zRo1IMBqZdfIkb6Wl+epE8OB7I/pd7drUAN7IyeGtvDw8Injh9OOx0FDsXi+ji4r4u9d7RuelwveGE3zvxj4o8ZqHAznF6j8tUX8FcMS/PRJYVqK+OfCLf/spYG2J+kR8CQXAN7/vxxL1nYEu/u2x+OboFdcDuMO//RfgeIn6h4C7/dsTAId/W/nLEIOBniYTSimmOZ0owOCvMwDhv/xCz9BQ3MD8zEwMSp2uMyhFq7Q02LuXIo+Hb1NTfe0qdbr+pNsNmZm43G72Zmb62j7VhlI4MjNBKTyFheQWFf3Wvj+RlSgFJhMGiwWbP85TxyilMMfEQHQ0tpAQ6uXknL72qURYtiZNIDKS6PR0rjEYfne+vU0biIigTmoqXfbtOx3bqfNDExPBbqfZkSPc679hKn5MSPv2EBLCdQcOMPjgwdNxnyqmm28Gs5nOe/diOXLkjLaVUtC5MyhFz127SEhNPaPOajJBp06gFA/t2EGt5s2pAp4FBgLbgCH4fuRL/tpoVcDmzZsZPHgwmzdvpkePHkybNg0RX8K6119//Yxj33//fWrVqkXPnj0DFG3wGTVqFFu2bOGtt95i8eLFjBs3jsLCQurWrcvIkSP54IMPeOGFF3TnRTUzbtw4vv76a4YPH067du1o0aJFpcdw/Phx+vXrR9OmTXnvvfeq9BvZ4iIiIpg/fz433HAD/fr1Y+XKlZhMl/aWNikpiX79+rF69WpuvfXWUsdisVh47LHHLvm85cuXA7Bt2zbmzp3LmDFjKqXzAsBsNvP8888zePBgUlJSuPPOOyv8muWt1CMwAJRS1+PLP9EL2AH8W0Q+KnNQSrUHXhaRbv7nzwGIyKvFjlnhP+ZbpZQJSAVqyHm+oIr4pGTh2LH0ef11XrvjDsYuK/mWo5REICcHz5EjrFu5ktR9+zh+6BCpqamkpqXRNTSUhwwGThw5Qnxa2uk3TadMBJ632zkWF0ffjAxqR0RQOyaGuJgYwsLC6N62La2aNiVbKb47dAh7dDRhMTHY4+Kwx8YSW68elqgouAxHe4jXi/J4wOUiPyuLgtxcXIWFuAoKcBcWojweGtauDS4Xv+zeTUZGBu6iIt8xRUXYTSZubtYM3G5SNm3iRGYmrqIi3C4XLpeLeLud+1q0ALebqevWcTwnB7fbjcv/Bv+qyEiGNm8OLhcjvvmG9MJCXB4Pbo8Ht9fLzZGRjE1IALeb2378kRy3G7fXi1sEtwj32e2Mj4xEXC7qHD3q2w+4RXABI5Visgi5+D6VLekl4GXgKFDnLPVv4ntzvBO48iz17+F7J/I90O4s9R/jeyP8FXC2fxdLDAbutlhYJkI/pxOj/02kUSmMwLzYWG4KDWVxYSGjMjJ8+4uVjxs2pEVYGIuys3nz2DHf+UphNBgwGgx80Lo1dcPCWHTiBHMOHcJgMPjO9de/fcMNRNtsLD58mGWHD/vqDYbTj5M6dSLEYmHZr7/yzZEjGIxGjEaj7xpGI8/deivKaGTlnj1sP34cg9GIwX++1WJhUKdOYDCwetcuDmRm/lZvNGK32bjn+uvBYGDDnj2cyM7GaDb/Vh8aSserrwaDgR/37iW3sNB3vr+E2e20bNoUDAZ2HTqE0+XCYDKdrg+126lXpw4oxeETJ/CKYDCZUAYDBpOJEJuN6OhoMBjIzMnx7TcafccYjZgsFqwhIWAw4PZ6T58bLDc8WsW7xBEYdqBQRDz+50bAKiKO859ZtVTnERj5+fm89NJLTJkyhZo1azJ16lTuvfdelFJMnTqVkSNHsmvXLpo2bQrAoUOHaNCgAWPHjmXSpEkBjj64OBwOOnbsyN69e9m4cSPNmjXjmWee4a233mLUqFG88cYb+m9tNXTs2DHatGlDXFwcGzduxG63V9q1PR4P3bt3Z926dXz33XdcffXVlXbt8jJnzhwGDBjAs88+y6uvvnrhE4opKCggPj6ee+65hzlz5lRQhOfWt29fUlJSyM/PD8jveFFREc2aNaNWrVps2LChyv59Odd9RZk6MIo1Hgf8DXhYRMr8rtffIbEL3weGR/B9sPiQiPxU7Jg/Aa1FZKhS6kGgj4jcf752K+pGo0+dOqQcPcr/Vq6kadeu5d7++XiKikjftYvUX34hdfduUvfvp43dztVKsX/PHgauXUuqw0Gqy0Wm/3s9E3gM+Ba46SxtfgrcD6y2WLjf5cJuNGI3GgkzmbBbLExu1YrEunX5sbCQWfv3Y/J3dJz64X/i2mtJiIxk07FjzNu163S7p+qfvv56atntrD98mM/37j1VyalfnWfatyfKauXLPXtYvnev7827x4Pb7cbt8fB/7doRCny0Zw/Jhw/j8XpPv8F3e72saN0ag8fD6wcPMi89/bc3+F4vZmBrfDy43QzLyODTwsLTb+5dQBy+njCAe4AlJV6bxviWvQHfJ9qrS9S3Abb4t9tx5jrDADcDX/u3r8L3Q27GNxTKrBTdzWbmxsaCyUSHEyc46fViMhgwKYXZYKBbVBQTGzYEk4meP/2EUwSz0YjJaMRkMNA1Pp4hV14JZjOPf/utb7/RiMlkwmQ00ql+fe6+6ipcSvH6N99gMpkwmky+epOJ6xs35vomTSjweJi3ZYuvzmw+XVo2bEjjevVwuN1s3L0bk8XiO8ZqxWgykVCnDnE1alDodnPoxAmMZjNGi8V3nMVCVHQ0IWFhuEVwut0YLRaMVitGiwXDZdhhpmnVySV2YGwAuopInv95GPCFiJzt31KVVV07MFasWMHQoUP59ddfGTx4MJMnT/Z1cPp16dKF1NRUfvrp9G0ZL7/8Mq+88gp79+6lYcOGgQg7qB04cIDExERiY2Pp0aMHb775Jn/605+YOnVqlX1zoZXdl19+ye23386AAQP417/+VWnXnTBhAuPGjWPGjBkMGjSo0q5b3oYMGcL06dNZtGgR99xzzyWf+9FHH5Gamkp4eHgFRfh7LpeL8PBwnE4nTz75JFOmTAnI7/j06dMZMmQIy5cvp1u3bpV+/YtR7h0YSqkIoDe+ERiNgYXAf0Tkh7IEWqz9O4G/41uRZKaITFRKvYIvmcdipVQI8CHQFsgAHhSRfedrs6JuNI5u3sxV113Hw3Xq8I9Dh6CK/qPxFBXhOHkSs9NJiMdD7vHjbNu2jbzMTPKzssjLziYvO5tuDRrQyGrlpwMHmLZpE3kFBeQXFpLndJJfVMTf4+NJ9HpZcPIkSVlZZ8zTBlhttdLOYGCWy8UwtxtK1G8xm7lKKf7P7Wa01/u7+n0GA/WUYjIwwePBBJiU8hVge506RJnNvJWTw8zc3N/q/J+Sf33NNZjMZt45epRlGRm+DgB/nc1sZk6nTmAyMWvfPn5IT8dkMmE2mzGbTESGhjLmllvAbGbxzp0cyM7GbLFg9r8JjwoPp+eNN4LZzHf79pFVWIjZasVstWKyWomIiKDllVeCycTBtDTcgNlmw2yzYbJaCQkLIywqCsxmvP5PvjVN06qDS+zA+FFE2lxoX1WllOoB9GjSpMng3bt3BzqccpOWlsbTTz/Nxx9/TPPmzZk+fTqdOnU645iMjAxq1qzJ2LFjmThxIuDLkdGgQQNatWp1emi0dulWr15N165d8Xg8DBw4kOnTp5dpfr4WHE7lw/jXv/5FUlJShV/vq6++omvXrjz00EPMmTMnqDvICgsL6dChA/v27TudN+Ziffvtt9x0003MnDmzVNNASkNE6N+/Px9//DHdu3dn2bJlAXv9i4qKaNq0KXXq1GH9+vVV8ufgnPcVZ8vseTEF2A9Mwb8SSDCUilzu7McXXxQXiMycWWHX0DRN07SqiktbhWQ9cG2x59cB317s+VWlVJdlVL1er8yaNUtiYmLEbDbLuHHjpKCg4KzHzpkzRwDZuHHj6X2LFi0SQBYsWFBZIVdbc+fOlRdeeEHcbnegQ9EqidvtlltuuUVsNpts3769Qq+VmpoqtWvXlubNm0tuBa1IVdn27dsnUVFRcu21157z79bZeL1eadasmXTq1KkCozvzei+88IIAopSSjIyMSrnu+bz77rsCyBdffBHoUM7qXPcVZRmBoaS0JwdIhQ719Hqhc2cyt27Fs349cS1bVsx1NE3TNK0KusQRGO2Af+NLuaOA2sADUk6jOCtLdZhCsnfvXoYMGcJ///tfbrrpJqZPn07L89zD9OnTh40bN3Lw4MHTowPuuusutmzZwoEDBzCbzZUVuqZVG5WRD6N43ouNGzfSunXrcr9GoCxdupQePXowePBgpk+fftHnvfrqqzz//PPs2bOHxo0bV2CEvml248ePJzY2lquuuoq1a0umY698TqeTJk2aUL9+fdauXVvlRmGc677ikselKaX+7t9crJT6XSlzpMHKYMD5zju0zc7mT3fcceHjNU3TNO0yJSKb8OUCHgYMBa4Kts6LYOdyuZg8eTKtWrVi06ZN/OMf/2Dt2rXn7bxwOBwsX76cXr16ne68OHDgACkpKQwcOFB3XmhaKcXHx/PJJ5/w888/M2LEiHJr1+VykZOTw/Hjxxk/fjxffvkl77zzTrXqvAC4++67ee6555gxYwazZ8++6PP69++PUqrCE3lOmDCB8ePH069fP9LT06vMyh9Wq5Vnn32W9evXs2rVqkCHc9EueQSGUuo6EflBKfWHs9WLyJpyiawCVMYnJRNvu40Xv/ySRS+8wD1//WuFXkvTNE3TqopLGYHhP/4moAHFlnQXkcpPB18GwToCY9OmTQwePJitW7fSu3dvpk6dSp06Z1t76kyLFy+mZ8+erFy5kq7+pOV/+ctfmDhxIvv376d+/foVHbqmVWunPqV/7rnnSEhIwOFwUFBQcEa5lH0ej+eM9h955JGgz3txLm63m9tvv50NGzawYcOGi15ZpVu3buzcuZN9+/ZVSM6ZSZMm8cILLzBgwAA6derEwIED2bx5M23bti33a5VGYWEhjRs3pkmTJqxZU7XexldEEs8nReTtC+2rSirjRqMoL4/r4uLIdLvZ8euvRNStW6HX0zRN07Sq4BKnkHyILwH4j8CpO2wRkZEVFV9FCLYOjLy8PF588UWmTp1K7dq1eeedd+jdu/dFn//HP/6RBQsWkJaWhtlsxuVyUb9+fdq2bcvnn39egZFr2uXB4/Fwxx13sHLlyjP2GwwGbDYbNpuN0NDQ09vFy4X2R0dH07t3b0JCQgL01VW848eP07ZtW8LCwti0aRORkZEXPGfu3Lk89NBDrFq1is6dO5drPK+//jpjx47l4YcfZvbs2Tz88MOsWbOGo0ePVqlOpFNLY3/11VfccsstgQ7ntIpI4rn5LPu2lLa9yiiVlWxrwwcfiAL5U+vWlXI9TdM0TQs0Li2J58/4P0QJRAEaAf8E5hXbZwdmAzPwLQtfZe4rysPnn38uCQkJAsiwYcMkKyvrks53uVwSGxsrDz/88Ol9CxYsEEAWLVpU3uFq2mXL4/HIvn375NixY5KVlSVOp1O8Xm+gwwoaX3/9tRiNRunTp89FvW4Oh0MiIiLk0UcfLdc43nrrLQHkwQcfFJfLJS6XS6KjoyUpKalcr1MeCgoKJD4+Xm655ZZAh3KGc91XlCYHRj+l1BKgYYn8F1/hW870snfDwIGMbNOGQ9u24akCCVo0TdM0rYrZji9x5yVTSs1USp1QSm0vsb+7UmqnUmqPUurZ87UhIvtEZGCJ3X3wdWgMBu4pTWxVkYiQlJTEXXfdRVhYGOvWreMf//jHRX0yWdw333xDeno6vXr1Or3v/fffp06dOlVmPremVQcGg4GGDRtSu3ZtIiMjsVgsVerT+qru5ptvZvLkySxYsIApU6Zc8HibzcYDDzzA/PnzycvLK5cY3n77bUaNGkXfvn358MMPMZlMbNy4kczMTO6ogrkSQ0JCGDt2LKtXr+brr78OdDgXVJqJPt8AbwG/+B9PlVFAt/ILLbi9sWoVyfXqYRwyBJzOQIejaZqmaVVJHLBDKbWiFInAZwHdi+9QShmBacAdQAugn1KqhVKqtVJqaYlS8xzt1gUO+bc95zgm6Bw4cIDZs2czaNAgNm/eTIcOHUrVTnJyMlarle7dfS/9/v37+eKLLxg0aBAmk+kCZ2uaplWeP//5z/Tp04cxY8awbt26Cx6flJREfn4+8+bNK/O1p02bxlNPPUWfPn34+OOPT/99TElJwWAwcNttt5X5GhXh8ccfp1atWowfPz7QoVzQJXdgiMgBEVktIu1FZE2xsllE3BURZDAyR0ej3n+ffT//zCcPPRTocDRN0zStKnkZ6AVM4swPQy5IRL7m9yM+rwf2+EdWFOFborWniGwTkbtLlBPnaPowvk4MOM/9kVLqcaXU90qp79PS0i4m5IDyer2A71NJq9VaqjZEhIULF3LbbbcRFhbGjh07GD58OEopBg0aVJ7hapqmlZlSipkzZ9KwYUMeeOABTpw41599n/bt29O0aVNmzZpVpuu+9957jBgxgp49ezJ37twzVmZKSUmhffv2REdHl+kaFcVmszFmzBhWrVp1UZ0+gVSaKSTr/I+5SqmcYiVXKZVT/iEGsTvuYEKjRiQtWMCOxZfvCrOapmmaVpz4Viz7FTD7tzcBm8vQZB1+Gz0Bvs6Icy6roZSKVUq9B7RVSj3n370AuFcp9S6w5DyxTxeRRBFJrFGjRhlCDh7/+9//+PXXX2nVqhU9e/akZcuWrFmzhkmTJlFXJyvXNK0KioyMZN68eWRkZNCvX7/frchSnFKKpKQk1qxZw759+0p1vRkzZjBs2DB69OjBf/7zHywWy+m648eP88MPP1TJ6SPFDR06lJo1a/LKK68EOpTzKs0IjI7+x3ARiShWwkUkovxDDG6TlywhXCkGP/IIXrceoKJpmqZpSqnBwDzgff+uOkByZV1fRNJFZKiINBaRV/378kXkMREZJiIfn+98pVQPpdT07Ozsygk4gESE119/HYDXXnuNdevW8dJLL3Hw4EHGjh0b4Og0TdPO7ZprruHdd99l1apVjBs37rzH9u/fH6UUc+Zc+mreM2fO5PHHH+fOO+/ks88+O6PzAmDFihUAVb4DIzQ0lGeeeYaVK1fy7bffBjqccyr1pEWlVGPgsIg4lVK3AFcDc0Qkq7yCqw5qtmjBlEGDGDBjBu898gjD//3vQIekaZqmaYH2J3zTPr4DEJHd58lNcTGOAPWKPa/r36eVksvl4tNPP2Xy5Mls374di8XCG2+8wcCBA7Hb7YEOT9M07aIkJSWxfv16Jk2aREJCAs2bN0cphVIKg8Fwxna7du2YPn06d955J0aj8azHlNxevXo1w4YNo1u3bsyfP/+sU/VSUlKoVasWbdq0CcArcGmGDRvG66+/zvjx41m+fHmgwzmrsmRdmg8kKqWaANOBRcAngE5FXUL/997jo/nzefbTT7ln1CjqtmsX6JA0TdM0LZCcIlJ0KrO+UsoESBna2wQ0VUo1xNdx8SBQYQmoRGQJsCQxMXFwRV2jvPhWort4+fn5zJw5kzfffJODBw/StGlTACZMmMDIkSMrIkRN07QKNXXqVDZv3szQoUMv6vgbbrjhktrv2rUrCxcuJCQk5Hd1Ho+HL774gh49emAwlGb9jMplt9sZPXo0Y8eO5bvvvrvk16IylKUDwysibqVUb2CqiExVSm0pr8CqE2Uw8P6CBfy9Sxcixo2DZctAL4ekaZqmXb7WKKWeB2xKqduA4Zwn70RxSqm5wC3HHfWTAAAgAElEQVRAnFLqMPCSiPxTKTUCWAEYgZki8lPFhO6bQgL0aNKkSUVdotxdaBnG9PR03nnnHaZOnUp6ejodO3Zk2rRp7Nmzh6effpo+ffpUUqSapmnlKyQkhLVr1/L999/j9XoRkdOPxbcdDgePPPII7du358knn/xd/dnOsVgs3HXXXdhstrNee+PGjWRkZFT56SPFDR8+/PQojGXLlgU6nN8pSweGSynVDxgA9PDvM5/n+Mtawz/8gbcnT4bRo2HePOjbN9AhaZqmaVqgPAsMBLYBQ4BlwAcXc6KI9DvH/mX+dipcMI3AuJCDBw/yt7/9jRkzZuBwOOjRowdjx449vdzqLbfcQqtWrQimzhpN07SSQkND6dSp0wWPe/jhh5k7dy633norYWFhZb7u8uXLq/TyqWcTFhbGqFGjeP7559m0aRPtqtjsgbKMY3kMaA9MFJH9/mGbH5ZPWNXUk0+y+aqr6PrII2Tu3x/oaDRN0zSt0imljMCHIjJDRPqKyH3+7bJMIalU1SGJ5/bt23n00Udp3Lgx06ZN47777mP79u0sXrz4dOfFyZMnWbt2Lb179w5wtJqmaZUjKSmJ/Px85s+fXy7tpaSkcMMNNxATE1Mu7VWWESNGEBMTUyVXJCl1B4aI7BCRkSIy1/98v4hMLr/QqiGTCcNLL7G6qIhnuncPdDSapmmaVulExAPUV0pZLnhwFSUiS0Tk8cjIyECHcsnWrVtHjx49aN26NQsWLGDEiBHs3buX2bNn07JlyzOOXbp0KV6vl169egUoWk3TtMp100030aRJE2bNmlXmttLS0vj++++DavrIKeHh4fz5z39m6dKl/PDDD4EO5wyl7sBQSnVQSq1USu1SSu1TSu1XSpVu4dzLSJsHHmD0DTfwz127WPXWW4EOR9M0TdMCYR+wXin1F6XUn0+VQAd1sYJpBMapgS1btmyhY8eO3HzzzXz77beMHz+eAwcOMGXKFBISEs56bnJyMvXq1aNt27aVGbKmaVrAKKVISkpi9erV7C/jiPkVK1YgIkHZgQHwxBNPEB0dXeVGYZRlCsk/gb8BHYF2QKL/UbuAl5Yto7HJxOPPPktBRkagw9E0TdO0yrYXWIrvPiS8WAkKwTQCo6CgAIApU6Zw+PBhpk6dysGDBxk3bhyxsbHnPM/hcPDFF1/Qq1evCyYA1TRNq0769++PUoo5c+aUqZ2UlBRq1qzJtddeW06RVa6IiAiefvppFi9ezJYtVWetjrJ0YGSLSIqInBCR9FOl3CKrxmwxMcx47TX2ut28p5N5apqmaZcZERkvIuOBN05t+59r5SwtLQ2AO++8k927dzNixAhCQ0MveN4XX3xBQUGBnj6iadplJyEhgS5dujB79my8Xm+p2vB4PKxYsYJu3boFxfKp5/LEE08QGRlZpUZhlOXV/Eop9YZSqr1S6tpTpdwiq+Y6jxrFsttu44nVq+HHHwMdjqZpmqZVGv+9ww7gF//za5RS/whwWBctmKaQnFKvXj3M5otfLG7hwoVER0dz8803V2BUmqZpVVNSUhL79+9n7dq1pTr/+++/Jz09PWinj5wSFRXFU089RXJyMlu3bg10OEDZOjBuwDdtZBLwlr+8WR5BXS7u+Pe/MdWoQWZSEu7CwkCHo2mapmmV5e9ANyAdQES2Ahde366KCKYpJKXhdrtZsmQJPXr0uKROD03TtOqid+/ehIeHlzqZZ0pKCgaDgdtvv718AwuAJ598koiICCZMmBDoUICyrULS+Szl1vIMrtqLieHIyy9z1datvK2nkmiapmmXERE5VGKXJyCBVHOlWZ127dq1ZGZm6ukjmqZdtkJDQ7n//vv57LPPyMvLu+TzU1JSuP7668+bayhYREdH8+STTzJ//ny2bdsW6HDKtApJLaXUP5VSKf7nLZRSA8sakFIqxr+6yW7/Y/Q5jluulMpSSi0t6zUD6YrHH+f6WrX4y9Kl7Fu9OtDhaJqmaVplOKSUugkQpZRZKTUa+DnQQWk+ycnJhISEVItPDjVN00orKSmJ/Px8FixYcEnnpaWlsWnTpqCfPlLcU089RXh4eJUYhVGWKSSzgBXAFf7nu4CnyhoQ8CzwXxFpCvzX//xs3gD6l8P1AkoZDExbtAgjMPTee5FSJorRNE3TtCAyFPgTUAc4ArTxPw8KwZgD42KJCMnJydx+++3Y7fZAh6NpmhYwHTp0oHHjxpc8jWTlypVBvXzq2cTExDBy5EjmzZvHTz/9FNBYytKBESci/wG8ACLipnyGf/YEZvu3ZwNnHb8oIv8FcsvhegFX74YbeK1vX1ZmZPDh0KGBDkfTNE3TKoRSarJ/s7OIPCwitUSkpog8EkwrmVXnHBg//vgjBw8e1NNHNE277CmlSEpK4quvvuLXX3+96PNSUlKIi4vjuuuuq7jgAuDpp5/GbrcHfBRGWTow8pVSsYAAKKVuBMrjo4haInLMv50K1CpLY0qpx5VS3yulvj+1lFhVNOyTT2gfFsaq2bPhxIlAh6NpmqZpFeFOpZQCngt0IJcb38t+YcnJyRgMBu6+++4KjkjTNK3qe/TRR1FKMWfOnIs63uv1VovlU88mNjaWESNG8J///Ieffw7crM+yvKp/BhYDjZVS64E5wBMXc6JS6kul1PazlJ7FjxNf5qlLzz51ZhvTRSRRRBJr1KhRlqYqlMFkYvl//8u/vF54+ulAh6NpmqZpFWE5kAlcrZTKUUrlFn8MdHCab/nUjh07UpXvmTRN0ypLQkICt956K7NmzcJ7EVP9f/jhB9LS0qrV9JHiRo0aRWhoKH/9618DFkNZViHZDPwBuAkYArQUkf9d5LldRaTVWcoi4LhSKh7A/3jZDEeIuP561AsvsPeTT1j72muBDkfTNE3TytuLIhIFfC4iESISXvwx0MFVR5eyCsnevXvZtm0bvXv3rsCINE3TgktSUhL79+9n3bp1Fzw2JSUFpRTdunWrhMgqX1xcHH/605/497//zc6dOwMSQ1lWIekL2ETkJ3x5Kj5VSl1bDjEtBgb4twcAi8qhzaAhzz5L/9BQej7/PL9exC+JpmmapgWRb/2PQT3aorom8Vy0yHfL1bNnzwscqWmadvno3bs3YWFhF5XMMyUlhXbt2hEXF1fxgQXI6NGjCQkJCdgojLJMIfmLiOQqpToCXYB/Au+WQ0yvAbcppXYDXf3PUUolKqU+OHWQUmot8BnQRSl1WClVLbq5VEgIcxYvxiNC327dcOYE9T2epmmaphVnUUo9BNyklOpTsgQ6uIsVTEk8L2UERnJyMtdccw0NGzaswIg0TdOCi91u5/777+ezzz4jPz//nMelp6fz3XffVdvpI6fUqFGD4cOH88knn7Br165Kv35ZOjBOrThyFzBDRD4HLGUNSETSRaSLiDT1TzXJ8O//XkQGFTvuZhGpISI2EakrIivKeu2qokmXLswaM4bvHQ6eat8+0OFomqZpWnkZCtwMRAE9ShSdNbICXSiJ54kTJ1i/fr1efUTTNO0skpKSyMvLY8GCBec85osvvqh2y6eey+jRo7FarUyaNKnSr12WDowjSqn3gQeAZUopaxnb04rpPXkyoxMTeW/HDpJ1Uk9N0zStGhCRdSIyDBgjIo+VKH8MdHyXs6VLl+L1enUHhqZp2ll07NiRRo0anXcaSUpKCrGxsSQmJlZeYAFSq1Ythg4dykcffcTevXsr9dpl6XC4H1gBdBORLCAGeKZcotIAeHXtWiY3aEC399+Hn34KdDiapmmaViZKqVv9m5nBPIUkmFzsFJKFCxdSv359rrnmmgqOSNM0LfgopUhKSmLVqlUcOHDgd/Ver5fly5fTrVs3jEZjACKsfGPGjMFsNjNx4sRKvW5ZViFxiMgCEdntf35MRL4ov9A0U0gIY775BltEBDm9epF79GigQ9I0TdO0sviD/7Hk9BE9haSCnW8KSV5eHitXrqR3794XnGqiaZp2uXr00UcBmDNnzu/qtmzZUq2XTz2b2rVrM2TIEHbt2oXb7a6065oq7Upa6cTHU/Thh7S//XZa3nADnx44gDLomTqapmla8BGRl/yPjwU6FqVUI+AFIFJE7jvXvmB3MSMwVqxYgdPp1NNHNE3TzqN+/frceuutzJo1ixdffPGMDt/qvnzquUyePBmLxVKpnd/6nXAQsNx2G492785nhw/zf/dVi/spTdM07TKklPrz+coltDNTKXVCKbW9xP7uSqmdSqk9Sqlnz9eGiOwTkYEX2nc5SE5OJjY2lg4dOgQ6FE3TtCotKSmJffv2sW7dujP2p6SkkJiYSI0aNQIUWWBYrdZKH7mnOzCCxJjPP+ee2rUZvXAh37z/fqDD0TRN07TSCPeXRGAYUMdfhgLXXkI7s4DuxXcopYzANOAOoAXQTynVQinVWim1tESpWfYvpXpwuVwsXbqUHj16YDLpgbmapmnn06dPH8LCws5I5pmRkcGGDRsuq+kjgaQ7MIKEMhiYvWEDCSYT9w8fzgmd1FPTNE0LMiIyXkTGA3WBa0VklIiMAq4DEi6hna+BjBK7rwf2+EdRFAH/BnqKyDYRubtEOVHar0Ep9bhS6nul1PdpaWmlbabSXGgKyddff01WVpaePqJpmnYR7HY7ffv25bPPPiM/Px+AlStX4vV66d69+wXO1sqD7sAIIlH16zP/ww9pKoJryBDweAIdkqZpmqaVRi2gqNjzIv++sqgDHCr2/LB/31kppWKVUu8BbZVSz51rX0kiMh0YD2y2WCxlDLnynGuI78KFC7HZbNx2222VHJGmaVpwSkpKIjc3l4ULFwK+6SMxMTFcf/31AY7s8qA7MIJMmwcfZNX06dRZvx556aVAh6NpmqZppTEH2KiUelkp9TLwHb5pIZVGRNJFZKiINBaRV8+17xznLhGRxyMjIysv4AogIiQnJ9OtWzdCQ0MDHY6maVpQ6NixI40aNWLWrFmnl0+9/fbbL5vlUwNNd2AEITVoEFkPPUSPiRP5/OWXAx2Opmmapl0SEZkIPAZk+stj5+swuEhHgHrFntf17yt3SqkeSqnp2dnZFdF8uTrfFJIffviBI0eO0Lt370qMSNM0LbgZDAYGDBjAqlWrWLx4McePH9f5LyqR7sAIUtapUzkSEkL/V17h1xJZcDVN0zStqhORzSLytr9sKYcmNwFNlVINlVIW4EFgcTm0+zvBOALjbFNIkpOTMRqN3HXXXQGISNM0LXg9+uijiAjDhw8HuOyWTw0k3YERpGwxMcxbuhSvCPd164YzJyfQIWmapmlapVBKzQW+BZorpQ4rpQaKiBsYAawAfgb+IyIVkvE6mEZgnE9ycjKdOnUiNjY20KFomqYFlQYNGtC5c2eOHTvGddddR61aZU3jpF0s3YERxBp36cLsZ5/lB4eDp9q3D3Q4mqZpmlYpRKSfiMSLiFlE6orIP/37l4lIM38Oi4kVeP2gG4FR0u7du/npp5/06iOapmmllJSUBKCnj1Qy3YER5Hq++ipjrr+exTt2cPLddwMdjqZpmqZVe9VhBMaiRYsA6NmzZ4Aj0TRNC059+/Zl6NChDBo0KNChXFZ0B0Y1MHHNGn688UbiRo2C7dsDHY6maZqmVWvVYQTGwoULadu2LfXr1w90KJqmaUHJZrPx7rvv6r+jlUx3YFQDppAQaixYgDs8nNc7dybn8OFAh6RpmqZp1VYwjcA42yokqampfPvtt3r6iKZpmhZ0TIEOQCsn8fFsnTCB54cMYdONN/KfgwdRBt0/pWmaVp2J241yu/EUFJB18iQuh4Mih8P3WFBA7chIom02cjIz2bJjB67CQm5s0YKwHj0CHXpQE5ElwJLExMTBgY7lYhVfhWTJkiWIiF4+VdM0TQs6ugOjGrnu8cd5ddEixixbxtv33stTCxcGOiRN07SgI16vrwMgLw+cTsIsFnA62bN7NwU5ORQVFODMz6eooIA4m41WV1wBTieffv01hQUFFDmdFBUWUlRUROu4OLrWr4+nsJDnv/ySIpeLIpcLl8tFkdtN95o1eTA+nlyHg/s2baLI4/mteL0Mj4piiN3O4YIC2qWmUiSCSwQXUARMAUbiW3Kj9Vm+lpnAY8AO4Bb/vv9FRNA6CEYOaOXjbCMwkpOTadSoEa1atQpARJqmaZpWeroDo5oZvWQJ39SpwzPJybR79106DBsW6JA0TdPOz+0Gp5OctDRy09Nx5uZSmJODMz8fiopo26ABOJ1s2LqVQ6mpOB0OnAUFOAsLCTMYePTqq8HpZPqGDexMS8NZVOQrLhf1rFYmNmsGTieDt25lR14eRR4PTq8Xp8dDosXCx5GR4HRyTWYmv3i9FBUL7R5gkX+7A3CiROgPAR/7t/8IOErUDwG6Agp4G7ACFqV8xWDgyuxsyM3FYDSS43RiMRiwmUxEhoRgNhqJbtAAGjXCLkKPLVuwmM2YTSbfo9lM4pVXQuPGXOF2839bt2K2WLBYrZj95frmzSEhgauKivjv/v2YQ0JodPXV5fe9u0wppXoAPZo0aRLoUC7aqREYubm5fPnll4wYMeKMURmapmmaFgx0B0Y1owwG/rVhA4lNmvDoE0+ws2dPTFdcEeiwNE2rosTrBbcb5XSSn55O+rFjFObkUJibS0F2NoV5edzYqBFWr5dtO3fyw65dFDocFDgcFBYUUFhYyPOJiVjdbj7bsYOl+/fjLCqi0OXC6XZT6Haz6sorUU4nLx06xEdZWRR6vRSK4BTBBGT5YxkKzC0RXy0g1b89CVhSor4x8Ohc31nzgG8Aq1KnyzU2G5jNYLWivF5C/J0DVpMJq8nEVTEx0K4dWCz027qVLLcbi8WC1WrFYrXSLD4eEhPBYuG9//0Pj8GANTQUS0gIVrud+Fq1oFkzMJv58dgxTDYbltBQLHY7FrudkIgICA/HYDRSeJ7vgx349jz10cD089THAE+cpz4SuPU89dqlCcYpJKcsX76coqIinf9C0zRNC0q6A6MaiqpfnwUff4yrf39Mjz4KK1aA0RjosDRNuwjuwkIKMjJwZGRQkJVFQVYWV4SHE2kykXbsGBu2bqUgL89X8vMpcDjo3bQpDUJC+PHAAWZs2UKB0+krRUUUuFz8vWFDrlKKBampjElNpdDjoVCEAhEKgf8BLYEPgKfOEtOvQH1gMfDiWeqf2LABq83GHo+HNQUFhBgMWI1GQoxGrEYjbrsdc1wcDYxGbkpPJ8Rsxmq1EmKxEBoSAt26gdXKHw8c4JbsbKw2GyGhoVhDQwkLD4cbbwSrlSlpaUz0eLCGhflKeDi2yEioUQOsVr64wN+583UAADx7gfoLZQtoqkc2aFVQySkkCxcuJC4ujptuuilAEWmapmla6VW5DgylVAzwKdAA333z/SKSWeKYNsC7QATgASaKyKeVG2nVdvX990NeHgwcyLbhw2n9/vuBDknTgpvXizcvj7SDB3FkZJCfno4jK4v8zEwSIiJoHBlJXmYmH61eTUF+Po78fBwFBTgKCrinTh06R0dz8ORJhn3/PY6iIhxuNwVuNw6Ph4l2Ow8A3+XlcaPH87tLfwrcD2zFN6WhpGZAA6U4YrHw76IibAaDrxiN2IxGnCJQowY1bDZuMBiwWa2E+DsQbDYbMR06QI0adM3M5J9HjhASGkqI3Y4tLIyQsDBqXnstREYyrLCQh9xubJGRhPiLNSLidMLg5/zlXB7zl3PpeoFvQeML1Guadn5FRUV8/vnn3HfffRj1BxuapmlaEKpyHRj4PgT7r4i8ppR61v98bIljHMCjIrJbKXUF8INSaoWIZJVs7LL2xz8yd84cHpo+naXx8dz18suBjkjTKo4IFBWRcegQuSdOkH/yJPmZmeSlpxNtMtGmZk3Iz+e9FSvIyskhPz+ffIcDR0EBN0RF8Vh8PJKXxx82bCDf5cLh8eDweMj3ehlsMPCqx0M+UPssl/4L8AqQBxTPOmPANzWg0Z49dI6LQ5lMnMjPJ9RsJsZmI9RiwWaxULNlS2jcmASvl1d27CA0NBSb3Y4tNBRbWBg3Xn01JCRwvdfLphMnsEVG+kpUFLboaMLi4iA0lLuUIv08L9HN/nIuLf3lXGL8RdMud8GUA6P4CIzVq1eTk5OjVx/RNE3TglZV7MDoyW/J0mcDqynRgSEiu4ptH1VKnQBq8NtUas2v14IFtKlbl/6vvMLmrl1p0LFjoEPSNNyFheQdP07u8ePknTiBNy+PljVrQl4eK775hl8PHSLP38mQl5dHLbOZUU2aQH4+Q777jh05OeS7XOS53eR7PNxoMDBfBDwe2gIHS1yvN7DAv/0ikI4vqaIdCFWK0PBwyMlBhYZiMxqJCAkh1GLBHhKCPSSEdo0bQ5s22G02pm3eTGh4OPaICEIjIrBHRdGwQQNo0oQaVitH8/MJjYnBFhuLOTT0jCR59YBN53ld4vF1hpxLBJB4Sa+0pmkVIRhzYCilSE5Oxm6306VLl0CHo2mapmmlUhU7MGqJyDH/diq+HG7npJS6HrAAeys6sGBki4lh/uefc+2tt9K1c2cGdenCkPHjib7hhkCHpgURd0EBpoICyM3l0K5dHNq3j9yTJ8lJTycnI4Oi/HyGXXMN5OUxc+NGvj54kNyCAvKcTnKdTkJF+LJGDcjLo1dGBou83jPabwbs9G+/hq/X8pQQ4EazmVFHjoDdjrOwELPBQN2ICOxWK2EhIbSOj4cOHSAsjL/u2IHLZMIeEUFYVBT26Gji69aFFi3Abme3y4UtNhZrZOTpqQ/FrTjP62AAhp+n3oivE0LTNK2qEREWLVpE9+7dsdlsgQ5H0zRN00olIB0YSqkvOftI7BeKPxERUUr9fgHz39qJBz4EBoiI9xzHPA48DpCQkFDqmINZo86dWfDmm4wdN45xK1YwdMUKaN6cr6+7DtMf/sCNf/wjBlNV7MvSysLrdpN3/Dg5R4+SffQoTaOjsRQU8NNPP/Hdtm3kZGWRm5NDTk4Oufn5vNmyJWGFhbz7yy/MOHKEXLebHLebHH+ixyLADEwGppW4lgkYOm8eymJhq1KsdrsJM5kIN5sJs1ioHRoKN98MYWH0PXiQ6woKCAsPJzwykrDISOJq1YKOHSEsjI8cDpTdTljNmthr1sRosZxxrVkX+Lr7X6A++uJfQk3TtGrj+PHjHD16VK8+ommapgU1VTI7daAppXYCt4jIMX8HxWoRaX6W4yLwfVA7SUTmXUzbiYmJ8v3335drvMEmfds2YteuheRkblm5kjVALYOBe5o1o9eDD3Lrk08SEhUV6DAve0V5eeQcOUL2kSPkpKaSfeIEV8fFEeP18suuXSz47juyc3LIzs0lJz+f7IIC/l6vHk2Liphz9CgjMzLIAYr/du/EN9LhLWB0sf02IMJgYEtCAvHR0cxxOPgsM5MIm43w0FAiwsKICA/nmTvvxBodzfbMTI4UFhIeF0dEzZqE16xJeO3aRNeti7JaK/FV0jStKlFK/SAil9Usp2C4r1i8eDE9e/YkMTGRLVu2kJaWRnS07srVNE3TqrZz3VdUxY/dFwMD8I0kHwAsKnmAUsoCLATmXGznheYT27o1tG4Nw4eTfOAAKW++SfKiRcz95RdmvPwyd0yYwLLevaFXL/L/8AfsdesGOuSgVJSXR/ahQ2QdPkzW0aNkHTtG88hIEkwmDv36K++tXk1WTg5ZublkORxkFRbySnQ0XdxuvkhPp5vT+bs2U4DuwM/4hipZgUiliDCZiDSbcRiN0LQpTevVY8DRo0SEhxMZGUlkTAyRsbHU6tgR4uP5owh9DQbCa9cmPD4eU0jIGdd51F/OpZW/aJqmXa6CKYnnKXv37uWWW27RnReapmlaUKuKHRivAf9RSg0EDuBbPRClVCIwVEQG+fd1AmKVUkn+85JE5McAxBu0ourXp9/UqfSbOhVnTg5f/d//YfnuO1i3jvR586gLdIiOpleXLvQcPZp6l1HeDPF6yUtNJfPAATIPHSLz6FHiTSaah4aSm5rK6ykpZGZnk5mTQ5bDQWZhIUPCwxkA7M7IoFlh4e/anIYvf0IGvmkYUUoRZTQSZbEQZbWi6teHZs1ophSv7NtHZFSUr/MhLo7IGjW4pk0bSEjg7tBQCsPCsEZEnDX29v5yLtHoaRSapmllEYxJPDMzM/X0EU3TNC3oVbkpJBUpGIZ6VgleLydWrGDKK6+QvHkzvxQVAXCtzca0Rx7hxieegFatoNjqClWRMyeH7EOHyD56lOxjx7C73VwVGQmZmUxZtIi09HRfJ0RuLpkOB7fZbIy22XBlZBCano67RHujgTeAHHwdAFFKEX2qAyIkhEFNm/Jgq1bk2GxM/flnovwjH6Jq1CCqdm2atWxJzcaNkchIsNvPmkBS0zQtWOkpJFXTqSkkAAcPHqRevXoBjkjTNE3TLiyYppBogWYwUPOOO3j1jjt4FdiZksKiqVNJXruWGjNmwIwZLK1Vi1V16nBP//7UadkSg9GI0WymQb16YDCQkZ1NgdOJwWRCGY0YDAaMZjOxsbFgMOAoLMTt8fxWbzRiMJmw2mygFIV5eWQfPkz2kSNkp6aSffw4FqeTTnXqQHY201auZE9qKtl5eWT7c0C0Mpv5e2QkZGfT5MSJ3y1L0weY79+eiG/N3WiliDaZiLZYcMfEwHXXYY6O5vlt2wiPjCQ6Lo7oGjWIrl2bRldeCS1bEh4VhSss7JyJTyMokY22hKrd7aNpmqZVR7Vq1dKdF5qmaVrQ0x0Y2gU1v+MOxtxxB2MAUlNhyRK2v/UW/9i8mSmbN58+zgY4/NsjgY9LtFMTOO7f7ocv2UlxjfhtLdxuwNcl6tsAW/zbs/Hlgog0GIg0m4k0mzFERMC110JkJMN27aLQZPJNw4iNJTI2lvqNGkG7dhAdzQGLhdAaNc45CmL8eV4Phe6E0DRN04JDTk4OAI0aNQpwJJqmaZpWdroDQ7s0tWvD4P9n787jbCz7P4B/rruP4XcAACAASURBVLPPPmdmGIxlmGEsZakRsi/hQaEIpeJRiqxpkSfpSVoeFUpCi5QkFCVlVLbIvm8TMsKYwZh9Pdvn98cZ87Nvc86cM+P7fr3u15xzn/u+ru+5Mb7ne677up7C2KeewrOnTmHNxx8jIyUFDrsdWqWApk0BhwODDh5Eq+RkkITD4QAdDph0OqBJE8DhwL/37kWrM2f+/3USQUajs8DgcGDYgQPo43A454AoVw5B5cqhXJUqQMOGQFAQNvn7Q6PXXzXMMdd5G36uvSpCCCFKGaVUDTgHzAWR7FW4rweArnAOpvuM5EoPhugS2dnZAICAgAAPRyKEEEIUnxQwxC0LqFQJ90+ceMXX2hZuV9P9Om33vs7rMnuEEELcvpRSnwPoBuAMyTsu2N8ZwDQAWgCfknz7am2QPApgkFJq8QX7lgJYqpQyA3gXQKkvYJynkXmXhBBClAFSwBBCCCFEafMFgOkAvjy/QymlhXPBp/sAnASwVSn1I5zFjLcuOf/fJM9co/1XCtsSQgghhBeRAoYQQgghShWS65RSkZfsvgfAkcKRFVBKLQDQneRbcI7WuC6llIJzOfdfSO643vFCCCGEKFkynlAIIYQQZUEEgBMXPD9ZuO+KlFKhSqmZABoppV4u3D0cQAcAvZRSz1zlvMFKqW1KqW1nz551UehCCCGEuBEyAkMIIYQQtx2S5wA8c8m+DwB8cJ3zZiulkgDcbzAY7nZjiEIIIYS4xG1VwNi+fXuKUuofFzcbBiDFxW0Kua7uItfVPeS6uodcV/dw13Wt5oY2b0YigCoXPK9cuM/lSC4DsEwp1bO05BUrVqyA8w6Z25b8PnEPua7uIdfVPeS6ukeJ5hW3VQGDZDlXt6mU2kYy1tXt3u7kurqHXFf3kOvqHnJd3aMMX9etAGoqparDWbjoC+ARd3YoeUXpIdfVPeS6uodcV/eQ6+oeJX1dZQ4MIYQQQpQqSqlvAGwEEKOUOqmUGkTSBmAYgDgABwEsJLnfk3EKIYQQwrVuqxEYQgghhCj9SPa7yv6fAfxcwuEIIYQQooTICIzim+3pAMooua7uIdfVPeS6uodcV/eQ6+rd5M/HPeS6uodcV/eQ6+oecl3do0SvqyJZkv0JIYQQQgghhBBC3DQZgSGEEEIIIYQQQgivJwUMIYQQQgghhBBCeD0pYBSDUqqzUuovpdQRpdRYT8dTFiilqiilViulDiil9iulRno6prJEKaVVSu1USv3k6VjKCqVUsFJqsVIqXil1UCnVzNMxlQVKqdGFvwP2KaW+UUqZPB1TaaSU+lwpdUYpte+CfSFKqV+VUocLf5o9GaP4f5JXuJ7kFe4jOYV7SF7hHpJXuIY35BVSwLhFSiktgI8A/AtAXQD9lFJ1PRtVmWADMIZkXQBNATwr19WlRsK5vKBwnWkAVpCsDaAB5PoWm1IqAsAIALEk7wCgBdDXs1GVWl8A6HzJvrEAfidZE8Dvhc+Fh0le4TaSV7iP5BTuIXmFi0le4VJfwMN5hRQwbt09AI6QPErSAmABgO4ejqnUI5lEckfh4yw4f2lHeDaqskEpVRlAVwCfejqWskIpFQSgFYDPAICkhWS6Z6MqM3QAfJRSOgC+AE55OJ5SieQ6AKmX7O4OYG7h47kAepRoUOJqJK9wA8kr3ENyCveQvMKtJK9wAW/IK6SAcesiAJy44PlJyH+ILqWUigTQCMBmz0ZSZkwF8CIAh6cDKUOqAzgLYE7hMNpPlVJ+ng6qtCOZCOBdAMcBJAHIILnSs1GVKeEkkwofJwMI92QwoojkFW4meYVLSU7hHpJXuIHkFW5XonmFFDCEV1JK+QP4DsAokpmejqe0U0p1A3CG5HZPx1LG6ADcBeBjko0A5ECG4xdb4b2T3eFM5CoB8FNK9fdsVGUTnWupy3rqosyTvMJ1JKdwK8kr3EDyipJTEnmFFDBuXSKAKhc8r1y4TxSTUkoPZ5LxNcnvPR1PGdEcwANKqWNwDktup5Sa59mQyoSTAE6SPP9t3mI4Ew9RPB0AJJA8S9IK4HsA93o4prLktFKqIgAU/jzj4XiEk+QVbiJ5hctJTuE+kle4h+QV7lWieYUUMG7dVgA1lVLVlVIGOCeC+dHDMZV6SikF531/B0m+7+l4ygqSL5OsTDISzr+rq0hK5bmYSCYDOKGUiinc1R7AAQ+GVFYcB9BUKeVb+DuhPWQSM1f6EcAThY+fAPCDB2MR/0/yCjeQvML1JKdwH8kr3EbyCvcq0bxC587GyzKSNqXUMABxcM5k+znJ/R4OqyxoDuAxAHuVUrsK940j+bMHYxLiWoYD+LrwA8dRAAM9HE+pR3KzUmoxgB1wriCwE8Bsz0ZVOimlvgHQBkCYUuokgAkA3gawUCk1CMA/AB72XITiPMkr3EbyClHaSF7hYpJXuI435BXKeZuKEEIIIYQQQgghhPeSW0iEEEIIIYQQQgjh9aSAIYQQQgghhBBCCK8nBQwhhBBCCCGEEEJ4PSlgCCGEEEIIIYQQwutJAUMIIYQQQgghhBBeTwoYQogSo5QKVkoNLXxcqXBJKyGEEEKImyZ5hRC3H1lGVQhRYpRSkQB+InmHh0MRQgghRCkneYUQtx+dpwMQQtxW3gYQpZTaBeAwgDok71BKDQDQA4AfgJoA3gVgAPAYgAIAXUimKqWiAHwEoByAXABPkYwv+bchhBBCCC8geYUQtxm5hUQIUZLGAvibZEMAL1zy2h0AHgTQGMAkALkkGwHYCODxwmNmAxhO8m4AzwOYUSJRCyGEEMIbSV4hxG1GRmAIIbzFapJZALKUUhkAlhXu3wugvlLKH8C9ABYppc6fYyz5MIUQQghRCkheIUQZJAUMIYS3KLjgseOC5w44f1dpAKQXfssihBBCCHEtklcIUQbJLSRCiJKUBSDgVk4kmQkgQSnVGwCUUwNXBieEEEKIUkXyCiFuM1LAEEKUGJLnAGxQSu0DMPkWmngUwCCl1G4A+wF0d2V8QgghhCg9JK8Q4vYjy6gKIYQQQgghhBDC68kIDCGEEEIIIYQQQng9KWAIIYQQQgghhBDC60kBQwghhBBCCCGEEF5PChhCCCGEEEIIIYTwelLAEEIIIYQQQgghhNeTAoYQQgghhBBCCCG8nhQwhBBCCCGEEEII4fWkgCGEEEIIIYQQQgivJwUMIYQQQgghhBBCeD0pYAghhBBCCCGEEMLrSQFDCCGEEEIIIYQQXk/n6QBKUlhYGCMjIz0dhhBCCFHmbN++PYVkOU/HUZIkrxBCCCHc42p5xW1VwIiMjMS2bds8HYYQQghR5iil/vF0DCVN8gohhBDCPa6WV8gtJEIIIYQQQgghhPB6UsAQQgghhBBCCCGE15MChhBCCCGEEEIIIbzebTUHxu2IDgcOxcWh1sGDUPv348eEBCxMSIDNbofd4YDd4YDN4cDXDRogAMCnx4/j6+Rk2M6/RsLucGBTzZrQOxx4PTkZ8zIynPtJOAAEaLXY36gRVEgIPk9NxY7cXJiDgmAOCYE5NBRhFSvi/o4dAbMZaUpBX64c/MqXh9JI/UwIIYQQQpQ+f//9N/r27Yv27dvj+eefR1hYmKdDEuK2IAWMMig3JQWrp0/Hz999h1/i45Fgs2EXgAYVKiDRYsGmzExolYJWKeg0GmiVgu30acBkgt1igYOEXqOBj04HrUYDrUYDVq0KGAyoYjIh9swZaLVaaDUaaDQaOCwWqIAA4MwZ7Dx8GPOzspBOgoXxVACQ9OabAIAnACyD8y+eWSmYdTrc4e+P7+65BzCb8eHJk0h2OBASEoKwChUQFhGBytHRaNCsGRAaCgYGSuFDCCGEyymlqgL4AEAqgEMk3/ZwSEIIL5WTk4OePXviyJEj2L59Oz766COMGDECY8aMQUhIiKfDE6JMUySvf1QZERsby7I6W7gtPh66X3/Fxq+/RtvNm1EAwBdA+/BwdGnbFr1eeAFhd91VYvE4bDZkJiYi7Z9/kHfmDOqazUBaGn5auxYHjx5FWloa0jIykJaVhVAAH1WoAKSlof2xY1hjs8FxQVv3AthQ+LgRgCSNBmF6PcJMJoT5+6N5lSoY3a4dEBaGJceOwRgairAqVRAaGYmw6GgERkRI0UMIIdxMKbWdZKyH+v4cQDcAZ0jeccH+zgCmAdAC+PRaRQmlVFcAZpLzlFLfkuxzvX7Lcl4hhLgykujXrx8WLVqEX375BZUrV8brr7+OhQsXwt/fH6NGjcLo0aNhNps9HaoQpdrV8gopYJRS+enpWPvRR/h50SL8cuAAHrNaMR5AdnQ0xgcEoEvv3mg5ZAhMwcGeDvWm0eFA5smTOHf0KFISEqDJzESs2QykpOCdn37C0aQkpGRmIiUnB+fy89Fco8EsiwWw2xEK51dnF3pMKXxZoQIQGopOiYnw8/FBiL8/Qs1mhIaEoNmdd6Jls2ag2YwD6ekIqVYNIVFRMAYEeOLtCyFEqeThAkYrANkAvjxfwFBKaQEcAnAfgJMAtgLoB2cx461Lmvg3ADuAxQAI4CuSc67Xb1nKK4QQN+bdd9/FCy+8gLfffhsvvfRS0f59+/bhv//9LxYvXoygoCCMHj0ao0aNQlBQkAejFcK9jhw5AoPBgKpVq7q8bSlgoAwkGgkJ4M8/4+E33sDy5GTkATABaFuuHJ584AE8+PLLQFSUp6P0DBLIyMCR7duRcuwYzp04gZTERKQkJyPGZEI3sxm2M2fQfs0anMvPR6rVinMOBywAXgTwDoAMABeWe/wAhGi1GFuxIobGxCAtIADjDh1CqNmMkNBQhJYvj5AKFdDorrtQOSYG9sBAWHx94SNDB4UQtyFPFjAK+48E8NMFBYxmAF4j2anw+csAQPLS4sX5858HsIXkOqXUYpK9rnLcYACDAaBq1ap3//PPFZepF0KUQb/99hs6deqEBx98EAsXLoRS6rJj9uzZg9deew1LlixBcHAwxowZgxEjRiAwMNADEQvhPiTRsWNHHDx4EAkJCdDr9S5t/2p5hcyB4cUKMjOxftYs/Pzttzh16BC+ycqCAhASEIBB9eujy0MPoc2wYfKBGQCUAoKDEd2+PaKvcogOwNoLntPhQG5KChwpKYDFAmNSEr5duRKpp0/j3NmzSE1Lw7n0dFQ2m4G8PKQePYrFx44htXDy0vM+BvAMgD0A7gJgBBCs0cCs0yHYYMDEunXRIToaRzUafJ6QALPZDHNYGMzlyyM4PBwNY2NhrlYN9oAAaIKCoLRat1wiIYS4zUQAOHHB85MAmlzj+BUAXlNKPQLg2NUOIjkbwGzA+cVI8cMUQpQGx44dQ58+fVCnTh3MmTPnisULAKhfvz6+//577Ny5E6+99hrGjx+PKVOmYMyYMRg+fDgCZISvKCPi4uLw22+/YcqUKS4vXlyLjMDwNvn5+OHFFzFn0SL8lpyMHAAGAG1DQ7Fs3Djou3UDatZ0fmAXHnF+fo/UhASc++cfVDEYUEGjQWJCAr5as8Y5v0dmJtKyspCWl4fxYWFobbNh5dmz6JyVhUv/xcUB6AjgOwAPAwhWCsFaLYL0egQZjfioUSPUrVIFW/Pz8WNiIoKCgxEYHIyg0FAElSuHFk2bwr9iReQaDLD7+cG/QgWZ80MIUeK8cARGLwCdST5Z+PwxAE1IDnNBX/cDuD86Ovqpw4cPF7c5IYSXy83NRfPmzZGQkICtW7eiZs2aN3zutm3b8Nprr2H58uUIDQ3FCy+8gGeffRb+/v5ujFgI97Lb7WjYsCFyc3Nx8OBBGAwGl/chIzC8XH56OtTnn8P4/vtISUzELq0Wj9erhy4PPoi2w4bBr3x5T4coCml0OgRXq4bgatVQ44L9EQDGjh171fM6ArDZbMg6dQppx48jPTERaYmJaBAWBthsqHXwIMZt2uSc3DQzE5l5ecjIz4fu1Cng6FHsPHMGb+blXTT6AwAOA4gG8BGct8MoAIEAggqLIKsaNEBYWBiWZGRgZWoqAvz8EBAQgMDAQAQEB+Ox++6DPiQE/+TkIBNAQPnyCAgPR0DFijDItwRCiNIrEUCVC55XLtxXbCSXAVgWGxv7lCvaE0J4L5IYPHgwdu/ejWXLlt1U8QIAYmNj8dNPP2HLli2YMGECxo4di/feew8vvvgihg4dCl9fXzdFLoT7zJ07F/v27cO3337rluLFtcgIDA/LS03F7CefxDs//ICxDgdGtGwJx/jxUO3by7fo4jJ0OJCdnIzMU6eQceoUMpKTcVeFCjDm5WHr7t1Ys2cPMtLTkZmVhYzsbGTk5uLrmjXhl5ODN48dw5S0NGSRKLigTSuclcwhAGZe0l8ggIzQUCAgAONzcrA6Px8BRiMCTCYE+PigQnAwJnXqBPj7Y8Xx4zhtscA/OBj+wcHwM5thDg9HvQYNAD8/5Gm1MIaEQKOTuqkQZZEXjsDQwTmJZ3s4CxdbATxCcr+r+vTGvEII4VrTpk3DqFGjMHHiRLzyyivFbm/jxo2YMGECfv31V4SHh+Oll17CM888Ax8fHxdEK4T75eTkoFatWqhSpQo2btx41dupiksm8YR3JRq5KSmY9eST+N+yZUh2ONA6KAhvTJyIFsOHezo0cRuw5uYiKykJ2adPo2pgIJCZiT27d+PQkSPISktDVkYGsjIzYcvLw4T69YGsLLy9fTtWJiUhy2JBls2GLJsNwQD2kwCJznDeDnOh2gAOFj5uBeAPOJf39VMK/lot7vHzw4I6dQB/fzx/7BiSbTb4+/jA39cXfn5+qB0RgX733gv4+uLnQ4dg1+vhFxwM36Ag+JnNCKtUCRUjIwE/P9iNRmiNxhK7hkKIi3l4FZJvALQBEAbgNIAJJD9TSnUBMBXOlUc+JznJRf3JLSRC3AbWrFmDDh06oFu3bvj++++hceGXi+vXr8eECROwatUqVKxYEWPHjsXgwYNhMplc1oc7FRQUYMOGDUhMTERYWBjCwsJQrlw5hIWFwc/Pz20faoXnvfHGGxg/fjz++OMPtGjRwm39SAEDXlLAyM0FZs5E93Hj8GNBAdoGB2PCa6+h9ciRno1LiFvlcDgnOT15EulJSchOSUF2aipyUlOhs1jQtnp1ICcHX61di7+TkpCdk4Oc3Fxk5+Whml6PN6pVA7Kz0X3fPuzNy0OO3Y5sErkAOgP4pbCbKnDOwHehXgAWFT4OAZADwFcp+CkFX60WfUNC8HpUFODri17798NgMMDHYICvyQQfkwltoqPRpUED2AwGzNm5Ez5+fvANCICPvz98g4JQo0YNVImMhN1gwOmcHPiYzfAxm2EMDJQRUkJcwtMjMDzBK/IKIYRbnDhxAnfffTdCQkKwZcsWt60ism7dOrz66qtYu3YtIiIi8PLLL+PJJ5+E0cu+lCGJv/76CytXrkRcXBzWrFmD3NzcKx5rMpkuKmhc6eeFj0NCQqCVSexLhdOnTyM6OhodOnTAkiVL3NqXFDDg2UQj58wZzBw0CP03bUJ4Sgo2x8bC8sQTaDms2HOJCVEmOWw2WDMzYbTbgZwc/LV/P7LOnUNOWhpyMzKQk5GBCj4+aFG5MpCTg7dWrEBGVhZy8/KQm5+PnPx8tA4OxjPlysGRk4O7du1Cjt2OXLsdeSTySAwDMBmXL6F73msAJsA59rzyBfsVAB8A7/j6YlhoKBJ0OvRISoJJq4VJp4NJp4OPXo9nY2JwX/XqOG61YsqBAzAVFk5MJhNMPj74V6NGqFmtGs5aLNj8zz8w+fsXbT5BQagWGQn/kBBYNBrkkzAFB0Pv6yvFE+GVbqcChozAEKJsy8/PR8uWLfHXX39hy5YtqF27ttv7XL16NV599VWsX78eGo3GuWqd2YyQkJCi7dLnl+4zm80unY8gJSUFK1asQFxcHFavXo3EROc0QpUrV8Zdd92FO+64A61atUJQUBBSUlJw9uzZop8XPj7/MzMz84r9KKUQEhJSVNAIDQ2FyWSCTqeDXq+HTqdzyWONRgOHw3HRZrfbL9t3MxtJBAYGXvbnEhISgqCgIJeO2vEGQ4cOxezZs7F//37ExMS4tS8pYMAzBYzs5GTM+Pe/8e6KFThLYmadOnj6k0+A5s1LNA4hxOVot0MVFMCRk4NTx44hLz0duWlpyMvMRF5mJqoFBaFGUBCyUlMxf9065OXkIC83F3l5ecjLy8P9lSujldmM4ykpGLltG/KsVuRbrci32ZBvt2NCSAh66nTYkpWFDmlpyIdzzpHzFsE5imQlgE5XiO8XOEehfA/goQv2GwGYAKwwm9E0IAA/WK14JTUVJq0WxsIiilGnw/RGjVA9NBSrUlOx8MQJmAwGGA0GGI1GGAwGDGvVCsHBwdh1+jR2JCXBaDLB4OMDo48PDD4+aHfPPTD4+eFUZibO5ebC6OcHg58fjP7+MAYEwBweDmU0AjqdrIwkbqsCxnkyAkOIsock/v3vf+OLL77A0qVL0b179xLte9WqVVi9ejXS0tKQmppatJ1/np6ejmt9fvP3979i4SM4OBg2mw25hXlMbm7uRY/z8vKQk5ODjIwMZGdnw2KxXLOf80wmE1auXImWLVte91iLxYKUlJTLChuX/jx37hwKCgpgs9lgs9lgtVov+nnhY2+m0WgQHBx80Z9FaGjoFYsdF27BwcHQeeGccfHx8bjjjjvw9NNP46OPPnJ7f1LAQMkmGszMxOQ+fTA5Lg4pJDqFhmLCm2+i2eDBJdK/EMI72S0W5GdkID89HX4aDUwAMs+exeHDh5GXlYX8rCzkZWcjLzsbrWrUQAUfHxw6fhzLdu5EQUEB8vPznT8tFoyuWxeRBgNWHz+O6fHxyLdaUWCzId9mQ4Hdjm8rV0YNEp+eO4f/pKWhoHAC1wIABHAczltzJgJ49QqxpgIwA3gJwP+u8LoFgB7AcACfwLnks0EpGJSCv0aDQ5GRgMGAV8+dQ1x2NgxabdEWZjTiq6ZNAYMB0//+G3syM2HQ62HQ66HX6RAeGIjnWrUC9HosPnAASbm50BsMMBiN0BuNKBccjM6NGwN6PTb9/TdybDYYTCbofXygN5kQbDYjKioK0OuRlJoKGAww+Po6X/f1hd7XFzqjUQovLiQFDCFEWTBjxgw8++yzGD9+PF5//XVPh3MZu92OjIyMqxY4rrYvPT3deSutjw98fX2Lfmo0GmRnZyM9PR1nz56F1er8qqVixYqoVasW6tWrh5iYGAQEBFx2rlarxYABA5CUlIR169ahQYMGJXotSMLhcFyxsHGlfXa7HVqtFhqNpmi79PnNbgCQmZl52bW/0nbu3LmL/jyupUOHDli+fHmJr/BxLT169MCqVatw5MgRlC+BFTKlgIGSSTQKzp6F8ZNPgPfew8OpqcguVw6vvvkmmj75pFv7FUKIG0WHA7aCAujsdiirFZkpKUg7cwYFOTmw5OSgIDcXlpwc3BMVBa3djn2HDiH+2DEU5OXBkpeHgoICFOTlYUTTplBWK37Yswcbjx+HxWKBxWqFxWqFcjgwKzYWsFjw7oED+P3MGVjs9qItSKPByqpVAYsF/z51Cr/k5cFKwkLCAiASQHxhvG0ArL3kPTQCsKPwcSyA7Ze83uqCc2LgXIriQl0ALAcAnQ417XacIaFTCvrCraevLz6oUAHQ69Hi2DHkA9BrNNBpNNBrNLg/PByjo6MBnQ59tm+HVquFrnDTa7W4r1o19IqJQQGACZs3Fw1hPb+1jIpC81q1kOtwYN727dDp9f+/GQxoGBWFWtWqIcdqxZ9//QWdwQCtwQCdwQCdXo/qVauiXLlyyLfb8c/p0879hRPZ6oxGBJvNMPn7w64ULA4HdEYjdCYTlBvvMb6dChhyC4kQ7kEScXFxaNq0KYKDr3Rzp3utX78ebdu2RceOHbFs2bIyN/wfcK4gsXbtWsTFxSEuLg5//fUXACAiIgKdOnVCp06d0KFDB4SEhNxQe8ePH0fz5s1htVqxYcMG55cH4rrsdjvS09OvWOg4evQopk6diueffx6TJ0/2dKgAgD/++AOtWrXCG2+8gf/85z8l0mepK2AopToDmAbnzOGfknz7kteNAL4EcDeAcwD6kDx2rTbdWcDIOH4cH/7735i6ahXWkajbtSssL78Mg9wqIoQQN48E7HbAakV2Whrys7JgzcuDNS8PltxcaB0OVA8PB6xW7DlwAOnp6bDm5zu3ggIEG41oWbMmYLFg0caNOJeRAUtBAawWC2w2G6oHBuLh2rUBqxWvr12LtLw8WAu/pbHa7bgnJATPVK8O2Gzo8+efyLZaYXM4YLXbYXU4cH9QEF4sXx4OiwV3/PUXrCTsJKwkbCSeNhrxmtGITKsV5XNyYANgv+Dt/RfOUS+Xzq9y3nsAnoOziFPnCq/PAjAYwDYAja/w+nwA/QCsBtDugv0aADtDQlD/3Lmb/AO5vtupgHGejMAQwnXsdjueeeYZfPrppwgLC8OkSZMwaNCgEpvcMTExEXfffTcCAgKwdetWjxRQ3CU5ORnz5s3DL7/8gvXr18NiscDHxwetW7dGx44d0alTJ9SpU+eWVw45ePAgWrZsicDAQGzYsAEVK1Z08Tu4/QwZMgQzZ85EXFwcOnbs6NFYSKJp06ZITEzEoUOH4OvrWyL9lqoChlJKC+cXZvfBufDAVgD9SB644JihAOqTfEYp1RdAT5J9rtWuyxMNhwMZJ05g2sCBmLJmDdJJdAsPx+Tp01G7Vy/X9SOEEKLUo8MBu8UCW14eNA4HDBoN7AUFOH3qFGwFBbAVFMCanw+bxYLwwECE+fsjNycHOw8cgM1qhc1igb3w5x1VqqCq2YxzaWlYuXOn8/XCzW6zoX10NGqGhuKfM2fwzY4dsBcOo7XZbBjWvDnC3377+gHfJClgiNtNWloazGazp8MoE2w2G5544gnMnz8fQ4cOxZ49e7B+/Xo0atQI06ZNu6H5FYqjoKAAbdq0wd69e7F582bUq1fPrf2VBJJYvXo1Zs6ciSVLlsBmFz7sBwAAIABJREFUs+HOO+9Ep06d0LFjR7Rs2dKlS7Zu2bIF7dq1Q40aNbB27Vr5t1FMubm5aNy4Mc6dO4c9e/aUyC0bV/Ptt9+ib9+++PzzzzFw4MAS6/eqeQVJr9sANAMQd8HzlwG8fMkxcQCaFT7WAUhBYUHmatvdd99NVypo3Jh+zlvJ+UCFCtw2b55L2xdCCCFKCwDb6AU5RElsAO4HMDs6OtpVl0+UMitWrKBGo+H06dM9HUqpl5+fz549exIAJ02aRJJ0OBxcsGABq1SpQgDs27cvjx8/7rYYBg8eTABctGiR2/ooKampqZwyZQpjYmIIgGazmc899xz/+usvt/f966+/Uq/Xs3nz5szJyXF7f2Xd7t27aTQa2bVrVzocDo/EkJ+fz+rVq7N+/fq02Wwl2vfV8gpvvbErAsCJC56fLNx3xWNI2uBcCTH00oaUUoOVUtuUUtvOnj3r0iCz7HbkFD7+Jz3dOeRZCCGEEGUayWUkBwcFBXk6FOEBSUlJ6NOnDxwOB8aMGYPs7GxPh1Rq5ebmonv37liyZAmmTZuGcePGAXAuq9mnTx/Ex8fj1VdfxdKlSxETE4PXX38deXl5Lo3hk08+wezZszF27Fj0KqUjqEli8+bNGDhwICpVqoTRo0fDbDZj7ty5SExMxHvvvYdatWq5PY4OHTpg/vz5+PPPP9G7d++iCUHFralfvz4mT56M5cuX48MPP/RIDDNmzEBCQgImT55cYrdzXdeVqhqe3uBcWfDTC54/BmD6JcfsA1D5gud/Awi7VruuHoFBkju/+YaRWi1ROBLjvpAQ/rVkicv7EUIIIbwZbqMRGOc3d+QVwrvZ7Xa2adOGSikajUYCYJs2bTwdVqmUmZnJVq1aUSnFTz/99JrHJiQksHfv3gTAatWqcdGiRS75Rnrjxo00GAzs2LFjiX+77ApZWVmcPXs2GzVqRAD08/Pj008/zZ07d3o0rlmzZhEAH330Udrtdo/GUto5HA5269aNBoOBu3btKtG+U1NTaTab2bFjxxLt97yr5RXeOgIjEc7V/c6rXLjviscopXQAguCczLNENezbF3/n5+Pdbt1gAPBbaipSe/YEevSATe6LFUIIIYQoM9555x2sWbMGJPHLL7+gatWqWLNmDaZOnerp0EqVtLQ0dOjQARs2bMDXX3+NQYMGXfP4yMhILFy4EKtXr0ZQUBB69+6Ndu3aYc+ePbccQ3JyMh566CFERETgm2++8Z5vl2/Avn37MGzYMERERGDw4MGw2WyYMWMGTp06hZkzZ6Jhw4YejW/w4MGYNGkSvv76a4waNer8l83iFiil8PnnnyMkJAT9+vVDbm5uifX95ptvIj093WtWQilypaqGpzc457Q4CqA6AAOA3QDqXXLMswBmFj7uC2Dh9dp19zclCX/8wVk1a5IAqdWyO8CeFSty17ffurVfIYQQwtNwG43AgMyBcVvasGEDNRoNNRoNH3vsMZLktm3bCIBKKS5fvtzDEZYOp0+fZoMGDWgwGLh06dKbPt9qtXLGjBkMCQmhRqPhkCFDmJKSclNtFBQUsEWLFvTx8Snxb7VvVX5+PufNm8cWLVoQAI1GI/v3788NGzZ4bH6Ea3E4HBw9ejQB8PXXX/d0OKXeypUrCYBPP/10ifSXkJBAg8HAAQMGlEh/V3K1vMLjScDVNgBd4FyJ5G8A/ync9zqABwofmwAsAnAEwBYANa7XZokM9XQ4yNmz+ZvJRANAU+GtJQ9WqsTdCxe6v38hhBDCA26nAsb5TW4huX2kpqaySpUqNJlMDAoK4unTp4tee+ihh6jRaOjr68tt27Z5MErvd/LkSdauXZs+Pj6Mi4srVlvnzp3j8OHDqdVqaTab+cEHH9Bqtd7QucOGDSMAzp8/v1gxlIQjR47wxRdfZFhYGAEwKiqKkydP5tmzZz0d2nXZ7XY+/vjjBMAZM2Z4OpxS74UXXiAAfvfdd27vq1+/fvTx8eGJEyfc3tfVlLoChju2kkw0jm/axH8V/qKpqtUWrVYy9+67yd27SywOIYQQoiRIAUOUVQ6Hgw8++CA1Gg0BcObMmRe9/tdff1Gj0TAgIIAVKlRgQkKCZwL1ckePHmX16tUZEBDAdevWuazdvXv3sn379gTAevXq8bfffrvm8XPmzCEAjhkzplj92u12zpkz56JilqtYrVYuWbKEnTp1IgBqtVr27NmTK1euLHVzSlgsFt5///1USnHBggWeDqdUKygoYGxsLM1ms1tX5dm6dSsBcNy4cW7r40ZIAcMDiYbDbuecQYMYBNAHYJewMJ728yMBbmvXjrsXLy7ReIQQQgh3kQKGKKtmzJhBAPT392eTJk2u+AFy0KBB1Ov1DAwMZJ06dZiamuqBSL1XfHw8IyIiaDabuWXLFpe373A4uGTJElavXp0A2LNnT/7999+XHbd161YajUa2a9fuhkdrXM0vv/xCALzrrruYlZVVrLZI54iSpUuXcvTo0axcuTIBMCIigq+99hpPnjxZ7PY9KTc3ly1btqRer+eKFSs8HU6pdujQIfr5+bF169ZumXjW4XCwdevWLFeuHDMyMlze/s2QAoYHE43E7dt5f3g4pwNk48bk0KHsULhySa+ICO6RQoYQQohSTgoYoizavXs3jUYjq1SpQo1Gc9XVHf755x8aDAZ27dqVBoOBrVq1Yn5+fglH6512797N8uXLs3z58tzt5lHIeXl5nDRpEv38/Gg0Gjlu3Lii4sLp06dZpUoVVqtWzSW3XwwcOJAmk4kajYb333//TX+YPHPmDBcvXszhw4ezfv36VEoVzW3RuXNnLlmypNhFFm+Snp7OBg0a0NfXlxs3bvR0OKXaF198QQB84403XN72jz/+SACcPn26y9u+WVLA8HCi4bDb6fjqKzIkhF/rdHy1VSv+p3lzBhTeWtK7cmXuk+VXhRBClFI3UsAAEHKt7Xrne8smk3jeHrKzs1m7dm2GhIRQKcVRo0Zd8/iRI0dSq9Xy/fffJwD27du31A33d7XNmzfTbDYzIiKC8fHxJdbvyZMn2b9/fwJgpUqV+NVXX7FNmzY0mUzcvn17sdsvKChgcHAwH3vsMU6fPp0AOHz48Guek5SUxAULFnDIkCGsW7cuUfgZwMfHh+3bt+frr7/OtWvXMi8vr9jxeaukpCRGRUUxJCSE+/bt83Q4pZbD4WDfvn2p1Wr5559/uqxdq9XK2rVrs1atWrRYLC5r91ZJAcPDBYwiSUkcVK0aAbCxnx/Xz5jBV1q0YADADwDy4YdJ+QcthBCilLnBAkZC4SpjCQDsAFLgXALdDiDheud72+YVeYVwm0GDBhVNmhgREcHMzMxrHp+cnExfX1/269ePb7/9NgHwxRdfLKFovc/atWsZEBDAGjVq8OjRox6J4c8//2RsbGxRseDLL790Sbs//fQTAXDZsmUkWbTaxtSpU4uOOXHiBOfNm8ennnqKtWrVKorB39+fnTt35ltvvcUNGzawoKDAJTGVFkePHmXFihVZqVIlmS+mGNLT0xkZGcnIyEimp6e7pM2ZM2cSAL///nuXtFdcUsDwokTDYbfz21GjGKYU9QAntm/P5D17mPfSS6S/Pz8D2MzfnxPbt+e2efNoL0PDx4QQQpRNN3MLCYBPAHS54Pm/AMy60fO9ZfOWvEK43vz58wmAHTp0IAAuWrTohs4bN24cAXDXrl0cMmQIAfCjjz5yc7TeJy4ujj4+Pqxdu7bH52+w2+2cO3fuZZOvFsfjjz/OoKCgouKDzWZjp06dqJRiu3btWKNGjaKCRVBQELt168bJkydzy5YtZeq2kFu1Z88eBgcHs2bNmm6ZBPV28eeff1Kr1bJfv37FXko3MzOT4eHhbN68udcsyysFDC9MNM4cOMA+VaoQAFdGRZG7dpEpKZzdvTsb+/kV/eIL12g4qGZNOr79lkxL83TYQgghxGVusoCx90b2efvmbXmFcI0jR44wICCAd999NwMCAti5c+cbTuhTU1MZFBTEBx54gFarld26daNGo+EPP/zg5qi9x5IlS2gwGNigQYMy+eE0Pz+fAQEB7NKlC2fPns3HHnuMVatWLcrbAbBNmzacMmUKd+zY4ZaJFsuCDRs20MfHh40aNfL4ZJGl2cSJE50rXc6de83jMjIy+NFHH111tMarr75KAF41P4kUMLw40dj8zjtkeDip03HtE0+woHCyoeS9ezl38GD2rVqV9+v1zj8urZajIyL4ZqdO3LVwIR23+b2VQgghvMNNFjDiALwCILJw+w+AuBs931s2b80rxK07v0xhcHAwu3btSpPJxCNHjtxUG5MmTSr6IJCdnc3GjRvTx8eHmzdvdlPU3mP+/PnUarVs0qRJqV+JpaCggPv37+f333/Pt956iwMGDGCzZs3o7+9/UbGiXLly7NWrFz/88EOuXr2a1apVY4UKFXjs2DFPvwWvt3z5cup0OrZu3bpMz/3hTjabja1ataK/vz8PHz58xWPWrVvHyMhIAuArr7xy2euJiYn09fVl79693R3uTZEChrcnGikpPPnggzQAvNNk4u5LhypareSGDbSPG8emvr5FvzQraTQcVKsW177+OinVSyGEEB5ykwWMEADTAOwEsAPA1NI0ief5zavzCnFLxowZU5TkA+DEiRNvuo2srCyWL1+e7dq1I+mcG6N69eosV67cFZf2LCs+/fRTKqXYunXr684X4i0cDgeTkpK4Zs0azpo1i8899xy7du3KqKgoajSaiwoVFStWZJs2bRgdHU0fHx/+8MMP/Pvvvy8bnbN//34GBQWxXr16LpuboCz7+uuvCYA9evSQ22tu0fHjx2k2mxkbG3vRnCoFBQUcO3YslVKsUaMG77rrLkZERFw2KujJJ5+kXq+/6WKtu0kBo5QkGsvGj2cFjYa+AL+5xmzGp3bu5OcDB7J35coMAvgOQOp0TG/Zkv/r2pX7li6V0RlCCCFKzA1O4vlV4c+R1zu2NGylIa8QN2758uUEwMGDB7NGjRqMiYm55aVQp06dSgD87bffSJLx8fEMCQlhrVq1mJKS4sqwvcK0adMIgJ07d2ZOTo6nw7mM1Wrlnj17uHDhQk6cOJH9+/dn48aNGRgYeFGRwmQysX79+uzduzdfeeUVfvXVV9yyZUvRLQ65ubn09/fnoEGDrtnfb7/9Rp1Oxw4dOnjFag7e7oMPPiAADhw40GvmXyhtvvvuOwLgSy+9RJLct28fGzZsSAAcNGgQMzMzi45Zvnx50Xn79u2jRqO57ipL1+KuiWilgFGKEo1TO3eyeUAAAXDM3XfTcZ1ffJacHGavWEG+9BJ/KRweBIBVtFo+Xbcufxg3jjll8B5EIYQQ3uMGCxgHAFQCsBuAubQuo3p+Ky15hbi+xMREhoWFsX79+nz55ZcJgL///vstt5eXl8cqVaqwSZMmRR/I/vjjDxqNRt57773Mzc11Veged/6WmZ49e95ywcddHA4Hly1bdtEqIABYuXJltm/fnkOHDuW0adO4YsUKHjt27LrL3n7//ffOuetWrrxu33PmzCn68Cgfyq/v/BwML7zwgqdDKbUGDx5MABwyZAiNRiPDwsK4ZMmSotcLCgpYvnx59uzZs2hfly5dGBQUdEuFVZvNxpEjR7JTp05uKdS5vIABYNAlz7UAJtxqeyWxlaZEoyAri8PuvJPjAbJtW/LMmRs+98SWLfzkscfYs2JF+hf+oj6g15MtWnB5+/ac0Lo15wwaxDVTp/LYhg203WbLNwkhhHC9GyxgjABwEEDBBcupnt+OXu98b9kA3A9gdnR0tKsvo/AAm83Gtm3b0tfXl8uXL6der2f//v2L3e6nn35KABdN4Llw4UIqpdirV6/rflj2dg6Ho6jY079/f68b/r9//3527NiRABgTE8M5c+Zwx44dzCqca+5W9O3bl6GhoTf8Xs/fivTmm2/ecp+3C4fDwaFDhxIA33nnHU+HUyodOnSIvoVTDdx3331MTk6+7Jjnn3+eOp2OycnJ/P333wmA//vf/266r9zcXD744IMEwJEjR7plstqr5RXK+drNU0rNBxAMYFDhNydfAFhL8vlbarAExMbGctu2bZ4O46bwiy+gnnkG64OCYJo8GbGPP35T51uys7Hp00/R8sQJqC1bMHb3bvwvKwsX/qkbAWRXrw5djRr4xm7HUZ0OkTVronqDBoi85x5UuPNOaHQ6l74vIYQQZYtSajvJ2Bs89mOSQ9wdk7uVxrxCXO6NN97A+PHj8dlnn+Hrr7/Gjh07EB8fj/Dw8GK1a7PZULduXZhMJuzatQsajQYA8P7772PMmDEYPXo03n//fVe8hRKXnJyMMWPGYP78+Rg8eDA+/vjjovfnaampqZgwYQI+/vhjBAQE4LXXXsPQoUOh1+uL1W5ubi7Kly+PRx99FLNmzbqhc0iif//+mD9/PhYsWIA+ffoUK4ayzuFw4NFHH8WCBQsQGxuL1q1bo1WrVmjZsiXMZrOnw7tIWloaNm/ejJ07d0IpBX9/f/j7+8PPz++Kj88/12q1bolnwYIFGDJkCPLz82G1WvGvf/0LP/74I5RSFx0XHx+POnXq4J133sGCBQuQmpqK+Ph4mEymG+7r7Nmz6N69OzZt2oT3338fo0aNcvXbAXCNvOJKVY0b3QD0AZAC4B8AzYvTVklspWkExoUcW7fyHoOBRoBzrnPP3Y3Iz8jg4V9/5cq33uLs/v35ZuvWZN++ZNOmfNRkumiIHQBWB8iYGLJTJ37csiXf7tyZ344axc2ff84zBw7IXBtCCCFuahLPsrKV1rxC/L8//viDWq2W/fr141dffUUA/Pjjj6973q+//soaNWqwbdu2/OCDD3j8+PErHvfNN98QAOfPn1+0z+FwcMSIEQTAqVOnuuy9XI3FYuFnn3122XwOt6KgoIDvvvsuAwICqNfrOWHCBK+5PcJisfCDDz6g2WymRqPhkCFDePbsWZe1v2jRolu6tSg/P58tWrSg0Wjk+vXrXRZPWVVQUMBJkyaxVatWNBqNBEClFBs0aMDhw4dz8eLFJb48r81m4969ezl79mwOHDiQtWvXvuzz0o1uJpOJYWFhrFatGuvVq8cmTZqwXbt2fOCBB/jII4/wqaee4ujRo/nVV1/d0L+t1NRUPvLIIwTAJk2a8PDhw0Vz8EyfPv2K57Ro0YIVKlQgAM6bN++mrsXhw4cZHR1Nk8nExYsX39S5N+tqeUVxRmDUBDAXwF4AdeC8r/U5krm31GAJKM3flKTEx6Pvvffi97Q0DL3jDkzZuBEGf3+39JWbkoJ/Nm3CsR07kHDgABxnz2JYSAiQkIDWu3djnc120fGtlMLaqCigcmW8kpICR0AAKletispRUahcty6qxcYitFYt4JIKoBBCiLLjZkZglBWlOa8Qzm/qGzZsCL1ej1WrVuGee+5BZGQkNm7ceM3RBPPnz8eAAQNQvXp1aLVaHDx4EAAQGxuLnj17omfPnqhTpw4A5zfKjRo1Qm5uLg4cOFA0CsBut6N3795YunQpFi9ejAcffNAt79FqteKRRx7B4sWLL9pfsWJF1K5dGzExMRf9rFq16lXf+8qVKzFy5EjEx8ejS5cumDp1KmrWrOmWuG9WXFwcRo8ejYMHD6J9+/aYMmUK7rzzTpf28fDDD2Pt2rVITEyE7iZHJp87dw7NmjVDamoqNm3ahOjoaJfGVlbl5+djy5YtWLt2LdatW4c///wTubnOj5p16tRBq1atikZpREREuKzftLQ0bNq0CRs3bsTGjRuxZcsWZGZmAgBCQ0PRtGlTNGvWDM2aNUPjxo2h0+mQnZ2N7Oxs5OTkFPtxVlYWcnJy8MADD+Czzz5DWFjYFeNctWoVnnjiCSQlJWHChAl4+eWXodPpQBLdunXD77//jq1bt172b+GTTz7B4MGDUatWLRw8ePCGR09t3LgRDzzwAEjixx9/xL333lu8C30dLh+BASAeQPvCxwrAGAD7b7W9kthK+zcl1rw8vtC4MQHw3oAApsfHeySOjBMnuGfxYv4wbhyn9uzJuf/6l3MER/PmvMtgoP6SSmNvgDQYyBo12C0khI9GRvKlJk34Ya9eXDJ2LI8sXUomJ5MykkMIIUotyAgMUYo4HA726NGDer2eW7du5ZAhQ6jRaLhjx45rnvfee+8RAFu3bs20tDSSzhVG3nrrLd5zzz1FuU9MTAzHjh3LzZs3c+nSpQTATz755KK2cnJy2LRpU5pMJv75558uf48Wi4W9evUiAL733ns8ePAglyxZwrfffpsDBgxgs2bNaDabr7oKx/jx4zlv3jwuXbqUXbt2JQBGRUVx2bJlLo/1VsXHx18U29KlS90yIiQrK4s+Pj4cMmTILbdx+PBhhoaGsmbNmmVyJZqSUFBQwI0bN/Ltt99mly5dLlpFJioqigMHDuQXX3zBo0eP3vDfA5vNxj179nDWrFkcMGDARaMrNBoNGzRowGeeeYZz587loUOHSmTEkd1u55QpU2gwGFipUqXLRv3k5eVx9OjRBMBatWpxy5Ytl7Vx+vRphoeHs169epdNGjxx4kQCYKdOnW44pu+//54mk4lRUVE8dOjQrb2xm3S1vKI4BYzAK+yrdavtlcRWVhKNb0eOZH+tlvYKFcgNGzwdzmXsViuTdu/m1i++4Pcvvsh1I0eSL75Ia58+bBUYyOo6HQ0X/Gf5HEACzNXpGKnTsUVgIPtVq8YXGjfmtJ49ufvdd8lNm2g/flwmHBVCCC91swUMAOEAuhVu5W/mXG/ZykpecTuaPn160Qf7zZs3UynFkSNHXvV4u93O5557jgDYq1cv5uXlXfG4kydPcvr06Wzfvj21Wi0BsFKlSgwPD2e5cuWYmZl50fFnzpxhdHQ0Q0NDXfqh4MLixZQpU656nMPh4OnTp7lu3TrOnj2bY8aMYdeuXRkdHU2NRnNRcSMwMJBt2rThkCFDilbuOHXqlMtivhlpaWkcPXo0dTodAwMDOXnyZLeugLJgwQIC4Jo1a4rVzvr162k0GtmyZUuvW7GlNLLZbNy2bRvff/99du/enSEhIf+/GmOVKnz00Uc5e/ZsxsfHFxUezp07x+XLl3P8+PHs0KEDAwpXfgTA0NBQduvWjZMmTeLvv/9+2b/XkrZz507GxMRQKcWXXnqJFouFu3btYr169QiAQ4cOveayxXFxcUWrkpx39uxZBgYGsmrVqvTx8WF6evp145g2bRqVUmzSpAnP3MTCEsXl8gJGadzKVKKxZw8ZFcVjOh1nPfJIqZuHwm618vTevdw+bx6PfPwx+eGHPDdiBB+NjGTroCDW0OloLPxl8n5hgeMQQC3Aylotm/r786GICI5s2JDbRo4kv/mGOb/+yqPr1jHfw79shBDidnQzBQwAD8M5f9ZcAF/CuQpJrxs931u2MpVX3EZ27txJg8HALl26sKCggI0aNWKlSpWuOjdEQUEB+/XrRwAcNmzYDc+2f+7cOc6dO5c9evSgwWAgAPr4+PDxxx/nkiVLij54HD58mGFhYYyKinLJvf03Wry4GofDwYULF7Jy5coEwBYtWvCll17iE088wSZNmjAoKOiiwkatWrU4ePBgfvPNN0xKSip2/Ndis9n48ccfMywsjEopPvXUU1dcacHVevbsyQoVKrhkpYXzxZBHHnnEa+YPKSvsdjv37NnD6dOns3fv3ixfvnzR39Pw8PCLltPVaDRs2LBhiY+uuFnZ2dl86qmnipb/1ev1rFChAn/++ecbOn/MmDEEwKVLl5IkR4wYQY1GU/T3cObMmVc91263F4306NGjxzWLJe4gBYyymGikpnJM9eoEwIE1azKvcChjWeGw23k2Pp7p69aRy5Yx8a23+Erz5hwQHc0OISGsbTDQD+CiwgLH7xf8Z1peKd7l48MHKlTgjt69yTff5KkPPuDvkyfz4PLlzDx50tNvTwghypSbLGDsvnDUBYByAHbf6PnespW5vOI2kJWVxZiYGFasWJFnzpzhtGnTCIALFy684vEZGRns0KEDAfCtt9665Q84OTk5rF+/Pk0mE4ODg4uKGT179uSXX37JuLg4mkwmNmnSpFgfEiwWCx966KFbLl7s3buXbdu2JQA2aNCA69atu+wYh8PB5ORkrlmzhu+++y67du160bfYtWvX5jPPPMNvv/3WpcWF33//nXfeeWfRLTw7d+50WdvXkpmZSaPRyOHDh7uszTfffJMA+Morr7isTXE5h8PB+Ph4zpo1i4888ggfeOABTpo0iatWrSrWcrolLSEhgXXq1CEAarVafvTRRzd8bkFBAe+66y6GhIRwzZo11Ol0fOqpp+hwOFi/fn3GxsZe8bzc3Nyi3yUjRoxwyzKp1yMFjDKaaNitVo5v2ZIAGOvry3/ccA+lN3PY7bSnppL79jHx66/52YAB/G/btnyqdm3+q1w53mkycVtAAAnwi0vm5vAHGKPX88A995CPPsqtjz3GqT17ctFzz3HDzJlM+OMP5hdjpm4hhLid3GQBY+8lzzWX7isNW1nMK8q6AQMGUCnFVatWMTExkQEBAezUqdMVCxNJSUls1KgRtVot58yZU+y+N23aRAD873//y99++43PPvssIyIiCIA6nY7169enUoodOnSgxWK56faLU7xITU3liBEjqNVqGRISwhkzZtBqtd7w+VarlVu2bOH//vc/dunS5aKCRt26dTl06FAuXLjwloafHzlyhD169CAA/h979x1f8/U/cPx1sqfEJmaIvWqXWvWlpWrWpkbt2l97lVKlSlG+qjWCGG2KtkaMtqpG7ZEiJPZMkMiQPe7790ciP1si9+YS5/l4fB6593PP55z3JyQ5933PKFq0qKxfvz5TPylfs2aNALJ3716j1WkwGKRXr14CyPLly41W7+vOYDDIjh07pGPHjvLpp5/K//73P9m9e7dRd5N5nRgMBlm5cqU4OzuLs7OzzJkzR+qmvO/r0qVLmncicdl6AAAgAElEQVQU8vf3F0dHR7GyshJHR8fUqV/ffvutAHLy5MlHyt+9e1dq164tSin55ptvjH5faWWKNTA2As0Ai5etI7OPrNzR+HXcOHEGyaWUnPjhB3OH8+qJipK7Bw7IX3PnyuoBA2TWBx/I0LfeknYFC0pQ9eoiRYvK9JS5qo8ft3LkEKlYUdZV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1rqp1tqstY7RWr/r3L9Ga91Oa91Ga/1cLV5PhpAIIS6a1ppXX32VK509rzdt2sTUqVN/0zuhX79+LF26lO3btzNixAgqKyvdFe5FKSoq4q9//SuVlZV88cUXhIWF1en1S0tLWblyJePHjycqKor+/fvTv39/rr76ar7//vtau0737t0bfALjtddeo6Kigsce+92MD27R4Cfx1Fov0Fr30Fr3cOdsqeczMCODD/396T1xortDEUIIIcQfkB4YQoiLlZuby0033cS0adNITEzkp59+4vLLq18gadiwYbzzzjusW7eOCRMmYLef3SndM9lsNsaMGcO+ffv45JNPSEhIqJPr5uTksGjRIoYOHUpERATDhg1j9erVJCYm8umnnzJ//nySk5Pp27cvQ4cOZd++fTW+5mWXXcbRo0fJy8urhXfgeXJzc3nzzTcZOXIk7dq1c3c4gHsTGDWZXMtlE3PVOZuNsA0bGDN0KCYfH3dHI4QQQog/ID0whBAXY8uWLXTt2pW1a9cyZ84cPv300z9cLnXSpEk8//zz/POf/2Tq1Km1OgTCVWbMmMHq1auZM2cOgwYNcum1UlJSmDNnDv3796dJkyZMmDCBnTt3MmnSJDZs2MCpU6dISkpi2LBh3HvvvRw+fJhnn32Wr7/+mksuuYQ777yzRpOldu/eHYCdO3fW1lvyKG+88QbFxcXMmDHD3aFUcWcCoyaTa60DrlVKhTon77zWua/e2fvxx8zJyqKgf393hyKEEEIIIYSoZXa7ndmzZ3P11VdjMpnYvHkzU6ZMueAJLR977DGmTp3K3Llzef75510cbc0sWrSIl156iXvvvdclK45ordmzZw9PP/00l112Ga1ateKhhx4iOzubGTNm8OOPP5KamsrcuXMZMGDA7+bd8Pf3Z+bMmRw5coQHH3yQDz/8kPj4eB599FFyc3P/dDyXXXYZQIMcRlJUVMScOXO46aabuOSSS9wdzq+01m7bgBuBg8BhYKZz39PAX53Pe+KY36IEyAH2nnHsROCQc5twIdfr3r279jRPXHmlNoLOOXTI3aEIIYQQFw34QbuxTVGXGzAEWNC2bdvaun1CiAYqKytLDx48WAN6xIgROi8v76LOY7PZ9NixYzWg33nnnVqOsnZ899132mw264EDB+rKyspaO6/VatXffvutnjp1qm7VqpUGtFJK9+3bV7/8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+uknhgwZwsWLF1m8eDEjRowo0fk8aeDAgQwePJiXXnqJoUOHEhERUarnT09PZ9++ffzyyy/s2LGDHTt28PPPP5OVlQVASEgId9xxB/3798/tXVGzZs1SjUGIghgMBhYtWkTLli0ZM2YMX3/9dZGOMxqNtGnThvj4+GJdb+LEibz99ttMmjSJNWvWFHt425o1a7DZbPTr169YxwF89dVXpKWl0b59eypUKO3RnSVX4BASpVS01jpeKdUtv3qt9Xq3RuYG7h5Com02GlksdKhTB4CYo0c5cewYlVyvhRBCiPKqOENIXPvfiXPizdwvU7TWH7shtFInQ0hu3t13383p06e54447WLlyJWfPnsVgMGC324mMjCQwMJDNmzdz9OhRDh06xOHDh695/O23364Zl+/v709ERES+yY06depgMjn/ee3cuZOBAweSnJzMhx9+yAMPPJBvfNo1vOTZZ58lMjKS5cuXU79+/WK/T601Cxcu5Omnn6ZWrVp88803tGrV6uZumhc5efIkTZs2pUOHDsWeCyCHzWbj4MGDJCQksGfPntzHw4cP5w4DCQ4OJjo6+pqhIPXq1XP7HCVCFObVV19l8uTJLFmyhCFDhhTpmPHjx/Puu++SmpqK0Wgs8rXmz5/PuHHjiI2NLfY8Fk888QT/+c9/uHDhQrGGfGmtadGiBYmJiSxatIhHH320WNctTQW1K4oyB8YzWut5hZX5ArfPgbFlC9l33smlWbN45oUXCG/ThteLmW0TQgghfFEx58D4BOfE4LsBu6tYa63HuSs+dyiLubXKk4sXL1KtWjWee+45PvroI3r06MFnn30GOL/xGzZsGF9++WWByQVwfvg9fvz4NUmNnOeHDx8mIyMjd1+TyUS9evVo0KABGzdupFq1asTExNC6detCY121ahXDhg3DaDSyZMmSYk00mpmZyZgxY3j//ffp27cvn376KSEhIUU+3tstWLCAsWPHFtqjRGvN8ePHf5eo2LdvH9nZ2YDzW+1GjRrRokULmjdvTvPmzWnRogUNGzYscs8aIcqSzWajffv2nDx5kr179xbp//bHH3/Mww8/TGJiIpGRkUW+VnZ2Nk2bNiUoKIhdu3YV+f+E1po6derQrl27IvcUybFlyxbuvPNOlFKcPXuWatWqFev40lRQu6LQVUiAh4HrkxX/l0+Z+O9/8TMaqX72LEEI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\n", + "image/png": "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qXOutafOtmTJEvr06cOqVavo7kta/te//pVJkyZx4MAB6tevX9Gha1q1dvpb+ueee474+Hjsdjv5+flnlUvZ53a7z2r/wQcfDPi8F+fjcrm49dZb2bhxIxs3bizxyio9evRg165d7N+/v0JyzkyePJkXXniBIUOG0LlzZ4YOHcqWLVto27ZqpHwqKCigcePGNGnShLVrq9ZjfEUk8XxCRN6+2L6qpDJuNApzc7kuNpYMl4udv/1GeN26FXo9TdM0TasKLnEKyWN4V24+AbjxTiMREQmotfwCrQMjNzeXF198kWnTplG7dm3eeecd+vXrV+Lz//znP7Nw4UJSU1Mxm804nU7q169P27Zt+eKLLyowck27PLjdbnr16sWqVavO2m8wGLBarVitVkJCQs5sFy0X2x8VFUW/fv0IDg7205+u4p04cYK2bdsSGhrK5s2biYiIuOg58+bN4/7772f16tV07dq1XON5/fXXGTduHA888ABz5szhgQceYO3atRw7dqxKdSKdXhr766+/pkuXLv4O54yKSOK55Rz7tpa2vcoolZVsa+OHH4oCebR160q5nqZpmqb5G5eWxHMvEFPS48u7AI2AfwLzi+yzAXOAmXiXha8y9xXl4YsvvpD4+HgB5JFHHpHMzMxLOt/pdEpMTIw88MADZ/YtXLhQAFm8eHF5h6tply232y379++X48ePS2ZmpjgcDvF4PP4OK2B88803YjQapX///iX63Ox2u4SHh8vgwYPLNY633npLALnvvvvE6XSK0+mUqKgoSUxMLNfrlIf8/HyJi4uTLl26+DuUs5zvvqI0OTAGKqWWAg2L5b/4Gu9yppe99kOH8nibNhzevh13FUjQommapmlVzGEgqzQnKqVmKaVOKqV2FNvfUym1Sym1Vyn17IXaEJH9IjK02O7+eDs0hgN3lia2qkhESExM5Pbbbyc0NJT169fz7rvvluibyaK+/fZb0tLS6Nu375l9H3zwAXXq1Kky87k1rTowGAw0bNiQ2rVrExERgcViqVLf1ld1N910E1OmTGHhwoVMnTr1osdbrVbuvfdeFixYQG5ubrnE8PbbbzNmzBgGDBjARx99hMlkYtOmTWRkZNCrCuZKDA4OZty4caxZs4ZvvvnG3+FcVGkm+nwLvAX86ns9XcYAPcovtMD2xurVJNWrh3HECHA4/B2OpmmaplUl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1atXuXDhAra2ti/UTrVq1TAYDOh/y5r2ZC1atODw4cNcv34dKyur599gJEZbQiIiV0Vkj4jUFJG/Ux3HX/WBiGZ6boULM3DDBvoHBsL27RwrWZKRu3ZRpFo12hQowJ65cxGDwdxhapqmaaZ1CdijlBqllPriwWHuoNJKb+L5dOHh4TRp0oRLly6xceNG1q9fT3BwMHnz5uWzzz4zd3ivtblz55KQkMCwYcPM0v+vv/5KTExMhpePPKCUYvz48dy4cYNly5a9UBuXL1/myJEjevaFpj1Dz549CQwMZOvWreYOBXixJST7kr/eV0qFpzruK6XCjR+iliVZWMB771Ft714u/v03X1Srxu5bt3h78GDKOThwddIkuHvX3FFqmqZppnGNpP0vbADnVMcrQUQ2icinei+Hh8XExNCiRQtOnDjBmjVrcHFxYf78+QBMmzYNGxsbM0f4eitWrBgjRozgl19+McuGfF5eXnh6elKlSpr3+n2uRo0aUb16daZOnUp8fHy671+9ejWgl49o2rO8//775MuXjyVLlpg7FCADVUheRXqq58st+t49fhk2jA3r1rEhLAxLS0uWli6NVc2atBo/HhczTHfUNE3T0ia9VUiS73EQEePUQTQDPa74n/j4eNq0acPGjRvx9vamY8eO1KhRg5MnT1KkSBF8fX0zdeqx9mTR0dF4enri6OjIiRMnsLa2zpR+fX198fT0ZObMmQwdOtSobW/dupWmTZuydOlSPv7443TdW7lyZaysrDh06JBRY9K0rGb06NHMmDGDa9eu4e7unil9Gr0KiVKquFLKNvn7+kqpAUopt4wEqb3e7LNnp8fSpWwMDcXyv/9g+HB+On+e7osXk7tgQdoUKMC6YcOICQ01d6iapmlaBiilaiqlzgLnkh9XUEplfFG8ZhYGg4GePXuyceNG5s+fT5cuXVi4cCFHjx4lISGBKVOm6OTFS8Le3p45c+Zw5swZFixYkGn9/vTTT1haWtKlSxejt92kSRMqV67MlClTSEhI+2r2CxcucPz4cT37QtPS4OOPPyYxMfGFl2sZU0bKqK4DEpVSHsAPQEFA18fUjKNcOZg6lX+iovj3++/5tHx59t66RZtZs+iXOzd07w47dpCQwdJZmqZpmlnMBd4DggFExAeoa9aItBciIgwaNAhvb28mTZpEv379uHnzJmPGjMHe3p7y5cvTpk0bc4eppdKiRQsaN27MhAkTCAwMNHl/CQkJLF++nPfff5+8efMavX2lFOPGjePSpUusWrUqzfc9WD7Stm1bo8ekaVmNh4cH9evXZ+nSpRjMvF9hRhIYhuRNO1sB80VkGJDPOGFpWhJlYUHNTz/lWx8fbkZFsXPaNPq//z789hunGjfG3cGBvuXKsf+77zCkI+uuaZqmmZeIXH/kVKJZAtEy5Msvv2T+/PkMHjw4pUTqoEGDiImJITo6milTpmBhkZHhpmZsSinmzZtHTEwMw4cPN3l/O3bsIDAw0Gibdz5J8+bNqVChAl999RWJiWn7VbJ69Wpq1qxJoUKFTBaXpmUlvXr14uLFi/zzzz9mjSMjf1HilVIdgW7A5uRzmbOQTnstWdnZ0WjkSCr89hsEBqLmzqV+/vz8ePo0tT//nKJ2doyoUYPgv/+G12hvF03TtFfQdaVULUCUUtZKqaGAr7mD0tJn3rx5fPnll3Tv3p1Zs2ahlGLLli2sXbsWe3t7atSoQdOmTc0dpvYEJUuWZOjQoXh7e7Nv3z6T9uXl5UXOnDlN+v/Cg1kY/v7+KTMrnsXPzw8fHx/at29vspg0Latp3bo1rq6uZt/MMyMJjB5ATWCKiFxWShUFvI0TlqY9h50dZQcOZPX169y5eZPln31GmezZWXToELb160OZMhz45BMu/PWXuSPVNE3THtcb6AvkB24CbyY/1l4Rq1atYtCgQbRq1YrFixdjYWFBZGQkffv2JU+ePISHhzNlyhSUUuYOVXuKMWPGUKBAAfr165fmWQvpFRQUxMaNG+nSpYvJq9C0atWKMmXKMHny5OdOcX+Q5NDLmzQt7ezt7enSpQtr164lJCTEbHG8cAJDRM6KyAARWZX8+LKIfG280DQtbZzd3flo0SK23rlDwNWrOH33HeTKRb8lSyjRsCHVnJyY07Ilt44fN3eomqZprz2llCUwT0Q6i0geEcktIl1EJNjcsaWVUqqZUuqHsLAwc4diFnfu3OHzzz+nVq1arFy5MmWDzkmTJnH16lViYmJo0KABDRo0MHOk2rM4Ojoye/ZsfHx8WLRokUn6WLVqFfHx8SZdPvKAhYUFY8eOxdfXl3Xr1j3z2tWrV1O7dm3y589v8rg0LSvp1asXsbGxrFxpvq0vX7iMqlLqLWAiUBiwAhQgIlLMaNEZmS539nq5fugQv06ezKpduzgeHY0Chri7M7N/f2jWDDw9QX8ypGmaZhTpKaOqlNoHNBCROBOHZVKv67iiW7durFq1Ch8fH0qXLg3AqVOnqFSpEhUqVODYsWMcOHCAGjVqmDlS7XlEhIYNG3L8+HH8/f3JlSuXUduvVKkSSimOHTtm1HafJjExkTJlymBra8uJEyeeuP/K2bNnKVOmDPPnz6dfv36ZEpemZSWVK1cmMTGREydOmHSWndHLqAJLgW+A2kBVoEryV017KRSsXp2hmzdzLCqKc1u3MvHtt3nL3h5GjSKgbFk8bGwYVLEif82cSXxUlLnD1TRNe51cAvYrpcYppb54cJg7KO35/v77b5YvX87QoUNTkhcGg4HPPvsMV1dXzp8/zwcffKCTF68IpRTz588nIiKCUaNGGbVtHx8fTpw4kSmzLx6wtLRk7Nix/Pfff2zcuPGJ16xevRqlFB9++GGmxaVpWUmvXr3w8fHhuJlmt2ckgREmIttE5I6IBD84jBaZphlRqSZNGL9rFy0vXIAbNwidMIE3smdn0cmTNBw+nFyOjnQoVIjzs2fDvXvmDlfTNC2ru0jSBuAWgHOqQ3uJxcXF0adPH4oUKZJScQRg8eLFHDhwgFq1ahEeHs7kyZPNGKWWXp6engwcOJClS5dy+PBho7Xr5eWFjY0NnTp1MlqbadGhQwc8PDyYNGkSj840FxFWr15N3bp1yZdPF0/UtBfRsWNH7O3tWbp0qVn6z8gSkumAJbAeiH1wXkRe2o0GXtepntrTRd65w59z57Jp3Tq2XLjAUYOB/JaWbC1dGt8iRWjevz8l3n3X3GFqmqa99NKzhCTVPQ4i8spOgXvdxhXTp09n1KhRbNq0iQ8++ACA27dv88Ybb1CmTBlOnDjBBx98wK+//mrmSLX0Cg8Pp1SpUhQoUICDBw9iaWmZofbi4uLInz8/b7/9dpqqghibl5cXH3/88UP/r0LSUqfy5cuzcOFC+vTpk+lxaVpW0bVrV37//XcCAgJwcHAwSR+mWEJSnaRlI1OB2cnHrAy0B4BSKrtS6g+l1Pnkr9meca2LUuqGUmpBRvvVXk+OuXPTYupUlvj5cSsujvwHD8LIkWwLCGDo5s2UfO893rC1ZVjVquydPx8SEswdsqZp2itPKVVTKXUWOJf8uIJSaqGZw9Ke4cqVK0yaNImWLVs+9Ibwiy++ICoqCg8PD2JiYvjyyy/NGKX2olxcXJg1axZHjx7lxx9/zHB7mzdvJigoiO7du2c8uBfQpUsXihQp8tgsjNWrV2NhYUHr1q3NEpemZRW9evUiPDyctWvXZnrfLzwDw1SUUjOAeyIyXSk1EsgmIiOecu08IFfy9c/dhed1+6REy5gr+/axed48Nu7axZ579ygHHMueHd5/n70eHpTv0QPXQoXMHaamadpLIZ2beB4C2gAbRaRi8rnTIlLWlDEa2+s0rmjevDl//fUXvr6+FEr+2/fHH3/w7rvvMnjwYBYuXEjHjh3x8vIyc6TaixIR6tWrx9mzZ/H39yd79uwv3FazZs04duwY165dS6lSk9kWL17Mp59+yrZt22jcuDEiwhtvvEHBggX5888/zRKTpmUVIkKpUqXIly8ff//9t0n6MPoMDKVUHqXUUqXUtuTHnkqpnhkJMlkLYFny98uAlk/pvzKQB9hphD417TFFatem35o17AwOJuj6dVbMmQNNmxK9dSvvTZxIrsKFaZQjB3NbteLM778jz6k5rmmapv2PiFx/5FSiWQLRnuv3339n06ZNTJw4MSV5ER0dTZ8+fShZsiTh4eEYDAYmTJhg5ki1jFBKsWDBAkJCQh7a4yS9AgMD2bZtG127djVb8gKSquUULFgwZRaGj48P/v7+tGvXzmwxaVpWoZSiZ8+e/PPPP/j7+2dq3xlZQvITsANwT37sDwzKaEBAHhEJSP4+kKQkxUOUUhYkLVkZ+rzGlFKfKqWOKqWO3r171wjhaa8jlwIFKD1oECxfjs2tW+yYP59BVatyIyKCwb/9RtmWLZnp5gZduxKzeDE3X5NP5DRN017QdaVULUCUUtZKqaGAr7mD0h4XGRnJgAEDKFu2LIMG/W+YN336dC5evMj48eNZtmwZn3zyCUWKFDFfoJpRlC9fnr59+7Jo0aIXrjDg7e1NYmJiplYfeRIbGxtGjRrFgQMH2LVrF6tXr8bS0lIvH9E0I+nWrRuWlpaZvplnRjbxPCIiVZVSJ1JN/zwpIm+m4d4/gbxPeGoMsExE3FJdGyIiD+2DoZTqBziIyAylVHegil5CopnLlX37+GvJEt66e5c3Dh9mS1AQHwClbWx4p1QpGn7wAfV799bLTTRNy9LSuYQkJzAPaAgokmZTDsysamZKqWIkjTlcRaRN8jlHYCEQB+wRkZ+f187rMK4YMWIEM2bMYO/evdSuXRuAy5cvU7p0aT788EMsLS1Zs2YNFy9exN3d/Tmtaa+C0NBQSpYsiYeHB/v27cPCIu2fd4oIZcqUwc3NjX///deEUaZNTEwMxYsXp3jx4ty6dYvixYuzY8cOc4elaVlGq1atOHz4MNevX0/X74q0MMUmnpFKqRyAJHdQAwhLy40i0lBEyj7h+B24rZTKl9xmPuDOE5qoCfRTSl0haePQrslVUTQt0xWpXZueP/3EG1u2wO3blNu2jVkffEBhFxeWnjpFy2nTyF64MP5vvgnjxhG8cSOx4eHmDlvTNC3TKaW+Tv72bRHpLCJ5RCS3iHRJa/JCKfWjUuqOUur0I+cbK6X8lFIXkvfQeioRuSQijy57bQ2sFZFPgOZpfU1Z2enTp/nmm2/o0aNHSvICYMiQIVhZWdGrVy9WrFhBv379dPIiC3Fzc+Prr7/mwIEDeHt7p+veI0eO4Ovra/bZFw/Y2dkxYsQI9u7dy8WLF/XyEU0zsunTp3Po0CGjJy+eJSMzMCoB84GywGmSNtNsIyL/ZSggpWYCwak28cwuIsOfcX139AwM7SUVGx7OQS8v/tmwgTExMVgcOcKnBgM/A3Vz5qRhjRo0/OgjyrVujYUZ14lqmqZlVFpmYCilTgHlgWMiUukF+6kLRADLH2z6qZSyJGkpayPgBnAE6EhSufdpjzTxsYjcSb5vbaoZGKOAbSJyUim1UkQ6PS+WrDyueLCh45kzZ/Dz8yNnzpwA/PnnnzRq1IipU6dy7Ngxdu7cyaVLl1Ke17IGg8HAW2+9xaVLl/Dz88PNze35NwF9+vRh2bJlBAYG4uLiYuIo0yY6OpqiRYsSHBzM7du3M7Q5qaZpmcfoMzBE5DhQD6gFfAaUyWjyItl0oJFS6jxJU0unAyilqiillhihfU3LNLYuLtQbOJBxe/ZgcfAgBAfT/ssv+bhcOa6EhzN082bebN+e6vb20LEjLF1KyH/G+GekaZr2UtoOhADllVLhSqn7qb+mpQER+Qe498jpasCF5JkVccAvQAsROSUiHzxyPGlmJyQlPgokf//U8dHrsrfWsmXL2Lt3L19//XVKciI+Pp6BAwdSvHhx6tevz7p16xg8eLBOXmRBFhYWLFiwgLt37zJx4sQ03RMdHc2qVav48MMPX5rkBYC9vT1Lly5lzpw5OnmhaVlARmZgtAW2i8h9pdRYoBLwVXJi46WUlT8p0V5NN44c4a8ffiD+1Cl6Xb2KBAaSD3C2tqZe0aLUrlOHOh07Uuztt1GZODVL0zQtvdI4A8NWRGKVUr+LSIsM9FUE2JxqBkYboLGI9Ep+/BFQ/WmzM5OXwE4hacbGEhGZlrwHxgIgBtj3Ou+BERwczBtvvEGJEiUe2gPh22+/ZeDAgfz222/MnTsXHx8fLl++jKurq5kj1kyld+/eLFmyhBMnTlCuXLlnXrtq1So6derEX3/9RYMGDTIpQk3TsipT7IExLjl5URt4B1gKfJeB9jTttVOgalW6LV5Mr4MH4dYt4k+cYFSrVryRLRvrz5+nx9KleDRsyFgXF2jThvjZszm6fDkJMTHmDl3TNO1FHEj+ataNgEQkWER6i0hxEZmWfC5SRHqISJ/nJS+UUs2UUj+EhaVp669XzqhRowgJCWHRokUpyYu7d+8yfvx43nvvPUJDQ9mzZw/Tpk3TyYssbsqUKbi6utKvXz+e96Gnl5cXRYoUoX79+pkTnKZpr6WMJDAe1GtvCiwWkS2ATcZD0rTXlFLYvPkmA9evZ9Pt2wTFxXH6t99Y1KkTLerUgWPHODF0KFW7dcPN3p6G2bMzsX59/pwxg6g7T5sRrWma9lKxUUp1AmoppVo/emSg3ZtAwVSPCySfMwkR2SQin2bFN+8HDx5k8eLFDBw4kPLly6ecHzNmDJGRkUycOJGhQ4dSs2ZNPvnkEzNGqmWGHDlyMHXqVP755x9++eWXp1537do1/vzzT7p165apm/lpmvb6ycgSks0kDQ4akbR8JBo4LCIVjBeecWXVqZ7a6yPk9Gl2Ll7Mvt272XfhAj7R0Qiwy8KCtytW5Gzp0pzNnZva3bqRN9XAU9M0zdTSuISkNtAZaAdsfORpEZGP09hXER5eQmJF0iae75A0NjkCdBKRM+l5DWmllGoGNPPw8Pjk/PnzpujCLBISEqhSpQpBQUH4+vri7OwMwPHjx6lSpQqDBw8mNDSU5cuXc/z48ecuKdCyhsTERKpXr05AQADnzp1L+f8ita+++opx48Zx6dIlihYtaoYoNU3Lap42rshIAsMBaAycEpHzySVPy4nIzoyFajo6gaFlNWHXrnHQ25s69+/jcOgQ4/bt46uEBAA8rK2pXbgwtd96iy5DhmBbtiwoZeaINU3LqtKSwEh1bU8RWfqC/awC6gM5gdvABBFZqpR6H5hLUuWRH0Vkyou0nx5ZbVwxd+5cBg8ezNq1a/nwww+BpGokderU4fz583h5edG0aVNGjBjB9Om6ev3r5ODBg9SsWZNhw4YxY8aMh54TEUqUKEHBggXZvXu3mSLUNC2rMXoC41WU1QYamvaouIgITvz6K/t++419x46xLzCQOBHuAZY5c/JdvnwE585N1bffpkq7duQoUcLcIWualkWkcQZGAxHZ9bTlIiKy3jTRmUZWGlfcvHmTN954gzp16rBlyxZUcsJ75cqVdO7cmUWLFjF37lxiYmI4c+YMDg4OZo5Yy2w9e/Zk+fLl/Pfff5QuXTrl/D///EO9evVYtmwZXbt2NWOEmqZlJTqBQdYaaGhaWojBwK19+8h//jzs20frtWvZEBGR8nwxKytaFivG7E8/hapViS9XDuts2cwYsaZpr6o0JjC+FJEJSimvJzyd5iUk5pYVl5C0a9eOTZs2cebMGYoVKwZAREQEpUqVwt3dnWbNmjFhwgS2bt1KkyZNzBytZg537tyhVKlSVKlShZ07d6YkuXr06MG6desICAjA0dHRzFFqmpZV6AQGOoGhaZC07OTYmjUc+fNPjpw6RYHwcObevw9AIcDF1paqBQtStXJlqjZpQvlWrbB9ieq5a5r2ckrPEpKsIquMK3bs2EHjxo2ZPHkyY8eOTTk/ZswYpk6dyurVq/noo49o3rw5q1evNmOkmrktWLCA/v37s2bNGtq0aUNERAR58+alQ4cOLFmyxNzhaZqWhegEBllnoKFpRnf7NgmHDvHVN99w5OxZjgQFcTf5d8MACwvmVapEfKVKrIiPp2qzZpRu2hRLG110SNO0/0njDIwvnvW8iHxj3KhMKyuMK6KjoylXrhxWVlb4+Phga2sLwMWLF/H09KR9+/YEBARw+PBhfH19cXd3N3PEmjklJCRQuXJlQkJC8PX1Zc2aNfTo0YN9+/bx1ltvmTs8TdOykKeNK6zMEYymaS+ZPHmwat6cic2bA0lLT64dOMCR9espFhQE165xesUKPo6KAi8vHIFKLi5UK1GCHu3bU6Z5c/DwAEtL874OTdNedg/KF5QCqvK/SiTNgMNmiegFpFpC8v/s3Xl8U1Xex/HPadOmTZruC4W2gLJDBaFUQBaVTWVweRid0ZlxQxHcR9RxZxEUl3lkFAUVxQ33BxdcWBVBZCsgsoMF2lIK3Zs0TdK0Oc8fLR2QoiBNk7a/9+t1X725vbn53UtbTr4551xfl3LGZsyYQWZmJsuXL68Lbcql6QAAIABJREFULwAmTpxIcHAw5513HnfccQezZs2S8EJgMBh46aWXGDRoEE899RSrVq2iU6dODBgwwNelCSFaCOmBIYQ4JZ6qKvYsXsyGL75gw9q1rM/M5Ce7nS+AEcAyo5FHDAZ6JifTMzWVcwYP5pzLLiMiJcXXpQshGsFp3oVkJTBKa22rfWwBvtJaD/ZmjQ2tqbcr9uzZQ2pqKn/+85+ZP39+3fYlS5YwcuRIJk2axOzZs2nXrh0//vgjgRJSi1r/+Mc/+PDDD3G73Tz55JM89NBDvi5JCNHMyBASmn5DQwh/U1lejtqxg6Dt21n25Zc8+e23bCkro/iYvys7Wrema9++bIyLIysyknMuvpizhgwhwCAdwIRoTk4zwNgNnKO1dtU+NgI/a607e7PGhtaU2xVaa0aMGMGGDRvYtWsXrVq1AsDtdnPOOedQVVXFkCFDePPNN8nIyKBXr14+rlj4k7y8PDp37ozdbic7O5s2bdr4uiQhRDMjQ0iEEA0uOCwM0tMhPZ1hN97IMGqGn+Ru3MiWr75iy5o1dIiIgK1befPzz5kF8NxzhAGpYWH0TEnhxQkTMPTujad7dwIiInx7QkKIxvI2sF4p9Wnt4yuAN31XzulpDkNIPvzwQ5YtW8asWbPqwguomaRx165dPP300/zrX/9i4sSJEl6IEyQmJvL666+TmZkp4YUQolFJDwwhRKOoKCxkx1dfseW779iyeTNbsrIostnY5vEAcBWw2WCgZ3w853TqxDnp6fS48EI6Dh0KQUG+LV4I8btO9y4kSqnewKDahyu11pu9U5n3NNV2RVlZGV26dCEpKYm1a9fWDQ3Jz8+nY8eODBgwgJycHKxWKzt27CAsLMzHFQshhGhppAeGEMKnTLGxpF1/PWnXX//fjVpDdjb8/DNDX3sNNm1iS34+nx46hF6xgvRnnmFdUBB07MiDVVUEx8fTtVcvug4cSOfhwwmNjvbdCQkhzojWehOwydd1tESPPfYYR44cYeHChcfNa/Hwww9TUVFBt27dWLRoEV988YWEF0IIIfyK9MAQQvgde34+O775hsq9ezm/qgp27iRt8WI2u1x4avdRwDiLhTmDB0PXrrxntXJW3750HTFCJg4VwgdOtwdGc9AU2xWbNm2ib9++TJgwgVmzZtVtz8jIID09nbFjxzJ//nwuvvhiFixY4MNKhRBCtGQyiSdNs6EhhPgvV1kZe5YtY+cPP7Dzp5/o4nLxl/JyynbvJrKysm6/xIAAukVEMOG88xhz2WVUd+pEYUIC8d26oQICfHgGQjRfLSnAOGYOjFv27t3r63JOWXV1Nf379yc7O5tdu3YRGRkJgMfjYeDAgezbt4/U1FTWrl3Lzp07SUpK8nHFQgghWioZQiKEaPKMERGkjhlD6pgxx223uN3sXbmSHd9+y85Nm9i5dy87Dx+m/LvvYNEidgPdgWil6GQ20yEujo7t2nH1pZfSZfBgdIcOKBmOIoQ4RVrrhcDCtLS0W3xdy+l49dVX2bBhA/Pnz68LLwDmz5/PmjVrmDBhArNnz2bmzJkSXgghhPBL0gNDCNF8aQ25uRz58Uc++OADdu7axd7Dh/nFaiWnupovgD8Bi4FrlaKDyUTHuDg6tG1Lh65dueTKK4lJSwMJN4T4XS2pB8ZRTaldceTIETp37kxaWhpLly5FKQWAzWajc+fOtG7dmoMHD5KUlMS6deuOmxtDCCGEaGzSA0MI0fIoBUlJJFx9NXdfffVx33KWlqIOHIDsbBK+/56rFy3il8OH+SEnh/cOHEB//z2b58whBnjPbOZ5rWvCjZQUOnbrRoc+fegzahTBiYk1ryOEEH7svvvuw+Fw8NJLL9WFFwDTp08nLy+PAQMGsHnzZr766isJL4QQQvgtCTCEEC1SSGQk9OoFvXrR67LLmP3vf9d9z2W1sm/VKs52uSArC9OSJUSuX8+a3Fw+yMpCr1oFQCEQExnJK+HhLK2upl2rVrRr3552XbvS7txz6T5sGMpi8dEZCiFEje+++453332XRx99lM6dO9dt37t3L88//zyjRo1iwYIF3HXXXfTp08eHlQohhBC/TYaQCCHEaXBZrexfvZrMtWu5NDISlZnJs0uX8saBAxyorMRZu18oYAdUbCxTg4P5WSnaJSbWBRxn9elDt4suArlFoWgmWtIQkqY0iWdVVRWpqalUVlaybds2QkND6743evRovv/+e5KSkrBarezcuROLhK5CCCH8gAwhEUKIBmAMD6fLJZfQ5ZJL6rbdX7toj4f8HTs4sG4dhXv21EwMeuAA9sWL2Z6by1e5uThrQ9ROwG6A2FhuV4r84OD/BhzdutEpPZ2OAwdCeLgPzlII8Vua0iSeOTk57Nq1i5dffvm48OKbb77hyy+/ZNSoUXz11VcsWLBAwgshhBB+TwIMIYRoICoggIQePUjo0eO47U/XLtrj4cj27RxYvx5HVhaYzXDgAM6FC9laUMDC3FxctQHHMGApgMXCJR4P1UYjSTExJCcmktS2LT179yZ96FBISoLISJmHQwhRr6M9bc1mc922yspK7rnnHs466yy+/fZbRo8ezRVXXOGrEoUQQohTJgGGEEI0EhUQQKvUVFqlph63/fXZswHwVFfX9OBYv56AvDwICYGDB4lesIBfiovZnplJ3t69aODGd94hHdBAHBATFERyWBhJ0dEktWrFsPR0LrjoInRSEsVmM9Fnn40KCGjsUxZC+KEXX3yRPXv2kJ6ezpEjR5g1a9ZxE3sKIYQQ/srvAgylVDTwIdAOOABcrbUuqWe/FGAukExNG/5SrfWBRitUCCEaWEBgYL0Bx/yZM+vW3RUVHN66FfLywO2mcv9+rvvwQw7m53OwtJRvDxzgUGYmgatXc8Hzz1NETcARAiQFBdHGZCIxIoIbevdmZP/+2KOj+bGwkMTOnWnVvTsxHTpI0CFEM3b48GGmTJlCnz59WL9+Pc899xwpKSm+LksIIYQ4JX4XYAAPAsu11jOUUg/WPv5XPfu9DUzXWi9VSoUBnsYsUgghfCHIZCL5vPPqHhuB/33ggeP2qa6spDI7G4qKCNq9m5mffcbBnBxyjhwht6yMjLw8Rn79NXz2GXuAEcceH2gVGMiLZ53F5V27ciAsjDdzc0ls04bEdu1I7NSJxK5daZWaiuGY8fRCiKbh4Ycfxul0kpOTQ8+ePbn77rt9XZIQQghxyvwxwLgcuKB2/S1gBb8KMJRS3QCD1nopgNa6vBHrE0IIvxYYHExohw7QoQMR553H3dddV/+ONhsdMzP5ftUqDmdmkpedTd6hQ+QVFJAYFQX797MrK4spVusJT10EjIyN5buwMJ6yWkkIDycuOpr4uDjiWrXi8uHDiT37bCosFjwxMZjj46VnhxA+tn79eubNm0efPn3YtGkTCxcuxGDwx6agEEIIUT9//F8rQWudV7t+GEioZ59OQKlSagHQHlgGPKi1rv71jkqpccA4QLpICiHEsSwWwnr1YnCvXifd5WKg0m7nyI4dHN6xg7y9e8k7cICerVpBeTnOLVsoKyhg78GDFBw4gL32ef3eeotY4HXgLmpuKxsXGEi80Uic2cy8Cy8kISWFDJeL7RUVxCUnE9++PXFnn018166ERkd7/fSFaEk8Hg933nknMTExbNy4kdtvv5309HRflyWEEEKcFp8EGEqpZUCrer71yLEPtNZaKaXr2c8ADALOBbKpmTPjBmraysfRWr8KvAqQlpZW37GEEEL8hiCzmaS+fUnq2/eE711Suxxlz8+nYM8eWgcEQEkJAzMyeGb9evLz88kvLqbAaiXfbse4ejV8/jmfuFw8Xc9r2k0mTPHxPF9VxSKHgxizmZiICGKiooiLj+f2K66AmBiy3W6qwsKIOesswpOTpZeHaBRKqdHA6A4dOvi6lFP2448/sn79etq2bUtwcDDTp0/3dUlCCCHEafNJgKG1Hnay7ymljiilErXWeUqpRCC/nt0OAj9prffVPuczoB/1BBhCCCEajzk+HnN8fN3jc0eN4tyT7aw1j+fnM27HDvIzMyk4cID8gwcpOnIEU9euUFCAJyOD0pISMsvKKMrJoVRrIoHbP/kEgPuBj2oPFwhEK0WXkBBW9u4NMTG8eOQIWVVVxMTEEBMXR0xiIq1TUuh//vkQFYU9KIjQhAQCgoK8d1FEs6O1XggsTEtLu8XXtZyqjz76iLZt25KVlcVHH31ERESEr0sSQgghTps/DiH5ArgemFH79fN69tkARCql4rTWBcBFQEbjlSiEEOKMKYUpIYGzEhI468IL691lYu1yVJXLhTU7GzweKCrintWruWT3bory8ykuKqKopIRQtxuCgyErixV79vCNw4HjmGOcC2yqXb8A2AiEA1GBgUQGBzMwOpoX+/aFqCie2bsXV1AQkdHRRMXGEhkfT7sOHejRuzdEReEwGgmJjpaeH8JvaV3T+bSsrIzKykouueQS/vznP/u4KiGEEOKP8ccAYwbwkVJqLJAFXA2glEoDxmutb9ZaVyul7gOWq5obl28EXvNZxUIIIRqFwWgkumPHusf9Bwyg/2/s/3+1Xx3FxRRlZlK0fz/aaoW4OCgp4Y4lS9iXm0tpWRklNhuldjuhSsEvv0BpKXNzc9mrjx99OAb4pHY9CbABEUoRERhIeFAQf05I4OHUVAgP5+6ff8ZkNhMeHk5EZCThUVGkdulCz1690BYL+0pLCU9MJLxNG4zyibjwgtLSUgBiYmKoqKjgpZdeoqbpJIQQQjQ9fhdgaK2LgKH1bM8Abj7m8VLgnEYsTQghRBMVGh1NUnT0CfN4XH/DDb/5vD2Au6KCspwcSrKzKT10CJPLBZGRUFrKQ59/TlFxMSVlZdgqKrA6HJgCAiA7m6qyMt7LyqJMa9zHHPN+oCdgBY6dQSEYCFeKR6KjuSc5mcLQUG7MzCQsJISw0FDCTCYsZjN/6tmT9G7dsAYGsiwzE0tUFGExMTVLXBwJ7dphio8HoxHkjWqLZ629i1BRUREzZsygffv2Pq5ICCGE+OP8LsAQQggh/EmQyURs587Edu58wvfuGzfupM8zAAWA9nhwWa1Yc3Ox5uURVl0NwcEEFxTw9rffYi0upqy0FKvVirW8nE5xcWCx4MzP55DNRnlJCeXV1ZR7PNiAxB9+IB3YR01vkF97k5rxl2sDArjY4yEsMBBLYCBhBgOW4GBe7d+fDl9/3QBXRjQFlZWVAERFRXHvvff6uBohhBDizEiAIYQQQniRCgggJDKSkMhI4rt3r9seCvzj6qtP+rwkasZHHkt7PHjsdnA46FxQwE/bt2MrLKwJOYqLKS8r4/w2bSA0lJjsbK7/8UfKKyoodzqxOZ2Uu1wYaj+RFy1DYWEhAD169CBIJqsVQgjRxEmAIYQQQjQRKiCAQIsFLBZC4+PpeUwg8msdgf80XmnCzwUGBvq6BCGEEOKMybTpQgghhBBCCCGE8HsSYAghhBBCCCGEEMLvSYAhhBBCCCGEEEIIvycBhhBCCCGEEEIIIfye0lr7uoZGo5QqALIa+LCxQGEDH1PIdfUWua7eIdfVO+S6eoe3rmtbrXWcF47rt6Rd0aTIdfUOua7eIdfVO+S6ekejtitaVIDhDUqpDK11mq/raG7kunqHXFfvkOvqHXJdvUOuq3+Tfx/vkOvqHXJdvUOuq3fIdfWOxr6uMoRECCGEEEIIIYQQfk8CDCGEEEIIIYQQQvg9CTDO3Ku+LqCZkuvqHXJdvUOuq3fIdfUOua7+Tf59vEOuq3fIdfUOua7eIdfVOxr1usocGEIIIYQQQgghhPB70gNDCCGEEEIIIYQQfk8CDCGEEEIIIYQQQvg9CTDOgFLqYqXUbqXUL0qpB31dT3OglEpWSn2nlNqhlNqulLrb1zU1J0qpQKXUZqXUl76upblQSkUqpT5RSu1SSu1USvX3dU3NgVLqn7V/A7Yppd5XSoX4uqamSCn1hlIqXym17Zht0UqppUqpvbVfo3xZo/gvaVc0PGlXeI+0KbxD2hXeIe2KhuEP7QoJMP4gpVQg8BJwCdANuEYp1c23VTULVcBErXU3oB9wu1zXBnU3sNPXRTQz/wEWaa27AD2R63vGlFJtgLuANK11DyAQ+Ktvq2qy3gQu/tW2B4HlWuuOwPLax8LHpF3hNdKu8B5pU3iHtCsamLQrGtSb+LhdIQHGH5cO/KK13qe1rgQ+AC73cU1NntY6T2u9qXbdRs0f7Ta+rap5UEolAaOAub6upblQSkUAg4HXAbTWlVrrUt9W1WwYgFCllAEwAYd8XE+TpLVeCRT/avPlwFu1628BVzRqUeJkpF3hBdKu8A5pU3iHtCu8StoVDcAf2hUSYPxxbYCcYx4fRP5DbFBKqXbAucA631bSbMwEHgA8vi6kGWkPFADzarvRzlVKmX1dVFOntc4FngOygTygTGu9xLdVNSsJWuu82vXDQIIvixF1pF3hZdKuaFDSpvAOaVd4gbQrvK5R2xUSYAi/pJQKA/4PuEdrbfV1PU2dUupPQL7WeqOva2lmDEBvYLbW+lzAjnTHP2O1Yycvp6Yh1xowK6X+7tuqmiddcy91uZ+6aPakXdFwpE3hVdKu8AJpVzSexmhXSIDxx+UCycc8TqrdJs6QUiqImkbGfK31Al/X00ycD1ymlDpATbfki5RS7/q2pGbhIHBQa33007xPqGl4iDMzDNivtS7QWruBBcAAH9fUnBxRSiUC1H7N93E9ooa0K7xE2hUNTtoU3iPtCu+QdoV3NWq7QgKMP24D0FEp1V4pFUzNRDBf+LimJk8ppagZ97dTa/2/vq6nudBaP6S1TtJat6PmZ/VbrbUkz2dIa30YyFFKda7dNBTY4cOSmotsoJ9SylT7N2EoMolZQ/oCuL52/Xrgcx/WIv5L2hVeIO2KhidtCu+RdoXXSLvCuxq1XWHw5sGbM611lVLqDmAxNTPZvqG13u7jspqD84F/AFuVUj/VbntYa/21D2sS4rfcCcyvfcOxD7jRx/U0eVrrdUqpT4BN1NxBYDPwqm+rapqUUu8DFwCxSqmDwCRgBvCRUmoskAVc7bsKxVHSrvAaaVeIpkbaFQ1M2hUNxx/aFapmmIoQQgghhBBCCCGE/5IhJEIIIYQQQgghhPB7EmAIIYQQQgghhBDC70mAIYQQQgghhBBCCL8nAYYQQgghhBBCCCH8ngQYQgghhBBCCCGE8HsSYAghGo1SKlIpdVvteuvaW1oJIYQQQpw2aVcI0fLIbVSFEI1GKdUO+FJr3cPHpQghhBCiiZN2hRAtj8HXBQghWpQZwNlKqZ+AvUBXrXUPpdQNwBWAGegIPAcEA/8AXMClWutipdTZwEtAHFAB3KK13tX4pyGEEEIIPyDtCiFaGBlCIoRoTA8CmVrrXsD9v/peD+B/gL7AdKBCa30usAa4rnafV4E7tdZ9gPuAlxulaiGEEEL4I2lXCNHCSA8MIYS/+E5rbQNsSqkyYGHt9q3AOUqpMGAA8LFS6uhzjI1fphBCCCGaAGlXCNEMSYAhhPAXrmPWPcc89lDztyoAKK39lEUIIYQQ4rdIu0KIZkiGkAghGpMNsPyRJ2qtrcB+pdRVAKpGz4YsTgghhBBNirQrhGhhJMAQQjQarXURsFoptQ149g8c4m/AWKXUFmA7cHlD1ieEEEKIpkPaFUK0PHIbVSGEEEIIIYQQQvg96YEhhBBCCCGEEEIIvycBhhBCCCGEEEIIIfyeBBhCCCGEEEIIIYTwexJgCCGEEEIIIYQQwu9JgCGEEEIIIYQQQgi/JwGGEEIIIYQQQggh/J4EGEIIIYQQQgghhPB7EmAIIYQQQgghhBDC70mAIYQQQgghhBBCCL8nAYYQQgghhBBCCCH8ngQYQgghhBBCCCGE8HsGXxfQmGJjY3W7du18XYYQQgjR7GzcuLFQax3n6zoak7QrhBBCCO84WbuiRQUY7dq1IyMjw9dlCCGEEM2OUirL1zU0NmlXCCGEEN5xsnaFDCERQgghhBBCCCGE35MAQwghhBBCCCGEEH5PAgwhhBBCCCGEEEL4vRY1B4bwIq2pcjpxlpbiLCvDabPhtFoJCwykVVgYVeXlrFi/HqfdjquiAqfdjrOignPi4+mbkICtrIxnV6zA6XTidLmo9ngwhYTwp27dGNK1K7aAAD7Ytg1TWBihFgsmi4XQ8HA6d+xIq5QUKg0Gil0uTNHRhEZHE2Qy+fqKCCGEEEIIIZqpjIwMvvjiC4YNG8bgwYN9XU6LIQGGOC3527eT8fHHbPj+ezbs2MF5DgePVVeD00mIx0P1r/a/C/gP4AaG13O8h4G+gBOYBoQAIUoRADi0JjEjgyFAHjCunufPBsYD24A+x2w3ACZgbkQEV0VHswm49cgRIoxGIkJDiTSbiQwPZ2z//nTr1Ik8ICM/n8iEBCITE4lMSiIyOZmwVq1QAdJRSQghhBBCiJbObrfzwQcfMHv2bDZu3AjAE088waBBg3j00UcZPnw4SikfV9m8SYAhTqo0K4vcZcvoXlAAGRmkL1zIhspKABTQ1Wjk/K5dYehQCAlh2vr1GIKDCQkNJcRkIiQ0lK7t20O3boQYjazcs4cQi4WQsDBCwsMJCQ8nMj4eYmKINRqpDgo6MSzQGlwuzrJaycnKoqKkBEdpKRVlZTisVjrFxIDZTNLhw7z84484KiqosNtxOBxUOByc3b49mM0EHDpEXHk5VqeTw0VFlB4+TKnHw8iNG+kG/Aj8uZ5rsFIpBkVG8nlQEFNtNiKPBiBhYURaLNx/0UUkJifzS2Ulu8vLiUpMJDo5meiUFKLatyfIbPbyv5IQQoiGoJRKAV4AioE9WusZPi5JCCGEn9i+fTtz5szh7bffxmq10r17d2bNmsWYMWP4+OOPeeaZZxg5ciR9+/bl0UcfZfTo0RJkeInSWvu6hkaTlpam5XZnJ2G3s/mjj1jx+edk/PQTGw4dYq/bTSdgN8DZZ/OM2UxgSgp9hw+n91VXEZaY6OOiG4DbDWVllOXksHfr1ppg48gRSgsLKS0q4u8dOtCqqoqlu3bxwtatlDqdlLpclFZVUVpdzWagA/As8EA9hz8YGkqb2Fhe83h4z24n2mQiKiyM6IgIoqKiuPdPf8KYkECmw0FJQEBN+NG+PeFt2hBgkHxRCNF0KKU2aq3TfPTabwB/AvK11j2O2X4xNR0BA4G5vxVKKKVGAVFa63eVUh9qrf/ye68r7QrRUpWXl3PPPffw7bff0rp1a9q0aVPv0rp1a0JCQnxdrhB/iMvlYsGCBcyZM4eVK1cSHBzMVVddxfjx4zn//POPCyhcLhdvv/02Tz31FPv37+ecc87hkUceYcyYMQQGBvrwLJquk7UrJMBogSrLy/l5wQI2fPMNP//0Ey8bDKgdOxjr8fAG0CYggL4JCfTt0YO+F17I8FtvhehoX5ftn2oDkILMTPZv307xoUOUHD5McX4+JUVF3Ne9OyFWK6//9BNv7d9PsctFidtNsceDk5qhNQbgNmqGwxwVAMQpRV67dqiYGP5dVsZ6p5OosDCiIiKIio4msVUr/nHppRAVRZbTiQ4PJ7pdOyytW8uwFyFEo/NxgDEYKAfePhpgKKUCgT3UjGA8CGwArqEmzHjqV4e4CagGPgE08I7Wet7vva60K0RLtG3bNsaMGcPevXsJCgrCaDSitcblcuF2u0/YPzY29qQBx9ElOjpaPq0WfmPfvn28+uqrvPHGGxQUFHDWWWcxfvx4brjhBuLi4n7zuVVVVXzwwQdMnz6dXbt20blzZx5++GGuueYagoKCGukM6ufxeNBa1/2uKaX8+vdOAgxaeENj82a+ePhhnli5kp8rKqis3RyrFD9fcAGJAweS1bYtwX36kNirl09LbSkcxcWEOp1QUsLOTZvYs2sXJUeOUFJYSHFREe6KCmZ06QIlJTzw0098XlhISVUVJVpTBaQAWbXHuhhYXLseCEQqRVpoKIt69ICoKKbm5nJY65rwIyqKyJgY2rdrx9DBgyEyklynk9CEBCKSkwk0Gn1xOYQQTZwvA4za128HfHlMgNEfmKy1Hln7+CEArfWvw4ujz78PWK+1XqmU+kRrXd/IQpRS46idliklJaVPVlZWfbsJ0exorZk3bx633347brcbrTV/+ctfKCoq4sCBA+zfv/+EACMsLAyz2UxgYCDV1dVUVFRgs9lOOHZISEhdmJGSksK4ceMYNGhQY52aEFRVVfHVV18xZ84cFi9eTEBAAKNHj2bChAkMGzaMgNP8cLC6uppPP/2UadOmsWXLFtq1a8eDDz7IDTfcgLGR2toej4fNmzezZMkSli5dyurVq6msrKx331+HGscu9W0/dlvHjh3ZtGlTg9cvAQYtM8DQHg/OZ58l9LHH+DowkOdCQujbqRN9Bw4k7coraTtggHxa38Rojwd7fj7lubm0MhigpIQVq1aRuW8fJYWFlBQXU1JWRozWPJGcDCUljN62jTUOByVa46k9zgXAd7XrnYC9tesWIDIwkNEREbzUvTtERfHPvXvRRiOR4eFERkcTGRNDt06dSE9Ph6gossvLsbRuTXibNgQGBzfyFRFC+AM/DDD+DFystb659vE/gPO01nec5Pk9gMlAIVCutb7v916zJbYrRMtUXl7ObbfdxjvvvENgYCCRkZF88sknXHDBBXX7eDweDh8+zP79+9m/f39dqHH0a3Z2NtXV/53uXSlFdHQ0ERERhISEoJTC7XZz5MgRysrK+Mtf/sIzzzxDSkqKD85YtBSHDh1i7ty5vPbaaxw8eJDWrVtzyy23cPPNN5OUlHTGx9da89VXXzFt2jTWrVtHmzZtuP/++7nlllsweeGuidnZ2SxdupQlS5awfPlyioqKAOjZsycXXXQRkZGRdXUdu5zqtvq2x8XF8dBDDzX4uUiAQctraBTt3csNAwdizM/n48suQ82bJ0NBWjjt8VB++DAqFYH7AAAgAElEQVSlOTl4SktpGxoKpaV8vGQJeXl5lBQXU1pWRqnNRqrRyL2xsVBaSo8dO8hxu7Eec6wbgTeo6WsdBHV3oAkDIgICGB8by6MdOuC2WLhu504izGYiLBYiIiOJiIykf2oqvXv1wm02s6u4mIjWrYlo0wZL69Yy/4cQTVBTDzBO87VGA6M7dOhwy969e393f+E71dXV3Hzzzaxdu5aHHnqIa6+9FoP8H3Natm3bxlVXXcWuXbsA6NOnD59++inJycmndZyqqipyc3NPCDaOfj148GDdm6PU1FSO/m498MADPPDAA5hlYvQWwePxYLPZCA0NJdhLH4p5PB6WL1/OnDlz+Pzzz6murmbEiBGMHz+e0aNHe+VvhNaa5cuXM23aNL7//nvi4uKYOHEiEyZMIDw8/A8f12q1smLFirrQYs+ePQC0bt2a4cOHM3z4cIYNG0ZCQkJDnUqjkQCDlhVgrJo1i2vvuYf86mqeHTOGOz/6SHpaiDNWXVmJNTeX0pwcgisqaBMcjKeoiLe++Yay4mLKSksps1opLS9nWGQk11oslBUXk7Z9O2VVVZRpXTd86QngUSCHmuEwRylqeoE8GxXFuNatyTIauTUri/DQUCLMZsLDwgi3WLgyLY1zunShJCCA9YcOER4XR3hCAuGtWhGemIglMZEAH481FKIl8cMA47SGkPwRLald0RRprRk3bhxz586lffv27N+/n86dOzNp0iSuvvpqmVjvdxwdMnLHHXfg8XhwuVzceOONvPzyy16ZmLOyspKcnBzefvttpk6dyhVXXIHRaOTDDz8kKSmJZ555hr/+9a9+PWbfH5WVlZGVlUVubi6BgYGYTKa6JTQ09Lj10x0m8XucTidFRUWntZSUlODx1PQXDgkJISIigvDwcCIiIk5p+fW+R3v3ABQVFTFv3jxeeeUVfvnlF2JiYrjpppsYN24cHTp0aNBz/y0//PAD06dPZ9GiRURFRXH33Xdz5513En0KHzRXVVWxYcMGli5dytKlS1m7di1VVVWYTCaGDBnCiBEjGD58ON26dWvyvysSYNAyGhrVlZU8demlTFq+nLOCgvhw3jx6/+1vvi5LiDrO0lJKc3IIcbmIrO0Rsuj77ykrKqKspKQuBLmyVSuGmEzszsvjup9/xup2Y62qwurxUA7MB64FvqdmOMyvfQpcERbGd0Yjt9lshAcFEW40YjEasYSG8uB559G1bVt2OZ0szcnBEhmJJSoKS3Q0lpgYzunVC3NCApVGIyo8nCAvdPMTojnxwwDDQM0knkOBXGom8bxWa729oV6zJbQrmiqtNRMnTuT555/nkUce4YknnuCzzz5j0qRJbN26lW7dujF58mTGjBnT4G/amoNjh4yEhobidrt54YUXGD9+fKO8KZo+fTqPPvoof//73xk7diwTJ05k06ZNDBgwgP/85z+kpfnsT41f0VpTVFREVlYWWVlZHDhw4IT10tLSUz5eSEjIcQHHr0OO+pbq6uqThhEVFRUnfS2TyURMTEy9S2RkJE6nk7Kyst9cysvLf/ecgoKC6sKMgwcP4nK5GDhwIOPHj2fMmDE+vUtORkYG06dP57PPPsNisXDbbbdx7733Eh8ff9x+mZmZdfNYfPvtt5SVlaGUok+fPnW9LAYMGNBoc2s0FgkwaAENjbw8jlx9NT1++IERbdsye/Vqwtu08XVVQjS46spKtM2GoaIC66FDbNuyBWtBAdbCQqzFxVhLS7miXTvOMhjYkJnJc5s2YXU4KHM6sbnd2Kqq+Nhspq/DwZtuNzfW8xo/AT2Bl4HbASNgUQpLYCAWg4GvevQgKTaWhTYbn+XnE2YyEWY2ExYWRpjFws3DhxMaHc0vVit5DgdhMTGExcYSFhdHWHw8YQkJKPn0TzQjPr4LyfvUZJmxwBFgktb6daXUpcBMauY3fkNrPb2BXk+GkPi5yZMnM2XKFO666y5mzpxZ96bb4/Hwf//3f0yaNImdO3eSmprKlClTuOKKK5r8p5UN5eiQkd27d2MwGIiOjmbBggUMGDCgUeuYNm0ajz32GP/4xz+YO3cu7777Lg899BD5+fnccMMNPPnkkyQmJjZqTY3N4/Fw5MiRk4YTWVlZ2O32455jsVho27Ytbdu2pV27dnXrycnJaK2pqKg4YXE4HPVu/719HA4HSimioqKIiYkhNjb2pKHEr5eGCA6qq6ux2Wy/G3QcXeLj4xk7diypqaln/NoNaevWrTz55JN8+OGHhISEMG7cOAYMGMDy5ctZunQp+/fvByAlJaWuh8XQoUOJiYnxceXeJQEGzTvAWPfCC6RNm0ZgeTkHp06lzb33ypARIU6Bu7yc0oMHsR05gi0/H1tBAbaiIga2bYulqoqM7dtZtGULNpsNm92OraICm8PB6x06EON08kJ2Nk8XFmKv7RlydC6QMiAcuA/4d32vCxjMZh7Umo8rKwkzGAgLCsISHExUaCjvDx0KZjMf5uSw02rFHBZWs4SHEx0Tw+ghQ8BsZn9pKZUGA+bYWMLi4zHHxUlvEeETvu6B4QvNuV3RlP373//mvvvu48Ybb2Tu3Ln19rCorq7mww8/ZMqUKezZs4dzzz2XqVOnMmrUqBYbZBw7ZCQgIAC73c6AAQP45JNPfBYUHA0xrrvuOt544w3sdjvTpk1j5syZGI1GHn30Ue655x6fffLsdDopLy/H5XLhcrlwOp2n9PX39ikuLiYrK4vs7GxcLtdxrxkdHX1COHHselRUVKP9DB8d6iG9mBrG7t27mTFjBu+88w7V1dVYLBYuvPBChg8fzogRI+jYsWOL+vvU5AIMpdTFwH+o+dRkrtZ6xkn2G0PNfdv7aq1/sxXRHBsa7ooKHh86lBlr1/JSYiK3LVsG3br5uiwhWiTt8VBps1F+5AjRQUEou519u3ezLzOT8pISyktLKS8ro8Jm494+faC8nHkZGSzPyqLc6aTc5aK8spJAj4fV8fFgt/PX4mI+9HiOe51kILt2/dhb6B7VA9gaGQlmM3+3WtlRVYU5KKhmMRrpERvLlP79wWTi5R07KNMak9mMKSwMs8VCSps2DExLA5OJ7Xl5BJrNmGNiMEVHY4qJISQyUgJScYKWFGBIDwz/9eqrr3Lrrbdy1VVX8f777//uPBdVVVW89957TJkyhX379tG3b1+mTp3KyJEjW9QbhWOHjERHR1NcXMyECROYOXOm1yZSPFVPPPEEjz/+ONdffz2vv/46gYGB7N27l/vuu48vvviCs88+m+eee47LL7/c6/9mbrebdevW1U2YuH79+ro38X+EUoqQkBCMRuNxXyMjI+sNJ9q2bYvFYmnAMxL+KDs7m0OHDtGnTx+CWvB8bk0qwFBKBVIzbnU4cJCacavXaK13/Go/C/AVEAzc0dICjKzVq7nm4otZU17OLV26MHPVKkyxsb4uSwjRwKorK6koLMReu1SVl9M5Lg7sdlatX0/2wYPYrVbs5eXYy8uJDAjgji5dwG7noTVr2FZURHllJXa3G3tVFakGAx+YzVBRQbfycnb+6vUuAb6uXU+m5o/wsf4MfGw2g8lEr9JSKpXCZDBgMhgIDQpiVGIid6WmQmgod2dkYDQa/zuO1mymT4cODDjnHKqDg1m2ezem8HBCIyIIjYjAFBVFTGIi4QkJ6JAQMBgkLGkiWlKAcVRza1c0de+99x5///vfueSSS/j0009P64232+3m7bff5oknniArK4v+/fszdepUhg4d2uyDjGOHjISHh+NwOJg9ezY33XSTr0urM3XqVCZNmnRciAGwdOlS7rnnHnbs2MHQoUOZOXMmPXr0aLDX1VqzZ8+eugkTv/vuO2w2GwEBAaSlpTF06FBatWpVFz78Ooj4va8Gg6HZ/3wJ8Uc1tQDjlGYOV0rNBJYC9wP3taQA45vHHuPa6dOp1ppX77qLv/7nP74uSQjRBGmPB5fNRkVhIRXFxVQUFxNUVUX7yEioqOCbVasoLSmhwmbDbrNRYbfT0WJhTNu2YLdz87JllDocOCorcbjdVLjdjA4L4xGLheqKCuLy8nBojfOY17wPeJaaYTaR9dQ0GZhEzayLKUAoEKoUoQEBhAYE8HBCAte3aUOOUtz6yy+EBAURGhxMqNFIiNHI31JT6X/22RyuquL9HTsINZkINZsJDQsjxGSib2oqiW3aYKuuJqu4mJDw8P8ukZGYoqMJ8PEnjk2RBBjClz7//HPGjBnDoEGD+PrrrwkNDf1Dx6msrGTevHlMmzaNgwcPMnjwYKZOncqQIUMauGLf01rz5ptvcvvttxMcHExFRQUJCQksWLCAvn37+rq8E0yZMoXJkydzww03MHfu3LoQo6qqijlz5vD4449TVlbG+PHjmTp16h+eH6CwsLBu7oGlS5eSnV3T57F9+/Z18w9cdNFFREVFNdi5CSFO1NQCjN+9d7tSqjfwiNZ6jFJqBScJMJRS44BxACkpKX2ysrIa4xS8x+WC++/nxxdfZKLZzDuff06HoUN9XZUQQvwmT1UVztJSKoqKCKqqIsJgwG21krF5MxVlZThsNipql57x8ZwbE0NJcTHPrViB0+XC4XTicLlwuFxc16YNl4aH80txMdfs2IGzuhpHdTUOjwen1rxgMPA3t5vVwMB6avkEGAMsAUbW8/1FwMjAQL4wGLipspIQpQgJCCAkMJCQwEDe6NSJc2Ji+NZu5+WcHEKDgzEGBRFiNGIMDua+888nMSaGzUVFrMzJwRgaSkhoKMbQUIwmEyPPOw9zZCS5ViuHy8sxms2EhIdjDAsjxGIhpnVrAkJDITgYmtAncxJgCF9ZtmwZo0aNolevXixbtqxButi7XC7mzp3L9OnTycvL46KLLmLq1Kmcf/75DVCx7x07ZCQ5OZmcnByGDBnCRx99dMIdEPzJ0RCjvvlNioqKmDx5MrNnzyY8PJzJkyczYcKE3+2C73K5WL16dV1gsWnTJrTWREZGctFFF9Xd5eHss8/29ukJIY7RrAIMpVQA8C1wg9b6wG8FGMdq6g2NPUuWsOimm7grNxf++U/0U0+hmtntcoQQokFoTXVFBbaCAhylpTVLWRmOsjLOiosjOjiYw4cO8cNPP+GsqPjv4nBwVZcutA0JYVNWFm9s2YLD5cLpcuF0u3G63fzvWWfROTCQBXl5PHboUE2A4vHg0hqX1mQEBNDF4+F/gYn1lJYDJAFPAI/X8/1iIAp4kJrbZxiBYKUwKoUxIIDdHTpgCAnh2aIivrRaMQYGYjQYMBoMWIxG5g0ZAkYj8/fvZ0tJCcbgYIJruzZHWiyMGzkSvNA1vCUFGDIHhv/48ccf695crlixgujo6AY9vsPh4JVXXuGpp54iPz+fESNGMGXKFPr169egr9OYjh0ykpKSQlZWFvfccw/PPPNMkxhvf/QOMyebpHX79u3cc889LFu2jK5du/L8888zcuR/42qtNdu3b6+7LeXKlSupqKjAYDDQv3//usAiLS0Ng8HQ2KcnhKjV1AKM3xxCopSKADKBozf/bUVNm++y3woxmnKAMf+22xg/ezYhSrHrnXeI+dvffF2SEEKIk6mqqpnQtbgYl82G02rFVV6Oy2ajW1ISQVVV7N23j12ZmTgrKnA5HLhqA5RxaWkEVVXx9datfL9vH67KyprF7abS7eadPn1QlZU8v2cPnx8+TGV1Na7qalweD0FaszkhAVwubiwp4QO3Gxdw9H/6ROBQTAwUFjb4KbekAOOoptyuaA42b97MhRdeSHx8PKtWrSIhIcFrr2W325k9ezZPP/00hYWFXHrppUyePJm0tLQmM4fBsUNGQkND6+40MnfuXK699lpfl3dajoYYN910E6+99toJIYbWmoULF3LvvfeSmZnJn/70J6688kpWrFjBsmXLyMvLA6BLly51gcUFF1wgE2QKnykrK2P58uUsXryYJUuWUFpaSnp6Ov369aNfv36cd955DR7Q+rumFmAYqJnEcyg1w6A3ANdqrbefZP8VNNMeGPb8fO4cOJB5e/cyKDyc95YuJSk93ddlCSGEaCK0x0OV00lleTluu51Ikwm88EZPAgzRmHbu3MngwYMxmUysWrWKlJSURnnd8vJyZs2axbPPPktxcTEhISEkJib+7hIbG+vTW03a7XZuu+023n77bbp06UJmZiZJSUksWLCAXr16+ayuMzFp0iSmTp160hADaoaHvPDCCzzxxBPYbDZiY2MZNmxYXWiRnJzsg8qFN7hcLkpKSiguLq77+uv10NBQ+vbtS3p6Om3btvVp+FhdXU1GRgZLlixh8eLFrF27tu7WqUOHDiU+Pp5169axdevWujvddO7cuS7Q6NevHz169GjWvYSaVIABoJS6lJres4HAG1rr6UqpqUCG1vqLX+27gmYYYFRv2cJ5/fqxyenkkYEDmbR0KYaQEF+XJYQQQpygJQUYMoTEt/bv38/AgQOprq5m1apVdOzYsdFrsFqtvPvuu+zbt4+8vLzjlrKyshP2NxgMJCQk0KpVq98MOlq1avWHhnForbHZbBw6dIhDhw6Rm5tbt37o0CEyMjLIysqid+/ebNy4kREjRvD+++836U90tdZMmjSJJ554grFjx/Lqq6+eNCQqLCwkLy+P7t27N1iQlJOTw4IFCwgNDSU5ObluiYiIaJDjn4mKigqys7PJzs4mKyuLrKws8vPzGT16NKNGjfJpmHYqDh8+TF5eXl3w8FuhxNHHdrv9pMdTShEVFYXdbsflcgEQFxdHeno66enpnHfeefTt29frvw8HDx6sCyyWLVtGcXExSinS0tIYOXIkI0aMoF+/fsf9DSgvLycjI4O1a9eyZs0a1q5dS35+PgAmk4m+ffvSv3//ulDDmz3RGluTCzC8oakEGNrjQc2dC3ffzfzgYFo9+ihD77/f12UJIYQQJ9WSAoyjmkq7ojnJzc1l0KBBlJWVsWLFClJTU3/3Oa+88gpr1qxh7ty5jfJppcPhOC7QOPpm7NdLQUEB9bXDIyMjsVgsWCwWwsLCMJlMGAwGAgIC0FrjdruprKzE4XBgt9uxWq2UlpbidDpPOFZ4eDitW7cmPj6egoICdu7cyYMPPsi0adPq7uLRlB0bYtx888288sorXn1z7vF4WLp0KbNnz2bhwoV1n4wfy2KxHBdoHLskJSWRnJyM2Wz+wzVorSkuLq4LJo4NKY4+LigoOO45AQEBmM1mbDYb3bt354EHHuCaa67xqzlPtNYsW7aM559/nm+++abefYxGI9HR0cctUVFRJ318dD0iIoKAgADcbjdbt25l/fr1rFu3jvXr17Nz586638MOHTrUBRrp6en06tWLkDP48NjhcLBy5cq6YSHbt9cMJmjdujUjRoxg5MiRDBs2jNjY2NO6TgcOHGDt2rV1y+bNm3G73QC0a9eOfv361YUavXr1Oq1bSvsTCTBoGg0NT1UV13XsyMUHDvD3ESPg7be90tVXCCGEaEgSYAhvKygoYMiQIeTk5PDtt9+e0q0+rVYrycnJWK1WJk+ezKRJkxqh0lPjdrvJz8+vCzSys7NZunQpu3btwmq1Ul5ejsPhoKqq6g+/hlIKs9lMVVUVgYGBvPXWW4wZM6YBz8L3tNY8/vjjTJs2jVtuuYU5c+Y0eIhRWFjIvHnzeOWVV8jMzCQuLo6xY8cyduxYgoODOXjwIDk5OfUuR44cOeF4UVFRJw05kpOTCQoKOiGcOLqenZ19Qm+D0NBQ2rZtW7ekpKQct96mTRu01nz00UfMmDGDbdu2kZKSwsSJExk7duwZBSpnyul08v777/P888+zdetW4uPjmTBhAr169TohkPijt0f+LVarlY0bNx4XauTm5gI1Pad69uxZF2ikp6fTuXPnk/58HTtB7OLFi1m5ciVOpxOj0cjgwYMZOXIkI0eOpHv37g06fMXpdLJ58+a6Hhpr164lJycHqAl9evfuTb9+/UhPTyc+Ph6TyVTvEhQU5Fdz+kiAQdNoaHw1eTJ/mjKFqYMH89h334Gfd/ESQgghQAIM4V1lZWVceOGF7Ny5k0WLFjFkyJBTet5zzz3H/fffz6BBg1i9ejUrVqxg0KBBXq729BQWFjJnzhxmzZrFkSNHSExMrHvT2bp16xOWNm3aYDKZqKiowGazUV5ejs1mO27919vcbjfjx4+ne/fuvj5dr9Ba89hjjzF9+nTGjRvH7NmzzzjE0FqzZs0aZs+ezccff4zL5WLQoEFMmDCB//mf/8F4incCdLlc5Obm1gUa9YUdRUVFv3mM2NjYE4KJYx/HxMSc8htPrTVff/01M2bM4IcffiAmJoY777yTO+64g5iYmFM6RkMoKChg9uzZvPTSS+Tn55Oamsq9997LNddcc8rX1ltyc3PZsGFDXaixYcMGbDYbUNOrKS0trS7U6N69O5s2barrZXE0/OjWrVtdL4uj8/U09jmsW7eubuhJRkZGvb20jhUYGFgXZpjN5pMGHccuZrOZhIQEbrzxxgY/BwkwaBoNjQujovjFZmOf1UpQI/+gCyGEEH+UBBjCW+x2OyNHjmT9+vV88cUXXHzxxaf0vMrKStq3b0+XLl347LPP6N27Ny6Xi59++skv5n7YvXs3M2fO5K233sLhcHDJJZdw7733MnToUL/6FLSp0Frz6KOP8uSTT55RiFFeXs78+fOZPXs2W7ZswWKxcN111zF+/Hh69Ojhhcpr5qw4Nthwu9114cSZDjn5LatXr+bpp59m4cKFmEwmbrnlFu69916vToq7fft2Zs6cyTvvvIPL5eLSSy/ln//8p1//3Hs8Hnbv3n1cL40tW7Yc1zsqKiqKYcOG1c1l4W8TxLrdbnbu3ElpaSkVFRUnLHa7vd7tv/d9rTVdunRh586dDV7zSdsVWusWs/Tp00f7s4x339WAfnbUKF+XIoQQQpwWaibZ9vn/9Y2xAKOBVzt06NBQl0+chMPh0MOHD9cBAQH6448/Pq3nzps3TwN60aJFWmutN2zYoA0Gg77yyiu1x+PxRrm/y+Px6BUrVujRo0drQBuNRn3zzTfrbdu2+aSe5sbj8eiHH35YA/rWW2/V1dXVp/zcrVu36ttuu01bLBYN6F69eulXXnlF22w2L1bsH7Zt26avu+46bTAYtMFg0Ndff73evn17gx3f4/HoxYsX65EjR2pAh4SE6FtvvVXv3LmzwV6jsTkcDr1mzRr92muv6TVr1uiqqipfl9ToPB6PdjgcurS01CvHP1m7wueNgMZc/D3AuKZtW20BXZqV5etShBBCiNPSkgKMo4u/tyuausrKSn355ZdrQL/55pun9dzq6mrdrVs3fc455xwXVjz77LMa0LNnz27ocn9TZWWlnj9/vu7du7cGdGxsrJ40aZI+fPhwo9bREng8Hv3QQw9pQI8fP/43Qwyn06nnz5+vBw4cWBcoXXfddXrNmjU+C7l8KSsrS999993aZDJpQF922WV69erVf/h4DodDz507V3fv3l0DulWrVnratGm6oKCgAasWzZUEGP7e0MjK0j8EBOg3R470dSVCCCHEaZMAQzSk6upq/be//U0D+sUXXzzt5y9cuFAD+t133z3huCNHjtQhISF669atDVXuSZWUlOhnnnlGJyUlaUB36dJFv/rqq7qiosLrr92SeTwe/eCDD2pAT5gw4YQwYt++ffpf//qXjouL04A+++yz9bPPPqsLCwt9VLF/KSgo0JMmTdLR0dEa0IMGDdJffvnlKYc6hw8f1pMmTaq7vj179tRvvfWWdjqdXq5cNCcSYPh7Q2PiRK0DA7WW3hdCCCGaoFMJMICtwM8nW37v+f62+HW7ognzeDz61ltv1YB+8skn/9AxBg0apFNSUnRlZeUJ3zt8+LCOj4/X3bt391qQsG/fPn333XfrsLAwDeiLLrpIf/nll6c1pEGcmV+HGG63Wy9cuFBfeumlWimlAwIC9BVXXKEXL14s/y4nUf7/7N13fM3X/8Dx17m5N5EIkZixR8zWVqMUUZSK2dZq6KTUV6t20YVqzVKqrVkdmirVkha1ldqzShFixIpEIhIZd7x/f2T8VIOMe3MTzvPxOI/kfj6fc97vEPG575xzPrGxMnPmTClTpowAUrNmTfn222/FbDane/1ff/0lL7/8sri5uQkgAQEBsmnTpodyNouWfbqAkYtvNKLPnZPBJpOc7dTJ2alomqZpWpZksIBRLqVNSWk1U9rHwMf365/bWm69r8jLbDabDB8+XAAZPXp0lsbYuXOnADJz5sy7XrNu3bq0JQb2tHPnTnn22WfFYDCI0WiUPn36yIEDB+waQ8s4m80mo0aNEkC8vb0FEF9fX3n33XflwoULzk4vz0hKSpIlS5ZIjRo1BJBy5crJ7NmzJS4uTmw2m6xZs0batGkjgLi7u8vAgQPln3/+cXbaWh6nCxi5+EZjWkCAALLvm2+cnYqmaZqmZUlmlpAAB9M5diCj/XNLy633FXmVzWaTDz74QAAZNGhQln9r261bN/H29r7v5osjRowQQFasWJGlOKksFossX75cmjRpIoAUKlRIRo8eLWFhYdkaV7OP1O+r9u3by/Lly9OdlaNljNVqlVWrVqV9rxcpUkSqVasmgJQsWVImTZqkl+FodnO3+wr9GFUnM9+6RaWCBano6cmW6Ghnp6NpmqZpWZKZx6gqpQ4Bg0RkR8rrx4G5IlLHkTnai1KqI9DRz8+v36lTp5ydTp4nIqxbt453332XvXv30rdvXxYvXpylR2CePHmSatWqMWbMGCZOnHjPa5OSkmjatCkhISEcPnw404+OjI2NZdGiRcycOZPQ0FAqVqzIkCFDeOmll/D09Mx07nlNbGws0dHRlC5d2tmpaDlMRNi+fTtTp04lMjKSgQMH0r17d1xdXZ2dmvYAudt9Reb/Z9Ds6seRI7lgtTLsjTecnYqmaZqm5ZSXgblKqbNKqbPA3JRjeYKIrBaR/l5eXs5OJU8TETZu3EizZnaSijsAACAASURBVM1o37494eHhLFy4kEWLFmWpeAEwffp0XF1dGTx48H2vdXV15fvvv8disfD8889jsVgyHOfy5cv4+fnx5ptvUrJkSVasWMHJkycZPHjwQ1G8AHj55ZcpU6YMzZs3Z+HChcTExDg7JS2HKKV44oknWLVqFTt27CAwMFAXL7QcowsYTiQ2G9MXLaKqqysd3n3X2elomqZpmkMppd5M+dRdRGoDtYHaIlJHRA44MTUth/3xxx/4+/vTunVrzp07x+eff87Jkyd5+eWXcXFxydKYV65cYcmSJbz44osUL148Q338/Pz44osv2L59+31nbNxu9uzZhIeHs3nzZrZv3063bt2ynHdedPnyZX766SdatGjBtWvXePXVVylRogSBgYGsX78eq9Xq7BQ1TXtA6QKGEyWsX0+D+HhG9+qFwWh0djqapmma5mgvpXycDSAiN0TkhhPz0XLY7t27adu2Lc2bN+fEiRN8+umnhISE8PLLL/P999/Ttm1bDh48mKWxZ8+eTVJSEsOGDctUv+eff56+ffsyYcIEtm3bdt/r4+Li+OKLL+jatSstW7bMUq553eLFi7FarcyfP59jx46xa9cuXnzxRX799Vfatm1L+fLlGTNmDCdOnHB2qpqmPWD0HhjO1LEj7N4N586Bu7uzs9E0TdO0LMvIHhhKqe+BBkBJ4PTtpwARkVoOTNHuct19RS524MAB3n33XX799VeKFCnC6NGjGThwIDabjfnz5zNjxgzCwsIAaN++Pb/99lumxr958yZly5blySefZPny5ZnO7+bNm9SrV4+EhAQOHz6Mj4/PXa+dO3cugwYNYvv27TRt2jTTsfI6m82Gn58f5cqVY/Pmzf86l5CQwOrVq/nqq69Yt24dVquVxo0b88ILL9CjRw+8vb2dlLWmaXmN3ffAUEq9csdrF6XUe1kd72ETumEDO4ODYdAgXbzQNE3THgoi0gt4AggBOt7WAlI+ag+YI0eO0LVrV+rXr8+ff/7JRx99RGhoKH379uXjjz+mbNmyDB06lEqVKvHbb78xYcIE1qxZw+HDhzMVZ8GCBURHRzNixIgs5VmgQAGCgoK4evUqr7zyCnf7BZ/NZuOTTz6hYcOGPP7441mKlddt2rSJ0NBQ+vfv/59z+fLl47nnnuPXX38lLCyMadOmERsby8CBA/H19aVHjx6sWbMmU/uNaJqm3S47S0ieVEr9ppTyVUo9AuwCCtgprwfeR4MH0wqI6t3b2alomqZpWo4RkSsiUltEzt3ZnJ2bZj/Hjx+nR48e1K5dm02bNvHBBx9w9uxZevbsydtvv025cuWYMGECLVq0YOfOnWzZsoX27dszaNAgPD09mTJlSoZjmc1mZsyYQYsWLWjUqFGWc65fvz4ff/wxP//8M1988UW61wQHBxMSEsKwYcNQSmU5Vl42b948fHx86Nq16z2vK1GiBMOGDePIkSPs37+f/v37s3HjRp5++mnKlCnDiBEjOHr0aA5lrWnaAyO9Z6tmtAE9gAjgHNA0O2PlRMstz2u/evSouIG8Vr26s1PRNE3TNLvgLs9rf5BbbrmvyE1OnjwpgYGBYjAYxNPTU8aOHSvXr1+Xw4cPy/PPPy8uLi5iMpnkpZdekmPHjqU7xrBhw8RgMMiZM2cyFPPrr78WQH799dds52+1WqVdu3bi5uYmR44c+c/55s2bS9myZcVsNmc7Vl4UHh4uJpNJhgwZkqX+iYmJsnLlSuncubMYjUYBpH79+jJ79myJiIiwc7aapuVld7uvyM4SksrAm8CKlAJGH6WURzbrKQ+Fz15/nUTgrenTnZ2KpmmapmlatoWGhvLyyy9TvXp1VqxYwbBhwzhz5gxt27YlMDCQ2rVr8/PPP/Pmm29y5swZFi1aRPXq1dMd66233sLFxYXpGbhPEhGmTJnCo48+Svv27bP9dRgMBr766isKFSpEr169uHXrVtq5ffv2sW3bNt58802MD+nm60uWLMFsNtOvX78s9Xd1daVLly78/PPPXLp0iVmzZmGz2Rg8eDC+vr5069aN1atX33UJj6ZpWnaWkKwG3hGR14AWwClgrz2SUkq1U0qdUEqFKKVGp3N+qFLqmFLqiFJqo1KqnD3i5oT469eZ+8cfdCxenKp2+I9W0zRN0/IqpZSnUsrT2XlkllKqo1Jq3o0b+gEqFy5cYMCAAVSpUoWlS5cyePBgQkJCaNq0KZ06daJFixbs2bOHCRMmcP78eaZPn07p0qXvOWapUqXo06cPCxcuJDw8/J7Xrl27lqNHjzJixAi7LekoXrw433zzDX///TdDhw5NO/7JJ59QoEABXnnllXv0fnCJCPPnz6dp06bUqFEj2+MVLVqUN954gwMHDnD48GEGDx7Mjh076NSpE99//70dMtY07UGUnQJGQxHZCMnbhovIdODei+EyQCnlAnwGtAdqAL2UUnf+lDwINJDk3cqXAxlfKOlkR6dOxSbCsDFjnJ2KpmmapjmFUqqmUuog8DdwTCm1Xyn1qLPzyigRWS0i/b28vJyditNERETwxhtv4Ofnx6JFi+jfvz/Hjx+ndu3atG7dmi5dunDlyhXmzJnDuXPnGDdu3D2f7HGnESNGkJiYyOzZs+953ZQpUyhdujQ9e/bM7pf0L23atGHkyJF8+eWXrFixggsXLrBs2TJeffVVHta/923btnHy5Mksz764l1q1ajF9+nTCwsIoXbp0lp4ko2nawyHLBQwRiUnn2MnspQNAQyBERM6ISBIQBHS+I85mEUmd07cLuHcpP7ew2Xjsp5+4ULcuzf/3P2dno2mapmnO8iUwVETKiUhZYBgwz8k5aZnQo0cP5s6dS9++fTl06BB+fn40b96cl156CZPJxHfffcepU6cYNGgQHh6ZX2FcrVo1unTpwpw5c7h582a61+zdu5ctW7YwZMgQXF1ds/sl/ceECRN47LHHePXVV5k0aRI2m40333zT7nHyivnz5+Pl5cVzzz3nsBgmk4mAgAB+//13EhMTHRZH07S8KzszMBylFHDhttdhKcfu5hVgjUMzspPwb7/FdvIkHiNHogy58Y9e0zRN03JEfhHZnPpCRLYA+Z2XjpYZGzduZNOmTYwfPx5fX1+aNWv2r0ehHjp0iN69e2d7n4hRo0YRHR3N/Pnz0z0/depUvLy8HDIjAJL3a/j++++xWq3Mnz+fbt26Ua5cnlm1bFfXr19n+fLlBAYGZqkglRkdO3YkLi6OLVu2ODSOpml5U55+F62UCgQaAFPvcU1/pdQ+pdS+a9eu5Vxy6Xh28GDa58sHzz7r1Dw0TdM0zcnOKKXeUUqVT2njgDPOTkq7PxFhzJgx+Pj4MHHixHQfhWqvvSgaNWpEy5YtmTFjBklJSf86FxISwooVKxg4cCAFCxa0S7z0VKpUiS5dumC1Wh/apSMA33zzDYmJiQ4rFt3O398fd3d3goODHR5L07S8JztPIflJKdVBKWXvIshFoMxtr0unHLszfmtgLNBJRO46x0xE5olIAxFpULRoUTunmnF7lyzhj5gY2j31FDykO1drmqZpWoqXgaLATyQ/zawI8JJTM9IyZPXq1ezZs4ekpCRq1arFsWPHWLlyJY0bN3ZIvFGjRnHx4kW+++67fx2fMWMGRqORN954wyFxU1mtVrZv307RokVZvHgxW7dudWi83Ch1887HHnuM2rVrOzyeu7s7rVu3Jjg4WD+NRNO0/8hO8WEu0Bs4pZT6WClV1U457QUqK6UqKKVcgZ7AqtsvUErVJXn9bCcRuff21LnE9HfeoSDwypw5zk5F0zRN05yttYi8ISL1RKS+iAwB2jg7Ke3ebDYb48aNo2jRosTGxjJ16tS7PgrVXp566ilq167N5MmTsdlsAISHh7N48WL69u2Lr6+vQ+P/8ssvhIaGMmPGDCpVqkRgYCCRkZEOjZnb7Nq1i7///jtHZl+kCggI4OzZsxw7dizHYmqaljdkZxPPDSLyPFAPOAtsUEr9qZR6SSllysa4FuB/wDrgOLBMRP5WSo1XSnVKuWwq4An8qJQ6pJRadZfhcoVzO3aw/MIFXnvsMQre59FhmqZpmvYQeDuDx7Rc5IcffuCvv/4CoEmTJjRr1szhMZVSjBo1ihMnTrBqVfLt3pw5c0hMTGT48OEOjz9jxgwqVKhAr169CAoK4urVq7zyyisP1cyA+fPn4+npafcnvdxLhw4dgOQZP5qmabdT2fkBrJQqDAQCfYBLwHdAM6CmiLS0R4L21KBBA9m3b1+Ox32/SRM+3LWL0D17KP3YYzkeX9M0TdMcTSm1X0Qa3Oea9sDTQHfgh9tOFQRqiEhDB6Zod866r3AGs9lMjRo1SExM5MKFC/z888907tz5/h3twGKxUKVKFYoVK8b69espV64cLVq0YOXKlQ6Nu3v3bho3bsysWbPSlqp88sknDB06lM8++4zXX3/dofFzgxs3buDr60tgYCDz5uXsg4Lq16+Pu7s727dvz9G4mqblDne7r8jOHhgrgT8AD6CjiHQSkR9EZDDJsyM0gOhoxv31F3889ZQuXmiapmkPu0vAPiAB2H9bWwU85cS8tPtYsmQJISEhGI1GqlWrRseOHXMsttFoZPjw4ezevZuxY8cSFRXFyJEjHR53xowZeHl58dJL/789y5tvvkn79u0ZOnRo2myUB9nSpUuJj4/P0eUjqQICAti5cycRERE5HlvTtNwryzMwlFJPi8hvdxxzu9eGms7mjN+UyJQpqFGj4MABqFs3R2NrmqZpWk7JyAyM2641iYjZ0Tk52sMyAyMxMZHKlSvj4eHBiRMnWLhwIS+//HKO5hAfH0/ZsmWJjY2lQYMG/PHHHw6Nd/bsWSpVqsSwYcOYMmXKv86Fh4dTu3ZtvL292bdvn8MfK+pM9erVQ0Q4cOCA3Z4uk1F79+6lYcOGfPPNNwQGBuZobE3TnM/uMzCAiekc25mN8R44SbGxPDZuHN/XqKGLF5qmaZqWIjcWL5RSNZRSy5RSnyul9PPOb/Pll19y4cIFPDw8KFmyJM8//3yO5+Du7o6/vz8JCQk899xzDo83e/ZsDAYDgwcP/s+5YsWK8c0333D8+HFmzpzp8FycZf/+/Rw8eJB+/frlePECkpeQlChRQj9OVdO0f8l0AUMpVUIpVR9wV0rVVUrVS2ktSV5OoqVYNmIE+81mvLp3d3YqmqZpmvbAUkotUkqFK6WO3nG8nVLqhFIqRCk1+j7DtAdmi8hAoK/Dks1j4uLi+PDDD2nQoAEHDx7krbfews3NLcfzEBGOHz+OUopdu3Y5NFZMTAzz58+ne/fulClTJt1rWrduTbt27Zg1axbx8fEOzcdZ5s2bh7u7u1MKVgAGg4EOHTqwdu1azOZcV/PUNM1JsjID4ylgGlAamAFMT2lDgTH2Sy1vE5uN6UuWUN3VlXZjxzo7HU3TNE3LdZRS9vrFx1dAuzvGdgE+I7kwUQPolTLLoqZSKviOVgz4BuiplJoKFLZTXnnep59+Snh4OAUKFMDLy4v+/fs7JY/169dz9OhR2rZtyw8//EBoaKjDYi1YsICbN2/y1ltv3fO6UaNGER4ezpIlSxyWi7PExsaydOlSunfvjpeXl9PyCAgI4MaNG3ojT03T0mS6gCEiS0TEH3hRRPxva51E5CcH5JgnbZoxg0Px8Qzr1QuD0ejsdDRN0zQt11BKPa6UOgb8k/K6tlJqblbHE5FtwPU7DjcEQkTkjIgkAUFAZxH5S0QC7mjhKW0QMBq4666BSqn+Sql9Sql9165dy2rKeUJ0dDRTpkzB39+fLVu2MHDgQAoWLOiUXKZOnYqvry9z587FxcWF6dOnOySOxWJh1qxZNG/enAYN7r2lS4sWLWjYsCHTpk3DarU6JB9n+eGHH4iNjXVawSpV69atcXV11ctINE1Lk5UlJKm76JRXSg29s9k5vzxr+pQpFFOK5x/gtZGapmmalkWfkDyjMxJARA4Dze0coxRw4bbXYSnH0qWUKq+Umgd8DUy923UiMk9EGohIg6JFi9ot2dxo2rRpREdHU7hwYVxdXXnzzTedkseBAwfYsGEDQ4YMoWLFivTt25eFCxcSHh5u91g//fQT58+fZ+jQ+9/SKqUYNWoUp0+fZsWKFXbPxZnmzZtHjRo1aNKkiVPz8PT0xN/fXxcwNE1Lk5UlJPlTPnoCBdJp2rFjjLx2jdnPPUe+QoWcnY2maZqm5ToicuGOQ079FbaInBWR/iLyvIg89PPVw8PDmTlzJp06dWL16tW88MILlChRwim5TJ06lQIFCvDaa68BMGLECBITE5k9e7Zd44gI06dPx8/Pj4CAgAz16dy5M1WqVGHy5Mlk9cl+uc2RI0fYs2eP0zbvvFNAQAAnT57k5MmTzk5F07RcICtLSL5M+XSuiHxwZ7NzfnnTjBm0dHen+9wsz4bVNE3TtAfZBaXU44AopUxKqeHAcTvHuAjcvgNj6ZRj2aaU6qiUmnfjxg17DJcrffTRRyQkJODr60tSUhLDhg1zSh6hoaEsW7aMAQMGpO3FULVqVbp27cqcOXO4efOm3WLt3LmTPXv2MGTIEFxcXDLUx8XFhREjRnDgwAE2btxot1ycaf78+bi5udGnTx9npwKQVkzSszA0TYPsPUZ1h1Lqd6XUK0opb7tllMddOXKEIYsXc+m556Cw3gNM0zRN09IxABhE8pKOi0CdlNf2tBeorJSqoJRyBXoCq+wxsIisFpH+ztzc0JHCwsL4/PPP6d27N0FBQXTr1o0qVao4JZcZM2bg4uLyn+Uro0aNIjo6mvnz59st1vTp0/H29ubFF1/MVL8+ffrg6+vL5MmT7ZaLs9y6dYtvv/2WZ555hsK55D62fPnyPProo7qAoWkakI0ChohUAcYBjwD7U3bxDrxPtwfeZ4MG8anNxq1cUrXWNE3TtNxGRCJSlmoUF5FiIhIoIpFZHU8p9T2wE6iqlApTSr0iIhbgf8A6kmd3LBORv+2R/4M+A2PChAnYbDbKli3LjRs3GDVqlFPyiIiIYOHChQQGBlKq1L+3L2nYsCH+/v7MmDGDpKSkbMc6ffo0K1euZMCAAeTPn//+HW7j5ubGkCFD2LBhA/v37892Ls60fPlyoqOj6devn7NT+ZeAgAD++OMPoqOjnZ2KpqWJiopi48aNREZm+b8vLQuyMwMDEdkjIkNJ3un7OvDgPUcqE+KuXWPujh109vXFr3VrZ6ejaZqmabmSUmqJUqrQba+9lVKLsjqeiPQSEV8RMYlIaRFZmHL8NxGpIiKVRORDe+SeMu4DOwMjJCSEhQsX0q9fP7766iv8/f157LHHnJLLZ599Rnx8PMOHD0/3/KhRo7h48SLfffddtmN9+umnGI1G/ve//2Wp/2uvvUbBggWZMmVKtnNxpvnz51O5cmVatGjh7FT+JSAgAIvFwu+//+7sVLSHWGJiIps3b2bs2LE0atSIIkWK0Lp1a0qUKMHTTz/N119/TUxMjLPTfOBluYChlCqolHpBKbUG+BO4THIh46G1ZPBgroswbNw4Z6eiaZqmablZLRFJ+1WqiEQBdZ2Yj5bi/fffx9XVlcqVK3Px4kVGjhzplDxu3brF7Nmz6dixIzVq1Ej3mrZt21KnTh0mT56MzWbLcqzo6GgWLlxIz549KVmyZJbG8PLyYuDAgSxfvpzTp09nORdnOn78ONu3b881m3fernHjxhQuXJjVq1c7OxXtIWKz2Th06BDTpk2jXbt2eHt706pVKyZPnozRaGTcuHGsXr2aoUOH8vfff/PCCy9QrFgxunXrxrJly7h165azv4QHksrqjslKqVDgZ5KnZO60a1YO0qBBA9m3b59DxrYmJVHN0xMfV1d2xcSgDNma3KJpmqZpeYpSar+INMjgtYeBlimFC5RSPsBWEanpyBztRSnVEejo5+fX79SpU85Ox26OHj1KrVq1GDFiBKtXr8bV1ZWDBw865c3sZ599xv/+9z/++OMPmjVrdtfrgoKC6NWrFytXrqRLly5ZijV16lRGjhzJwYMHqVOnTlZT5vLly5QvX55XXnmFuXlwI/ehQ4cyZ84cwsLCKFasmLPT+Y++ffvy66+/Eh4enuFNVjUts86dO8eGDRvYsGEDGzdu5Nq1awBUr16d1q1b07p1a1q2bEnBggX/1U9E2LVrF0FBQSxbtowrV66QP39+OnfuTM+ePWnbti1ubm7O+JLyrLvdV2SngKEkjz0vypEFjBvffceQwEA6DhtGt2nTHBJD0zRN03KrTBYw+gJjgB8BBTwLfCgi3zgwRbtz5H2FM3Tt2pVNmzYxd+5cAgMD+e677+jdu3eO52GxWKhSpQolSpRgx44d9yygWCwWqlatStGiRdm5c2emiy1ms5mKFStSpUoVuzxFpF+/fnz77becO3cuVxYB7iYxMZFSpUrh7+/Pjz/+6Ox00rVs2TJ69OjB9u3badq0qbPT0R4QUVFRbN68Oa1okVqULlGiRFrBonXr1v/Zh+derFYr27ZtIygoiOXLl3P9+nUKFSpEt27d6NmzJ/7+/hiNRkd9SQ8MuxUwlFIzRWSIUmo18J/OItIp62k6lkNvNJo1g4sX4dQp0N+QmqZp2kMmMwWMlOsfAfxTXm4SkWOOycxxHqQCxt69e2nYsCHjx49n7dq1XLx4kZCQEKfcZP/www/07Nkzw7MqPv/8c15//XW2bNmS6b0bli5dyvPPP09wcDAdOnTIasppTp48SbVq1RgzZgwTJ07M9ng5JXUmy++//06bNm2cnU66oqOjKVq0KMOHD+ejjz5ydjpaHpWYmMiff/6ZVrDYt28fNpuN/Pnz07JlS9q0aUPr1q2pUaOGXWafmc1mNmzYQFBQECtXruTmzZsULVqU5557jp49e9K0aVMMeuZ+uuxZwKgvIvuVUun+DyEiW7OYo8M56kbjeFAQcb160WDWLHjjDbuPr2mapmm5XRYKGC5AcSDtHbKInHdEbvb2IC4hadu2LQcPHuS7777jqaee4tNPP2Xw4ME5noeI0KBBA2JjYzl+/HiGbuzj4+MpX7489erVY82aNZmOFRcXx7Fjx+z2JuKZZ55h06ZNnD9/ngIFCthlTEd78sknCQ0NJSQkJFe/mWrVqhXXrl3jr7/+cnYqWh5y6tQpgoODWbt2LX/88Qfx8fG4uLjQuHHjtBkWDRs2xNXV1aF5JCQksGbNGr7//nuCg4OJj4+ndOnS9OjRg549e1K/fv1ct/+MMzliCcmbIjLrfsdyE0cVMJ4rU4b1YWFcunoVj9w2XVCEWxERRJw6RfSlSyTGxlK+cGGKursTee0aWw8eJCEujsT4eBITEkhMSKCDnx9+np78c/EiC/bvJzEpiUSzmcSkJBLMZt7x8+NRNzc2Xr7Mu2fOkPo9lPoPbl6lSjySPz/B168z+eLFtFRS/zkuqVqVCu7uLL92jTmXLv3/+ZT+PzzyCMXc3Ai6do1vrlzBxWDAaDBgdHHBxWBgfpMmeObLx09hYfx+6VLycRcXjEYjLgYDH7VqhYvJxJrQUPZfuYLRaExuJhNurq4M9PcHk4kdoaGci4rC5OaG0WTC5OaGR/78tGrQAEwmTly6RExiIkY3N0xubpjy5SOfpyflypUDk4kbt24hRiMmd3eM+fJhdHfHxWTKmb9XTdO0XCaTS0gGA+8BVwEryf9FiIjUcmCKdvegzMDYsmUL/v7+TJ8+nS1btvDnn39y7ty5ez5O9MCBA/zyyy94eXlRqFChdFvBggUzPYNj06ZNPPnkk8ybNy9Tj/KcNGkSY8eO5dChQ9SuXTtDfbZt20aLFi344osveO211zKV573s2bOHRo0aMX36dIYOHWq3cR0lJCSEypUrM3HiRMaOHevsdO7pk08+YejQoYSGhlK+fHlnp6PlUmazmT///JPVq1cTHBzMiRMngOR9LFJnWLRo0eI/+1jkpJs3b7J69WqCgoJYu3YtZrOZSpUq0bNnT3r27Mmjjz7qtNxyC0cUMA6ISL07jh0UkVy7i7gjbjRCt23Dr0ULRjRqxMe7dtl17PQkREdju3YNj7g44i5cIHjDBiIuXybi2jUiIiOJuHGDQB8fOgBHL1+m4dWrxN8xxlfAC8AOIL1tsZYDzwDrlaKLCG5K/X8zGFhUtixNfXzYmpDAhLAwDEr9ay3Rp1WqUD1/fn67do3pFy4AcPv32aKqVSnv7s7y8HDmpBQ4JPkiAH6sXp1iRiMLL1/miytXsIhgFcFis2ERYX+pUhSw2ZgQFcVncXFYRJKvASxArNGIi8XCQOCLO742dyB1P+BA4M4HrxUj+W4aoDOw6o7zFYHUvcVbAZvvOF8HOOjqCiYTrRMSOGyzYVIKo1KYlKKhuzvfly0LRiPdz5/ngtmMyWDA5OKC0WCgsY8PHzzyCBiNDD58mBtWK0YXF4wuLpiMRhqUKMFLtWqB0ciEXbuwKpVWoDGZTNQqU4Y2Kf0X79qFi8mE0WTC6OqK0WSiStmyPFqxIlal2HrsWPLxlHNGNzd8ixfH19cXC3Du6lVcXF0xurmlNU8vL/Llz4+4uGABXNzcMOiNtDRNI9MFjBCgkYhEOjgth3oQChgiQrNmzTh79iyrVq2iQYMGvP/++7z33nv37NeoUSP27Nlz3/ELFChwzyLHne3DDz/k2LFjnD17lnz58mX464iOjqZs2bIEBASwdOnSDPXp0qUL27dv5/z583h4eGQ4Vkb4+/tz6tQpzpw54/Df6mbX6NGjmTZtGufPn8/yU1hyyqlTp6hSpQqzZ8/O8iNvtQfT9evXWbt2LatXr2bt2rVER0djMpnw9/cnICCAgIAAKlSo4Ow00xUVFcXKlSsJCgpi48aN2Gw2WrRowU8//YSPj4+z03Maey4h6QX0Jvm97x+3nSoA2ETkyewkelucdsAswAVYICIf33HeDfgaqA9EAj1E5Oy9xnTEjcabdeow9/Bhzu7dS6kGRXzIdAAAIABJREFUGZ45m/xm/dYtLvz1FxGhoUReuEDkxYtEXr1K1Xz5eNLLi/grV+i6cSMR8fFEJCYSYbUSB7wLfABcAXxvG9JbKYoYjYwpU4YXa9QgwtOTySEhFClShCLFi+NVuDD58uenTrVqlC5ThjibjZCrV3Hz9CRfwYK4eXriVqAABQoXxuTpmef38rBZLFiTkrAmJmJJTMQcH481MZEiXl5gNnP1yhWiIyOTzyUmYklIQNls1K9UCcxm9h8/zpVr1zAnJWFOucbDaKRLrVpgsfDT3r2ci4jAnJSExWLBYrFQNF8+Bqacn7Z7N6FRUZitViwWC2arlcr58/NulSpgsdDvwAHO3bqF2WZLvsZmo7GHBzN9fcFsplloKJcslrQCjVmEziYTC1xdwWymUGIiN+74mvsB80guCKU3AXQoMB24CaRXc0793roMpHcLMxUYDpwEqqYcUyTP/3YB5ri58Uq+fBwB2sTEYFQKl9QGfFK8OB29vNiflES/ixdxUQqjwZB83mDgIz8/HvfxYU9sLBNOn8bFYPhXe6dWLWr4+LD7+nUWnDqVfDxlZo6LiwtDGzSgjLc3e69eZdXp08nnUs8bjfRr3BifAgU4cOkSf547hyH1vNGIi4sLPRo3xsPDg7/Cwjh2+TIuRmPyNUYjLkYj7R57DKOrK6cuX+ZCZOT/nzeZMLi40KhWLZSLCxfCw4mKi8Pg4pLcUgpJfhUqgIsLEdHRJJjNGIzGtL5GNze8fXzAYCDBbEaUwmA0/qvppxtpuVkmCxibgTYiYnFwWg71IBQwfvvtNzp06MAXX3zBzp07+fHHHzl//jyFCxe+a59//vmH6tWrM3XqVPr37090dHSW2o0bN9J9/OmkSZN4++23M/21jBgxghkzZnDq1CkqVqx4z2tPnTpF1apVGTduHOPHj890rPtZu3Yt7du3Z/Hixbz44ot2H99ekpKSKFOmDE2aNOHnn392djoZUrVqVSpUqMDatWudnUqeYLVa0zapfOONN3J9kSqjRIQTJ06kzbLYsWMHVquVokWL0qFDBzp27EibNm3yzDKuVFevXmXp0qWMHj2aKlWqsG7dugfm7yyz7FnAKAdUAD4CRt926iZwxB43IynrYk8CbYAwYC/Q6/YNvpRSr5P8HPkBSqmeQFcR6XGvce19oxEVGkqZihXpWqECM9etI/LMGSLPncP11i3qe3tDZCSTVq3ifHg4kTExRMTFEZmQQCsXF2ZaLJCYiAf8Z4bEq8D8ggWRwoV5PDwcbw8PihQoQJFChShSpAjNa9emWePGWL29OXHzJkUqVcKnUiWMmfhNhfZgEJsNa1IS5lu3sCQk4CKCh6srkpTEhfPnsaQUbyyJiZgTEiicPz+lixTBkpjIjkOHsCQlYTWbsSQlYUlKonKJElQvUYJbcXGs2LUr+bzVisVsxmI283jZstTz9SUiJoYvd+5MLsyYzVitVqxWK8/4+dGoaFHORUXx0b59WG02LFYrVpsNq9XKoEqVeNzbm7+uX2fssWNYbLbka1I+flS2LE3y52drVBRvnT+PNWX2TWr7pmhRGplMrIyNZVBUVPJxkuefW0XYli8fdUSYZzYzwGb7zy7DJ4HKJBdiRqbz53mJ5KLgu8CEdM7fBDxJLgR9kt7fR8rHfsCCO84VAGJSPu8J/HDH+ZJA6oKrAODXO85XAU4AGAw8KcJ2EQyQ1uq5uLC1YEEwGGgdE8NfVisGkgtLBqV43M2NoOLFwWCgzaVLnLdYMCiFSjnv7+nJ7NKlwWCg3enTXE/pb1AKpRRtvb15r1w5MBjo8NdfJIqknTMoxdPFijG4QgVEKbru25d2PPVjx5Il6VOxIvFWK/327sVgMCTHNhgwKEXncuXoVL480WYzb+/dm9zvtmu6VKqEf9myhCckMCW1v1KolP5dq1XjsVKluHjzJvMPHfr//ik5dHnkER7x9eV8dDQ/HDmS1jftfK1aVChShNDr1/n12LF/9zcY6FS7Nr7e3py+do2tJ08mx73t/NO1a1O4YEFCwsPZFxr6n/GfqluXAh4enLp8mb/DwtKOp17Tum5d8uXLR8jly5y+fPn/+6Z8bFmnDi5GIyGXLnExIuI/55vWrg1KcebSJa5FRycfTzlnNBqpU60aKMXZy5cpXqwY7pkpuGdQJgsYC0mug/4KJKYeF5EZdk/MAR6UPTBsNhsNGjTgxo0brF+/nqpVqzJw4EA+/fTTe/YbM2YMU6ZMISwsjBIlSmQrfmxsbFoxIzo6mlu3btGqVStMWViSeenSJSpUqMCrr77KZ599ds9rBw0axIIFCzh37ly2voa7ERHq1q1LUlISR48ezbX7SqxYsYJnn33WbpuY5oRhw4YxZ84cIiMj8fT0dFoet27dYsiQIfj5+dG5c2eqVq16/045RETYu3cvS5cu5YcffuDKlSsA9OjRg6CgICdnl3VJSUn88ccfaUWL06eT50XXrl2bgIAAOnbsyGOPPZZr/71lxqZNm+jcuTNFixZl/fr1VKpUydkp5Ti7LyFxJKVUE+B9EXkq5fXbACLy0W3XrEu5ZqdSykjyhISi93q0q70LGJt9fWl95QrCvx/H0gpIfRBXNeC6UhQ2mSiSLx+FPTxoWa4cQ5o3h8KFWRoSgruPD4VLl6Zw2bIUrlABn4oVcXXiD2RNe1CkFnisKYWafCYTBhHiY2OJi43FajYnn7NYsJnNlC5WDBeluHbtGteuXcNmtSZfY7Fgs1io6+eHi1KcuXCBC5cvJ5+3WLCazYjNRrt69cBm48DJk5y9ehWb1ZrWDED3xx4Dm41Nf//NmatXsVqt2Gw2bFYr7kYjLzdsCFYrKw4f5lR4OCKSfN5mwydfPgY1aAA2G/P27yc0KirtnM1mo1T+/AytUwdsNj7at4/zN29iTT0vQtUCBRj1yCNgtTJ0/34ux8djSxlfRKhfqBBv+/mBCIH793PdbE7uC9hEaFWoEGPKlgUR2hw+TLzVmtxfBBvQtVAh3i5eHJvNRt1//kn+uZhyTkR4ycuLEd7e3LRYqHP+PJIyrgA2YKinJ295eHDJYqFORETa8dSfrxPd3BhkMnHCaqXerVv/Of+5UrwC7BGhUTrfC9+TXDjaBKQ3TTAY6AD8AqT3zIOtQHPgW6BPOuf3A/WAz4HX0zmfWjybAoxK5/xloAR3L57FAvmBt4CZd5xTJP9ZQHIBfOEd5wtC2mytHsC4ggWpeePO+VvZl8kCRrrrE0TkA/tm5Vh5fQbGjz/+SPfu3fn66685dOgQs2bNIiQk5J57C1itVsqXL0+tWrX49dc7S63O9+qrr/Ldd9/d8zGm169fp3Tp0vTs2ZNFixY5LJfUJ5z88ssvdOqUOx/S165dO/7++2/Onj2LSx5ZErp582ZatWqV4afUOMrUqVMZOfL/fx1StWpVOnfuTOfOnWncuLFT3kT/888/LF26lKVLl3L69GlcXV3p0KEDvXv3Zs+ePUydOpW9e/fSwAFFbEeJiIjgt99+Izg4mHXr1hETE4ObmxutWrWiY8eOdOjQgbJlyzo7TYfYu3cv7du3x2Qy8fvvv1OzZk1np5Sj7DkDY7uINFNK3eTf79tTN+DK9m4oSqlngXYi8mrK6z4kr5X9323XHE25Jizl9emUayLuGKs/0B+gbNmy9c+dO5fd9NL80749NdaupYrJxICnn6aIry+FfX0pU7kyjzZsCIULIwUL6mnfmqZpOUhstrRms1gQmy1tmZLVbCb+1q3/v8ZqRUTI7+6OyWgkMSGBmBs3ks+JYLNaEZuNwl5euLm6EhcXR0RkJCKCpBSnRIQyJUrgZjIRFR3NlfDwtP6pcaqUK4ebycTViAgu3XlehDqVK2NyceHC5ctcuHr1P+ebPvIILgYDpy5c4MId/RGhTb16IMJfZ85w4dq1f/U1Ggy0Tzm/9+RJqpQrh1ePe05YzJLMPoUkpY+HiNy6/5W5U14uYFgsFmrWrInBYGDr1q1UqFCBzp078+23396z34YNG2jTpg1BQUH0cMD3UXadOHGC6tWr3/Mxph999BFjxozhyJEjDn1DYLFYqFy5MiVLlmTHjh0Oi5NVZ8+epWLFirz77ru8//77zk4nw8xmM0WLFuWZZ55h4cI7S7Y5IzY2lgoVKlC/fn3mz5/PqlWr+OWXX9i8eTMWi4XixYvTsWNHOnfuzJNPPom7u7vDcgkLCyMoKIilS5dy8OBBlFK0atWK3r17061bNwoVKgRATEwMlSpVolatWmzYsCFXP+3ixIkT/PTTTwQHB7Nz505EhBIlSqTNsnjyySfvucnwg+TYsWO0bduWuLg4fvvtN5o0aeLslHLMXe8rRCTXNeBZkve9SH3dB5hzxzVHgdK3vT4NFLnXuPXr1xd7m9G5swAy4ckn7T62pmmapuUVwD7J+P/zTYBjwPmU17WBuRntn1uaI+4rcsrixYsFkBUrVsjEiRMFkMOHD9+3X58+fcTLy0vi4+NzIMus6datmxQqVEhiYmL+cy4xMVF8fX2lTZs2OZLL7NmzBZDt27fnSLzMeOedd0QpJefOnXN2KpnWo0cPKV68uFitVqfE//jjjwWQnTt3/ut4VFSULF26VHr06CEFCxYUQDw8PKRr167y1VdfSUREhF3iR0REyJdffiktWrQQpZQA0rBhQ5k5c6ZcunTprv1mzZolgKxZs8YueTjCjh07xMXFRQCpV6+evPfee7J3716n/V3nBqGhoeLn5yceHh6ybt06Z6eTY+52X5GdIkMlwC3l85bAG0ChrI53x9hNgHW3vX4bePuOa9YBTVI+NwIRpMwouVtzxI2GzWqVwAoVRIGsGjfO7uNrmqZpWl6QyQLGbqAMcPC2Y0cz2j+3tLxawEhMTJTy5ctL/fr1JS4uTooWLSrt2rW7b7+YmBjx8PCQ/v3750CWWbd7924BZNq0af85t2TJEgFk7dq1OZJLXFycFClSRDp27Jgj8TLKbDZLyZIlpX379s5OJUu++eYbAWTPnj05HjsmJkYKFy58338ziYmJsm7dOnn99delVKlSAojBYJDmzZvLjBkz5PTp05mKGxsbK0uXLpWAgAAxmUwCSNWqVWX8+PFy6tSpDI2RmJgoFStWlFq1aonFYslU/JxgsVikbt26UqpUKTl//ryz08lVrly5IrVr1xaTySQ//vijs9PJEY4oYBxKKRz4kby8dyrwW1bHu2NsI3CG5M1CXYHDwCN3XDMI+CLl857AsvuN66gbjVuRkVLP3V28QCLvqMRqmqZp2sMgswWMlI+3FzAOZ7S/sxvQEZjn5+dnxz/BnPPZZ5+lvYn//PPPBZDNmzfft1/qrI3cOJvgTv7+/lKyZElJSEhIO2az2aR27dpSo0YNsdlsOZbLBx98IIAcPXo0x2Lez6pVqwSQn376ydmpZElERIQYDAZ59913czz2pEmTBJDdu3dnuI/NZpO9e/fKuHHjpGbNmqnbN8mjjz4qY8eOlT179qQ7wyApKUmCg4Old+/e4uHhIYCUKlVKhg8fLgcOHMjS9/H3338vgCxZsiTTfR0t9edRUFCQs1PJlaKioqRp06ZiMBhk/vz5zk7H4RxRwDiQ8nEEMFjuuBHJbgOeTimMnAbGphwbD3RK+Twf8CMQAuwBKt5vTEf+puTcn3/KTwULilStKhId7bA4mqZpmpYbZbKAsRx4HDgAmEh+QnNQRvvnlpYXZ2DExcVJiRIl5IknnhCz2SyVKlWShg0bZuiNkL+/v/j5+eXom/+sWrdunQCycOHCtGMbN24UQBYsWJCjuURERIiHh4e88MILORr3Xjp27CglSpSQpKQkZ6eSZc2aNZO6devmaMwbN26Ij4+PPP3009ka5/Tp0/LJJ59IixYtxGAwCCAlS5aUAQMGyJo1a2Tr1q0yYMAAKVy4sADi4+Mjr732mmzdujXbSymsVqvUr19fypYtm6uWgkVERIiPj4+0bNkyT/yMcZa4uDhp166dADJlyhRnp+NQjihg7AZ6kbwXRYWUY7l6+qfDbzS2bhUxGuVI8+ZiNZsdG0vTNE3TcpFMFjCKAN8BV4Fwkh/wUjij/XNLy4sFjClTpggg27Ztkx9++CFtH4z7OXv2rAAyfvz4HMgy+2w2m9StW1eqVq2a9oavQ4cOUrRoUae8aXvjjTfEaDTmimnxYWFhYjAY5O2333Z2KtmSug9FWFhYjsX88MMP7b50JSIiQpYsWSLdunWT/Pnzp83O8PDwkF69esnq1aslMTHRbvFE/r+YN3XqVLuOmx2vvfaauLi4yF9//eXsVHK9xMRE6dGjhwAyevToB7bg44gCRg3gU6BXyusKwKisjpcTLSduNI6OHStGkHefeMLhsTRN0zQtt8hoAQNwAb7LyLW5veW1AkZ0dLT4+PhIu3btxGazSb169aRy5coZWgs/YcIEASQ0NNTxidpJUFBQ2jKJ48ePCyDvv/++U3I5e/asuLi4yFtvveWU+LcbP368ABISEuLsVLLl6NGjAsiXX36ZI/Fu3Lgh3t7eEhAQ4LAY8fHxEhwcLMuWLZObN286LI6IyFNPPSXe3t5y/fp1h8bJiH379olSSoYMGeLsVPIMi8Uir732mgDSv3//XLmnSXbZvYCRF1tO3GjYrFZ5qXLl5N9ojBjh8HiapmmalhtkcgbGdsA1o9fn1pbXChjvvfeeALJv3z7ZsGGDADJv3rz79rPZbFK5cmVp0aKF45O0I7PZLBUrVpSGDRtK//79xc3NTa5eveq0fAIDAyV//vwSGRnptBysVquUK1dOWrdu7bQc7MVms0n58uVzbIPU1CLevn37ciSeox06dEiUUjJy5Ein5mG1WqVRo0ZSvHhxidbL8DPFZrPJ22+/LYB0797d7jN1nO1u9xUGskgp1VQptV4pdVIpdUYpFaqUOpPV8R4UymBg7p49NMyfn75Tp3J05Upnp6RpmqZpuc0ZYIdS6h2l1NDU5uykHmQRERHMmDGDZ555hvr16zN58mRKlChBnz597tt3165dnDp1ihdeeCEHMrUfo9HIiBEj2LNnDwsWLKBv374UK1bMafmMHDmSuLg45s6d67Qc1q9fz7lz5+jXr5/TcrAXpRQBAQFs2LCB+Ph4h8a6ceMG06dPp1OnTtSvX9+hsXJK7dq1CQwMZNasWVy4cMFpeSxZsoTdu3czZcoUvLy8nJZHXqSUYtKkSUyZMoVly5bRuXNn4uLinJ2Ww2W5gAEsBGYAzYDHgAYpHx96+QoV4qctW/A0GOjSvTs3zp1zdkqapmmalpucBoJJvg8pcFvLE5RSHZVS827cuOHsVDJs8uTJxMbGMn78eA4cOMD69esZMmQI+fLlu2/fJUuW4O7uzrPPPpsDmdrXCy+8QLFixbDZbAwZMsSpudSsWZOnn36aTz/91OFvuO9m3rx5FClShM6dOzslvr117NiR+Ph4Nm3a5NA4s2bNIjo6mvfee8+hcXLahAkTEBHeffddp8SPjo5m1KhRPP744wQGBjolhwfBiBEjmD9/Pr///jtt27YlKirK2Sk5VnrTMjLSSHkEWl5qOT3Vc/vnn8v7BoNY27YVeQDXJWmapmlaKjKxhCS1AR6Z7ZObWl5ZQnLx4kXJly+f9O3bV0REevToIQUKFJCoqKj79o2Pj5dChQrJ888/7+g0HWbZsmXywQcfODsNERHZunWrAPLZZ5/leOwrV66I0WiUYcOG5XhsR0lISJD8+fPLgAEDHBYjKipKvLy8pHPnzg6L4UzDhg0TpZQcOXIkx2O/8cYbopSSAwcO5HjsB9GPP/4oJpNJatWqJZcvX3Z2Otl2t/uK7MzA2KyUmqqUaqKUqpfasl9SeXA0HTCA9z7/HMPvvxMzfLiz09E0TdO0XCHl3uEY8E/K69pKKefNq3/ATZw4EYvFwnvvvceZM2f48ccfGTBgAIUKFbpv39WrVxMdHZ3nlo/c7rnnnnPab5jv9MQTT9C4cWOmTZuGxWLJ0dhfffUVFovlgVg+ksrNzY22bdsSHBycWhS1u5kzZ3Ljxg3ef/99h4zvbGPGjMHLy4vRo0fnaNwjR44wZ84cBgwYQN26dXM09oPq2Wef5ddffyUkJIRmzZoRGhrq7JQcIjsFjEYkLxuZBExPadPskdQDpX9/jnXvjt/MmSx76y1nZ6NpmqZpucFM4CkgEkBEDgPNnZrRA+r69essWLCAV199lYoVKzJ9+nSMRmOGl1MsWbKEUqVK0apVKwdn+nBQSjFq1ChCQ0NZsWJFjsW12WwsWLCA5s2bU7Vq1RyLmxMCAgIICwvjyJEjdh87KiqKTz75hK5du1KnTh27j58b+Pj48Pbbb/Pbb7+xZcuWHIkpIgwePBhvb28mTpyYIzEfFm3atGHDhg1ERkbSrFkz/v77b4fFstlsnD9/nkOHDjksRnqyXMAQEf90mv7fLR1+CxdSpUABXpo5k8PLljk7HU3TNE1zOhG5c9c4q1MSecBFR0djNptp0qQJ4eHhLFq0iD59+lCyZMn79r169Spr164lMDAQFxeXHMj24dCpUyeqVavG5MmTHTZr4E5btmwhJCTkgZp9kapDhw4ABAcH233smTNnEhMT88DOvkg1ePBgSpcuzciRI3PkezIoKIht27YxadIkfHx8HB7vYdOkSRO2bduGzWajefPm7NmzJ1vjxcTEsHfvXr799lveeecdevToQZ06dfD09KRcuXJ0797dTplnTHaeQlJcKbVQKbUm5XUNpdQr9kvtweHq6cny7dspZDDQ5fnniTx1ytkpaZqmaZozXVBKPQ6IUsqklBoOHHd2Ug+62bNnk5iYyPAMLmtdunQpVqs1Ty8fyY0MBgMjRozg4MGDbNiwIUdizp8/H29vb5555pkciZeTihcvTsOGDVm9erVdx42KimLmzJk888wz1KpVy65j5zbu7u6MHz+evXv3snz5cofGunnzJsOHD6d+/fq88op+6+goNWvWZMeOHXh5edGqVSs2btx4z+stFgunTp0iODiYGTNm8Nprr9GyZUt8fX3x8vKiYcOG9OnTh0mTJrF//35KlSrFgAED+Pzzz1mwYEEOfVXJVFarbCmFi8XAWBGprZQyAgdFpKY9E7SnBg0ayL59+5wWf8/ixTzx8ss84e3N2kuXMGZg529N0zRNywuUUvtFpEEGry0CzAJaAwr4HXhTRCIdmKLdOfu+IiPOnDlDpUqV+PLLLxk9ejQtWrRgZQYf8V6nTh1cXV2z/ds77b8SExOpWLEi1atXd2gRIzExkUWLFjFkyBAGDBjArFmzHBbLmSZMmMB7773H5cuXKV68uF3GfOedd5g4cSJHjhyhZs1c+/bGbqxWK3Xq1CEhIYFjx45hMpkcEmfUqFFMmTKFnTt30rhxY4fE0P7fpUuXeOqppzh58iRBQUE88cQTnDhx4j/t9OnTmM3mtH4+Pj5UrVr1P61SpUq4ubnlSO53va9Ib2fPjDRgb8rHg7cdO5TV8XKi5Ybdwhe99JJ0BYkbPNjZqWiapmma3ZCBp5AAk1M+Pne/a/NCyw33Ffdz+vRpAaR3794CyM6dOzPU79ChQwLInDlzHJzhw2vq1KkCyL59++w+dmJionzxxRdSpkwZAaRp06YSFhZm9zi5xYEDBwSQxYsX22W8yMhIKVCggDz33HN2GS+vCA4Odui/++PHj4vJZJKXXnrJIeNr6YuMjJRGjRoJ8K9mMpmkevXq0qVLFxk1apQsWrRIduzYIREREc5OWUTufl+RnRkYW4BngPUiUk8p1TjlxqRFlgbMAbnlNyUyeDBqzhzk669Rffo4Ox1N0zRNy7aMzMBQSv0F1AL2i0iefXKZUqoj0NHPz6/fqVy+LDR1BoaPjw+PPvooW7duzVC/oUOHMmfOHC5fvkzhwoUdnOXDKSYmhrJly9K2bVuW2WmPNLPZzFdffcWHH37IuXPnaNKkCR988AGtW7dGKWWXGLmRiFCmTBkaN25slyUQY8eO5aOPPuLIkSM8+uijdsgwbxAR/P39OXbsGKdPn6ZAgQJ2Hfupp55iz549nDhxwm4zZbSMiY2N5dNPP8Xd3Z2qVatSpUoVypcvj9FodHZqd3W3+4rsPIXk/9i77/CoqvSB498zJb0XEiChh9AUkCKIughiI6wUBREEQURFF+WHiqKrawdRFBRUFpWgLIqgCC4LKK4oSEdgpUgoCSEE0kN6ppzfHzNExIBIMplJ8n6e5z4zc8+5975zCcmZd075P2AF0FIptRFYCPytCuerN9TMmRy78kp6jR7NzkWL3B2OEEIIUVNWA7nA5Uqp00qpgrMf3R3cxdJar9Rajw8ODnZ3KBctJyeHxx9//KLqWq1WFi1aREJCgiQvXCgoKIgHHniAZcuWcejQoSqdy2Kx8P7779O6dWvGjx9PdHQ0q1evZuPGjfTr169OJy/AsbpLQkICa9asoaysrErnysrKYvbs2dx+++31KnkBjvv46quvkpmZyWuvVe/iksuXL+frr7/m+eefl+SFGwQEBDB16lQmTZrELbfcQqtWrTw6eXEhVVmFZCfwF+Aq4D6gvda6+tcvqovMZnw//JA0g4GBo0eT4cLlbYQQQggP8rTWOgT4t9Y6SGsdePaju4Ori870tI2JieGWW265qGPWrFlDRkaGTN5ZAx5++GHMZvMlf1i0Wq18+OGHtGnThnHjxhEZGcmqVavYtGkTN954Y51PXJwtISGBwsJCvv/++yqd5/XXX6eoqIhnn322miKrXbp3787tt9/O66+/zsmTJ6vlnMXFxUyaNIkOHTowYcKEajmnqL+qsgrJ7YCv1novMBD4VClVa7uD1rTItm35IjGRTJuNob16YSkudndIQgghhKttcj7Wmt4Wtd2JEycA6N2790V/mE1MTCQ8PJybb77ZlaEJIDo6mtGjR7NgwYI/9WHRarWSmJhImzZtGDt2LKGhoXz11Vds2bKFm2++uV4lLs7D7ffoAAAgAElEQVTo06cPPj4+VVpONTMzk7feeothw4bRrl27aoyudnn55ZcpKyvj+eefr5bzTZ8+nZSUFN5+++1a+62/8BxVGULyd611gVLqaqAv8D7wTvWEVT9cMWIE8x94gPX5+Uzu2dPd4QghhBCu5qWUuhO4Sik1+NzN3cHVRTabDXAsk3gxcnNzWbFiBXfeeSdeXl6uDE04Pfroo5SXlzN79uw/rGuz2fjoo49o164dd999N0FBQaxYsYJt27bRv3//epm4OMPPz4++ffuycuVKLnWOv9dff53i4mKeeeaZao6udmnVqhX33Xcf8+bN4+DBg1U615EjR5g+fTrDhw/nL3/x2KkSRS1SlQSGzfnYH/in1vrfgPyl+5NGzJ3L5C5d+G7PHgrnznV3OEIIIYQr3Q9cA4QAA87ZEtwYV531Zz/ILVmyhLKyMhk+UoPi4uIYMmQIc+fOpaCgoNI6NpuNRYsW0a5dO0aNGoWfnx9ffPEFO3bsYMCAAfU6cXG2AQMGcPToUQ4cOPCnj83MzOTtt99m+PDhtG3b1gXR1S5///vf8fX1ZerUqVU6z6RJkzCZTMyYMaOaIhP1XVUSGGlKqfeAYcAqpZR3Fc9Xb03bsIFNvXsTMGkSbNni7nCEEEIIl9Bab9BaPwA8rrUec8421t3x1WV/ZvhIu3btuOIKGRVck6ZMmUJ+fj7z5s37zX6bzcbixYvp0KEDI0eOxNvbm2XLlrFz504GDhwoiYtz9O/fH4CVK1f+6WNnzJhBSUlJve99cUZUVBSPPvooy5YtY/PmzZd0jlWrVrFixQqeeeYZGjduXM0RivqqKgmHocAa4EatdR4QBjxW1YCUUmFKqa+VUknOx9BK6nRSSm1SSu1VSu1RSg2r6nXdyeTjg//SpRRGRzOhTx/Sd+1yd0hCCCFEtVNK9XE+zZUhJJ4nKSmJTZs2MXr0aPlgXMO6du1Knz59eOONNygvL8dut7NkyRIuv/xy7rzzToxGI5999hm7du1i8ODBGAzynWFlYmJi6NSp05+eByMjI4M5c+Zw5513Eh8f76Loap/JkycTFRXF448//qd7c5WVlfHwww/TunVrHnnkERdFKOqjqqxCUqy1/lxrneR8na61XlsNMT0BrNNaxwHrnK/PVQyM0lq3B24C3lRKhVTDtd0nPJzkmTNJLC5myDXXUHZa5jcTQghR55wZAH3u8BEZQuIBFi5ciMFgYOTIke4OpV6aMmUKaWlpTJw4kY4dOzJsmOP7uU8//ZQ9e/Zw2223SeLiIiQkJLBx40ZycnIu+phXX32V0tJS/v73v7swstonICCAZ599lh9++OFPJ4VmzpzJoUOHeOutt2Q+HVGtPPG34K1AovN5Io4VTn5Da33wrMTJCSADiKyxCF2kw5AhfPjII2wqLKR7VBT/nTnT3SEJIYQQ1UZr/azz8dzhIzKExM3sdjsLFy6kX79+NGrUyN3h1Ev9+vWjc+fOvPfee1itVhYvXsyePXsYOnSoJC7+hISEBOx2O6tXr76o+idPnmTu3LmMGDGC1q1buzi62mfcuHG0bt2aJ554omJS4D+SmprKiy++yODBg7nhhhtcHKGobzzxt2GU1jrd+fwkEHWhykqp7jgmDz18nvLxSqntSqntmZmZ1RupCwx94w2WPfYY+RYLfSZPZkaHDnDkiLvDEkIIIapMKfV/F9rcHV99tn79eo4dO8aoUaPcHUq9pZRi8eLFfPHFF/z888/ccccdGI1Gd4dV63Tr1o0GDRpcdI+BV199lfLycul9cR5ms5mXX36Zffv2kZiY+McH4FhZx263M1O+jBUu4JYEhlLqG6XUz5Vst55dTzsGW513wJVSqiHwETBGa22vrI7Wep7WuqvWumtkZO3opDH41VfZn5HBi9dfz6AjR6BtW9IfeogC51ruQgghRC0V6Ny6Ag8AjZ3b/YDMGulGCxcuJDAwkIEDf9fxVdSg+Ph4Bg4cKImLKjAYDPTv35///Oc/WCyWC9ZNT0/nnXfeYeTIkcTFxdVQhLXP4MGD6dGjB8888wzFxcUXrPvtt9+yZMkSpk6dStOmTWsoQlGfuCWBobW+XmvdoZLtS+CUMzFxJkGRUdk5lFJBwL+Bp7TWlzY1rgfzDQvjqa+/ptWhQ3DHHdw3Zw6tY2P5cOxY7Faru8MTQggh/jSt9XNa6+eAGOAKrfVkrfVkoAvQpKbiUEq1UEq9r5RaetY+f6VUolLqn0qpETUViycoKipi6dKlDB06FD8/P3eHI0SVJSQkkJeXx48//njBeq+++ioWi0V6X/wBpRTTp08nLS2N2bNnn7eexWLhb3/7Gy1atOCxx6q8toMQlfLEISQrgDOLj48Gvjy3glLKC/gCWKi1XnpueZ3SqBEkJvL0Bx/Q3M+PsR9+SLegIDbMmePuyIQQQohLFQWUn/W6nD8YMnqGUuoDpVSGUurnc/bfpJT6RSl1SClV2QTgFbTWR7TW95yzezCwVGt9L/DXi4mlNriYlQM+//xzCgsLZfiIqDP69euH2Wy+4DCS9PR03n33XUaNGkXLli1rMLra6dprryUhIYFp06aRnZ1daZ23336bffv28eabb+Lj41PDEYr6whMTGNOAfkqpJOB652uUUl2VUvOddYYC1wJ3K6V2ObdO7gm3ZnQfM4aN+fksmjCBjPJyrnnoIRZeeSWkpLg7NCGEEOLPWghsVUr9Qyn1D2ALsOAij12AYwWyCkopIzAHuBloBwxXSrVTSl2mlPrqnK3Bec4bA6Q6n1/cTHW1yIWWRV24cCHNmzfn6quvrsGIhHCdwMBAevfufcEExrRp07BarTz99NM1GFntNm3aNAoKCnjppZd+V5aens6zzz7LLbfcQkKCLColXMfjEhha62ytdV+tdZxzqEmOc/92rfU45/OPtdZmrXWns7Zd7o3c9ZTBwJ1z5nDgxAle6tOHv+7ZA23akPTggxRlVDrSRgghhPA4WuuXgDFArnMbo7V+5SKP/R44d33E7sAhZ8+KcuAT4Fat9f+01gnnbOf7g3kcRxIDLtA+qm2Tg/9RD4zU1FTWrVvHqFGjZKULUacMGDCAAwcOcOjQod+VpaWl8d577zF69GhatGjhhuhqp/bt23P33XczZ84ckpOTf1M2ZcoUysrKePPNNy+YMBWiquQvVS3k36ABU9etI+TgQfTAgdw+dy6tGzbk4/vvl/kxhBBC1Apa651a61nO7acqnq4xv/aeAEcyovH5KiulwpVS7wKdlVJPOnd/DgxRSr0DrLxA3LVucvAL+fjjj9Fay/ARUef0798foNJeGNOmTcNms/HUU0/VdFi13nPPPYfBYPjNvCEbNmzgo48+4tFHH5XJUIXLSQKjNouNRS1ezNx336WRjw93vfceV4WEsOX9990dmRBCCOGxnL0979datzzT80NrXaS1HqO1fkBrvehCxyulBiil5uXn59dMwC6itWbhwoVcffXV8i20qHNatGhBu3btfpfAOH78OPPmzePuu++mefPmboqu9oqJieGRRx5h0aJF7Nq1C5vNxkMPPURMTAxTp051d3iiHpAERh1w1X33sSU/nwXjxnGspIQe48axpk8fOH7c3aEJIYQQNSENiD3rdYxzn0torVdqrccHBwe76hI1Ytu2bRw4cIDRo0f/cWUhaqGEhATWr1/P6dOnK/a98sor2O126X1RBVOmTCE0NJQpU6bw3nvvsXv3bmbOnIm/v7+7QxP1gCQw6giDycTof/6Tg2lpzOjThz4bN0J8PD898ADFWVnuDk8IIYRwpW1AnFKquXOlsjtwrGomLiAxMREfHx9uv/12d4cihEsMGDAAq9XK2rVrAcecL/Pnz2fs2LE0a9bMvcHVYiEhITz99NOsXbuWyZMn06dPH2677TZ3hyXqCUlg1DEB0dE8um4d5gMHKL3pJm55913aREfzycSJaLvd3eEJIYQQVaKUWgxsAuKVUseVUvdora3AQ8AaYD+wRGu914Ux1PohJGVlZSxevJiBAwdS23uSCHE+PXr0ICwsjJUrHdPavPLKK2itpfdFNZgwYQLNmjXDarXy1ltvycSdosZIAqOuat4cn2XL+GTWLMK9vBj+1lt0CQjgH717k7xsGchkn0IIIWohrfVwrXVD52pkMVrr9537V2mt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bRg/fjxfffVVsY4zGo20b9+euLi4El1vypQpvPXWW0ydOpV169aVeHjbunXrsNlsDBw4sETHAXz55Zekp6fTqVMn/P39S3y8uxU6hEQpFaW1jlNK9SyoXmu90a2RuYG7h5Bom42mFgud69cHIPrYMU4eP04112shhBCisirJEBLX/kYgBK58maK1/s0dsZU1GUJy4+68807OnDnDbbfdxurVq0lMTMRgMGC324mIiKBKlSps3bqVY8eOceTIERISEq56/PXXX68al+/r60t4eHiByY369etjMjn/ee3atYshQ4aQnJzMBx98wH333VdgfNo1vOTpp58mIiKClStX0qhRoxK/T601ixcvZuLEidStW5evv/6atm3b3thN8yKnTp2iRYsWdO7cucRzAeSy2WwcPnyYffv2sXfv3rzHhISEvGEggYGBREVFXTUUpGHDhm6fo0SIorzyyitMmzaNZcuWMXz48GIdM2nSJN555x1SU1MxGo3FvtbChQt58skniYmJKfE8Fo899hj/+c9/uHDhQomGfGmtad26NfHx8SxZsoSHH364RNctS4W1K4ozB8ZTWusFRZVVBG6fA2PbNnJuv51Lc+bw1HPPEda+Pa+VMNsmhBBCVEQlnANjIjATSATsgAK01rqNG0Msc+Uxt1ZlcvHiRWrVqsUzzzzDhx9+SO/evfn0008B5zd+I0eO5Isvvig0uQDOD78nTpy4KqmR+zwhIYHMzMy8fU0mEw0bNqRx48Zs3ryZWrVqER0dTbt27YqMdc2aNYwcORKj0ciyZctKNNFoVlYW48eP57333mPAgAF88sknBAUFFft4b7do0SImTJhQZI8SrTUnTpz4XaLiwIED5OTkAM5vtZs2bUrr1q1p1aoVrVq1onXr1jRp0qTYPWuEKE82m41OnTpx6tQp9u/fX6z/2x999BEPPvgg8fHxREREFPtaOTk5tGjRgoCAAHbv3l3s/xNaa+rXr0/Hjh2L3VMk17Zt27j99ttRSpGYmEitWrVKdHxZKqxdUeQqJMCDwLXJiv8roEz897/4GI3UTkzkM6XQX37p6YiEEEIIb/QUcKvWOsnTgYjy89///he73U6rVq04e/Zs3vARrTVz5syhWbNmDBs27LrnMJlMNGrUiEaNGtG3b9+r6rTWnDlz5qqkRu5j3759eeedd4o9m37fvn358ccfGaMp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\n", "text/plain": [ "
" ] @@ -1666,7 +1728,7 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABDcAAALICAYAAABrWRshAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAgAElEQVR4nOzdeXxMV//A8c+dJZM9EREkRJHYaq2tilYf1KNVWkVtpX2qWmot7YOiVC0tfpbaqqpauiitavtQ1aq1tVNq3yIICSL7NjP3+/tjJiOJiFiSKOf9ep1XJvece+6ZyWTmnu899xxNRFAURVEURVEURVEURfmnMhR1AxRFURRFURRFURRFUW6HCm4oiqIoiqIoiqIoivKPpoIbiqIoiqIoiqIoiqL8o6nghqIoiqIoiqIoiqIo/2gquKEoiqIoiqIoiqIoyj+aCm4oiqIoiqIoiqIoivKPdlcGNzRN+7emaUc0TTuuadqwXPLf0DTtoKZp+zRN+03TtHJF0U5FURRFURRFURRFUYreXRfc0DTNCMwGWgPVgC6aplXLUWwPUE9EagLLgQ8Kt5WKoiiKoiiKoiiKotwtTEXdgFw0AI6LyEkATdO+BtoBBzMLiMjvWcpvBbrnp+LAwEB54IEH7lxLFUVRFEW5xq5duy6JSImibkdh0DTtaeBpHx+fVypVqlTUzVEURVGUe1pe5xh3Y3AjBDiT5fezQMM8yr8MrM5PxQ888AA7d+68jaYpiqIoinIjmqadLuo2FBYR+RH4sV69eq+ocwxFURRFKVh5nWPcjcGNfNM0rTtQD3gsjzK9gd4AoaGhhdQyRVEURVEURVEURVEKy1035wZwDiib5fcyzm3ZaJrWAngbaCsi6derTETmi0g9EalXosR9MUJWURRFUZRComna05qmzY+Pjy/qpiiKoijKfe1uDG7sAMI1TSuvaZob0Bn4IWsBTdPqAB/hCGzEFEEbFUVRFEVREJEfRaS3n59fUTdFURRFUe5rd91tKSJi0zStH7AGMAILReSApmnvAjtF5AdgMuANLNM0DSBSRNoWWaMVRSlStowMMhISyEhKQk9PJ8DDA6xWThw7RmJcHOnJyVjT0khPTcXXbKZ++fJgtfLD1q0kJCVht1qxZmRgtVoJ8fGhbbVqYLXyf+vXk5SWhm6zYbXZsNntPBgQQI/KlcFmo//69aRbrdh0HV3XsdntPBwQQL/wcDKsVjpv3Yqu69h1HV0EXYSWAQG8ERpKbGoq7f/+27U9Mz1XrBhvlizJiZQUnjt1Ch0QZ54AL/n58WZAADtTUuh64YIjz1lGgEG+vgz09mZNaiovx8YCOPKdr9UoT0/6enryRUoKA5OTIUueANM8POjp5sas9HRGpqZmywNYaLHQwWxmbFoak222a/JXmM20MhoZYLXysd2eLQ9gg8lEQ4OBHlYrS51tzuqQwUBFg4F2djurRK7Z/5Km4W8w0MxuZ3Nu7wWDI2ZfV9fZmyPPBKQ786voOsdy5FuAFMd3CuVEsk3+BOADxDvzS4pwMUd+gLN9AP4iJOTIDwbOOvO9RUjJkV8ROOZsn7uuY82R/yCwz5lv1nX0HPkNgT8MBtJ0HW+u1RxYYzQSqetUcL62a9zcaJ5+3cGPSj5kTigaFhZW1E2556xevZpRo0bxwQcf8K9//auom6MoiqLc5e664AaAiKwCVuXYNjrL4xaF3ihF+QfLSEoi4dw5ki9eJOnyZSoWL447cOzoUQ4eP05acrIjpaaSlprKy7Vr4w38sH8/G06eJMNqJT0jgwybjQyrlYV16uAuwgeHD/NLTAwZuo5N17GJoOs6O8PCwG6n19mzrE9JwS6CHdBFMAERxYuDrvN4fDx7bDbsODqwOuABXHZzAxHCrFYinHmZHVxPIMn52B/IORDcK0t+dSAtR34xINb5+DnAliO/FJAZKR0K13S+ywM9VjvmMJ6Vy2u9NyKCfrt3owMrcsmPvXSJN44eJR7YkEu+X3Iyb549SyywL0eeBvx18SJcvsxlXedklu2ZTsfHQ1IS8brORV1Hy5KvAfFpaaDrZFitpDk7uFnzrXY76Do48wzOzrirjMkEFgsedjsednu2fQEs3t5gsVA8KYliKVe775nt8ChWDCwWysTHU9KZn7WNllKlwGwmLDaWssnJaDmObypbFoxGHoyJISo1NdvrYwAoXx6AOhcukJwlXwMsBoMjX9Ood+4chrTs7w4/gwEqVACgwZkzeOfo9AeZTK76658+TYQ1e/gh1GyGcuUc+RERnLdlf3dVcnODso67LuucOkWsM/iTqZa7O4SEAFDj1CmS9avhCwHqubtDcDAAVU6exJYjOFTb0xNKlsRgt1MhMpKcHvTygsBA3G02Hjh7FoBiZcteU065OVknFC3qttxLRIS3336bPXv20Lx5c4YMGcL48eOxWCxF3TRFURTlLqWJ5Dx1v3fVq1dP1EzmSkGypaWRcPYsbunpeIuQcO4cf+7cSWJsLMnx8STGx5OSnMwTZcpQ28+PvadPM3PPHlIzMkjLyCDVaiXdZmNY6dK08vTkm5gYRkdHYxXBliXN8fTkOZOJ91JSmGi1okO29A2Ojnt34Itc2vkL0BJ4ihxRRKe/gJrAo8CmXPLP4wgC1AV255Jvx9Epri/CHhwdS4PzpxuQ4OkJmkaz1FT+EsHgzDcCvgYDR0uXBqORdjExHLLZHHmahlHTKGU280vlymAw0OPUKU5lZGAyGDBqGiaDgQc8PZlXpw6YTAzev5+YjAxMRiNmoxGTyURFf3/erF8fTCYm7thBkt2O2WTCYDRiNpupGBhIp7p1wWzm0x07sItgtlgwms2Y3dwIDQqiUfXqYDbz2759GN3cMFksmN3dMZrNBJUsSWiZMugGA6ejo135Jnd3TBYL7t7eePr6ohsMYDJhMN2VMWZFuS2apu0SkXpF3Y7CpM4x7qwNGzbQrFkzpk2bxpEjR5g3bx41a9bkiy++oHr16kXdPEVRFKWI5HWOoc6qlXteRlISF/bvJ/rIES6ePs2V6GjKeXjQpGRJUi5eZPjatSSnppKclkZSejqpGRm09vVlSPHinE5I4F8REWSIkOEcJm4ToZvRyFyjkfVWK//KZWh9F+BL4EccAYacTgFzcVy5/zSX/Efi42kFnASOcTU4kJmSbDYwmfA2mfC22Rwde03D7PxZIiQEihWjZVwcpy9fxs1gwM1kwmIy4WYyEfbQQ1C8OK9HR1Pp/HnczGYsFgsWiwV3d3ceePRRKFaMWRcvciw2Fg9vb9y9vfHw8cHD15fAGjXAx4dNBgMGb2/cvL1z7aTvuMHfZv0N8lfeIP/zG+RPu0H+8Bvkv3SD/OZPPnndPANQvmrVPPMVRVGU3E2fPp3ixYvz6quv4uHhwVNPPcXLL79MvXr1mDRpEgMGDMBgUJ+kiqIoylVq5IZyV0qJjMQzJgZiYvjmf//jTGQksbGxXImPJy4xkTCzmXeDgyEpidoHDhBrt5Om66SLYAVqA39oGroIxlzqr4FjyH8CkNsUcA8Df+IIQoTjGFFgxBENNGkaL7i7MyMwkGPAM9HRuBuNWIxGLM4AQs9y5egSHs4pm40phw/j5e6Op6cnnl5eePv48HitWlStVIk4TePQxYv4BAXhExSEX3Aw3sHBmNzdC+BVVRRFKRz308iNLHNuvHLsWM6ZXJRbceLECcLDwxkxYgTvvfeea3tMTAy9evXixx9/pEWLFixatIgQ561ciqIoyv0hr3MMFdxQCs2Fffs4uHYtx3bvJiM6mv4lSsD58zTfsYNDaWkk6TqpOOZAyDovghtcM7FeEBDtfOyJ4zYIE+CmaViAxu7ufFuuHHh50erkSdzMZvw8PfHz9sbPx4eGFSvSrmFDdG9vfjp2DP9SpfAvXRr/kBACKlbEMzBQXRFSFEW5RfdTcCOTOse4cwYOHMjcuXOJiIgg2DnPTCYR4eOPP2bw4MFYLBbmz59Phw4diqiliqIoSmFTt6UoBSctjZ2ffsqOjRs5deIEZ6KjiYqLw261stnfHxITqZiU5Jr4MJMb0N/5+BCOQIanphFiMFDczY2axYrB449DsWJMPXYM3cODwNKlCSpblhLly1OmRg2oXBlMpmtWHMhpTR55Bq5OHqkoiqIoStGKj49n4cKFPP/889cENgA0TaN37940a9aM7t2707FjR3r27MnMmTPx9fUtghYriqIodwsV3FBuyr7vvuPrKVP488ABfgMMCQl0AY7nKGcEx4oLnp7U9/TEX4QgLy9CAgJ4oGxZqtaoAS+8AFWqEOXpmecx++eZqyiKoijKveKTTz4hKSmJQYMG5VmuUqVKbNmyhXHjxjF+/Hg2bNjA4sWLadKkSSG1VFEURbnbqNtSlOtLSIBly/hw5kymHDhAlN2ebdnMXRYLD1WqxBf+/pxyc6Ni1apUfuQRqrRqhWdAQJE1W1EURSla99NtKWrOjTvHZrMRFhZGaGgoGzduZPPmzbzzzjssXLiQcs5llnPzxx9/0L17d06fPs2wYcN45513cHNzK8SWK4qiKIVF3Zai3JBus/HnggV8M28em44e5VhqKvOAbjhGZZwDShuNPBQYyJOPP07HceMICAsDZxlFURRFuR+JyI/Aj/Xq1XulqNvyT/f9999z+vRppk1zrHXVuXNnzp07R8WKFZk6dSoDBw7Mdb9HHnmEv/76i4EDBzJhwgTWrFnDkiVLqFKlSmE2X1EURSliauTGfSrmwAGSly6l/I4dfLt1K53i4tCz5PsCk8qWpc/zz2Nr3x5To0ZF1VRFURTlH+Z+GrmRSZ1j3L4mTZoQFRXFsWPH+PPPP2natCkhISHExMRgtVpp2LAhv/76K97e3tet49tvv6V3796kpqYydepUXnvtNTRNK8RnoSiKohSkvM4x1HIQ94mUS5foX7MmD1oseGoaJatX58Vx4+Dnn2mUmEg5o5Hny5RhSZ8+JF+8SLwIfSIjYfJkFdhQFEVRFKVA7dixgy1btjBgwACMRqNrzo1evXpx7NgxqlSpwrZt2wgKCuKHH364bj3PPfcc+/fvp2nTpvTt25enn36a6Ojo65ZXFEVR7h0quHGv03XSBg4koEQJZu3fz8GMDDw0jSa+vvR4+mk4fJhgm42TNhtfnzlDtzlz8AwMLOpWK4qiKIpyH5k2bRo+Pj785z//ISoqil27duHl5cXYsWNp2bIlM2bMYPjw4aSlpdGuXTs6dOiAruu51hUcHMzq1auZOXMmv/76KzVq1MgzIKIoiqLcG1Rw4x72ba9e4OeH+8yZtNY0RjZpQnpiIpd1nU3x8bz8ww+O5VQVRVEURXHRNC1U07TvNU1bqGnasKJuz73u7NmzLFu2jF69euHr60v//o510tLS0mjVqhUArVq14ujRo6xevZoSJUrw7bffEhQUxN69e3Ot02Aw0L9/f3bt2kVwcDDt2rXj1VdfJTk5udCel6IoilK41Jwb96CfRo/mlfHjuaDrTAGGvPgifPQRqJnDFUVRlEJQlHNuaJq2EGgDxIhI9Szb/w3MwLFa+QIRmZRHHU8BxURkiaZpS0Xk+Rsd9345xygIw4cP54MPPuD48eOEhITg5eWFpmnY7XaOHj1KmTJlmDJlCuPHj8dgMDBy5Eh2797NsmXL0DSNN998k/fff/+69aenpzN69GgmT55MWFgYS5YsoUGDBoX4DBXl/qbrOmlpaaSkpLhSampqtt/zs+3hhx+mf//+GAzq+vz9LK9zDBXcuIfs/fpruvTsyeGMDACeCAjgiz/+IFCNzlAURVEKUREHNx4FkoDPM4MbmqYZgaNAS+AssAPogiPQMTFHFf8B7MByQIDFIvLpjY57r59jFJTk5GTKli3L448/zrfffsuIESOYOHEibm5utG3blmXLlrnKRkREMGjQIFauXEnVqlV54YUXGDduHKmpqYSHh7N+/XqCg4Ove6z169fTo0cPoqKiGD16NMOHD8dsNhfG01SU+8bvv//OwIEDuXLliisokZaWdkt1ubu74+HhgaenJ0ajkcjISJ555hk+++wzfH1973DLlX8KFdxwumdPPKKiyOjUCc8tW7ADtdzd+WrZMqq2aVPULVMURVHuQ0W9WoqmaQ8AP2UJbjQCxohIK+fvwwFEJGdgI3P/ocB2EdmoadpyEelwo2Pes+cYBWzu3Ln07duXTZs20aRJE/z9/UlISEBE2Lp1Kw0bNrxmn//973/079+fU6dO0aFDByIiIti5cycmk4nZs2fTu3fv6x4vLi6O119/nS+//JJ69erx+eefU7Vq1YJ8iopy3zh37hy1a9fG19eXZs2auQITWVPObdf73cPDI9sIDRFhxowZDB06lPDwcL7//nsqqwu49yUV3HC61048Ui5dYmCDBnx46hTuwHu+vjwyejT/GjKkqJumKIqi3MfuwuBGB+DfItLL+fsLQEMR6Xed/asDY4BLQJKIDL1Oud5Ab4DQ0NC6p0+fvrNP5B6n6zrVqlXDx8eH7du38/XXX9O1a1fc3d2pX78+GzduvO6+qampvP/++0yaNAk3NzdatmzJypUrsdvtPProo6xevRpPT8/r7r9s2TL69OlDcnIyEydOZMCAAWqou6LcBpvNRvPmzdm5cyc7d+4ssKDh77//TqdOncjIyGDx4sW0bdu2QI6j3L3UUrD3GN1mY0jduviXKMGCU6d412KBRYsYGR+vAhuKoiiKcptE5G8R6SAir10vsOEsNx8YC+x2U/Na3bSff/6ZI0eOMGjQIDRNY+TIkYBjItE333wzz309PDwYM2YMBw4coEmTJnz33XeEhYURHBzMxo0bCQoKYu3atdfdv2PHjvz999+0aNGCwYMH07x5cyIiIu7k01OU+8rYsWPZuHEjc+fOLdDRUI8//ji7du0iPDycdu3aMXbs2OuunKTcf1Rw4x/mw44d8TWb+b/duzEA7zz2GO8lJUHPnkXdNEVRFEW5W50Dymb5vYxzm1KEpk2bRnBwMB07dmTv3r2cPHkSd3d3qlSpwlNPPZWvOipWrMj//vc/VqxYQWpqKlFRUVStWpWUlBSeeOIJevTocd2OT6lSpfjhhx/45JNP2LlzJzVr1mThwoXcT6Oa72eRkZHs2bOH48ePExMTQ2pqqvrb36Jff/2V8ePH89JLL9GjR48CP15oaCibNm2iR48ejBkzhmeeeYb4+PgCP65y91O3pfxT/PQTtpdfxjsmBivQIyyMj/bswc3bu6hbpiiKoijZ3IW3pZhwTCjaHEdQYwfQVUQO3Klj/qPPMYrA/v37qVmzJhMmTGD48OE0bdqUzZs3A/Dxxx/Tq1evm64zOTmZCRMmMHnyZCwWC7quk5KSQqlSpVi3bl2eV5MjIiJ48cUX2bBhA23atOHjjz+mVKlSt/z8lLuXzWZjwoQJjBs3DpvNli3PZDLh4+ODj48Pvr6+2X7md1tgYCDFihUromdX+M6fP0/t2rUJDAxk+/bteHl5FdqxRYTZs2czePBgKlSowIoVK6hWrVqhHV8pGmrODad/4onH7i+/5OX//Icf09MpA6yuU4f6X32lVkBRFEVR7lpFvFrKV0AzIBCIBt4RkU80TXsSmI5jhZSFIjL+Dh3vaeDpsLCwV44dO3Ynqrwv9OrViy+//JIzZ86gaRqBgYGYzWaKFStGREQE7u7ut1z3kSNH6NevH7/++it+fn7Ex8djMBgYPXo077zzznX303WdmTNnMnz4cLy8vJg3bx4dOtxwLlnlH+To0aP06NGDbdu20bVrVzp06EBiYiKJiYkkJCRc8zjnz8yUV/9J0zQ6d+7MqFGj7vnJau12Oy1btmTr1q3s2LGDBx98sEjasXHjRjp27EhKSgqff/45zz77bJG0QykcKrjh9E8KbpzdsYMuLVqwOSEBgHdKlmTMhg2gghqKoijKXa6oR24UhX/SOUZRi4mJITQ0lBdffJF58+bRs2dPPv/8cwDGjx/PiBEjAPjiiy8YOXIkw4cPz3MFlNyICMuXL2fw4MGcO3cOo9GI3W6nevXq/P777wQGBl5330OHDtGjRw927txJ165dmTVr1n11Jf5eJCLMmzePoUOHYrFYmDt3Ls8///wt1ZU5Iii3wEdCQgL79u1j7ty5pKSk3PNBjrFjxzJmzBgWLlzISy+9dMv16LpOXFwcV65cITY2ltjYWOLi4oiLiyMhIcGVWrVqxZNPPplrHWfPnuW5555j+/btjBw5kjFjxmA0Gm+5TcrdK89zDBG5b1LdunXlbmePj5cOISGigQASajTK79OmFXWzFEVRFCXfgJ1yF3zvF0YCngbmh4WF3amX7543duxYAeTQoUNit9vFYrGI0WgUT09PuXz5sqtc8eLFBef5UFBQkHz99dc3fazExER58803xWg0itFoFEDMZrMsXrw4z/0yMjJk7NixYjKZJDg4WH7++eebPvb9IDExUQ4ePChr1qyRBQsWyNSpU+XMmTNF3axsoqKipHXr1gLIE088IWfPni3wY8bExMh///tf8fLyEk3TpEuXLnLw4MECP25hWrdunWiaJi+88ILouu7avn//fmnatKnUqFFDwsPDJTQ0VEqVKiUBAQHi4+MjHh4e4ubmJkajUTRNc/2P5ze99NJL121Tamqq/Oc//xFAWrduLbGxsYXxUiiFLK9zDDVy426h6zBkCMyaRaDNhl3TmNGrFz3mzy/qlimKoijKTVEjN5TrSU9Pp1y5cjz00EOsWrWKiRMnMmLECDRNo3///syYMQOAH374gXbt2tGoUSN8fHxYu3YtIkLZsmX56KOPaN269U0d98CBA/Tr14/169e7tjVr1oz//e9/eS4Zu2vXLnr06MHBgwd57bXXmDx5Mt73yXxn6enpnD17ljNnzlw3Xbly5Zr9LBYLffv2ZdiwYQQFBRVBy69atmwZr732GqmpqUyePJm+ffuiaVqhHf/ixYtMnTqVWbNm3VMjOaKjo6lduzb+/v7s2LHD9T+ROcdNYmIimqZhMBgwGAwYjUZMJhNmsxk3Nzfc3NywWCy4u7vj7u6Op6cnHh4eeHl54e3tjbe3N76+vnh7e+Pn54e/vz9ms5k+ffpw5coVqlevzp9//pnr/6KI8NFHHzFgwABCQ0P5/vvvqV69emG/REoBUiM37vKRG9OeeUZ8QTaBiLu7nB86VOxWa1E3S1EURVFuCfkcuQEE5JXyU0dRJ9TIjZuyaNEiAWTNmjUiIlKiRAkBRNM0OXXqlKtc1apVBXBd7Y6IiJDGjRu7rt6GhYXJpk2bburYuq7LF1984TomIJ6envLjjz/muV9qaqoMGTJENE2TChUqyObNm2/uSd+FbDabREZGypYtW+Trr7+WyZMny4ABA+TZZ5+VevXqScmSJXO9ah4QECC1atWSNm3aSJ8+fWTChAmyePFi2bBhg5w8eVKOHTsmL730khgMBvHy8pK3335brly5UujP78qVK9K9e3cBpH79+nL48OFCb0NWOUdydO3aVQ4dOlSkbbpVdrtdWrZsKe7u7rJv375seQ0bNhRA+vfvXyDHTk1NlXr16gkgPj4+8tdff1237ObNm6VUqVLi5eUl33zzTYG0RykaeZ1jFPlJQWGmuy24sXzoUCnhHI5lBJn58MMi6elF3SxFURRFuS03Edw4BZx0/rQDl4DLzsen8lPH3ZLutnOMu5Gu61KrVi158MEHRdd1+fHHHx3nQEajPP/8865yR48eFUAqVap0TR1///231KlTx9XZrlGjhuzdu/em2nHlyhV5+eWXs3Xa27VrJ9YbXFjasGGDlC9fXjRNk7feekvS0tJu6rh3iz179kiFChWuCVz4+PhItWrVpFWrVtKrVy8ZO3asLFy4UNauXSuHDx+WpKSkfB/j0KFD0qlTJwHE399fJkyYcFP7347ffvtNypYtK0ajUcaMGSMZGRmFctz8uBeCHO+9954AMn/+/GzbM283q1KlSoG3oX///gKIwWCQjz/++Lrlzp07J40aNRJA/vvf/4rNZivwtv1T2Gw2SUlJkbi4OLl8+XK2W4vudiq4cZedeNg3b5bKZrPjSgXIkyVKyOUTJ4q6WYqiKIpyR+Q3uJGZgI+BJ7P83hr46GbqKOp0t5xj3M3WrVsngKszkjk6A5CdO3e6yrVq1UoAWb58+XXr2rZtm1SpUsW1f4MGDeTo0aM31Z5ffvlFSpcu7arD19f3hqNBEhISpHfv3gJI9erVZc+ePTd1zKL25ZdfioeHh4SEhMjs2bNl1apVsn//fomLiyuQ4+3Zs0fatGnjmjdlxowZBRYUSk1NlcGDB7sCY9u2bSuQ49wJMTEx8tZbb4mnp+c/KsixYcMGMRgM0qVLl2yd4R07doimaeLu7p5t3pyCtHTpUjGZTALICy+8cN1yaWlp8uqrr7rmXCms9hWEb775Rvr37y+9e/eWF198Ubp27SodOnSQtm3bSqtWreTxxx+Xxo0bS/369aVmzZpSpUoVqVChgpQpU0ZKlCghfn5+4uHh4Zp/KGsqXry4tGzZUt566y356quv5MiRI2K324v6Kecqr3MMNedGIYrZsYOg11+HHTuoA5g8Pfn6xx+p+K9/FVmbFEVRFOVOu9k5NzRN2y8iNW607W6kloLNv3bt2vHHH38QGRnJ2bNnqVSpEkajkUcffZR169YBjnv2fX198fX1JTY29oZ1/vbbb/Tq1YuIiAjAMY/G4sWLKVOmTL7alJSUxLBhw5g9e7ZrW8+ePVm4cCEGg+G6+61atYpevXpx8eJFxowZw3//+19MJlO+jlkUbDYbw4YNY+rUqTRp0oTly5dTsmTJQjv+n3/+yYgRI1i/fj1ly5Zl9OjRvPjii3fsNduzZw/du3fn4MGDvP7663zwwQd5zqWyZMkSXnvtNdLS0lxzQWTOAeHp6Ymnpyc+Pj74+Pjg7++Pv78/xYoVo0SJEgQGBlKyZElKlixJqVKlCAwMzPO9kpeLFy8yZcoUZs2aRVpaGl26dGHUqFFUvgtXR7x48SK1a9fGy8uLXbt24ePjA0BaWholS5YkISGBVatW3fR8OLfjxIkTNGzYkMuXL1OlShW2bduGr69vrmUXLFjA66+/TkhICCtWrKBWrVqF1s47Yf78+bz66hmXirIAACAASURBVKv4+Pjg6enpmrckcw6TG/2eV56IcPDgQfbs2cP+/fuxWq0AeHt7U7t2berUqUOdOnV46KGHqFatGmazuUhfCzXnRhFfVbly6pQ8VaKEaCDzQKRiRZE//iiStiiKoihKQePmR26sAUYCDzjT28Cam6mjqJMauZG3Y8eOiaZpMnLkSBEReeKJJ1xXDFetWuUqN2DAAAFk1KhRN1X/d9995xqFoWmatGnT5qau0G7cuFHKlCnjalNgYOANR2VcvnxZOnfuLIA0bNiwyOd1uJ5Lly5JixYtBJC+fftKehHdAq3ruqxdu1YaNGjgmjflyy+/vK2rwzabTSZMmCBms1lKly59w1VtUlNTpXnz5q5bGipUqCClS5eWgIAA8fLycq3iATe3ggfO26ssFov4+/vLgAEDbnibU1ZZR3IYDAbp1q3bXfV+stvt8u9//1ssFss1/xeZc+G89tprRdK29PR0efjhhwUQb29v2bVr13XLbt26VYKDg8XDw0O++uqrQmzl7fnyyy9F0zR58sknC/z/Nz09Xfbs2SOffPKJ9OvXTxo3bixeXl6u97mbm5s89NBD0qtXL5k9e7b8+eefkpycXKBtyimvc4wiPxkozFTYJx7piYnySuXKYsz8otQ0+XHYsEJtg6IoiqIUtlsIbgQAM4A9wG5gOv+QCUUzkwpu5K1fv35iNpslKipKEhMTxWAwiNFodM2/kcnb21vMZvNNdQyzWrRokWsJWYPBIM8//7wkJibma9+UlBQZOnRotg7roEGDbrjf119/LQEBAeLh4SGTJk0qsuBBbvbu3Svly5cXNzc3+eSTT+54/UlJSbJq1SoZOXKktG3bVho2bHjDAIOu67Jy5UqpUaOGa96UlStX3vQ9/8ePH5dHHnlEAOnUqdMNg1m//PKLeHt7CyDlypWTOXPmyPz582X79u25/s3sdrtER0fLnj175Oeff5bFixfL1KlTZcSIEfLaa69J586dpXXr1tK4cWOpVauWhIeHS0hIiJidt55bLBYZNGjQPRHkmDRpkgAyZ86cbNsnTpwogISHhxdRy67KvCXJYDBc086szp8/L02aNBFAhgwZcsufNYVl5cqVYjQa5bHHHpOUlJQiaYPNZpPDhw/LV199JW+++aa0aNFCAgICXJ+TBoNBqlatKt26dZMpU6bIunXrCnQZXhXcKOwTD7td7O+8I36ZM3GDTHn66cI5tqIoiqIUsfwGN4DFzp8D81P+bkyo1VJu6MqVK+Ll5SU9evQQEZE+ffq4Too//fRTV7kFCxYIIM8999xtH3PGjBni6+srgJhMJnnllVfyHXTYvn27hIaGutpYpkwZOX78eJ77REVFyTPPPCOAVKtWTdavX3/bz+F2ff311+Lp6SnBwcGydevWW67HarXK5s2bZeLEidKpUyepXbu2lChRwtWJzy098sgjEh0dnWe9drtdvvrqKwkPD3fNm7J27dobBjl0XZf58+eLl5eX+Pn5yRdffJHnPna7Xbp27eoa1dOxY0cpV65criMvfH19JTQ0VBo0aCAdOnSQ4cOHy5IlS+TQoUP5HmGSnp4uAwYMEIvFcseCHN27d5cjR47ke/87adOmTWI0GqVjx47ZXuddu3aJpmlisVjk4sWLRdK2nL777jvXPBydO3e+7t8sPT1dXn/9dQHkX//6l1y6dKmQW5o/v/76q1gsFqlfv74kJCQUdXOy0XVdTp8+Ld9//72MHj1ann766Wyj3wCpUKFCgQR7/5HBDeDfwBHgODAsl3wLsNSZvw144EZ1FkZwY9nrr4vV11cEpKemyYBatcSamlrgx1UURVGUu8VNBDcOAsHAX0Ax/oFLwWYmNXLj+iZPniyA7N69W+x2u2sSxdKlS2c78c3scJ47d+6OHNdut8u7774rHh4eruHUb7zxRr46mWlpaTJixAjRnKvaaZomY8eOveF+P/74ozzwwAOuSQ4vXLhwJ57KTbHZbPLWW2+5ggznz5+/4T52u1327dsns2bNkhdffFEaNmwopUuXdnXQcyZN08RoNIrRaBSDwXBNXmawYOjQoTcMClitVlmwYIGULVtWAGnWrJls2bIl17Lnz593TVDavHlziYyMzLPuPXv2uJb+LVasmOuWGECaNm0qo0ePls6dO8sjjzwi5cuXFz8/P1fnOLdkNpulWLFiUrFiRWnSpIl0795dxo0bJ99//72cOXMm27Ezgxxubm63HOSIjo6WN998Uzw9PcVkMsmgQYMK9Ip4TpcuXZIyZcpIxYoVs006m56eLv7+/gLIypUrC609+XHy5EnX3zw8PDzPpYg//fRTsVgsEh4eLseOHSvEVt7Yn3/+KV5eXlK9evUCCb5ERETI0qVLZcSIEdKrVy85e/bsHak3JiZG1qxZI5MmTZIBAwbckTpz+scFNwAjcAKoALg5T3qq5SjTF5jnfNwZWHqjegvyxOO3KVOkrPMevQEg0qGDSD6HQSqKoijKveQmghsDgENAOleXhM1MJ/NTx92SVHAjd1arVUJDQ+Wxxx4TEZHZs2e7OoqTJk1yldu+fbsA8tBDD93xNthsNhkyZIirk+nh4SHTpk3L17579+51BStwzhNxo2BBcnKyvP3222I2m8XPz09mz55daEtQXr582TWfyWuvvXbdq6YfffSRPPbYY1KuXDlX8Odmk8FgEC8vLwkJCZG6devKM888I23atLkm2FG8ePEb3qoi4ggozZgxQ4KCggSQp556Ktv8Dt99950EBgaKu7u7TJ8+/YZBk6FDh7oCLVWqVHHNpREcHCwbN27Mc1+r1Sr79u2TRYsWyVtvvSXPPvus1K1bV8qUKSPe3t7XPMesycPDQ3r27Omah+BOBDkuXLggvXv3FoPBIMWLF5fZs2cX+O0UdrtdnnrqKXFzc7tmHotHH31UAOnVq1eBtuFWpaenu2498fLyku3bt1+37ObNm6V48eISGBgof9wlcyLu3btX/P39JSwsTKKiom56f7vdLocPH5bPPvtMhg4dKm3atJGaNWtKqVKlxN3dPdf3rcVikXXr1hXAs7nzCiS4AXwHPAUYbrWOPOpuRJaJxIDhwPAcZdYAjZyPTcAlcKz+cr1UECcef3/1ldTM8iZp6usrZ/L4B1IURVGUe11+gxty9Tt97s2UvxuTCm7kbunSpQLI999/LyIiwcHBrg5H1iuqjRo1EkA2bNhQYG1JT0+X3r17u67MN2vWLF9Dpq1Wq4waNcrVUTYYDDJz5swb7nf48GHX5JX16tWTHTt23ImncV379u2TChUqiNlslvnz51+33HvvvXfDwIWmaeLh4SGlSpWSGjVqSOvWraVfv34ye/Zs2bx5c54TCF6+fFnatm3rer0yU35uVRFxzOMxYcIE18iAjh07Ss+ePV3BrwMHDuS5/+nTp6VChQquDpuPj49r5M77779/w+PnV0pKivzxxx8yZ84c6devn7Ru3Vpq1KjhChaZTCbp0aNHtiBH//79swU5Bg8efFNBir1790qzZs0EHEsRr1279o49n5wyR1x9+OGH2bZ/8MEHAkjFihUL7NhZxcfHy9ChQyUkJERq166d50iMnDJHMGmaluf/7NGjRyUsLEzc3d3zXIK6MBw5ckSCgoKkTJkyEhERkWsZq9Uqe/bskY8++kj69+8vrVq1kmrVqkmJEiVc76/rBTCCgoKkRo0a8tRTT8ngwYPl008/ldGjR4umaaJpmkyZMqWQn/HNy+sc45aXgtU0rQXwEvAwsAz4VESO3FJl19bdAfi3iPRy/v4C0FBE+mUp87ezzFnn7yecZS5dr947vRSsXrw4pthYBHAHqnp4UNzDg1IeHixu0AAsFqafOMHBxEQsZrNj2R03N4L9/en36KNgsfD9oUNcTEvD4uGBxd0dNw8PSgQG0qRBA/Dz40JGBpbAQHxDQjC6ud2xtiuKUkREEF1Ht9vRbTZE1xG7Hd1ux+LmhgHISE8nLSUFPUue6DoB/v4YgMTERJKSklz1iK4juk7Z0qXRRLh0+TLxCQmIiOsYAJUfeAB0nbPnz3MlPt7xRaDriAhGoEZYGIhwPDKS2Ph4V57oOm4mE3UrVQIR9h8/TqyzftF1dF3Hy2Lh4apVQdfZdugQVxITr+4vgr+nJ42rVgURft+3j/jk5Gz5Qb6+NK1SBUT4aedOktLSsrWvbEAAjzqXxlu6dStpGRnZ8sOCgng0PBxE+GTzZux2e7Yvu+qlS9O0YkXsdjtzN2265suwXtmyNClfntSMDOZu2XJNftMHHqBRaChxqanM3bo1a6ccEaFVWBj1g4OJTkxk3s6d1+Q/W7kydUqVIjIujvm7dzvOMrKU6VatGtUDAzl6+TIL9u27emzn2+aV6tWpEhDAXzExLDpwwLU9c/9BtWpR3teXrefPs+To0WzHBni7Th1CvLz4/dw5vj5+3LX/2Mceo/S8eXf8bX6zS8HeC4p6ufm71SOPPEJ0dDRHjx5ly5YtPPbYYwC88cYbTJ06FYBLly4RFBREqVKliIqKKvA2xcTE0KhRI06ePElAQAAbNmygevXqN9zv8OHDPPnkk5w6dQqAmjVrsmHDBvz9/a+7j4iwdOlSBg8eTHR0NH369GH8+PF57nMrli9fzosvvoivry/ffvstjRo1yrXczJkzGThwIAD+/v6ULl2akJAQypcvT5UqVahVqxZ169a9pfbFxcWxa9cuGjdujLu7O1FRUbzwwguuZX4BDAYDb7zxBu+///4Nl0+Ni4tj6tSpTJs2jdTUVEaMGMGoUaNwy+N8ePr06QwdOhS73Y63tzdJSUkAPPvssyxZsiTP5WHvFF3Xeffdd5kyZQrJycmYTCa6dOnCnDlz8Pb2JiMjg6FDh/LRRx+RkZGBxWKhb9++fPDBB/laGldE+P777xk6dCgnT57k6aefZurUqYSHh9+x57B161aaNm1K27ZtWb58OZqmAbBv3z7q1KmDyWTizJkzBAUF3bFjZqXrOp988gnTp0/n0KFDjk6rpiEieHl5sWXLlnwv5frDDz/QoUMHrFYrzz33HN98802u771Lly7Rtm1btm7dyuTJk3njjTdcz7uwnD59mqZNm5KWlsamTZuuWRK4bt267N27F915XpeTwWDAbDa7ljbOutyrpmnYbDZsNhtWqxWbzYbdbsdut6PrOr6+vkRFRaHrOu3atWPFihWF/vzzK69zjFsObmSp3A/ogmPZtjPAx8ASEbHeRp13LLihaVpvoDdAaGho3dOnT99qs66xo0YNGvz9NwANvLzwNJtJt9kIMBj4KTQU0tN54dw5fk1LI12EDBHSgcrA3846HgH+zFFvAxyTiADUAvY5H/sAfkYjLX18WPjgg+Dnx+ATJ0gzGvHz9cXPzw//YsWoFhbGY40agZ8fhy9fxqtkSfxCQvAJDka7xXW4lYKV2QnVrVbMBgPY7aQkJpKemordakW3WrFbrWgilCpeHOx2os6fJykxEbvVit1mQ7fZcDMYqBIaCrrO30ePEp+Q4PjgslrRbTZ83N1pEB4Ous76v/4iLjHR0cm227HbbJT09aVZlSpgt7N82zYSnB1su82GruuUDwjg35Urg64ze+NGUtLT0Z2dW13XqREURFtn/e/8/jtW5wdmZnqkdGnaV6yIzWZj4IYNju2ZHWQRWgcH81xoKInp6by2dSu6iCM587uGhPBccDAxqan8Z+9ex76ZZUToGxLCs8WLczI5mZ5HjmTPB0aVKsXTvr78lZxMj8hIRx44ygHTAwNp5enJpuRkel686NquO/9GS/z8aObmxk+pqbyUmOjY7txfB37x8OBhTWOJ1corVuvVfZ0/9wI1gA9xjMXP6SRQHpiA4wM1p4tAIDACmJhLfhqOyYj6A7Ny5JmBDOfjF4HPcuQHAJedj5/DMTQvq1Ag89PzCWBtjvwHyftz7eEs22pkKZupJfCL8/EDWY6VqT3wrfNxcSA2R35PYJHzsRuQ8wvodRyvSQaO1yinYThe08s4XuOcxuN43SNw/I1ymonjdd8P1Mwl/1PgRYOBrSI0cX7valnSVyYT7Y1GftN1nnauL581f4W7Oy3MZn6w2XghNdWVD6BpGj97e9PQZOKrjAz6p6RkzwfW+/tTzWzmk7Q0RjpP9jVgQ3g44YcP59Li23M/BTc0TXsaeDosLOyVY8eOFXVz7irbtm3j4YcfZsaMGQwYMIC6deuye/duDAYDp06dIjQ0FIAePXqwePFiZs6cSf/+/Qulbbqu85///IfPPvsMg8HA9OnT83Vsu93OhAkTeOeddxARTCYTixYtolu3bnnuFx8fz+jRo5k1axaBgYFMnTqVbt263XbnwW63M2rUKCZOnEijRo1Yvnw5wcHBuZYdPXo048aNAxyv+Wef5fwmuHlxcXGsXLmSZcuW8csvv2C1WilTpgxjxoyhZ8+emEwmTpw4Qbdu3di2bZtrPz8/P5YuXUqrVq1ueIxLly5x+fLlazp6OdvRokULdu3ahcFgcHX+KleuzLfffsuDDz5428/1Zum6zrhx45g8eTLJyckYjUa6dOnC3Llz70iQIz09nenTp/Pee++Rnp7OgAEDGDVqFH5+frfV7tjYWOrUqYPRaGT37t2uQFdGRgalSpXiypUrfPfddzz77LO3dZzcbN68mXfeeYdNmzZhdX4XlitXjldeeYUhQ4YwevRoJk+ejNFoZNGiRXTv3j1f9UZGRtKgQQOio6OpUKECO3bsICAg4Jpyqamp9OzZk2XLltG3b19mzJiRr7/FnXDhwgWaNm3KxYsXWb9+PbVr186Wv2DBAl555ZVbqlvTNFcyGAyuZDQaMRqNiAiJiYnkjAuEhoZSs2ZNmjVrRvv27SlfPrczoMJXYMENTdOKA92BF4Ao4AugCVBDRJrdRr2NgDEi0sr5+3AAEZmYpcwaZ5k/NU0zAReAEpLHEyqIqyp1PDzYm5aGEVg/cyZN8vHFqFutGGw2SE8nNjqalPh40hMTSU9OJiMlBTcRqgUFQXw8y9au5ez588THxRGfkEB8UhKV3dz4b8mSEB/Pw3//zYmMDOJFXCfzXYAvnY99gUTnYw3HCJNXLBZmFCuGuLlR9fx53IxG3I1GLM7UuUwZeoWHk2Yy0Wf3btydI04sbm64Wyw0r1yZR6tUIUXT+GLvXtwslmxfzvUrVKBqSAhxycn8tHcv5PjifjgsjLBSpbiUmMgv+/dnf3E0jcaVKlGuRAnOx8by6/79ro63ruvY7XZaV61KqL8/xy9c4Ednfmaeruu8UKsWZb292RsVxfIDB7Ll2XWdobVrE+zhwfrISL44etS1PTNNr1WLILOZbyMjWRQZmS3PLsL3Vavip2nMi4rik5gY7CKupIuwNzQUN11nzOXLLExKcuQBdhE0IMbHB+x2eqelschux46j4wuO2fQyO20duNqZy5S1g9mKq53BTNWAA87HuXUwGwJbnY9r4uiIZdWCq53W8jg6clk9y9VObyBXO8OZenC10+yFo4NpyJJ6m838n6cnVk0jOD4eDTBomiNf03jd25vhxYoRJ0L9qCg0wKhprjIDAgN5JTCQ83Y7T588eXV/ZxoUEkLHoCAi0tN5+ehRx4d4ZhmDgcHly9OyZEmOJCfz34MHHR/umR/2msbgypV5OCiI/XFxTD582LU98+egGjWoHhjI3suX+ThLvsFgQNM0+teuTYWAAHbGxPDNkSOu7Zl19GvQgFK+vmw/d441J09m+6LRNI3XGjXC39OTbWfOsOX06WvyezVujIfFwraICPacPevY7szTNI0XmzbFaDSy/dQpDp8/j8FodOUZjUaeb9wYNI0dJ05w+tKlq/saDFjMZp6sXx80jV0nTnAhLu7q8Y1GPNzdebRmTdA09p44QWxS0tW2GQx4eXhQt0oVMBjYf/IkSamp2er39vSkWsWKoGkcioggLSMjW76Plxfly5YFTeNYZCQ2uz37/l5eBJcqBZpGxNmz6CKOfGcZb29vigcEgKZx7sIFgKv5BgOenp74+voiwOUrV67Jd3d3x8PDA12EpORkcB438/huFgtmNzcExwmeK98ZMDaaTBiMRseICOdn3v0cTL6fghuZ1MiNa3Xu3JnVq1dz9uxZ4uPjKVu2LJqm0bVrV5YsWQI4OoCenp4YDAaSkpJueDX/Tlu2bBndunXDarXSqlUrfvrpp3x1Zk6ePEmLFi1cozgaNWrEunXrcHd3z3O/PXv20KdPH7Zt28Zjjz3GnDlzqFat2i21/cqVK3Tr1o3Vq1fzyiuv8OGHH2KxXBu+1XWd9u3bs3LlSgD69OnDnDlzbumY4AjUZAY01qxZg9VqJTQ0lE6dOlGvXj2mTZvGtm3bqFy5MuPHj6d9+/ZomsbevXt54YUX+Pvvq+HtWrVq8csvv9zWCIClS5fSs2dP0tPTXVf3vb29mTVrFj179rzleu8UXdcZP34877//vivI0blzZ+bNm+cKcgwZMoT58+ffUpDjwoULjBw5koULFxIYGMi4cePo1asXRqPxptsqIjzzzDOsXr2aLVu2UL9+fVde8+bNWbduHT179mTRokU3Xff1nDlzhtGjR7NixQri4+MBR/Crffv2vPvuu5QpUyZb+aVLl9KtWzfsdjsDBw5k+vTp+TqOzWajZcuWrF+/Hg8PD3777bdcRzjpus6wYcOYPHkybdq04auvvsLb2/v2n2geYmNjadasGSdPnmTt2rXXtGvt2rU88cQTADz55JO0b98eT09PvLy88PLyyvbYx8cHb29v3N3db+rzVNd1tm3bxooVK5g3bx6JiYnXlDGZTJQoUYJq1arRpEkT2rZtS+3atQv9c7tAghuapq3AMQhhMbBIRM5nydt5Oyc1zmDFUaA5cA7YAXQVkQNZyryOI4jymqZpnYH2ItIpr3oL4sRj5+efU9/5wWkE1k2fzqPO4X6FSXSdtLg44s+eRUtMpKTJBPHxLF+zhrhLl4iLjSUhPp7UtDQaFC9Ox9BQbKmpdF+/nnSbjXSbjTSrlXS7nS7+/vTz8yMuOZmakZGk6zppzlEn6cB7OK4qRwLlcmnLNGAQjinwc4uTLwBexjE65eFc8pcCnYBfcVzNzWkV0BpYgeNqbk6bcETYluC4mmvE0bHO/LnF25uabm4ssloZkZzs6Dzj6EQbNY1fy5alnLs7n8bH82FsrGu70WDAqGmsrFGDYu7ufHbhAktjYq7mOdPiRo2wuLnxRUQEv0ZHX80zGjEbjcx4/HEwGll2/Di7Y2JcUVOjwYCnxcLQxx4Do5GfjhzheGwsRqPREV01mfD19KRro0ZgNPLb4cNcSEjAaDI5ktGIr7c3LR56CAwGth07RkJaGobMfJMJXx8falWuDEYjByMiSLfZMJrNGIxGDEYj3j4+hJYpAwYDZ6KjEU3D4Oy0Gd3ccPfwwM/fH4xGEpOTHXlmMwaTCc1gwOjmhtFsviagpSjK/eVWghuappUEMs+kt4tIzJ1vWcFRwY3szpw5Q/ny5Rk4cCBTp06lffv2rFixAnB08DOvSr7//vsMGzaMXr168fHHHxdJW8+dO0ejRo04c+YMJUqUYPPmzVSqVOmG+4kIEyZMYNSoUYgIbm5ufPHFF3To0CHP/XRdZ8GCBQwbNozExESGDBnCqFGj8PLyynebDxw4QLt27YiMjOTDDz/k1VdfzbVcbGws9evX5+TJkwB06tSJpUuX5vs4mRISEvjhhx/45ptvWLNmDRkZGYSGhtKxY0c6depE/fr1XRe6RISVK1cyYsQIDh06RL169Zg0aRLNmzcHYMuWLXTt2pXIyEhX/b1792bu3Lk31UnKyMigbdu2rFmzxrXNYDDw8ssvM2fOnDwDAyLCjh07XCNNSpcuneftLneCrutMnDiRSZMmkZSU5Ljo8PzzzJs3Dx8fn1yDHK+//jrvv/9+voIcu3fvZtCgQWzatImaNWsyffp0Hn/88Ztq4/Tp0xk8eDDTpk1j0KBBru0zZsxg0KBBPPDAA5w4ceK2O7Pp6elMnjyZBQsWkDmq3mw28+ijjzJmzBiaNGmS5/4HDhzgkUceISEhgSZNmvD777/ne4TF22+/zYQJE9A0jSlTpvDGG2/kWm7OnDn079+f2rVr89NPP1G6dOmbe5L5lJiYSIsWLdi7dy+rVq1y/Z9k2rZtG40bN8ZutwOQkpKCh4dHgbQlq759+7r+Jzt37kxsbCwHDhzgwoULrlE14PifCwgIIDw8nEaNGvHUU0/RrFmzAg145HmOcb3JOG6UgMdvdd981v8kjgDHCeBt57Z3gbbOx+445vo4DmwHKtyozoKa7KtNyZLiBaKBNAaR338vkOPcDXS7XeypqSLx8WKNipIz27fLid9/v5rWrZMru3eLHD8u6QcPyrFff82e1q6VuF27RI4elZS//pIjP/98Na1eLUdWr5aEnTtFDh2S5L175divv8rJDRskYvNmObN9u5zbtUvSIiJEYmIkPSpKrkRESMLZs5IUHS0ply9LemKi2NPTRfK5FrmiKIpy53HzE4p2wjEw7TPgcxyrpXS4mTqKOqkJRbN76623xGAwyKlTpyQ9PV1MJpNomiYtWrTIVi4oKEg0TZP4+PgiaqmD3W6X559/XnAuYfrRRx/le9/IyMhsK6rUq/f/7J15WFTVG8e/584GDAz7JrhD7qaSuWuumaam4pJpaVSGZWqaGv5yKzXXTMvM1NLMxKWy1Fyzcl8wzQ13TEWUfYfZ3t8fA1fAAWaGWVDP53nOM8O995zzzjAD53zvuzxjUvnV+/fv04gRIwgAVatWjX755RfS6/Xl9tuyZQsplUoKCAiggwcPlnrd0aNHycXFpZhd5pCenk7r1q2j3r17i0kKq1atSu+//z4dPXq0XFu1Wi19++23YonXLl26FKtasWPHDvL09BTtk8lk9MMPP5hk2/79+8nV1bVYssTmzZs/VI61JAkJCTR37lx66qmnHkqg6u/vEjzbIQAAIABJREFUT2FhYdSnTx965513aM6cOfT999/T/v376cqVK5STk2OSbeWh0+lo1qxZov0SiYQGDx4sfgfy8/Pp3XffLZZ41NQSxnq9njZu3CiWVe7bty9du3bNJLuOHz9OMpmM+vTpU+x3e+7cORIEgWQyWYXLNG/atInCwsLEajOMMWrYsCGtXLmy3Oo3JcnIyKDQ0FCxAo45ZZd37Nghvr99+vQpde5t27aRUqmkatWq0blz58yyzxRycnKoY8eOJJFIxKTLRTl37hzJZDLxc1qjRg2r21AW3377rfi7mjx5snj81q1btHTpUurXr5+YiLXo9wkAubu7U9OmTSnTBtVDy1pjOHwxYM9mq4XHye+/JyVAnzVpQhqASCIhnQ2zF3M4HA6HU5mxQNw4A8CvyM++AM6YM4ajGxc3HpCZmUkeHh4UHh5ORA8qFgCgXbt2idft3LmTAIhlYisDa9euFaup9O7d2+QNl16vFyt6oKCiyoQJE0zqf+DAAWrYsCEBoBdffJGuX79u9DqdTkdTpkwhANSiRQu6fft2qWMuWbKkWLWSgIAAkyrDZGRk0A8//EB9+vQhhUJBACg4OJjGjRtHR44cMXsDSkSUm5tLn332Gfn4+BAA6t+/P128eFE8v2bNGnEuAOTl5UWXLl0q9T149dVXi22ivL29aceOHaXOr9Vqafv27dS3b1/xd9uuXTv67rvvaNeuXbRq1SqaMWMGvfnmm2LFk6KiS8m5nn76aerRowe99dZbNHPmTFq9ejXt3r2bLly4QBkZGSa/LzqdjmbPni1Wc5FIJDRo0KBiIseoUaPETbiTkxMtXLjQpLFzcnJo1qxZpFQqSS6X06RJk8oUEFNTU6lGjRpUrVo1Sk5OFo9rNBry9vYmABQdHW3S3BcvXqR33nmH/vjjD9Lr9XTmzBnq3bt3sQ1wYGAgTZw40az3yxg6nY5eeukl8f0pS+wrya1btygwMJAAUGhoaKkVgGJiYiggIIDc3d1p3759FbK3KGq1mnr27EmMMVq3bt1D569fvy6+Z4XC65gxY6w2v6nExMSQUqkkANS5c+dS/wakpqbS999/T8OGDaMGDRqQq6srSaVSm9jExQ07LDzSX3iByMODaNUq+gsgN4D2zZ9vs/k4HA6Hw6msWCBunC3xs1DymD0bDCmMNgL4ylQPEi5uPOCLL74gAHTo0CEiIlKpVGLpyqJ3hBs1akQA6MyZM44y1ShxcXHipicgIKBUsaEkOp2O+vfvL3ohACAfHx/au3dvuX3VajUtWLCAlEolOTs706xZsygvL088n5qaSj179iQAFBERUexcSRvCw8MJBaVICzd98fHxpc6dkZFB69evp5deekkUGYKCgmjs2LF0+PBhiwQNY6Snp9O0adPI1dWVBEGgiIgI+u+//8TzU6dOFe8SA6D69esX23CePXu2mOggkUjoo48+KtW+Gzdu0EcffURBQUEEgPz8/GjixIkUGxtrkr1ZWVl06dIl2rdvH61Zs4ZmzZpFkZGR1KtXL2rWrBn5+fkZFUCqVKlCMTExJr8vOp2OPv3002Iix8CBAyktLY2IDCJHZGQkSSQSURjYb6KX+J07d0TRzd/fn1auXElarbbYNXq9nvr160dSqZSOHDlS7Fy3bt0IAA0ZMsSk+ZKSkqhmzZrFfkeFz5VKJQ0YMMDk998cCssbM8boyy+/NLmfRqOhtm3biqLazZs3jV538+ZNatCgAUmlUvruu+8qbK9WqxUFi+XLlz90/u7du6Jnz5w5c+jZZ58lAKXaZ2tSUlJE77SqVavS/fv3Tepnrb8dJeHihj0WHqdOkR6g62PH0qZx44gBJAFo77x5tpuTw+FwOJxKiAXixnwAu2Ao5jMcwO8A5pkzRpGxVgO4D+BciePdAVyCIZx1cjljjAfQruD5r6bMy8UNAzqdjkJDQ6l58+ak1+vp+++/Fzc3a9euFa+Li4sjAFS7dm0HWls6Re8IS6VSWrNmjUn9cnJyqFWrVqRQKKhdu3bia3/uuecoNTW13P63bt0SxYk6derQ3r176fz58xQaGkpSqZSWLVtWajhIamoqhYSEiB4GEomEGGOiyFSUzMxM+vHHH6lv377i3eEqVarQmDFj6NChQzbblBAZwnHGjh1LcrmcFAoFjR8/npKSksTzhe97YXvxxRfp3XffLXasa9eu4ua/KHl5eRQdHU1du3YlxhgJgkA9evSgLVu2mOS5Yi55eXl0/fp1+vvvv2n9+vU0b948qlq1KgUHB5sVJkFk+MzNnTtXFDkEQaABAwaIn5vk5GTq3Lmz+B60aNGi3DCcQo4fP06tW7cmANS0aVP6+++/xXNLly4lADS/xE3ZwuNVq1Y16fOg0WioVatWxTyGCptcLqfXX3+9WFiStdmxY4coKg4fPtysvoXhYQqFgo4ePWr0mrS0NPH9nzZtmkkhZMbQ6/X0xhtvEACaZ2SfmJqaKop4EydOJL1eT3K5nLy8vCyaz1rodDp64YUXCAA5OzuX+j7ZA5uIGzAUTegJQLB0DHs3Wy88JoWEkAdjlBoXR5vef58YQAJAu+fMsem8HA6Hw+FUJswVNwxd0A/AooLW19z+RcZpD6BZUXEDhpzS1wDUgqFa8JkC74xGALaVaH4F7csC0eWQKfNyccPAb7/9RgBo/fr1RETiXdzAwEBSq9XidS+++GKx6yor33zzjXj3ecCAASZt8hITEykkJIS8vb1py5YtYs4JmUxGs2fPNmneHTt2UK1atcQNl5+fX7ENaUmOHz8uuo63adNG9JZZsWLFQ9deuHBB9GYIDAyk9957jw4ePGhTQcMYcXFxNHz4cBIEgVQqFc2cOVOMz8/OzqY6deo8tEn29fU1ukE+d+4cjR07VgyhqF69Os2cObOYZ4i9OHXqFDk7O1Pbtm0tElR0Oh3NmzdP/B0KgkDh4eGiyBETEyN+NgRBoNdee82kefR6Pf3444/i53HAgAH0888/k1wup549exb7/cfGxop5NkwRUOLi4qhKlSri76lq1aq0YMECUqvVFBMTQ2+++aaY/yUsLIxWrlxZahhIRbh+/Tp5eXmJIk5pHk7GmDt3rvielvZ3KT8/n4YPH04A6NVXXzX796vX6+n9998nAPS///3vofPZ2dkUEBBAAGjkyJFERLRr1y5CQThXZWDq1Kni+2TM68Qe2Erc6AJD6ddrAD4FUMfSsezVbL3wOLV+PQGg6c89R0REmydMEAWOfZ9+atO5ORwOh8OpLFjguTHXlGNmjFejhLjRCsCuIj9/COBDE8aRANhaxvm3AJwEcLJatWo2eCcfPTp16kRBQUHipqZws7NgwQLxmtzcXJJIJOTu7u5AS03n8uXL5OvrK27aTNnsXblyhXx8fKh27dp0//59mjNnjnhXuWrVqnTixIlyx8jJyaFp06ZR7969y5zzyy+/FO+WT5w4UUyWOWrUqIeu/eeff8jX15f8/f1p7969dhc0jHHu3DnRW8PPz4+WLFkibkpPnTpF7u7uJJVKi32GiAzeJytXrqSWLVuK4tGAAQNo9+7dDn9dGzZsIAD01ltvWXyHX6fT0YIFC4qJHO3ataOTJ08SEdHq1avF0AVnZ2daunSpSeNmZ2fTjBkzRLEhODi4mOeMRqMRP+/liY937twp5k2iVCqNJsYkMng+LF26lOrXr0+AIeHke++9RxcuXDDxHTGNnJwcatKkiejBFBcXZ3LfzZs3i2Lm9OnTjV6j1+tp5syZBIA6duxokkdWITNmzCAANHr06Ic+FxqNRkwEO2jQIPF4oRD8119/mTyPrdm6dasY9hYREWH3+W0ibtCDf+zuAN4GcAvAYQAjAMgqOq4tmj3uqrwUGEjuAKUWfJF++uAD8gMoDiDaudPm83M4HA6H42gsEDdOGTn2rzljlOhbUtwIB7CyyM/DAHxRTv8VBTdx2poyJ/fcIDpz5owYI05E1KZNGwJALi4uxZIZTpgwQdyIPypotVrRJVsmk9GGDRvK7XP48GFycnKili1bUk5ODqWnpxfbCPbp04dyc3MttqlohReZTEZbt26lXr16EQBq27btQ9cfPXqUPDw8qGrVqnT58mWL57UVR44coQ4dOhBgqAqxdu1ao/khjh49Sm+88Ya4sa9Xrx4tXLjQ5DwA9uLDDz8kALRs2bIKjaPX62nhwoXFcnxUq1aNvvrqK9JoNDRq1ChxQx4cHEwHDhwwadxbt27R+PHjH8oPUvg5L7rBLsm9e/fohRdeKBaC0rBhQ5Mruvz11180ePBgUfDr0KEDbdiwwaqhQ4WJZ2UyGe00Yw8WExNDzs7OBIBefvnlUq9bu3YtyWQyql+/vkkCymeffSaGzJQU33Q6HdWrV48A0PPPP1/snEqlIoVCYbFIZiuuXr0qhs+EhYWZ5SVTUWwmbgDwBjCm4K7FrwAGAVgK4M+KjGurZo+Fx+noaEMsVtHM3z/9RMQYJQP019y5NreBw+FwOBxHYqq4ASASwFkA2QD+LdJuAFhnyhiljFshccPMuXoBWBESEmKbN/MRYsSIEeTi4kLJycmUnJwsbnw++OCDYtepVCqSSqU2yYFga5YuXSomvRw2bFi5G44tW7YQY4z69u0rbtT3798v3hl3cnKyaPObnp4uemj4+flRXFwcffTRRwQYkoGW3GQWlk6tXbu2WXey7Y1er6edO3dS06ZNxQ3z1q1bKSkpiRYvXixWlXFxcaHXX3+dDh8+XOk2fYVotVrq2bMnSaVS+vPPP60y5t69e6lZs2aioODs7EwRERF09epVeu6558TjrVu3NqkccUmWL18ufoaMeb+kpKRQnz59xO+2l5cXubu7U61atYp5f5jKvXv3aM6cOWKySn9/f4qKirLaZ7Ro1SBTQ8KIDAk9C7+jzz77bKmizb59+8jd3Z0CAgLK9MZauXKlGFpSciydTkfNmzcnANSqVati5y5duiT+PisjOTk51LhxY4u8ZCqCTcQNAD8DuACDa2dgiXNmx9rao9nrrkq/KlWoniCQruiX/JdfqHpBiMqOGTPsYgeHw+FwOI7ADHHDvUCI+BFA9SLNy5T+ZYxbUtywKCzFxLm4uEFECQkJJJfLKTIykoiIXnnlFQIM1RKKliwtTDDau3dvR5laYc6fPy/G9desWbPcxJGFd2zHjh0rHtPpdDRx4kTxjntoaKjJVSROnDgh5tdo27YtaTQa2rx5s7jpL+nB8Pvvv5OTkxPVr1+/zKoplQmdTkfR0dEUGhoqhmQUbjRXrFhRZlnTykRaWhrVrVuXfHx86MaNG1Yb9+7duzR48GCxug1jjFq3bk2rVq0SQxsEQaA33njDJG8KIkP4lUQiIalU+lBVjoyMDBowYID4e/D09KQlS5ZQ8+bNydXVlc6dO1eh11NYrvfFF18kxhgxxqhnz560bdu2h7x3zOXAgQNi0ty+ffuaLIbl5uaKITTBwcGlhp+cP3+eqlevTi4uLvTrr78+dH7Dhg3EGKPu3bsb9W7o0qULAaBGjRo9JCiNHDmSANDKlStNstlRDB06VPSS+f33320+n63EjR5GjiksHc8ezV7ixt19+ygXIProo2LHf4mKEnNwbC8ljovD4XA4nEcdR9/kMCJuSAFcB1ATDxKKNrDmnE96WMq0adMIAMXGxpJOpyO5XE4oSLpXlMJEiI4qaWgt1Go1derUiQBDJYjS8gwUMmbMGAJAixcvLnb87t274l1bxhi9+uqrZW5Gly1bJm4wCz1izp49SxKJhARBEPMxFLJlyxaSyWTUtGlTSkxMtPDVOg61Wk3ffPMNTZ48udKVDDaVS5cukbu7Oz399NOUlZVl1bF1Oh3Nnz9fTEJZ6HUxcOBAMaeGUqksN/GjTqcjf39/AlCsMlBWVhYNHTpUFOFUKhV99tlnpNfradiwYQSAfv75Z6u+pri4OJoyZYpoT/Xq1Wn27NlmV58pSnx8vPge1alTR0xcWx46nY569OhBAMjNza1UAfLu3bsUFhZGgiDQF198IR7ftm0bSaVSateundEEqv369SMAVKtWLaPf+6CgIGKM2TXkw1KKesl88sknNp3LVuKGsfjYh45VpmbXhUf//qR2c6PsEgmgtkZFkVAocEydaj97OBwOh8OxE44UNwq8QO4C0AC4DSCi4HgPAJdhSIQ+xYrzPfGeG8ePHycfHx/q0aMHERF98skn4kbr33//Fa8rzMnRuHFjR5lqdebPny+KDW+++Wapd4W1Wi317duXGGP0008/PXT+p59+EhNHurq6UnR09EPXDBkyRLw7WiimpKWliaVDi5baJTJ4yUgkEmrVqpVZSQ851uf3338XS7vaKozm77//pubNm4sbTIVCQaGhoeLns3r16nT48GGjfXv37k0AqF+/fkRkKHEbEREhJo1UKpU0Z84c0bNg4cKFBIBm2NAbPT8/n6Kjo6ljx47i537SpEkWv39qtVrMA6RSqej8+fMm9x07dqxow969e41ek5WVJea8GT9+PO3bt4+cnJwoLCzMqKdRYfnZwMBAo7l3UlJSCAA99dRTpr9IB1PUS6ZPnz42S+xrVXEDQACAMAAXATSFodxaMwDPAYg1dzx7NnuKG5lHj1JNgP5nJKHTbx99RAJATgBptmyxm00cDofD4dgDR3tuOKI9iZ4bCQkJ4gI9ICBATExYWI6zS5cuxa5v3749AaDdu3c7wlyb8c8//5CHh4coTIwZM4ZycnIeui47O5tatGhBTk5OdOTIkYfO63Q6evPNN8XNadOmTenWrVuUnp5OdevWJcBQCvX69evi9YW5CsaPH19srK+//poYY9SxY0eT71JzbMu8efMIAM2aNcum8yQmJtKwYcPETWbh57Lwefv27enevXvi9YX5IAIDAykvL49GjRolJvp0dnamadOmFduk7tq1iwRBoP79+9utKs3FixfFULeS3k/m8u6774ohc5s3bza537Jly8SQmdI8YbRarTg+Y4zq169v1GOqsBysl5dXqSFWs2fPJgAUFRVlso2Vgbt371JgYCABoJCQEJuEkFlb3HgNwH4AmQWPhe1XAP3MHc+ezd4Lj/5BQeQGUPLVqw+d2z59Om0GiBgjKseVkcPhcDicRwlLxA0Ycm10KXjuDMDN3DEc0Z5Ezw21Wk0LFy4klUpFMpmMPvjgA3EBu3XrVnETtW/fPrFPamoqMcbIz8/PUWbblNzcXBo4cKC4KZRIJNSjR4+H8izcv3+fateuTT4+PnTVyPqQyFCFoDDWXxAEMbygVatWxZKwdu3alQBQ586di/VftGgRAaCePXsaFVk4jkGv19Mrr7xCjDGjuRmsjU6no8WLF1NQUJD4nSz04hAEgSIjI+nq1askkUhIIpHQ66+/LubwcHJyokmTJj2U7+Ly5cvk4eFBjRo1srtoptPp6KWXXiJBEGjHjh0VGmvNmjXiezF58mST++3evVv8jr///vtGr9Hr9fT555/Tc889R3fu3Hno/McffyyGuRQVmUpSmDzX2BiVHY1GQ+3btycnJyeLEtuWh63CUvpb2tdRzd7ixr9bthAAmtKmjfELtm8nHUDdAPrlww/tahuHw+FwOLbCXHEDwJsATgC4VvBzKIB95ozh6PakeG7s2rVL9CLo3r37QzHohefq1atXzH389ddfJwA0b948e5tsV9RqNUVFRYmeHChIFFjUW+XSpUvk7e1NoaGhZebBWL16tViScty4ccXOFZbTrVGjhnj3XK/X08yZMwkAhYeHP5LVaB53cnJyKCwsjNzc3MwKi6gohw8fplatWhUr3Vq0FYafyOVyGjt2rNH8D+np6VSvXj3y9vYWvYfsTWZmJj399NOkUqnowoULFRrr1KlTYmLeadOmmdwvNjZW9ITp2bOnWd4rS5YsET1iyqoskp+fT4IgkK+vr8ljV0ZsFQ5nbc+NoQWP4wG8X7KZO549myMWHgOCg8kVoKRS6olf+PprEgBiAP30CNV753A4HA6nNCwQN07DkOjznyLHzpozhqPak+K5ce3aNerTpw8BoNq1a9Nvv/32UOx7bGysuFlav369eFyn05GTkxMpFAq7ubFXBn788UeqXbu2+J74+/vTggULSKfT0aFDh0ihUFDr1q3L9K7QaDQP3bldt26dGGqQkpJCRAZhY+LEiYSCJK6mVsjg2J9bt26Rv78/hYSEiL8/e5GSkkIjRowoFrKCglwSb7/9dqmJK3U6HfXq1YskEgn98ccfdrW5JDdv3iQ/Pz+Ly88WJSUlhSQSCXl6eprVLzk5mYKDgwkANWjQwGjOjJKsWbNGFJDKE2Y2bNhAAOiVV14xy64nBWuLGyMLHqcZa+aOZ8/mCHHj7M8/EwNoUQmXwaLs/OSTBwJHiVrwHA6Hw+E8alggbhwrePyn4FEK4F9zxnB0e1w9N7KysmjKlCmkUCjEpIKlbYAKSxr6+PgU21wXlkItWTnlSeH06dPUrl078a65k5MTRURE0Jo1a4gxRuHh4SaLPjExMSQIAkkkEjp79iwRGTae77zzDgGgyMjIJ0pAelQ5dOgQyWQy6tatm0OEKJ1OR19++SU1aNCAhg8fXm740pQpUwgALV261E4Wls3hw4dJLpdThw4dKuyh1LlzZwJQaqLQ0tBoNGKlIz8/vzLDL3755RdijJFUKqXjx4+XO3ZhEtWjR4+aZVNZ6PV60uv1pNPpSKvVklarJY1GQxqNpsLldu2NrcJSfC3t66jmqIXHsS5dSKdUEpXherh7zhxR4NhcIikUh8PhcDiPEhaIG/MARAGIBdAVwM8AZpkzhqPa4+q5odfr6ccffxTvTg4dOpRu375d6vWZmZni5v2zzz4rdi4gIIAYY5ScnGxrsys1KSkp9Nprr4l5DQRBED07SiYENUZSUpKYf2Pjxo1EZNhgDR8+nADQhAkTbFaJg2N9ChN5mvK7dyTR0dEEgCIiIirV5+v7778nlFOlyBROnjxJAKhly5YW9R88eLAYalKYVLko+/btI0EQSBCEYnmISkOv15OTkxM5OzsXe12JiYnUvn17ksvlJJPJSCaTkVQqJalUKuZNEQRBTHpqLPyotKZUKmnPnj0WvX5HUNYagxnOmw9j7DKAOADRAH4iolSLBrIjzzzzDJ08edL+E1+4ADRsCM2ECZDNm1fqZXs+/RQvfPgh3gOwKDoaGDjQfjZyOBwOh2MlGGMxRPSMGdcLACIAdAPAAOwCsJIsXaQ4AIetMWzAmTNnMHr0aBw4cADNmjXDkiVL0KZNmzL7REZGYvny5XByckJiYiJcXV0BAPv370enTp3Qpk0bHDx40B7mV3p0Oh0WLFiAhQsXIjExUTweERGBlStXltqnRo0auH37NqKiojBr1iyo1WoMHToUmzZtwvTp0zF16lQwxuz1MjhWYPTo0fjiiy+wdu1aDBs2zNHmPMTp06fRpk0bNGnSBH/88QcUCoWjTSpGVFQU5syZg8WLF2PMmDEWjxMQEID79+8jIyND/NtlDjNmzMD06dMhkUiwadMm9O3bFwBw4sQJtG7dGjqdDj///DP69OlT7lhHjhxB69at0bFjR/zxxx8AgNu3b6Nbt264ceMGIiMjoVAoxO+6sUdzz61evRpKpRKnT5+GRCIx+/XbmzLXGKWpHqY0AM8CWATgOoBtKMjHUVmbI11GN7dpQ0GMUeLFi2Vel/zTT0QSCRFAx994w07WcTgcDodjPWC+54YSgKTIzxIALuaM4ej2OISlJCUlUWRkJAmCQD4+PrRixQqT3JVTU1PFGP5JkyYVO9e0aVMCYPSOJodo+/btYmUUFOTRmDZt2kPve2EZ3Z49exKRoTrLiy++SABowYIFjjCdYwXUajV17NiRFAoFHTt2zNHmFOP+/ftUvXp1CgoKsknFC2tgrQoqU6dOFb2fLGXdunViBZZ58+bRhQsXSC6XEwBas2aNyeMMGTKkWN6iK1euUPXq1cnNzY3++usvi+0ri0LvHHPsdCRlrTGs8g8dgA+AtQB01hjPVs2RC4/zv/5KDKDJprg8HT5MXxZkLX7Rz490PCkUh8PhcB4hLBA3jgJwLfKzK4DD5ozh6PYoixsajYa+/PJL8vT0JIlEQu+9955JiQ51Oh1FRUWJlRYEQaD4+Hjx/K1btwgAVa9e3YbWPx6cOXOGVCpVsQSPgwcPpvv379O7775LACg0NJR0Oh1lZmZSp06dCAB99dVXjjadU0ESExOpRo0aVKVKlWLfH0eiVqvFUp4nTpxwtDllYo0KKjk5OSSRSMjLy6tCthw+fFgMOyv8u7hkyRKzxvD29iZBECgnJ4fOnDlD/v7+5O3tTSdPnqyQbWWh0+koLCyMqlWrZlJyVEdjE3EDgArAawB+B3AZwFwAYZaOZ4/m6IXHy9WrkxKg+yZ88e6dO0dBBepfiFRK6bdu2cFCDofD4XAqjgXixmlTjlXGhkc858aff/5JjRs3JgDUqVMnMUlleWzfvp28vb3F7P9SqZRef/31Ytf07duXANDq1attYfpjx71796hGjRpivD0AMXZepVJRRkYGpaamUuvWrUkQhEfmLiunfM6cOUMuLi7UsmXLUhP22pPIyEgCQOvWrXO0KSZx8+ZN8vf3r1AFlULvqIpWg7l58yZ5eXkRAJoxY4ZZfa9du0YAqH79+nTkyBHy8PCgoKCgCpe9NYW9e/cSAFq0aJHN56oothI3bgD4DEArS8ewd3O0uHFh2zZiAE169lmTrtfk5lIHd3cCQG4And2yxcYWcjgcDodTcSwQNw4BaFbk5zAAR8wZw9HN0WsMc/nvv/9o0KBBBICqVatGmzdvNikp361btygsLEz0MOjbty999dVXBKCYW31+fj5JpVJyc3Oz5ct47IiNjSUvLy966qmnaP78+RQUFESurq4UGxtLiYmJ1KxZM5LJZLR582ZHm8qxMps3byYANGLECIcm7ly+fDkBoA8esQqOhV4TllZQOXAD80iBAAAgAElEQVTgAAGg1q1bV9iW/Px8iwSJSZMmEQAaPnw4KZVKCgkJoRs3blTYHlPp2rUreXl5UVpamt3mtARbiRvM0r6OapVh4TGkwHsj7coVk/uMa9aMANBLAFGRuvEcDofD4VRGLBA3mgO4BuAAgIMArlZ2b9CSrTKsMUwhNzeXPv74Y3J2diYnJyeaPn06ZWdnl9tPo9FQRESEGFNep04dOnfuHBERPf/881SzZs1iG7KoqCgCQOPGjbPZa3lcOXDgACkUCmrbtq3oIh4fH08NGjQghUJB27dvd7CFHFtRmPvh888/d8j8f//9N0mlUurevfsjVx6UyJD3AhWooOLj40OCIFB6eroNrCufWrVqiWFpjRo1snuuk5iYGAJAUVFRdp3XXKwqbgBYXPD4G4BfSzZzx7NnqwwLj2t79tBxxojMTFizd/Jk0jFGBNDViAgbWcfhcDgcTsUxV9wwdIEMQMOCJjO3v6NbZVhjmMJbb71FACg8PJzi4uJM6rN69WpSKpViwsui4RCJiYkkkUgeSiTq4eFBEonkkYjfroxs2LCBANDAgQPpxo0bFBISQkqlssIu85zKjU6noz59+pBEIqG9e/fade6bN2+Sr68vhYaGUmpqql3ntiYffvghAaDFixeb3bfQc6Lk3zN7kJycLHrEtWzZ0qS8R7Zg8ODB5OzsXGnyvxjD2uJGWMFjB2PN3PHs2SrNwmPoUCJnZ9InJJjX78wZOuDkRAygTh4ePNEoh8PhcColFoobrQEMAfBqYTN3DEe2SrPGKIdu3bpR8+bNTbr27NmzFBoaKiYLHTlyJGlKrD2+/vprAkCnTp0Sj23atIkA0AsvvGBV25805s2bRwDI2dmZ3N3d6fDhw442iWMHMjIyqEGDBuTl5UXXrl2zy5zZ2dnUtGlTUqlUdLGcyo6VnYpUUElNTSXGGHl5edk9NCg8PJwAUJUqVSgzM9Oucxfl6tWrJJVKaeTIkQ6zoTzKWmMIMBMiiil42oSI/iraADQxd7wnEfrf//BWbi6ievc2r2Pjxmh48SJqSqX4Iy0NNZyckHTpkm2M5HA4HA7HTjDGvgewAEBbGEJUmgMwXsO+ksEY68UYW5Genu5oU0xGIpGUeT4rKwt9+vRBo0aNcOXKFTz77LO4desWli9fDqlUWuza6OhohISEoEmTB0vAqKgoAMDSpUutb/wTxIQJEzB27Fh4enpi//79aNWqlaNN4tgBNzc3bN26FUSEPn36IDMz06bzEREiIiJw+vRprF+/HnXr1rXpfLZGEAR8//33aNSoEQYPHoyLFy+a3NfDwwMtWrRASkoK/vzzT9sZWQQiwsyZM7F582YAhr+prq6udpnbGLVr18bIkSOxcuVKXL582WF2WExpqkd5DcApI8f+sXQ8e7TKdFdlWK1a5AxQwr//mt1Xp9FQD19fAkAuAB3/9lvrG8jhcDgcjoXA/JwbF/EI5vIq2irTGqMsunXrRi3LKEs/e/ZsksvlBIB8fX1p586dpV6bkJBAgiDQlClTxGPnz58Xs/1zrINOp3O0CRwHsGfPHhIEgfr27WvTz8CcOXMIAM2ZM8dmczgCSyuo7Ny5kwBQmzZtbGidAZ1OR2PHjhUrIzk7O1eK73tCQgIplUoKDw93tClGKWuNYbbnBmPsZcbYbwBqMsZ+LdL2A0ixgt7yRPC/r75CPoB5I0aY3VeQSrH9/n181K4dcgCMGDECWLXK6jZyOBwOh2MnzgEIcLQRTzJ//vknAgMDERUVBSLCtGnTcP/+fTz//POl9tmyZQv0ej0GDRokHhs9ejQAYO7cuTa3+UlBEMxernMeA7p06YKFCxfi559/xscff2zVsYkIarUaW7duRVRUFAYPHoxJkyZZdQ5HU61aNfzyyy+4c+cO+vfvD7VabVK/bt26wd3dHYcPH0ZKiu22tlqtFhEREVi8eDF69eoFIkK7du0qxffd398f48ePx+bNm3H8+HFHm2MWzCB+mNGBseoAagKYA2BykVOZAP4lIq31zLMuzzzzDJ08edLRZoi8Vrs2Nl2/jutnziCgcWOLxtjx0Ud4dvZs+Oj1SHrtNfh89511jeRwOBwOx0wYYzFEZHJYScENkiYAjgPILzxORGbGbzqOyrbGKI1u3bohMzMTR44cAQAkJCSgf//+OHz4MACge/fuiI6OhkqlKnesDh06IDExEefPnwdjDFlZWXB3d4eXlxcSExNt+jo4nCcBIsKIESOwZs0azJo1C76+vsjLy0Nubm6FHwv3gE2bNsXBgwfh4uLi4FdrG3744QcMHToUb775Jr7++mswxsrtM3bsWHz++ef48MMPMXv2bKvblJ+fjyFDhuCnn37C9OnTcfz4cezYsQObNm1CeHi41eezhIyMDISEhKBhw4bYt2+fSe+bvShrjWG2uPEoU9kWHlf37UPdLl0wplkzLIyJKb9DaVy6hPjmzVErMxNNlUocSEqC1MnJeoZyOBwOh2MGFogbHYwdJ0M+L5vDGKsFYAoAdyIKLzimBLAMgBrAn0T0Q1ljVLY1Rml069YNWVlZOHjwIMaMGYNly5ZBr9ejZs2a2Lx5M5o1a2bSOPHx8QgODsa0adMwbdo0AEBkZCSWL1+OTz75BFOmTLHly+Bwnhjy8vLQqVMnUZAsikwmg7OzM5ycnCx6VCqVGDJkCHx9fR3wyuzHlClTMHv2bCxevBhjxowp9/qEhAQEBgbC09MTycnJVt3YZ2dno2/fvtizZw8WL16M0aNHw83NDXl5eUhPT3dovo2SLFmyBGPGjMHOnTvL9OKzN1YVNxhjB4moLWMsE4ZyNeIpAERE5Uv9DqIyLjzWtmuH506cQLUbN4DAQIvHyUpIQPPq1RGrVsOfMZw6eRJVTFygcDgcDucRR68HtFqoMzKQlpgIdVYWNLm5yMvIgCYvDzV8fKCSyRB/9y7OxMZCk58PdU4Ouj3zDFQvv2x1c8wVNwr6VAcQSkR7GWMuACREVG4mPcbYagAvArhPRA2LHO8O4HMAEgAriehTE8baXETcGAYgjYh+Y4xFE9GgsvpWxjWGMbp164a4uDjcu3cPGRkZcHZ2xsKFCxEZGWnWOJ9//jnGjh2Lixcvom7dutDr9XBzc4NWq0Vubm6lcK3mcB4XtFot4uLiiokTTk5O5SYH5hjQ6/UIDw/H1q1bsW3bNrzwwgvl9mnWrBn++ecf7NmzB126dLGKHampqejZsyeOHTuGVatWYfjw4Th27BhatmyJxo0b48yZM1aZx1rk5+ejXr16UKlUOHXqVKX5u17WGkNq7GBZEFHbgke3ihrGAV797jugTh1g7lxg8WKLx3ENCMD57GwMqlkTm2/fRq2wMOxevBjtTVAnORwO55FHrwfUaiAnBwn//YfctDTkpKcjPzMTuVlZcJdK0bBKFSA3F5sPHEB2VhbycnOhzs+HOj8fIR4e6BMSAqjVmLhnDzRaLdRqNTRaLTRaLVp5eeGtGjWQk5eHQceOQavXG5pOB61ej54eHpjs54fbubnoce0atETQE0FX0F5xccHHKhVO5+Whe0oK9AB0MNwh0BNhpEyGuXI5fler0U+jQWGxe33B4/sA5gkCVuj1eBvF7ywAwIcAZsMQLzrdyNszD8AHAOYCWFLk+HYAPWwgbpgLY+xNAG8B8AJQG0AQgOUAOpvQ/TsAXwBYW2Q8CYAvAXQFcBvACcbYrzAIHXNK9H+diO4bGTcYwNmC5zpTX0tl5+zZs0hISABjDK+++iq++eYbyOVys8eJjo5G48aNxcoKy5cvR05ODl5++eVKswDmcB4XpFIpQkJCHG3GI4sgCFi7di3atWuHwYMH4+jRo6hXr16ZfaZMmYLw8HBMnz7dKuJGQkICnn/+ecTGxmLTpk3o168fAGD16tUAgFdeeaXCc1gbhUKBjz/+GEOHDsWGDRswZMgQR5tULhaHpTDGagO4TUT5jLHnADQGsJaI0qxon1WprHdVLvbrhw+2bsU3J08isGnTCo83r0cPTP79d3gBSFq8GOACB4fDMYI6KwtZ9+8jJzkZuWlpqO3rCyE3F+cvXsSNmzeRl5WFvJwc5GVnQ5Ofj8hnnwVyc/FjTAz+uXMH+Wq1oWk0kBLhmyZNAI0GE8+exam0NGgKNv8aIqgYw96aNQGtFi/evImLajW0hZt/AL6M4V93d0CvR730dNwigh4PNvf+AP6TSAAiuOv1KOk66AOgMMJfiod3okEw7HABQMDD4kAIgCsFz405nzYGcAZAGgBPI+fbAjhQMEadIuMUtgGMYb1MhpMA2qvVEAqOCwAExvC2QoE5rq44qNViYEaGeFwCQMIYxnt6ItLbG3/m5WFMQgIkjD1ogoBJVauid0AA/kxPx7ybNyERBMgkEkgkEsgEAeMaNEDzgAAcSknB+mvXIJVKIZdKMaZ9ewQvXGjkFVUMC8JSTgN4FsAxImpacOwsETUysX8NANsKPTcYY60ATCei5wt+/hAAiKiksFFynJKeG6lEtI0xtoGIBpfVt7KuMUoil8uh1Wpx7do11KxZ06Ix/vvvP1SvXh2zZs0Sy74GBwcjPj4eCQkJ8PPzs6bJHA6HYxVu3bqF5s2bQ6lU4vjx4/D29i71Wq1WCw8PD+Tk5ODu3bvw9/e3eN6bN2+iS5cuiI+Pxy+//IKuXbuK5wICAnDv3j3ExcWhevXqFs9hK/R6PZo1a4aMjAzExsZaJIZbG5vk3ChYiDwDoAaAHQC2AmhARD0stLNwXC8A0QXjxgEYSESpJa5pAuArACoY1rCziCi6vLEr68Lj+v79eKpTJ7zz9NP4/PRpq4y559NPofroI7TQapEzaBBcNmywyrgcDqcM9HogLw95SUm4GxeH7KQkZCYlISc9HdlpaXgmOBhVnJxw8epVbDt9WkzslZefj7z8fLwTEoIGLi749cYNrLh2DWqdDvlaLTR6PdR6PVZUqYJmMhnm3b+P5Wlp0ALFBII/lEo0Zgyv5+TgR52umDhAAC7DcEu8HYCDRsxPh+GPamM8uF1dlML/FiEArpU4xwrmAgy3u++UOC8HkF8Qs1qTCLfxYHPPAPgwhltKJSAIaJKdjdt6vbixlzCGmlIp/g4OBiQSdLl9G/f1esgKNvYyxlBfqcQ3DRsCUileO3cOmXo95FIppBIJZFIpnvb1xdiwMEAux8zjx6EXBMjkcjg5OUGuUOCpKlXwfNOmgFyOLf/8A5lCAYWLCxRKJRSurqhSpQqq16wJvVyOhPR0OKlUcPLwgNzVlec4MoIF4sYxImrBGPuHiJoyxqQwlJw3Kdu2EXEjHEB3Inqj4OdhAFoQ0bul9PcGMAsGT4+VRDSnIOfGFwDyABw0lnODMfYWDB4nqFatWtjNmzdNfckOQyaTQa/XQ6ez3BllwYIF+OCDD3Dp0iVs2rQJn3/+ORITE9GiRQscPXrUitZyOByOdTl69Ciee+45tGzZErt37y5zsz5y5EisWLECkydPxpw5ZWrjpRIbG4uuXbsiKysLO3bsQKtWrcRzV69eRWhoKAIDAxEfH2/R+PZg165d6N69O5YsWSJWxHIkthI3ThFRM8bYBwDyiGhp4aKkgsbOA5BCRJ8yxiYD8CSiSSWueQqG/B5XGGNVAMQAqFee10hlFTcAIOKpp/DDlSu4duIEgp4xK0y5dG7ehLpZM1RLSYG/kxOO3b0LJw8P64zN4TgYvVaLnKQkZNy5g8x795CZmAhPQUBtlQp5KSlYu28fcrKzkZ2ZieycHOTm5aG9ry/6+vsjPjkZkTExyNNoDAKCTge1Toeh7u4Y6+6Ok5mZ6HfvHrREhgZAR4R3pVLMkkqxUaPBKwXiQaFwAABjAXwGYD6AiUZsng5gGgwhBMaC/5cAGA0gEgZ//JJEAxjIGCKJsBIodvdfAoO40Vwuxwd5eViXnw9pwZ1/GWOQCgJ21ayJakolPk1MxPb0dMgEAXKJBDKJBHKpFN+3bg0XpRJr4+JwMiUFCrkccoUCCoUCzs7O+KB7d0ChwMGbNxGfnQ0XlQrObm5wcnODUqVCk6ZNAaUSWXo9BBcXOHl4QKgECj/H/lggbsyDwTHmVRi+BqMAXCAik7JSVlTcqAiMsV4AeoWEhLx55cqVcq93NNYQN5o0aYL//vsP2dnZUKvVEAQB7du3x5YtW+Dl5WVFazkcDsf6mFpBpVB88PDwQHJystkhd6dOncLzzz8PiUSC3bt3o3GJ6pgff/wxpk6dilGjRuHLL7+0+PXYGiJC586dce7cOVy7dg1ubo7NTmErceMYgMUwZBfvRUQ3GGPniibzsnDcSwCeI6K7jLFAGDKU1ymnzxkA4URU5qqiMosb1//8E3U6dkRk48ZYYsVkMuqsLLT280NMbi68GMPkF15A+KRJqNm+vdXm4DyZ5KWlIeX6daTHxyMtPh4ZiYlQaLV4rlo1ICsLy/buxd2UFGTn5CAnNxc5eXmopVBgeq1aQF4eusfEIEmthlqvR36BZ0JTmQw/qVSARgPv1FTkweCaVeiB0BTAiYLnxlJohQE4CSAehjCEkrQH8BeA0wVjlaQ/gM2CgINE6EQECR4IBxLGMNrJCTPd3fG3VovhqamQCgLkBU0mCBgfHIyBwcE4lpODuXFxUMhkUMhkcJLLoVAo8FqTJmhWowYuZWVh940bcHZxgdLdHS5ubnBRqRD29NPwCgxEFmPIYgyufn5w8fGBIDU7PRKH41AsEDcEABEAusGg2e2CwYPCpEWKtcJSKkJlXmMUpSLixsGDBzFq1CicPWvw7XJxccGrr76KefPmOXyxy+FwOOZgagWVBg0a4MKFC9i+fTt69DA9QOHvv/9Gr1694OnpiT179iA0NPSha+rWrYtLly7h8OHDxTw6KiMnTpzAs88+i2nTpmH69OkOtcVW4kZ9AG8DOEJEPzLGasIQQjLXclMBxlgaEXkUPGcwxLuW6m7AGHsWwBoYQmL0Rs4/Mi6jb9Spg3WXL1vXe6OA1596Ct8WuaO0UhAQERiI3/39cdrHB+ETJiC0SPwX59FCnZVlEBpu30Ydd3cgPR1/Hz2K81euID0tDZmZmcjKygI0GnzeuDGQk4P3T5/GibQ05Gq1UOt0yNPr4QrglI8PoNEgLDUVl3Q66PBAYHADUBgj5gogu4QdbgAyCp47Acgvcd4bQFLBcxkALR7kJBAANGQM/zg7AxIJArOyoAMgZQxyxiBjDM8plfimRg1AoUDHS5cglUigkEjgLJfDWS5Hh+BgRDRtCrVCgXmnTsFFqYTS1RWu7u5w9fBA3aeeQp0GDaCVyxGfkwNVYCBcAwJ4WAGHY2XMETcKkn+uJSKLs6kZETekMERidYYhSuoEgCFEdN7SOcqY+7H23CAiLF26FHPnzi3mNv3JJ58gKirKqiUSORwOx14UraBSr149MMbAGIMgCMWeJycnIy4uDkqlEo0aNTJ6nbF+Bw4cQI0aNbBnzx4EBwc/NH9SUhJ8fX3h4uKCjIyMR6LyzYABA/D777/j2rVrFcpBUlFsIm5UBMbYXgABRk5NAbCmqJjBGEslImP521Do2QHgNSIqN8izst9ViTt4ED906ID3IiLgtmKF1ce/8fffiJ49G3+dPIlvZTIEJCWhjVaLwwXnJQD8BAENPDyw6e234TF0KFBOJmFO2eSlpSHpyhWk3LyJlNu3kXr3LjpXqwaVRoM9MTH4/cIFZGZlISsvD5l5echRq7GhVi346XSY+N9/2JiRATUR1ETQFIRH3JXJoCIq9rsrSuE3+ik8SJBo7HxVPEiwWCgwKAFkODkBEgla5ObiGhFkBcKCgjEEy+XYX7cu4OSEt27cQLxWC2e5HEonJzgrFKjl44MPOnYElEpEx8ZCI5fDzdMTbt7eUPn6wjc4GNXr1wc8PAAuKHA4jy0WeG4cBNCJiNQWzPUjgOdgyCt7D8A0IlrFGOsBg4epBMBqIppl7tgmzv9YihtpaWkYP348fvzxR+Tm5oIxhhYtWiA5ORne3t44cuSInSzmcDgc25CdnY3JkycjPj4eRAQigl6vF58TETQaDfbu3Qu9Xo/27dtDLpcXO1/y+sKfg4KCsGzZMvj6+hqde9WqVXjjjTfQs2dPbNu2zc6v3DIuX76M+vXrIzIyEkuXLnWYHbby3GgDQwh5dRiS0zMY8mDUstDOwnFNCkthjKlgEDZmE9FmU8au7OIGAOCtt4A1a4CrV4GqVW0+3c0DB7Bx7lzsP3YM51JTkaDTGZIUwnAnvRWAOEFAPZUK7Rs3Rr/Ro9E4PNzmdtmLrIQEJF+5gsQbN5B86xbSEhLwrK8vaspkOBUbi29OnkRmTg6y8vKQlZ+PbI0Gs3x90UkqxbLERMxMT4caEIUHHYAfYQhvGArgoexzMGTffQFALwDG/pQdB9CcMfQjwjYUhETAkDdBBuCcnx/8XFzwQVoa9ubmwkkqhbNUCmeZDC4KBaI7d4agUmHz7du4kp0Ndw8PqLy8oPLxgVdAANp26AB4eEDt4gKpSsVDHjgcjtWxQNxYC6AegF9RxCmMiBbZwDyb8EisMVC+uBETE4OxY8fi0KFDICIoFAoMHDgQixYtQkpKCurUqYNFixZh3Lhxdracw+FwHMOwYcOwbt06TJo0CZ9+aixrmvm0a9cOBw8exMaNGzFgwACrjGkP3n77baxatQqxsbGoXbu2Q2ywlbgRC2AcDMk8xf+QRJRs0YAPxp0PILlIQlEvIppY4ho5gN8B/EZEi00d+5FYeMTFYUvt2rj8zDP48Ngxh5iQdPo0fP78E9i/H2137sQJtRpFb6WpAKT7+QH16mGVmxuCW7aEQqmEIJFAEAT4enqiTs2agCDg1OXL0BNBkEohCAIEqRRenp4IDgiAHsC127chyGTieSaRQKVSwcPTE9r0dPxz7BhS7txBemIi0pKSkJ6WhjBPT3Ty9UV8QgImHDqEnALRIVejQa5Wi1fd3DDG1RUHMzLQPzkZauBBUkgYMtUthKHczigjr38CDAkhZwH4n5HzcwBMFgR8CmCmXg8pIHo2yBnDN4GB6OrtjR+ys7E6KQkucjlcnZzg6uwMlVKJMe3bo1r16jiflYWrOTnwDAyEV1AQvGrUgFetWjzpK4fDeeSxQNyYZuw4Ec2wnlW24XHw3CAirF69Gh9//DEKw3f9/f0xfvx4jBs3DtICEbww+d2tW7eMullzOBzO48ipU6cQFhYGd3d3JCUliX8TLSU3NxcqlQp6vR6pqalQqVRWstT23L17FyEhIejTpw/Wr1/vEBtsllCUiFpUyDLj43oD2AigGoCbMOTxSGGMPQPgbSJ6gzE2FMC3AIrGzg4nojLrqD4S4gaA0Y0bY9nZszi5fj2avvyyo80BAMSfOoWf5szBvoMHocjMxAatFsjPhwQPyj8WUh2GGr6AwZ2nJHUBXET5SSFvwlAPuCQdAfxRcE1zI+cHAdggkeBvxtBdq4UMD/I2yBnDOE9PjA0Kwim9HpNu34ZSoYCrkxNUSiXcXV0x4Jln0KxBAyQIAs6kpMA7KAi+tWrBt25duPj4lPk+cTgcDsd8caNIPxciyrGFTbbmUVljFBU3srKyEBUVhdWrVyM72+Aw06RJE8yfPx9dunR5qG/Dhg3h6emJAwcO2NtsDofDcSi1a9fG9evX8csvv6BPnz4VGuu3335D79690aRJE/zzzz9WstB+FCZjjYmJQbNmzew+v63EjU9h2Jv+hCJ5A4nolEUD2oFHZeGReuMG6tSujdpKJQ6lplbasAF9QgK+HjcOZ86cgU6nAwHQE+FpT0+MqVcPIMLrhw5BrdM9iEUD0NLLC2NCQ6HX6TDg6FFDKU293vBIhE7e3hhTsybyJBK8dfYsXF1c4OriApVKBTeVCi0bNECLZs2gVioRm5YGj6pV4VWzJq8qweFwOJUECzw3WgFYBcCViKoxxp4GMJKIjDnYVSoeVc+NTp064Y8//oBer4dUKkXv3r3x2WefoVq1akb7nT9/Hg0bNsTSpUvx7rtWr6jL4XA4lZolS5ZgzJgxaNWqFQ4fNpb1znQGDhyITZs2Yf78+ZgwYYKVLLQf6enpqFWrFsLCwrB79267z28rcWO/kcNERJ0sGtAOPCriBgCsefNNDF+5EquGD8fr337raHM4HA6HwzEZC8SNYwDCAfxKRE0LjlW4vLw9eVTWGIIgoHDt5+npidGjRyMqKgoKhaLMflOnTsWsWbNw584dBAQYywnP4XA4jy+pqanw9fWFTqfDtWvXUKuWZWkmdTodPDw8kJWVhatXrzosb0VFWbRoEcaPH489e/YY9fSzJWWtMQRLByWijkZapRU2HjVeXb4cbVUqTFqzBmnXrzvaHA6Hw+FwbAoR3SpxyLRapRyzKBQ2tmzZguTkZMyYMaNcYYOIEB0djQ4dOnBhg8PhPJF4enqid+/eAIBly5ZZPM6xY8eQlZWFKlWqPLLCBgCMGjUK1apVw+TJk6HXl0xS4DgsFjcYY/6MsVWMsd8Lfq7PGIuwnmlPNkwiwbLVq/EZAHcrZeXlcDgcDqeScosx1hoAMcZkjLEJMKRnqvQwxnoxxlakp6c72hSz6NevHxgzlhnrYc6cOYPLly9j0KBBNraKw+FwKi+jR48GAKxYsQJqtdmVywEAGzduBAD079/fanY5AicnJ8ycORMxMTHYvNmkwqV2wWJxA8B3AHYBqFLw82UAYytqEOcBjfr3x9AxY8BWrgQ5qHIKh8PhcDh24G0A7wAIAnAHQJOCnys9RPQbEb3l7u7uaFNsRnR0NCQSySO/GOdwOJyK0KFDBwQGBiIzMxM///yzRWNs2rQJABAeHm5N0xzC0KFD0bBhQ0yZMgUajcbR5gComLjhQ0QbUVAsg4gKK21yrMmMGVitUqFz167QWagQcjgcDodTGWGMzS142pGIXiEifyLyI6KhFS0tz7EOhSEpnTt3hg+vGMbhcJ5gBEHAO+8YdPdFixaZ3fiQZuEAACAASURBVP/SpUuIj4+Hs7MzWrdubW3z7I5EIsGcOXNw9epVrFy50tHmAKiYuJFdULaVAIAx1hLAo+WT+SigUsF52DDsz8zEitdec7Q1HA6Hw+FYkx7MEBvxoaMNsZRHNSzFVE6ePIkbN27wkBQOh8MBMHz4cDDGcPz4ccTGxprVt9Dbo1u3bpA+JhUee/bsiXbt2mHGjBnIyspytDkVEjfeB/ArgNqMsUMA1gIYbRWrOMUY/Pnn6OjhgajoaNw/f97R5nA4HA6HYy12AkgF0JgxlsEYyyz66GjjTOFxD0vZuHEjZDIZ+vbt62hTOBwOx+EEBQWhc+fOAICvvvrKrL4//PADADxWYjFjDHPnzsW9e/ewePFiR5tToWoppwB0ANAawEgADYjoX2sZxnkAEwR8+f33yCbCpJdecrQ5HA6Hw+FYi/8RkQeA7USkIiK3oo+ONu5Jh4iwceNGdOvWDZ6eno42h8PhcCoFhaEpq1atQm5urkl97t27h3PnzkEQBDz//PO2NM/utGrVCi+99BLmzZuHxMREh9pSkWopAwA4E9F5AC8BiGaMNbOaZZxi1HvxRbzfogXWXL2KKxs2ONocDofD4XCswZGCx0fCS+NJ4+jRo/jvv/8eq7uMHA6HU1F69uwJT09PZGdni9VPyuO3334DADRt2hReXl62NM8hzJ49G9nZ2Zg9e7ZD7ahIWMpHRJTJGGsLoDOAVQDM883hmMX/fvkFB3x9ETpnDqDVOtocDofD4XAqipwxNgRAa8ZYv5LN0cY96URHR0Mul6N3796ONoXD4XAqDTKZDBEREQCAJUuWmNRnQ8HN6cdVLK5Xrx5GjBiBZcuWIS4uzmF2VETcKKyM0hPAN0S0HYC84iZxSsM1IABtvvoK+PdfpM2f72hzOBwOh8OpKG8DaAfAA0CvEu1FB9plMo9rQlG9Xo9NmzbhhRdewOOaT4TD4XAs5Y033gAAnDp1CqdPny7z2uzsbPz1118AgF69etncNkcxffp0CIKAqVOnOsyGiogbdxhjXwMYBGAHY0xRwfE4ptCvH76pXx+1oqJwt5wvEofD4XA4lRkiOkhEkQAmEtGIEu11R9tnCo9rQtGDBw8iPj7+sb3LyOFwOBWhTp06aNmyJRhjWL58eZnX7t69G1qtFlWqVEGdOnXsZKH9CQ4OxnvvvYd169bh338dk4qzImLEQAC7ADxPRGnA/9m77/gqq/uB459z90hys0lImDJkioooDlygICC4raM4ClpHW6tVaW2pm1b8aWudFUWqIpUiQ9yA0AIKuFhlDwkkZN2su8f5/XEvFDGElZtLku/79TqvPPd5nvs83xxC8s035zmHTOA3jRKVODilOO/ZZ/EA98nkokIIIZoxpdQF8U23PJZyfJk+fTp2u71F/5VRCCGOxe23347WmqlTp1JbW3vQ82bMmAHAFVdcQWz185brwQcfxOVyMX58clZ4P5bVUrxa65la603x18Va608aLzRxMF2HDOGBc87h7R07+PyZZ5IdjhBCCHG0zo1/PPCRlGbzWEpLFA6HmTFjBsOHDyclJSXZ4QghxHHpyiuvxOFw4PP5ePvtt+s9JxwO75tMdNSoUU0ZXlJkZGQwfvx4Pvjgg32P4jQlpbVu8psmS//+/fXKlSuTHUaj8FVW0qtNG+wGA99WVmJ2OpMdkhBCCAGAUuorrXX/ZMfRlJpLjrH3r4YN5X/z589n8ODBvPvuu1x55ZVNFZoQQjQ748aNY/LkyfTs2ZNVq1b9aGTG4sWLOffcc7Hb7VRVVWGxtPwpKn0+H127dqWwsJBly5Y1+miVhnIMmSOjmbJnZvLX8ePZEgyy/P77kx2OEEIIccSUUr9uqDVhHJ2VUpOVUjMa2tdaTJ8+HafTySWXXJLsUIQQ4rg2duxYotEoa9asYfny5T86PmvWLAAuvvjiVlHYALDb7Tz88MNkZGTQ1JNtS3GjGRvxyCNsGzKEs954A4qKkh2OEEIIcaRS460/8HOgIN5uB045nAsopV5TSpUqpdYcsH+oUmqDUmqzUurBhq6htd6qtb71UPtag1AoxL/+9S8uvfRSHA5HssMRQojjWv/+/enVqxcGg+FHE4tqrXn33XcBuOyyy5IRXtLccsstfPjhh6SnpzfpfaW40czlv/wyRCIsHzMm2aEIIYQQR0Rr/bDW+mGgEDhFa32v1vpe4FSg/WFeZgowdP8dSikj8DwwDOgJ/EQp1VMp1Ucp9f4BLbfRPqEWYP78+VRWVsoqKUIIcRiUUvtGb7z99tu43e59x9atW0dRURFKKYYNG5bEKJtesiZOleJGc9epE9NGjuT0BQv45Mknkx2NEEIIcTTaAMH9Xgfj+w5Ja70YqDxg9wBgc3z0RRB4BxiltV6ttR5xQCttjE+gpfjnP/9JWloaQ4cOPfTJQgghuOGGGzCbzQSDQaZOnbpv/+zZswE45ZRTyMnJSVZ4rYoUN1qAy199la5mM3dNmECgpibZ4QghhBBHaiqwXCn1R6XUH4EviY3IOFoFwM79XhfF99VLKZWllHoJOFkpNf5g++p53zil1Eql1MqysrJjCPf4EAwGee+99xg9ejRWqzXZ4QghRLOQlZXF5Zdfjslk4oUXXtg3YfPeR1KuuOKKZIbXqkhxowWwpqXxt4cfZlMoxFOXX57scIQQQogjorV+HLgZcMfbzVrrJhuOqLWu0FrfrrU+Ye9969tXz/teAR4Gvm4JE8V98sknVFVVySMpQghxhG699VbC4TAbN25k8eLF7N69m2+//RaAESNkZfOmIsWNFuKi8eO5sqCAx+fPZ9u//53scIQQQogjorX+Wmv9l3j75hgvtwtot9/rwvg+0YDp06eTkZHB4MGDkx2KEEI0KxdeeCHt27fHZDLx0ksvMXfuXADy8/Pp3bt3kqNrPaS40YI8M3Mm+Uqx9YEHkh2KEEIIkUwrgK5KqU5KKQtwLTAnETfSWs/VWo9zuVyJuHyT8fv9zJ49m8suu6zVLFcohBCNxWAw7Bu9MWPGDF599VWUUowePTppk2u2RqZkByAaT+GAAWx64gmM48fD+++DDIESQogWRUejhLxeAjU1BGprCdTWkudyYQyH2b1zJzt37iTg9RLweGIffT5Gn3QSxlCI/6xdy1dbtxLw+wkEAgQCAX51zjlkN/PJqJVS04DzgGylVBEwQWs9WSl1F/AxYARe01qvTdD9RwIju3TpkojLN5kPP/yQ2tpaeSRFCCGO0k033cQf//hHwuEwK1euBODSSy9NclSti9o74Ulr0L9/f733C63FCgYJn3QSr5WVcePGjdgzM5MdkRBCtAg6GiVYW4u/qgpfdTX+mhr81dW0TUsjzWSirKSEFatW4fd4CPh8sY9+PyO7daPAbmfV9u288913+OOFBX8wiD8Y5LETT6STycScnTt5avt2AuEw/mgUfySCPxplUXo6nUIh/s/j4b5IhAN/ahcDecAfgEfribsWSAF+DTyz334DsDovj57FxY3eV0qpr7TW/Rv9wsex5pJj7P0L4oH537XXXsv8+fMpLi7GZJK/fQkhxNEYNmwYCxcuJBAIYLPZcLvd2Gy2ZIfVojSUY8hPr5bGYmH5nXdy2913UzR6NI8sXpzsiIQQotGFvF58lZX4qqqwRaO4zGaCNTWs/PZbfDU1+Gpr8dXV4auro1+bNvTNyqKyooJnFy3C5/PhCwTwxwsMPy0o4CKXi42Vldy8di2+cHhfYcEXjfJXm42rolH+7fdzbj2xzAJGEXsOYng9x7sQW6bjv8AkwArYlMJqMGBTilqTCVwujMEgFqORVKsVm8mEzWzGarFgPeMMyMxkQHk5D+3cidVqjTWbDavNRso554DLxfXl5ZxRUYHV4cDqdO5r9p49weHg4VCIhwwGrKmpWNPSMEmy1ShawsgNj8fD3LlzufHGG6WwIYQQx+DWW2/lo48+wmAwcNFFF0lho4nJT7AW6My77uK6SZP407//zY2ffkrXIUOSHZIQojWIRPCUl+OtqMBbWYk3PsLBCXTPyQGvlxkLF1JdVYXX48Hr8eDzeumVns5V7dqB18sNCxZQGwjgCwbxhkJ4w2GudDr5rcNBwOslu7wcHxDZ77YPAk8SG6FwVj1hPQb0jR9/FLABdqVizWDg4lAI8vIwAw6zmUy7HZvZjN1qxWaxUNi7N3TqROdQiCfWrcNmt2Oz27E7ndgcDk7t2xcKCxkYDrOspAR7WhrWlBRsaWlYU1PJysuDtDSutli4xmg8aPcNp/7iyF5nx9vBdI+3g0lt4Jg4elrrucDc/v37j012LEdr3rx5eL1eeSRFCCGO0aWXXkp2djbl5eXySEoSSHGjhZo0axbvn3wyd//kJ3xYWooyyNyxQrR6kQh1e/ZQU1KCJ16A8FRVofx+BnbsCB4Pc5ctY+uuXXg9HjweD16fj1yTiQe7dQOPhztWrGB1TU2s8BCJ4IlE6G8wMNNggECAk4AtB9x2JP+byfFuoOSA4zcajVzlcoHDwdqyMrRSOEymWKHB4SCroAD69MFis/Gz5cux2+3YbbbYR4eD/t26Qa9euCwWPlq/Hnta2v+ay0V227bQpg3tbTaiVutBvx92Aj5toPsKgfENHM8AzmjguEwn1jK1hJEb06dPJy8vj0GDBiU7FCGEaNYsFgtjxozh2Wef5ZJLLkl2OK2OzLnRgv3l8sv51XvvMeO++7jiqaeSHY4Q4jCFvF7q9uyhtqSEurIy6ioqOK1DB5TXy4rvvmPVpk3U1dTgqavD4/EQ9Pt56uSToa6OSatWMa+4GE8oRF0ohCcSwQmsM5kgEGAUP14yohOwNb49BPgsvq0AJ3Cq2cznhYXgdPKzPXvYGgrhsFhwWq04bTZ65uRw39lng8PB62vX4gUcKSk4UlOxp6RQUFDAqf36gd3O1ooKzKmpODIysGdmYktPxyDD4FscmXPj+HXgnBu1tbXk5ubys5/9jOeeey6ZoQkhRIvg8/nYsGED/fr1S3YoLZLMudFK3fn22yzLyyNv6lT44x/B6Ux2SEK0ONFIBE9pKfZwGJPPx54dO1i/bh21lZXUVVVR63ZTV1PDzT17kh6J8PG6dby1bh11Ph+1gQB1wSC1oRCLc3LI9Pn4Q1UVj0YiP7qPB3AAbwF/2W+/EUhTij8XF6NSUvDX1RGJRsmy22mfnk6KzUZWSgpcdBGkpHDb999zic+HIzUVZ1oaTpeL9OxsOO00cDqZ5vdjSEnBkZWFNS3tR6McXj1Ef9x8iOOdD9mjQoimNHfuXPx+vzySIoQQjcRut0thI0mOu+KGUioTmA50BLYDV2ut3Qc5Nw1YB8zSWt/VVDE2FyabjXfmzYOzz4ZHH4WJE5MdkhDHhWg4jKe0lJrdu6ktLaWmtJTOaWlkGwx8v20bc5Yto7amhtqaGmrq6qj1eLi/Uyd6KcXH33/PPdu3UxMOUxuNUgto4EtgADAXqO/B+4tmzybdamWn2cx//H5SjEZSzGZSLRbapqURPfNMyM7m/IoKLOXlpKSmkhovPqRmZGCOTxr5u2CQXxsMpOTk4MzNxZKS8oMCxEPxdjCHGiCZfWRdKUSr19wfS5k+fToFBQWceeaZyQ5FCCGEOCbHXXGD2Nxw87XWE5VSD8ZfP3CQcx8FZDmQhpx1FjXXXceEP/+ZcWefTY8RI5IdkRBHT2uiXi+lW7ZQU1xMdUkJNaWl1JSX0yM9nRMdDvbs3s1T8+dT4/FQ7fFQ7fNR4/dzf0YGo7Xmy8pKBnq9P1pO8x3gGmATsXkhIPYNMk0pUg0Gbo5GoW1b0jMy6O31kmq3k+p0kpaaSmpqKgXnnAPt2jEsGGR+ZSUpWVmkZmeTkpNDal4eaXl5YLXyM+BnDXyK58fbweQcbd8JIRKiOU8oWlVVxUcffcSdd96JQebmEkII0cwdj8WNUcB58e03gM+pp7ihlDoVaAN8BLSq53qPlP+3v2XKtGl8d+ONzK+okMlFRfKEw1BdzdbVq6natYuqkhKq9uyhurycLk4n52RmEigv57aPP6bK46HK56M6GKQ6FOI2i4UHgkFKw2Hy67n0E8Qme/QCLwJpBgMuk4k0sxmX1Yq5XTvo3p32JhMPrV9PWloaaenppGZkkJqZGZsTolMnzrZY2KM1aQUF9T6WcTrwzwY+xYJ4E0KI493s2bMJBoPySIoQQogW4XgsbrTRWhfHt0uIFTB+QCllAJ4GbgAGN3QxpdQ4YBxA+/btGzfSZiK3Vy+euOYa7njnHYbl5nL72LEM//3vMTscyQ5NNDdaQ00NO9eupXzHDty7d+MuKcFdWkqOUowqLISqKn7+ySfsrK6myuejKhikOhxmmFK8Eg4D0BvwHXDpscA5gDktjUUeT6woYbHQLi2NXnY7nbt1g1NOIdPp5IU1a0jLzMSVnU1aTg6uNm0o7NIFOnakU2oqHrP5oJ9CPvBIA5+iFcg9pk4SQrQmzfmxlOnTp9OhQwcGDBiQ7FCEEEKIY5aU4oZS6jMgr55Dv9v/hdZaK6XqW87lDuADrXXR3lm/D0Zr/QrwCsRmMj+6iJu/cW+8QUVZGS8uXMhlEyfy0HPP8egvfwm33gqdZYq/VkVr6oqLqdi2DXdREe5du6gsLsbo8zG6Y0dwu5k4fz7f7t6N2+ul0ufDHQrRHZgXjUIkwjBg7QGXvRAYZTSCy8UGr5dqpUi32eiemorL6WRAhw4QnzdiysaNWF0u0tu0IT0vD1dBAVkdOkDbthiMRrY1EL4F+HmCukYIIY5Uc30spaKigk8//ZR77rmHQ+VSQgghRHOQlOKG1vqgoy2UUnuUUvla62KlVD5QWs9pA4FzlFJ3ACmARSlVp7V+MEEhN3tGi4WHPvuMB/1+Pnz8cXovXQoTJ/LZE0/wp8xMxv70p4x+9FEsKSnJDlUcAW95OZXbtlGxbRvVu3czqLAQKip4b/FilmzYQEV1NRW1tVR6vRjDYRalpIDbzU/CYd4/4FqdgNEARiNfGY2s0poMi4Vsh4OuTic927SBIUMgI4M/ff89IbudjPx8MgoKyGjXjswOHaBNG1CKBYeI++qE9IYQQojD9d577xEOh+WRFCGEEC2G2rvO+fFCKfUUULHfhKKZWuv7Gzj/JqD/4ayW0lzWoG8yRUXM/M1v+PW777IjEiFbKW469VTGPvYY3S6+ONnRtSo6GqV6505S/X6MlZWs/fprln/1FRWlpVRUVFBRVUVlbS1vnXACVreb32/fzqTaWvz7XUMBIWJLg94GvAlkGo1kmc1k2e3kp6by5rBhkJnJB3v2UBKNkpGbS0ZeHhnxkROFPXtCSgrIX/GEEMegoTXoW6rmkmPsHaUxePBgtm3bxqZNm2TkhhBCiGajoRzjeJxzYyLwT6XUrcAO4n/kVUr1B27XWje00IA4EoWFXD5tGqPeeINP//xn/v7iizy7ciVvDx3K94MGYRw3Dn355Si7PdmRNjvBmhpK16+nbMsWynfsoLyoiPKSEq7t0IEcn4/3v/uOp9eto9znozwUojwaJQxsI7YG8lxik2NC7D9plsFAltlMXWEh1s6dOa1NG+6uriYzM5Os3Fwy27Qhq6AAzjsPcnJ4IT2dl53Og8Z3qOVAhRBCtGwLFizgwQcflMKGEEKIFuO4G7mRSM3lryrJVLJqFRuff55B8+cT3rKFk41GLuzTh7F//CO9Ro1KdnjJoTWe0lLKNm4kIxjE5fOxY9063lm4kNKyMsrcbspqaij3evlrWhoDa2uZ7vFwbT2X+g9wVnY2c6xWnqqtJcfpJNvlIjsjg+ycHMZcfDFZnTpRbjJRa7WS3aULKXl5ssKNEKJZaU0jN/abUHTspk2bkh3OIe1fzPjuu+/o27dvEqMRQgghjkxDOYYUN0T9olHKZ8/m7l/9ipnff08QGJiSwrhrruHqiRNxZGcnO8JjEqmro+i77yjbsoXSbdsoKyqidPduzs3MZIDRyMZt27hh5UpKAwHKIhG88fdNBW4kVqQ4B7ADuUYjOVYrOU4nE049ldN79GC7ycSnJSVk5+eT06ED2R07kn3CCWR27oyhgZU8hBCiJWhNxY29mkuOsbe4ceKJJ7Ju3ToZuSGEEKJZaW6PpYjjgcFA9mWXMe2yyyhfv56p99/PKx9/zM2TJ1MwbRpDxowhdPPNmE87Lalh6miUupISKrZupWL7dlyhEF1sNgIlJUycM4eKysrYpJp1dVT4fIyx27nL76fE46FjPdebaDQyoG1bnC4XWQ4HPfLyyMnIIDc3l5y8PM466yzo04fTMzKoc7lw5ta/aGhHYkubCiGEEMeja665RgobQgghWhQpbohDyj7xRH49Zw73RKMsfeklBi5bBq+/zvgXX2SRw8GVgwbhTEnBYDSS6XRy7emng8HAvNWrKfN4MBgMGIxGDAYD2S4XF/XrBwYD89esoTYQwGAwYDSbY8fT0zmtRw9Qio/+/W+Kd+6korSU8vJyKqqqOMlq5a70dKiooNP69eyORAjuF+ttwEvEvrAfAVKBLJOJLKuVbIcDV9eucMYZ5GZm8urmzeQUFJDbqRM5nTuTe+KJpOTlgcFAAfBhA31ijjchhBCiOZJVUoQQQrQ08liKODpuN1PuvpunZ8xgTSCwb3dPYG18+yxg6QFvOx34Ir7dF1h9wPHBwKfx7U7A9vi2mdikmpe7XDzfpw9kZXHvpk2YnU6ysrLIys0lKz+fbj170uPUUyEri3BaGiabrVE+XSGEEIdPHks5fu0drdGa8j8hhBAthzyWIhpfRgY3vfkmY6ZOpXrnTiLBIJFQCEP8GNEo/yopwe/zEQ2HiUYiRMNhLCYT5OdDNMq7W7fi8/mIhMP7zkm126F9e4hGmVdSgj0vj6zOnUnNz//RpJpPHyJE+eIWQghxOJRSnYHfAS6t9ZXxfaOB4UAaMFlr/UkSQxRCCCHEIcjvf+KYKIOB9A4d6j2WV1DQ4Hu79+7d4PGeRx2VEEKI1kIp9RowAijVWvfeb/9Q4C+AEXhVaz3xYNfQWm8FblVKzdhv3yxgllIqA5gESHFDCCGEOI5JcUMIIYQQzdkU4G/EFrQCQCllBJ4HhgBFwAql1BxihY4nD3j/LVrr0gau/1D8WkIIIYQ4jklxQwghhBDNltZ6sVKq4wG7BwCb4yMyUEq9A4zSWj9JbJTHIanY5BQTgQ+11l8f5JxxwDiA9u3bH1X8QgghhGgchkOfIoQQQgjRrBQAO/d7XRTfVy+lVJZS6iXgZKXU+Pjuu4nNc32lUur2+t6ntX5Fa91fa90/JyenkUIXQgghxNGQkRtCCCGEaNW01hXA7Qfs+yvw10O9Vyk1EhjZpUuXBEUnhBBCiMPRqoobX331VblSakcjXzYbKG/ka4oY6dvEkH5NHOnbxJG+TYxE9Wv9M003nV1Au/1eF8b3NTqt9VxgrlLqsuaUY+xdErYVk+8piSN9mxjSr4kjfZsYTZ5jtKrihta60ceMKqVWHmydXXFspG8TQ/o1caRvE0f6NjFacL+uALoqpToRK2pcC1yXyBtKjtG8SN8mjvRtYki/Jo70bWIko19lzg0hhBBCNFtKqWnAMqC7UqpIKXWr1joM3AV8DPwX+KfWem0y4xRCCCFEYrWqkRtCCCGEaFm01j85yP4PgA+aOBwhhBBCJImM3Dh2ryQ7gBZM+jYxpF8TR/o2caRvE0P69fgm/z6JI32bONK3iSH9mjjSt4nR5P2qtNZNfU8hhBBCCCGEEEKIRiMjN4QQQgghhBBCCNGsSXHjGCilhiqlNiilNiulHkx2PC2BUqqdUmqhUmqdUmqtUuqXyY6ppVFKGZVS3yil3k92LC2JUipdKTVDKbVeKfVfpdTAZMfUEiil7ol/L1ijlJqmlLIlO6bmSin1mlKqVCm1Zr99mUqpT5VSm+IfM5IZo/gfyTESQ/KMxJIcIzEkx0gMyTEaz/GSY0hx4ygppYzA88AwoCfwE6VUz+RG1SKEgXu11j2BM4A7pV8b3S+JrR4gGtdfgI+01icCJyF9fMyUUgXAL4D+WuvegJHYkp7i6EwBhh6w70Fgvta6KzA//lokmeQYCSV5RmJJjpEYkmM0MskxGt0UjoMcQ4obR28AsFlrvVVrHQTeAUYlOaZmT2tdrLX+Or5dS+ybd0Fyo2o5lFKFwHDg1WTH0pIopVzAIGAygNY6qLWuSm5ULYYJsCulTIAD2J3keJotrfVioPKA3aOAN+LbbwCjmzQocTCSYySI5BmJIzlGYkiOkVCSYzSS4yXHkOLG0SsAdu73ugj54diolFIdgZOBL5MbSYvyLHA/EE12IC1MJ6AMeD0+HPdVpZQz2UE1d1rrXcAk4HugGKjWWn+S3KhanDZa6+L4dgnQJpnBiH0kx2gCkmc0OskxEkNyjASQHKNJNHmOIcUNcVxSSqUA/wJ+pbWuSXY8LYFSagRQqrX+KtmxtEAm4BTgRa31yYAHGd5/zOLPZo4ilti1BZxKqRuSG1XLpWPLp8kSaqJVkDyjcUmOkVCSYySA5BhNq6lyDCluHL1dQLv9XhfG94ljpJQyE0s43tJaz0x2PC3IWcClSqntxIY4X6CUejO5IbUYRUCR1nrvX/9mEEtExLEZDGzTWpdprUPATODMJMfU0uxRSuUDxD+WJjkeESM5RgJJnpEQkmMkjuQYiSE5RuI1eY4hxY2jtwLoqpTqpJSyEJuAZk6SY2r2lFKK2DOF/9Va/1+y42lJtNbjtdaFWuuOxL5eF2itpULdCLTWJcBOpVT3+K4LgXVJDKml+B44QynliH9vuBCZRK2xzQHGxLfHALOTGIv4H8kxEkTyjMSQHCNxJMdIGMkxEq/JcwxTom/QUmmtw0qpu4CPic2u+5rWem2Sw2oJzgJuBFYrpb6N7/ut1vqDJMYkxOG4G3gr/ovIVuDmJMfT7Gmtv1RKzQC+JrbCwTfAK8mNqvlSSk0DzgOylVJFwARgCfJDyQAAIABJREFUIvBPpdStwA7g6uRFKPaSHCOhJM8QzZHkGI1McozGdbzkGCr2+IsQQgghhBBCCCFE8ySPpQghhBBCCCGEEKJZk+KGEEIIIYQQQgghmjUpbgghhBBCCCGEEKJZk+KGEEIIIYQQQgghmjUpbgghhBBCCCGEEKJZk+KGEKLJKaXSlVJ3xLfbxpfiEkIIIYQ4JpJjCNF6yVKwQogmp5TqCLyvte6d5FCEEEII0YJIjiFE62VKdgBCiFZpInCCUupbYBPQQ2vdWyl1EzAacAJdgUmABbgRCACXaK0rlVInAM8DOYAXGKu1Xt/0n4YQQgghjjOSYwjRSsljKUKIZHgQ2KK17gf85oBjvYHLgdOAxwGv1vpkYBnw0/g5rwB3a61PBe4DXmiSqIUQQghxvJMcQ4hWSkZuCCGONwu11rVArVKqGpgb378a6KuUSgHOBN5VSu19j7XpwxRCCCFEMyM5hhAtmBQ3hBDHm8B+29H9XkeJfc8yAFXxv8gIIYQQQhwuyTGEaMHksRQhRDLUAqlH80atdQ2wTSl1FYCKOakxgxNCCCFEsyU5hhCtlBQ3hBBNTmtdASxRSq0BnjqKS1wP3KqU+g5YC4xqzPiEEEII0TxJjiFE6yVLwQohhBBCCCGEEKJZk5EbQgghhBBCCCGEaNakuCGEEEIIIYQQQohmTYobQgghhBBCCCGEaNakuCGEEEIIIYQQQohmTYobQgghhBBCCCGEaNakuCGEEEIIIYQQQohmTYobQgghhBBCCCGEaNakuCGEEEIIIYQQQohmTYobQgghhBBCCCGEaNakuCGEEEIIIYQQQohmTYobQgghhBBCCCGEaNZMyQ6gKWVnZ+uOHTsmOwwhhBCiRfvqq6/KtdY5yY6jKUmOIYQQQiReQzlGqypudOzYkZUrVyY7DCGEEKJFU0rtSHYMTU1yDCGEECLxGsox5LEUIYQQQgghhBBCNGtS3BBCCCGEOEpKqZFKqVeqq6uTHYoQQgjRqklxQwghhBDiKGmt52qtx7lcrmSHIoQQQrRqrWrODdEArSESIRIM4q+rIxIMEgmFiAQChINBMlNTsRgM1FRVsae0lEgwSDh+jsFopGufPtjy8yElBZRK9mcjhBBCCCFEk9Jas3PnTtq1a4eSfFiIJifFjRbOvXUrn/zlL5yxaxcdVq7kk8pKrq6tJQxE9mufABcC7wI/qec6XwIDgOnAuHqOrwF6AS8YDEzQmgyTiQyLhXSbjQyHg79dcAHZ+fksr6vju+pqMnJyyGjThoyCAtILCujYpw+G9HQwGhPRDUIIIYQQQiTUhAkTePTRRxkwYAD33Xcfl112GSaT/LolRFOR/20tTDQc5ptp0/hwyhQ+XLGCL2priQL/Z7dzz/DhFJrN3PTf/2I0GDAajRiNRkxGIx1POQVycuhXWcmfNmyIHTOZMJlMGE0mOvTvDxkZnF9ezj+2bcNkNseOm81EwmE6dOoEPh8nfvMNV373HVV1dbg9Htx+P9tqajC+/z5UV/NeOMzEeuL2AnaleMhi4a1IhAyzmUybjeyUFLJdLp677DJUdjYrqqtxG41kd+hAVseOZHfpgiMnB2WQJ6yEEEIIIURyvPzyyzz66KMMHTqUTZs2cfXVV9OpUyfuuecebrnlFpxOZ7JDFKLFU1rrZMfQZPr3769b4jJtFZs2UTp7Nj1WraL6ww/JLi8nAvR3OBh66qkMu+EGBowZg9FqTW6gWuMrL6d861aqiopw796Nu7iYqtJSxvTqBW43b37xBR9v3ozb46HS66U8ECAcibA1GgXgGuCfB1y2A7C9bVvIzmZCTQ3rw2GyXS6yMjLIzsmhQ8eOjLroIsjOplRrbPn5pLZtKwURIYRIEKXUV1rr/smOoym11BxDCHFoc+bM4bLLLmPo0KHMnj0bpRSzZ8/mqaee4osvviAjI4M77riDu+66i7y8vGSHK0Sz1lCOIcWNZigaDrPyH//gw6lT+WjlSpbX1XE2sCgzEy6+mI8KCjjlppvI7dUr2aE2nnAY3G6+X72anevXU15URPnu3ZSXlmL0ermvc2eoqOCOL79kgdtNeShEpdZo4GTg6/hlBgAriA1ZylSKTLOZczMyeGnAAMjM5KmtWwlarWRlZ5OZl0dWfj7tu3ena79+kJkpc4oIIcRhkOKGEKK1+OKLL7jgggvo3bs3Cxcu/NEIjaVLlzJp0iRmzZqF2Wzmxhtv5N5776VHjx5JiliI5k2KG3HNOfGo3roV17Jl8OGHXPHuu8wMBlHAAKeTof37M3zMGE776U9lzor9RIJBqnbswFdcTKHJBBUV/Oujj9j+/fdUVFRQWVVFRW0tXY1GnsjIgIoKuhUVsemA/xNXADPi2wVA1GAg02wm02ol0+FgeOfOjDvjDMjI4KU1a0jNzCSjTRvS8/LIKCgg74QTyOjUCWy2pu4CIYRIitZU3FBKjQRGdunSZeymTZuSHY4Qoglt2rSJM888E5fLxdKlS8nNzT3ouRs3buSZZ55hypQp+P1+RowYwX333cegQYNk8lEhjoAUN+KaU3EjEgyyYupUPvzHP/joq6/42uNhD5CZnc2Hffrg7tGDi+6+m+wTT0x2qC2Ov7oa97ZtVGzfTuXOnaSGQpycng4VFfzuvfcoc7uprK2l0uOhwu9nlNnMI5EIQa+X+h78uQ94CqixWOgWDpMen2w1w24n3eHgul69GHHyydTZ7byzcSMZubmkt2lDRn4+rvx88k44AWfbtmA2N3FPCCHE0WlNxY29mlOOIYQ4dnv27OHMM8+kpqaGZcuW0aVLl8N6X1lZGS+88AJ/+9vfKC8vp3///tx3331cccUVMvmoEIdBihtxzSLx2LqVf91+O7d99hkVWqOA01NSGHbaadwxfjzZF14IMlfEcUkHApRt3hybT6SoiKqSEtx79tAtJYVTUlOp3rOH33z8cWyyVa+XKr8fdzDIfVYrt/v9bIhEqK9U9SJwO7DKYuGicJg0oxGX2YzLaiXNbufek07irG7d+B54d8sW0jIycGVl4crOJi03l559++IqLCSSkoIhNVXmGhFCJJwUN4QQLVldXR3nn38+a9euZeHChZx++ulHfA2fz8fUqVN5+umn2bRpEx07dtw3+WhKSkoCohaiZZDiRtzxnHhs+vRTfH/7G33nzaPYYOCBwkKGDR/ORb/4BVlduyY7PJFoWhOuqqJ4wwbcRUW4d+3CXVJCTUUFp+fm0t1mY+v33/Onf/+bGq+Xap+Par+fmmCQp9PSuCgQ4KOaGobVc+mPgIuBmcBVQJpSpBoMpJpMpJpM/L1PH/rk57PU5+PtXbtIdTpJTU0lNS2N1PR0Rg8aRHpeHntCIcqCQVJzc0nNzyc1Px+z3d6k3SSEaB6kuCGEaKnC4TCjRo3io48+Yvbs2YwYMeKYrheNRpk7dy5PPfUUS5YsIT09nZ///Ofcfffd5OfnN1LUQrQcUtyIOx4Tj/++/z6P330307Zv50KDgU9+8Qv4zW+gbdtkhyaamWg4TF1JCdW7dlFTUkJ1SQnVe/ZwWn4+2VqzZsMGpi9fTnVNDbVeL7U+H7V+P8+1a0e3cJh/FBfzq8pKarUmtN91NwDdgEnAbw64pxXYmplJ2/R0XgkEeKOmBqfZTIrVitNmI8Vu55mLLsLmcrG4tJS1bjcpLhfOtDRSMjJwZmRw5hlnoFJTqdUalZKCIzsbgwzLFKJZk+KGEKIl0lozduxYJk+ezMsvv8y4ceMa9frLli3j6aefZubMmZjNZq6//nruvfdeerWkRQKEOEYN5RjyG0SSrJk5k0d/9Sve3bkTO/Dr/v25d/Jk6Ns32aGJZspgMpFWWEhaYWG9x3vH28HcGG8AgZoaaouLqd2zh0KnE/x+Rq1fT/s1a6itqoq1mhpq6+pI79sXfD4s69Zh9/moDQYp9njwRCLURSL8dds28PmYDrxwwD3NQDC+fTfwRnzbATiVosBs5ptu3cDh4OHSUlZ4vTgtFhxWKw67nbbp6fzuggvA6WTuli2UBYM4UlNxulw40tLIbtOGk/r1A4eDCr8fY2oqzpwczA7H0XSxEEIIIVqxRx55hMmTJ/PQQw81emEDYODAgcyYMYPNmzfz7LPP8tprr/H6669zySWXcO2115KdnU16evoPms1mkwlJhYiTkRtN7dtv4dFH+b+ZM5kA3D1wIPdMnkyOLAclWrJoFG95OTUlJdSVlVFXXo6nshJ/TQ0Xdu0KdXV8vGIFq7Zupa6uDo/HQ53XizkS4blevcDr5f61a1lQWYk3HMYTieCNRikAvo1/DzsXWHzAbfdfBrg/8FV82wTYgfMtFmbn54PDwZXFxZREIjjMZuxmM3aLhdPz8rinf3+w23nq228JGY3YHY5Yczrp1qEDA/v1A7ud5du2YXY6saWmYktLw+ZykZadjTMrC6xWWUJYtCoyckMI0dJMnjyZn/3sZ9x000289tprTVJQKC8v58UXX+S5556jrKys3nMsFsuPCh6H21wuF9FoFJ/Ph8/nw+/3/+DjofYd7Hh6ejp/+ctfyMvLS3gfidZHHkuJS2biseKNN3j0gQe4Ys8exrhceO+4A/+tt5J5wglJiUeIFiMaBb8f965d1JSW4nW78brdeKqqsITDnNG+PXi9/HPxYnaVleGpq8Pr9eLz++los/HLLl3A5+OWL75ge10dvnA41iIRzrVYeMVuB6+XXK+XA9OKG4Gp8W0bEDjg+M+JjVaJACnxc2wGw742Ljube9q3p85s5ur167GZTNgsln1tVPfuXHziidRozUvffovVZsNqs2Gz27E6HPTv3p2unTrhiUb5ZudOrE4ntpQUrCkp2FJTyc7Lw5GZSdRsBqtVHvcRTUaKG0KIluSDDz7g0ksvZciQIcyZMwfzQVawe+utt7jnnnsYMWIEzz77LGlpaY1y/0AgwNatW6murqaqquqgrb7jfr+/UWI4kNFoxG63Y7fbsdlsP9hevXo1hYWFLFiwgIKCgoTcX7ReUtyIS0biseyVV3j0oYf4sKyMDKWYOHIk4954A9LTmzQOIcSx0dEowbo6fG433spKfFVV2LWmbWoq+Hx8/O9/46urw+/x4Pd68Xu99MjM5NyCAkIeDw99+in+QCDWgkH8wSCX5uRwfXY2lbW1DF29Gl84jD8a3dd+azZzTyTClkiE+haY+xtwJ7AKOKme468DNwFLgLOJPQZkBaxKYVWKV3NyGJaezrJwmF+WlGA1GrEYjbGPJhMP9+nDSW3a8FVNDa9t2YLFYsFqsez7eNMZZ1CQk8MGt5sl33+P1WbDsl8755RTSHG5KKmtZbfbjcXhiDWnE4vDQZuCAow2G2GDAWW1YrRYEvOPJ5pccy9uKKXaA38FKoGNWuuJh3qPFDeESAytNeFw+KAFhURbsWIF5513HieeeCKLFi066Eomn3/+ORdccAF7f7cyGAwMHjyYl156iU6dOjVlyD/g9/sbLIoYjcYfFSfqK1gcuN3QsrVLlixh2LBh5ObmsmDBAtq3b9+En7Fo6aS4Edekicfixdx1/fU8X1REtlLce9FF3PHqqwedD0EIIQ5Gh8N43W4CNTUEamsJ1NURqK0lx+kk02aj1u3mi2++IRAvqgS8Xvw+H4M6dqRrWho7SkqYsnw5/kCAQCBAIBgkEAxyZ5cunJySwoqSEv6wbh3BSIRAOEwwGiUQifD3Nm0YYDAwq7qasW43Qa0J8L8RKiuIPe7zCnBbPXH/FzgR+D/g3nqO7wQKgUeACYABsBArwliUYmtuLmk2G3+uq+ONujrMSmE2GGLNaGRh//4YLBZe3rWLzyoqMJtMmI1GzCYTKVYrz55/PpjN/HPzZtZUVmI2m7FYLJgtFlxOJ7cOGgRmM59v3kxxbS0miwWz1YrZYiEtLY1zTj4ZTCbWFRXhDYcxW62YbDbMNhvO1FQK2rUDs5lqrxdMJswOR+y4w9Hql1xOZnFDKfUaMAIo1Vr33m//UOAvgBF4taGChVJqOJChtX5TKTVda33Noe4rxQ0hGl9VVRVXXXUVK1as4De/+Q2//OUvm3SZ1C1btjBw4ECcTifLli076GMWGzZsoE+fPoTDYd5//31WrVrFpEmTqKioAKBfv34899xznH322U0We7J9+eWXXHzxxaSnp7Nw4cKkFnhEy9IsixuHSkKUUlZiI8JPBSqAa7TW2xu6ZqITDx2NsvCZZzj1vfdwLVnC3PR0Npx9Nre/+iopbdok7L5CCNGUdDRK2O/HGA5jCIfxuN2Ul5QQqKsj6PUS8vkI+nz07dABu1Js3bGDNVu2EPT7Yy0QIOj3c8Mpp+AAFm/YwKLNmwkGg7EWChEMhfi/AQOwRiJMXb+eOUVFhCKRfS0cibCwZ08IhXh4506mu92EtCYUjRLSGhuwJTUVQiGu9/l4+4CfdW2BXfHt4cAHB3yO3YH18e365nM5Fdj70+QU4JsDjp8PLLBYwGymv9/P9mgUk1KYAJNSXOR08krbtmAyMWT7dqqiUUwGA6Z48WZIdjbju3UDk4nrv/mGMMSOG40YjUbOLyjgxh490AYDv166FJPRiMlkih03mTirY0eGdO9OEHj+yy8xmUwYTabYOWYzp3TqRL8TTgCnE0aPPqqvg4YkubgxCKgDpu4tbiiljMBGYAhQRKw29xNiOcaTB1ziFmJPk80ANPAPrfXrh7qvFDeEaFzbtm1j+PDhbN68mbPPPpuFCxeSk5PDb3/7W26//XZsNltC719WVsaZZ56J2+1myZIldO/evd7zysvL6dSpE3V1dbz00kvcdtv/yv0zZszggQceYOvWrQC0a9eOxx57jJ/+9KcJjf148fXXXzNkyBAcDgcLFiyga9euyQ5JNJFp06Yxb948pkyZ0uAon6PR7IobB0tCtNbr9jvnDqCv1vp2pdS1wGWH+stKohIPHY3yycSJPDpxIktqa3kqLY37HnkExo4FWZVBCCGSTkejRIJBQh4PQY+HSCBAZkoKhELs3rWLmqoqwn4/oUCAkN+PGTi5c2cIhfhi1SrK3G7CgQChYJBQMEi6xcLwXr0gHObtZcsoqaoiFAoRCgaJRCK0T0nh5vjxR5csYY/HQzgcJhQOE45E6Jeezj1dukAoxI3Ll1MZDMaKNtEo4WiUwWlp/CEvD8Jh+q9fT100SkRrwvF2g83Gkw4H4VCIzKoqIkA43qLElm3+M1AFZNTTH48Avwdo0wZKShq9v5P9WIpSqiPw/n7FjYHAH7XWF8dfjwfQWh9Y2Nj7/vuA5VrrxUqpGVrrKw9y3jhgHED79u1P3bFjR2N/KkK0SsuWLWPUqFGEw2Hee+89zj33XL744gt+97vfsWDBAgoLC/nDH/7ATTfdlJDHVbxeLxdccAHfffcdCxYsYODAgfWe5/f76dSpEyUlJdx///386U9/qve8FStWcOedd7JixQoAXC4Xv/rVr3jooYca/Re/4813333H4MGDMZvNzJ8/nx6yiEKLFwwGyczMxOv1sm3bNjp06NCo128wx9BaH3cNGAh8vN/r8cD4A875GBgY3zYB5cSLNQdrp556qm5U27frWX376gFOpwZ0odGon7/mGu1zuxv3PkIIIcRhikYiOhIIaO3z6WhNjXZv367LN27UJatX66KVK/WOpUu1+5tvtN64MdYSAFipk5tHdATW7Pf6SmKjQPe+vhH4WwPv701s5MZLwKTDuWej5xhCtFLvvPOOtlqt+oQTTtDr16//0fH58+frM844QwO6S5cu+q233tKRSKTR7h8KhfTIkSO1wWDQ77333kHPi0QiumfPnhrQV1111WFde+fOnfrSSy/VRqNRA9pisegxY8Zodwv/3WHNmjW6TZs2Ojc3V69evTrZ4YgEu/baazWgf/7znyfk+g3lGEkvZNQb1GEkIcAaoHC/11uA7Iau29iJR9Rs1sSGrOqx3btrf01No15fCCGEaI6ae3HjCO81EnilS5cujduJQrQy0WhUP/744xrQZ599ti4rK2vw3Dlz5ui+fftqQPfp00fPmjVLR6PRY47htttu04B+/vnnGzx3yJAhGtCnn376Ed/H4/HoO+64Q9vtdg1og8GgBw8erDdv3ny0oR/31q9fr9u2bauzsrL0119/nexwRIKsXr1aAzojI6NRi477ayjHaPEznimlximlViqlVh5sfeijVTdpEntXuP77hg20dbl4//e/b9R7CCGEEOKY7QLa7fe6kP9Nu3JMtNZztdbjXC5XY1xOiFYpGAxyyy238Lvf/Y7rrruOzz77jOzs7IOer5Ri5MiRfPPNN0ybNg2/38/o0aM544wz+Oyzz/YWHo/YE088wcsvv8z48eO54447DnreuHHj+PTTT+nYsSP/+c9/jvg+DoeD559/nrq6OiZNmkRmZiafffYZXbp04aSTTuLzzz8/qviPZ927d2fx4sU4nU4uuOCCfY/oiJbl0ksvBeDNN9/EkITJ1Y/X4sbhJCH7zlFKmQAXsYlFf0Br/YrWur/Wun9OTk6jBpn6i1/g3rGDNipW4qjUmpGPPcZVNhu8916j3ksIIYQQR20F0FUp1UkpZQGuBeY0xoWVUiOVUq9UV1c3xuWEaHXcbjdDhw5lypQpTJgwgTfffBOr1XpY7zUYDFx77bWsW7eOV199leLiYoYMGcIFF1zA0qVLjyiOKVOm8NBDD3HjjTfy+OOPH/S8J598kr///e9kZGSwevXqY5ozw2AwcO+991JWVsbMmTPp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9XWz0lsnJiaGfv36cejQId5//33Gjx9/VxbSdWfmxgHn6yRgvPP4oCt9FtZK46mKLSdHqmk0MuiaJwUP+Pk51q+2aOFyDSoqKioqKu6E4mdu7JYr5giADsfuam7PyCiC9nJVc6N79+7Svn37Am3BwcECyB9//CEajUYCAgJuus57x44dAsjSpUtdIfe2OH/+vCiKIpUqVSq035kzZwSQGjVquFTPrFmzBJD9+/e71M/tsGHDBgFkxYoV7pZSLB544AG577773C1DZs+enZ+J1KpVK5k2bZps375dcnNz3abJZrPJH3/8IRMnTpTQ0FABRKPRSFhYmDz00EOi1Wrl6NGjbtN3q2RmZsovv/wiEyZMyN++GZAKFSrI448/LsuWLSvzNWNuhYyMDBkwYIAAMm7cuFKrC1KWKGyO4eo/+LuBocBRINR57qgrfRbWSiVldONGiQc5vXhx/qnFQ4Y4ClTpdK73r6KioqKi4mZuIbgxF3gNOAl0A9YAbxdnDHe38rIs5UbBjbwb7379+skjjzwigCy+Yi5zI4YPHy5+fn5F3smktOnatasA8tlnn92wT1hYmAASHh7uUi2pqakSGBgojzzyiEv93A7du3eXqlWrlrsbpoULFwogJ924C2FiYqL4+vpK165d5a233pJOnTqJVqsVQPz9/WXgwIHy6aeflsoNt8VikV9//VWeffZZqVy5sgCi1+ulV69esnTpUklISBARkUuXLklgYKA89NBDZb5gpc1mk/3798u7774rDz/8sBgMBgHEYDDIww8/LO+++67s37//jlxmcy02m02mTJkigHTr1k1SUlLcLalUcWdwozHwATDU+T4UmOJKn4W1Upl4jBgh4u8v4twqKDcyUowgOpALe/a43r+KioqKioqbuYXghgZH3Y3vgXDnsVKcMdzdynNwIzMzUwwGg+j1ejl9+rQoiiIVKlS46ViXLl0Sg8EgL7zwgqvk3jaxsbGFfp6oqCgBpEqVKqWi55133imz9SyOHTsmgLz99tvullJsLly44Hbtzz//vGi1Wjlx4kT+uZSUFAkPD5fRo0dL9erV87MLGjduLBMmTJBff/21xLYXzczMlDVr1siIESMkICAgfyvTwYMHy4oVKyQ1NbXA6z766CMB5LvvvisRHa7AZrNJr1698r+/++67TyZMmCAbN26UzMxMd8tzG59//rno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UzdgRYiR0sUG4DwzqxX73dANTaIWb7OBAbHHA4DXQswi31KNERDVGcFQjREc1RiBUY0RvITXGJlBf0C6cvdSM7sNiFI+u+6z7r485Fjp4ELgemCpmS2JbRvh7m+EmEmkKm4H/hr7Q2QNcFPIeVKeu//TzF4GPqR8hYOPgInhpkpdZvYicDFwqpkVAA8Co4AZZjYQWA/0DS+hVFCNESjVGZKKVGPEmWqM+EqWGsPKL38REREREREREUlNuixFRERERERERFKamhsiIiIiIiIiktLU3BARERERERGRlKbmhoiIiIiIiIikNDU3RERERERERCSlqbkhIglnZtlm9qvY4yaxpbhEREREjolqDJHjl5aCFZGEM7Nc4HV3bxdyFBEREUkjqjFEjl+ZYQcQkePSKKClmS0BPgP+w93bmdmNwH8CtYHWwBjgBOB6oAT43+6+w8xaAhOABsAeYJC7f5L4H0NERESSjGoMkeOULksRkTDcC6x293OAuw55rR3QC+gMPAzscfeOwLvADbF9JgK3u/uPgN8CTyYktYiIiCQ71RgixymduSEiyeZtd/8K+MrMdgFzYtuXAu3NrA5wATDTzCreUzPxMUVERCTFqMYQSWNqbohIsik56HHZQc/LKP+dFQF2xr6REREREakq1RgiaUyXpYhIGL4CTqrOG939S2CtmV0DYOU6xDOciIiIpCzVGCLHKTU3RCTh3L0I+H9mtgwYXY1D/AIYaGb/ApYDPeOZT0RERFKTagyR45eWghURERERERGRlKYzN0REREREREQkpam5ISIiIiIiIiIpTc0NEREREREREUlpam6IiIiIiIiISEpTc0NEREREREREUpqaGyIiIiIiIiKS0tTcEBEREREREZGUpuaGiIiIiIiIiKS0/w8xg2nKQCrfjAAAAABJRU5ErkJggg==\n", + "image/png": "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aDQKIGazWZYsWZLnfhkZGTJu3DgxmUwSHBwsP//8800f+36QmJgoBw8elLVr18rChQtl2rRpcubMmaJuVjZRUVHyxBNPCCCPP/64nD17tsCPGRMTI//973/Fy8tLNE2Trl27ysGDBwv8uIVp/fr1ommavPDCC6Lrumv7/v37pXnz5lKzZk0JCwuTkJAQKVWqlAQEBIiPj494eHiIm5ubGI1G0TTN9T+e3/TSSy9dt02pqanyn//8RwB54oknJDY2tjBeCqWQ5XWOoUZu3C10HYYNg9mzCbTZsGsaM3v3pueCBUXdMkVRFEW5KWrkhnI96enplC9fnoceeojVq1czadIkRo0ahaZpDBw4kJkzZwLwww8/0L59exo3boyPjw/r1q1DRChXrhwfffQRTzzxxE0d98CBAwwYMIANGza4trVo0YL//e9/eS4Zu3v3bnr27MnBgwfp27cvU6ZMwfs+me8sPT2ds2fPcubMmeumK1euXLOfxWKhf//+jBgxgqCgoCJo+VXLly+nb9++pKamMmXKFPr374+maYV2/IsXLzJt2jRmz559T43kiI6Opk6dOvj7+7Nz507X/0TmHDeJiYlomobBYMBgMGA0GjGZTJjNZtzc3HBzc8NiseDu7o67uzuenp54eHjg5eWFt7c33t7e+Pr64u3tjZ+fH/7+/pjNZvr168eVK1eoUaMGf/75Z67/iyLCRx99xKBBgwgJCeH777+nRo0ahf0SKQVIjdy4y0duTH/mGfEF2Qwi7u5yfvhwsVutRd0sRVEURbklqJEbynUsXrxYAFm7dq2IiJQoUUIA0TRNTp065SpXrVo1AVxXuyMiIqRp06auq7ehoaGyefPmmzq2ruvyxRdfuI4JiKenp/z444957peamirDhg0TTdOkYsWKsmXLlpt70nchm80mkZGRsnXrVvn6669lypQpMmjQIHn22Welfv36UrJkyVyvmgcEBEjt2rWlbdu20q9fP5k4caIsWbJENm7cKCdPnpRjx47JSy+9JAaDQby8vOStt96SK1euFPrzu3LlivTo0UMAadCggRw+fLjQ25BVzpEc3bp1k0OHDhVpm26V3W6X1q1bi7u7u+zbty9bXqNGjQSQgQMHFsixU1NTpX79+gKIj4+P/PXXX9ctu2XLFilVqpR4eXnJN998UyDtUYpGXucYRX5SUJjpbgturBg+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EYvFgqZpdOjQgTfffJO+fftWaywAp0+f5ocffmDr1q3ExsZy9uxZCgsLHe9rmoavry9RUVF07tyZ3r1706tXL9zc3Ni6dStffvklP//8M3FxcaWSGREREdx222089NBD9OrVq0o/Z7PZzJo1a1i3bh1//PFHmQkPFxcXXFxc0Ol0F32/nEsoubu7O0a9eHh44OnpiaenJ0aj0ZFoOld8fX3x8/OjV69elX48ktwoUdM7HtlxcTzauDEv338/7ZcscXY4QgghxFW5iuRGR+BzwLfkpSzgEaVU2Wd2NVBN72NUN6UUP/30E9OnT+e///0vRqORxx9/nKeffprw8PBravv06dNER0eTl5fHuHHjmD17drnq5ebm0rhxY2JiYhg7diyDBw/mkUceYcGCBRWeDlMV8vLymDx5MosWLSIzMxOAiIgIHnroIdq2bUurVq1o2bJlpSRjrFZrnZyLf6F33nmHl19+GVdXV9auXUuPHj2uqh2z2cy7777LggULHKMI3N3d6dGjB1OnTqVt22u/PZDZbCY2Npb9+/fz999/c/z4cceInszMTOx2O/7+/oSGhhIZGUmTJk1o3bo17du3p0WLFpXy+/z999+ZMGECO3bsQCmFm5sb9957L++///41/7u9nHP3rpk1axanT58GwGg0MmzYMN5+++0aN10qIyODlStXsmnTJvbs2UNcXNxF00FcXFxKJTPq16/vSGb07t3b6fc5MZvNrFu3jrVr17Jnzx5MJhOFhYUUFRU5pvxYLBZsNhs2mw273V4qOVpeVZFruGwf41LLqNTFUtOXgl04erQC1P8WLHB2KEIIIcRVo5xLwQJPlfy8teSnL+Bbnro1pSBLwZZitVrV0qVLVadOnRSgQkND1bRp01RWVlaltH/48GHHsqUTJ06sUN233367uJ/1v/8ppZR69dVXFaDmzp1bKbFdrW3btqlbbrnFsQyrTqdTPXv2VPv27XNqXHXFwoULlaZpStM0tXjx4grVXbFihYqJiXH8bjRNU23btlWLFy92LCVbF2VmZqpHH31UeXp6OpbFbdu2rVq/fn2l7ufYsWNq4MCBys3NrdR+fvzxx0rdT3UoKChQK1asUGPHjlUdO3ZUjRs3VkOHDlWrVq2qc38rNptNZWZmqhMnTqg///xTbdq0SS1btkwtXLhQvf/+++qNN95Qzz//vHr66aer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8PHxwdfX96rXws4V9urm5nZdFsnDDz/MiRMnOHPmDO7u7rf8Gdu2bcvu3btZu3Ytffv2vaVrWrduzd69e9m0aRNdu3a9ZV8349KlS4SGhvLYY4+xcuXKEhvXWWRkZFC1alW6d+/O999/72o5N+WRRx7h4sWLHFN3HVS5ASaTiT///JPffvuN3377jQMHDgDg5+dH586defjhh/OLEWs0TtlMtFicOHGCdevWsXbtWv766y8AatWqRb9+/Rg5cmSZ2pbZFZR6QVG58jSjFmB0HHcCXgb8nOmzqFZamRu7HQW6lj777FXnf587V1qAJPv4iOTklIoWFRUVFRWV0obiZ260A44B0Y73TYCPizOGq1tpFy2/Xf744w8B5K233irU3qRJEwHk66+/Fo1GI97e3jfN2vjwww8FkEGDBkn//v2lc+fO0qpVK6lXr56EhISIh6OA+s2aTqeTwMBACQ0NlaZNm0q7du0EkA8++KDYnzMiIkIAqVKlyi31P378uABSo0aNYvu6FV5//XUB5NChQ04ZvyT56KOPBJBdu3a5Wsotkaf36NGjrpZS7oiNjXVZVpYzsdlscujQIZk/f75069ZN3N3d83/HhIWFyVtvvSV//fWXWCwWV0u9KbGxsbJ48WLp3r276PV68fLykg032KziXqGoOYazt4L9B2gJ1AQ2AuuARiLS02lOi6C0nqq80rQpnx48SHxUFL7VqwOQlZhIcIUKZAG7v/iCVsOHO12HioqKioqKK7iNgqK7gYHAenFsF68oyhERud9ZGkua8pK58fjjj7N7924iIyOvy4T4+eef6d27Nw0bNqR+/fqsXr2aefPmMX78+BuOJyI0btwYo9FIUZ8/NzeX9PR0UlNTSUtLy38teFzYq6+vLytXrrytde5hYWFs376d7777jsGDBxfZt3379uzcuZP169fTu3fvYvu6GUlJSYSGhtK5c2dWr15d4uOXFDabjQYNGuDn55e/hWVZJy4ujipVqjBjxgymTZvmUi0Wi4X//e9/NGvWjODgYJdqKQwR4dChQ6xevZo1a9Zw+PBhJk6cyNy5c10t7Y6Ji4vj999/z8/OuHjxIgD169ena9eudOnShY4dO+Lt7e1ipbdPTEwMffr04eDBg7z//vuMHTv2niyk68rMjQOO14nAWMfx3870WVQrjacq1pwcqaLRyIBrnhQ85ONj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OuCGkPOkPHf/h5m9ALxH5QoH7wNTwk2VuszsOeBC4FQzKwLuB8YBc8xsKLARGBReQjlANUagVGdIKlKNEWeqMeIrWWoMq7z8RUREREREREQkNemyFBERERERERFJaWpuiIiIiIiIiEhKU3NDRERERERERFKamhsiIiIiIiIiktLU3BARERERERGRlKbmhogknJk1NLNfxu43jy3FJSIiInJMVGOIHL+0FKyIJJyZ5QCvuHunkKOIiIhIGlGNIXL8ygw7gIgcl8YBbc1sBfAx8G/u3snMrgf+A6gHtAcmACcA1wJlwP929x1m1haYDDQB9gDD3P3DxH8MERERSTKqMUSOU7osRUTCcDfwibufDdzxnec6Af2BbsCDwB537wK8BVwX22cKcKu7/wj4NfCnhKQWERGRZKcaQ+Q4pTM3RCTZvOHuXwJfmtkuYEFs+0ogz8zqA+cBc83swGtqJz6miIiIpBjVGCJpTM0NEUk2ZYfcrzjkcQWVv7MiwM7YNzIiIiIi1aUaQySN6bIUEQnDl8BJNXmhu38BrDezKwGsUud4hhMREZGUpRpD5Dil5oaIJJy7lwD/z8wKgPE1OMTPgaFm9k9gFdA3nvlEREQkNanGEDl+aSlYEREREREREUlpOnNDRERERERERFKamhsiIiIiIiIiktLU3BARERERERGRlKbmhoiIiIiIiIikNDU3RERERERERCSlqbkhIiIiIiIiIilNzQ0RERERERERSWlqboiIiIiIiIhISvv/rP4GG72jwcMAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] @@ -1755,12 +1817,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " -0.414816\n", - " -0.876073\n", - " 1.227374\n", - " -2.444445\n", - " 2.570303\n", - " -0.957382\n", + " -1.818394\n", + " 0.323750\n", + " -1.130396\n", + " -0.235845\n", + " 3.003267\n", + " -1.249817\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -1776,12 +1838,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 2.451814\n", - " -1.136215\n", - " -1.698820\n", - " 1.238130\n", - " 2.486213\n", - " 0.362012\n", + " -0.286706\n", + " 1.481899\n", + " -0.190653\n", + " 0.384839\n", + " 3.928552\n", + " 0.322567\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -1797,12 +1859,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.471712\n", - " -0.151082\n", - " -1.797739\n", - " 0.288818\n", - " 2.313434\n", - " -0.686996\n", + " -0.112492\n", + " 1.481440\n", + " 0.010955\n", + " 1.837763\n", + " 3.394742\n", + " 0.547032\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -1818,12 +1880,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.704033\n", - " 0.896003\n", - " 0.451385\n", - " 1.046007\n", - " 5.043385\n", - " -0.671759\n", + " 0.836740\n", + " 1.890309\n", + " 0.855302\n", + " 1.396028\n", + " 3.634490\n", + " 1.340781\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -1839,12 +1901,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.901247\n", - " 0.895383\n", - " -1.412566\n", - " 1.901419\n", - " 3.837156\n", - " 0.147422\n", + " 0.233868\n", + " 1.963070\n", + " -0.356165\n", + " 1.342368\n", + " 3.063575\n", + " -1.318266\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -1860,12 +1922,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.242644\n", - " 1.337338\n", - " -1.103457\n", - " 0.432559\n", - " 2.887246\n", - " 2.096051\n", + " 0.915582\n", + " -0.012158\n", + " 0.380968\n", + " 1.772030\n", + " 2.638614\n", + " 1.998935\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -1881,12 +1943,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " -0.808071\n", - " 2.087179\n", - " -0.791739\n", - " 3.218673\n", - " 3.837424\n", - " 0.190466\n", + " 0.919766\n", + " 0.240276\n", + " 0.012171\n", + " 0.072701\n", + " 3.251369\n", + " -0.546210\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -1902,12 +1964,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.083943\n", - " 1.977401\n", - " -0.003218\n", - " 0.692508\n", - " 5.517687\n", - " 2.463217\n", + " 0.166633\n", + " 1.250029\n", + " -0.248000\n", + " 2.575797\n", + " 5.000227\n", + " 3.267072\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -1923,12 +1985,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " -0.678246\n", - " 0.868593\n", - " 1.344468\n", - " 0.650529\n", - " 3.649025\n", - " 1.408445\n", + " 0.638798\n", + " 1.308206\n", + " -1.515860\n", + " 1.361921\n", + " 1.807606\n", + " 0.022304\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -1944,12 +2006,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.623963\n", - " 0.095821\n", - " 1.552055\n", - " 0.295860\n", - " 4.188810\n", - " 0.128069\n", + " 0.187986\n", + " -0.482633\n", + " 0.326894\n", + " 1.982838\n", + " 2.642325\n", + " -0.265486\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -1965,12 +2027,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.035316\n", - " 0.673437\n", - " 0.068617\n", - " 1.458583\n", - " 2.803158\n", - " 1.455018\n", + " 0.405781\n", + " 1.092347\n", + " -0.468315\n", + " 1.235247\n", + " 1.189159\n", + " -1.747961\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -1986,12 +2048,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.912310\n", - " 2.633523\n", - " -0.515745\n", - " 0.620131\n", - " 4.286741\n", - " 0.179958\n", + " -0.249370\n", + " 0.873713\n", + " -0.119955\n", + " 1.518338\n", + " 6.376749\n", + " 2.518514\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -2007,12 +2069,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " -0.036992\n", - " 0.530859\n", - " -1.114001\n", - " 1.962801\n", - " 4.852431\n", - " 1.744331\n", + " -1.900392\n", + " 1.966896\n", + " -2.117369\n", + " -0.391538\n", + " 2.968232\n", + " 0.551456\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -2028,12 +2090,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " -0.402563\n", - " 0.933044\n", - " 1.046995\n", - " 0.395994\n", - " 2.288115\n", - " 1.817704\n", + " 0.556327\n", + " 0.466760\n", + " 1.585724\n", + " 2.304242\n", + " 4.338615\n", + " -0.543743\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -2049,12 +2111,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " -0.505098\n", - " 2.559202\n", - " -0.145338\n", - " 0.352249\n", - " 5.320218\n", - " 1.215976\n", + " -0.022463\n", + " 2.221990\n", + " -0.845991\n", + " -0.259019\n", + " 4.663322\n", + " -0.035982\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -2070,12 +2132,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.538138\n", - " 0.302181\n", - " -2.137766\n", - " 1.630837\n", - " 3.806037\n", - " 0.093093\n", + " -0.621709\n", + " -0.471851\n", + " -1.077408\n", + " 2.055719\n", + " 5.205709\n", + " 0.775267\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -2091,12 +2153,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.764999\n", - " 0.527020\n", - " 0.853451\n", - " 1.278411\n", - " 4.361549\n", - " -0.308099\n", + " 1.328609\n", + " 1.048814\n", + " 1.903001\n", + " 0.758393\n", + " 2.025149\n", + " 1.777222\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -2112,12 +2174,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.723098\n", - " 0.539088\n", - " 1.028430\n", - " 0.059518\n", - " 3.805920\n", - " 1.652130\n", + " 0.886509\n", + " 0.279781\n", + " -0.437013\n", + " 1.875357\n", + " 2.864437\n", + " 0.984361\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -2133,12 +2195,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.761027\n", - " 1.024605\n", - " 0.443612\n", - " 1.453533\n", - " 2.976122\n", - " 0.269625\n", + " 1.452422\n", + " 1.597938\n", + " -1.280079\n", + " 0.185404\n", + " 3.925955\n", + " 0.853126\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -2154,12 +2216,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.075774\n", - " 0.587967\n", - " 0.095493\n", - " -0.258109\n", - " 2.943583\n", - " 0.289256\n", + " 1.493436\n", + " 1.974988\n", + " -0.059626\n", + " 0.466490\n", + " 4.113576\n", + " 0.140379\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -2175,12 +2237,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " -0.002435\n", - " -1.179119\n", - " 0.299502\n", - " -0.345324\n", - " 5.717243\n", - " -0.411100\n", + " 1.828229\n", + " 0.864279\n", + " 0.389782\n", + " -0.399825\n", + " 3.735551\n", + " -1.209276\n", " 1.0\n", " 1.0\n", " 1.0\n", @@ -2194,73 +2256,73 @@ ], "text/plain": [ " time datatype t_presim k0 k0_preeq k0_presim observable_x1 \\\n", - "0 0.0 data 0.0 1.0 NaN NaN -0.414816 \n", - "1 0.5 data 0.0 1.0 NaN NaN 2.451814 \n", - "2 1.0 data 0.0 1.0 NaN NaN 0.471712 \n", - "3 1.5 data 0.0 1.0 NaN NaN 0.704033 \n", - "4 2.0 data 0.0 1.0 NaN NaN 0.901247 \n", - "5 2.5 data 0.0 1.0 NaN NaN 1.242644 \n", - "6 3.0 data 0.0 1.0 NaN NaN -0.808071 \n", - "7 3.5 data 0.0 1.0 NaN NaN 0.083943 \n", - "8 4.0 data 0.0 1.0 NaN NaN -0.678246 \n", - "9 4.5 data 0.0 1.0 NaN NaN 1.623963 \n", - "10 5.0 data 0.0 1.0 NaN NaN 0.035316 \n", - "11 5.5 data 0.0 1.0 NaN NaN 0.912310 \n", - "12 6.0 data 0.0 1.0 NaN NaN -0.036992 \n", - "13 6.5 data 0.0 1.0 NaN NaN -0.402563 \n", - "14 7.0 data 0.0 1.0 NaN NaN -0.505098 \n", - "15 7.5 data 0.0 1.0 NaN NaN 1.538138 \n", - "16 8.0 data 0.0 1.0 NaN NaN 1.764999 \n", - "17 8.5 data 0.0 1.0 NaN NaN 0.723098 \n", - "18 9.0 data 0.0 1.0 NaN NaN 1.761027 \n", - "19 9.5 data 0.0 1.0 NaN NaN 0.075774 \n", - "20 10.0 data 0.0 1.0 NaN NaN -0.002435 \n", + "0 0.0 data 0.0 1.0 NaN NaN -1.818394 \n", + "1 0.5 data 0.0 1.0 NaN NaN -0.286706 \n", + "2 1.0 data 0.0 1.0 NaN NaN -0.112492 \n", + "3 1.5 data 0.0 1.0 NaN NaN 0.836740 \n", + "4 2.0 data 0.0 1.0 NaN NaN 0.233868 \n", + "5 2.5 data 0.0 1.0 NaN NaN 0.915582 \n", + "6 3.0 data 0.0 1.0 NaN NaN 0.919766 \n", + "7 3.5 data 0.0 1.0 NaN NaN 0.166633 \n", + "8 4.0 data 0.0 1.0 NaN NaN 0.638798 \n", + "9 4.5 data 0.0 1.0 NaN NaN 0.187986 \n", + "10 5.0 data 0.0 1.0 NaN NaN 0.405781 \n", + "11 5.5 data 0.0 1.0 NaN NaN -0.249370 \n", + "12 6.0 data 0.0 1.0 NaN NaN -1.900392 \n", + "13 6.5 data 0.0 1.0 NaN NaN 0.556327 \n", + "14 7.0 data 0.0 1.0 NaN NaN -0.022463 \n", + "15 7.5 data 0.0 1.0 NaN NaN -0.621709 \n", + "16 8.0 data 0.0 1.0 NaN NaN 1.328609 \n", + "17 8.5 data 0.0 1.0 NaN NaN 0.886509 \n", + "18 9.0 data 0.0 1.0 NaN NaN 1.452422 \n", + "19 9.5 data 0.0 1.0 NaN NaN 1.493436 \n", + "20 10.0 data 0.0 1.0 NaN NaN 1.828229 \n", "\n", " observable_x2 observable_x3 observable_x1_scaled \\\n", - "0 -0.876073 1.227374 -2.444445 \n", - "1 -1.136215 -1.698820 1.238130 \n", - "2 -0.151082 -1.797739 0.288818 \n", - "3 0.896003 0.451385 1.046007 \n", - "4 0.895383 -1.412566 1.901419 \n", - "5 1.337338 -1.103457 0.432559 \n", - "6 2.087179 -0.791739 3.218673 \n", - "7 1.977401 -0.003218 0.692508 \n", - "8 0.868593 1.344468 0.650529 \n", - "9 0.095821 1.552055 0.295860 \n", - "10 0.673437 0.068617 1.458583 \n", - "11 2.633523 -0.515745 0.620131 \n", - "12 0.530859 -1.114001 1.962801 \n", - "13 0.933044 1.046995 0.395994 \n", - "14 2.559202 -0.145338 0.352249 \n", - "15 0.302181 -2.137766 1.630837 \n", - "16 0.527020 0.853451 1.278411 \n", - "17 0.539088 1.028430 0.059518 \n", - "18 1.024605 0.443612 1.453533 \n", - "19 0.587967 0.095493 -0.258109 \n", - "20 -1.179119 0.299502 -0.345324 \n", + "0 0.323750 -1.130396 -0.235845 \n", + "1 1.481899 -0.190653 0.384839 \n", + "2 1.481440 0.010955 1.837763 \n", + "3 1.890309 0.855302 1.396028 \n", + "4 1.963070 -0.356165 1.342368 \n", + "5 -0.012158 0.380968 1.772030 \n", + "6 0.240276 0.012171 0.072701 \n", + "7 1.250029 -0.248000 2.575797 \n", + "8 1.308206 -1.515860 1.361921 \n", + "9 -0.482633 0.326894 1.982838 \n", + "10 1.092347 -0.468315 1.235247 \n", + "11 0.873713 -0.119955 1.518338 \n", + "12 1.966896 -2.117369 -0.391538 \n", + "13 0.466760 1.585724 2.304242 \n", + "14 2.221990 -0.845991 -0.259019 \n", + "15 -0.471851 -1.077408 2.055719 \n", + "16 1.048814 1.903001 0.758393 \n", + "17 0.279781 -0.437013 1.875357 \n", + "18 1.597938 -1.280079 0.185404 \n", + "19 1.974988 -0.059626 0.466490 \n", + "20 0.864279 0.389782 -0.399825 \n", "\n", " observable_x2_offsetted observable_x1withsigma observable_x1_std \\\n", - "0 2.570303 -0.957382 1.0 \n", - "1 2.486213 0.362012 1.0 \n", - "2 2.313434 -0.686996 1.0 \n", - "3 5.043385 -0.671759 1.0 \n", - "4 3.837156 0.147422 1.0 \n", - "5 2.887246 2.096051 1.0 \n", - "6 3.837424 0.190466 1.0 \n", - "7 5.517687 2.463217 1.0 \n", - "8 3.649025 1.408445 1.0 \n", - "9 4.188810 0.128069 1.0 \n", - "10 2.803158 1.455018 1.0 \n", - "11 4.286741 0.179958 1.0 \n", - "12 4.852431 1.744331 1.0 \n", - "13 2.288115 1.817704 1.0 \n", - "14 5.320218 1.215976 1.0 \n", - "15 3.806037 0.093093 1.0 \n", - "16 4.361549 -0.308099 1.0 \n", - "17 3.805920 1.652130 1.0 \n", - "18 2.976122 0.269625 1.0 \n", - "19 2.943583 0.289256 1.0 \n", - "20 5.717243 -0.411100 1.0 \n", + "0 3.003267 -1.249817 1.0 \n", + "1 3.928552 0.322567 1.0 \n", + "2 3.394742 0.547032 1.0 \n", + "3 3.634490 1.340781 1.0 \n", + "4 3.063575 -1.318266 1.0 \n", + "5 2.638614 1.998935 1.0 \n", + "6 3.251369 -0.546210 1.0 \n", + "7 5.000227 3.267072 1.0 \n", + "8 1.807606 0.022304 1.0 \n", + "9 2.642325 -0.265486 1.0 \n", + "10 1.189159 -1.747961 1.0 \n", + "11 6.376749 2.518514 1.0 \n", + "12 2.968232 0.551456 1.0 \n", + "13 4.338615 -0.543743 1.0 \n", + "14 4.663322 -0.035982 1.0 \n", + "15 5.205709 0.775267 1.0 \n", + "16 2.025149 1.777222 1.0 \n", + "17 2.864437 0.984361 1.0 \n", + "18 3.925955 0.853126 1.0 \n", + "19 4.113576 0.140379 1.0 \n", + "20 3.735551 -1.209276 1.0 \n", "\n", " observable_x2_std observable_x3_std observable_x1_scaled_std \\\n", "0 1.0 1.0 1.0 \n", @@ -2377,12 +2439,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.514816\n", - " 1.276073\n", - " 0.527374\n", - " 2.644445\n", - " 0.829697\n", - " 10.573821\n", + " 1.918394\n", + " 0.076250\n", + " 1.830396\n", + " 0.435845\n", + " 0.396733\n", + " 13.498166\n", " \n", " \n", " 1\n", @@ -2391,12 +2453,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.912447\n", - " 1.820894\n", - " 1.890310\n", - " 0.159396\n", - " 1.198465\n", - " 1.773556\n", + " 0.826073\n", + " 0.797220\n", + " 0.382144\n", + " 0.693896\n", + " 0.243874\n", + " 2.168002\n", " \n", " \n", " 2\n", @@ -2405,12 +2467,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.108360\n", - " 0.884369\n", - " 1.894163\n", - " 0.871327\n", - " 1.419854\n", - " 12.670683\n", + " 0.692564\n", + " 0.748152\n", + " 0.085469\n", + " 0.677618\n", + " 0.338545\n", + " 0.330408\n", " \n", " \n", " 3\n", @@ -2419,12 +2481,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.133633\n", - " 0.165351\n", - " 0.375309\n", - " 0.094792\n", - " 1.312732\n", - " 12.421583\n", + " 0.266340\n", + " 1.159657\n", + " 0.779226\n", + " 0.255229\n", + " 0.096162\n", + " 7.703818\n", " \n", " \n", " 4\n", @@ -2433,12 +2495,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.340712\n", - " 0.179547\n", - " 1.482260\n", - " 0.780350\n", - " 0.121320\n", - " 4.131129\n", + " 0.326667\n", + " 1.247234\n", + " 0.425859\n", + " 0.221299\n", + " 0.652261\n", + " 18.788001\n", " \n", " \n", " 5\n", @@ -2447,12 +2509,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.689589\n", - " 0.638587\n", - " 1.169758\n", - " 0.673553\n", - " 0.811504\n", - " 15.429952\n", + " 0.362526\n", + " 0.710908\n", + " 0.314667\n", + " 0.665919\n", + " 1.060136\n", + " 14.458795\n", " \n", " \n", " 6\n", @@ -2461,12 +2523,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.354942\n", - " 1.405217\n", - " 0.855471\n", - " 2.124931\n", - " 0.155462\n", - " 3.564042\n", + " 0.372895\n", + " 0.441686\n", + " 0.051562\n", + " 1.021041\n", + " 0.430593\n", + " 10.930802\n", " \n", " \n", " 7\n", @@ -2475,12 +2537,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.457417\n", - " 1.311292\n", - " 0.064725\n", - " 0.390211\n", - " 1.851578\n", - " 19.218570\n", + " 0.374727\n", + " 0.583920\n", + " 0.309506\n", + " 1.493077\n", + " 1.334118\n", + " 27.257116\n", " \n", " \n", " 8\n", @@ -2489,12 +2551,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.214527\n", - " 0.217291\n", - " 1.284974\n", - " 0.422031\n", - " 0.002277\n", - " 8.721648\n", + " 0.102518\n", + " 0.656904\n", + " 1.575355\n", + " 0.289360\n", + " 1.843696\n", + " 5.139764\n", " \n", " \n", " 9\n", @@ -2503,12 +2565,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.092425\n", - " 0.541694\n", - " 1.494402\n", - " 0.767217\n", - " 0.551295\n", - " 4.034688\n", + " 0.343553\n", + " 1.120148\n", + " 0.269241\n", + " 0.919762\n", + " 0.995190\n", + " 7.970237\n", " \n", " \n", " 10\n", @@ -2517,12 +2579,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.491775\n", - " 0.048756\n", - " 0.012657\n", - " 0.404401\n", - " 0.821524\n", - " 9.279264\n", + " 0.121310\n", + " 0.467665\n", + " 0.524276\n", + " 0.181064\n", + " 2.435522\n", + " 22.750521\n", " \n", " \n", " 11\n", @@ -2531,12 +2593,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.389395\n", - " 2.020790\n", - " 0.570145\n", - " 0.425698\n", - " 0.674008\n", - " 3.429569\n", + " 0.772284\n", + " 0.260980\n", + " 0.174355\n", + " 0.472509\n", + " 2.764016\n", + " 19.955992\n", " \n", " \n", " 12\n", @@ -2545,12 +2607,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.555981\n", - " 0.070744\n", - " 1.166961\n", - " 0.924822\n", - " 1.250828\n", - " 12.253422\n", + " 2.419382\n", + " 1.365294\n", + " 2.170329\n", + " 1.429517\n", + " 0.633370\n", + " 0.324669\n", " \n", " \n", " 13\n", @@ -2559,12 +2621,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.917862\n", - " 0.341815\n", - " 0.995366\n", - " 0.634604\n", - " 1.303114\n", - " 13.024050\n", + " 0.041028\n", + " 0.124470\n", + " 1.534095\n", + " 1.273643\n", + " 0.747386\n", + " 10.590418\n", " \n", " \n", " 14\n", @@ -2573,12 +2635,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.016928\n", - " 1.977647\n", - " 0.195737\n", - " 0.671411\n", - " 1.738663\n", - " 7.041457\n", + " 0.534293\n", + " 1.640434\n", + " 0.896389\n", + " 1.282679\n", + " 1.081766\n", + " 5.478118\n", " \n", " \n", " 15\n", @@ -2587,12 +2649,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.029570\n", - " 0.270348\n", - " 2.187025\n", - " 0.613702\n", - " 0.233507\n", - " 4.154744\n", + " 1.130277\n", + " 1.044380\n", + " 1.126667\n", + " 1.038584\n", + " 1.633180\n", + " 2.666993\n", " \n", " \n", " 16\n", @@ -2601,12 +2663,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.259499\n", - " 0.037083\n", - " 0.805247\n", - " 0.267410\n", - " 0.797446\n", - " 8.135988\n", + " 0.823108\n", + " 0.484711\n", + " 1.854798\n", + " 0.252607\n", + " 1.538954\n", + " 12.717218\n", " \n", " \n", " 17\n", @@ -2615,12 +2677,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.220483\n", - " 0.017146\n", - " 0.981206\n", - " 0.945712\n", - " 0.249686\n", - " 11.495145\n", + " 0.383893\n", + " 0.276453\n", + " 0.484237\n", + " 0.870126\n", + " 0.691797\n", + " 4.817458\n", " \n", " \n", " 18\n", @@ -2629,12 +2691,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 1.261125\n", - " 0.475724\n", - " 0.397297\n", - " 0.453729\n", - " 0.572759\n", - " 2.302771\n", + " 0.952520\n", + " 1.049056\n", + " 1.326394\n", + " 0.814400\n", + " 0.377074\n", + " 3.532245\n", " \n", " \n", " 19\n", @@ -2643,12 +2705,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.421576\n", - " 0.045959\n", - " 0.050022\n", - " 1.252809\n", - " 0.598425\n", - " 2.080936\n", + " 0.996087\n", + " 1.432980\n", + " 0.105097\n", + " 0.528210\n", + " 0.571568\n", + " 3.569704\n", " \n", " \n", " 20\n", @@ -2657,12 +2719,12 @@ " 1.0\n", " NaN\n", " NaN\n", - " 0.497384\n", - " 1.714701\n", - " 0.254816\n", - " 1.335222\n", - " 2.181662\n", - " 9.060495\n", + " 1.333280\n", + " 0.328698\n", + " 0.345096\n", + " 1.389723\n", + " 0.199970\n", + " 17.042249\n", " \n", " \n", "\n", @@ -2670,73 +2732,73 @@ ], "text/plain": [ " time t_presim k0 k0_preeq k0_presim observable_x1 observable_x2 \\\n", - "0 0.0 0.0 1.0 NaN NaN 0.514816 1.276073 \n", - "1 0.5 0.0 1.0 NaN NaN 1.912447 1.820894 \n", - "2 1.0 0.0 1.0 NaN NaN 0.108360 0.884369 \n", - "3 1.5 0.0 1.0 NaN NaN 0.133633 0.165351 \n", - "4 2.0 0.0 1.0 NaN NaN 0.340712 0.179547 \n", - "5 2.5 0.0 1.0 NaN NaN 0.689589 0.638587 \n", - "6 3.0 0.0 1.0 NaN NaN 1.354942 1.405217 \n", - "7 3.5 0.0 1.0 NaN NaN 0.457417 1.311292 \n", - "8 4.0 0.0 1.0 NaN NaN 1.214527 0.217291 \n", - "9 4.5 0.0 1.0 NaN NaN 1.092425 0.541694 \n", - "10 5.0 0.0 1.0 NaN NaN 0.491775 0.048756 \n", - "11 5.5 0.0 1.0 NaN NaN 0.389395 2.020790 \n", - "12 6.0 0.0 1.0 NaN NaN 0.555981 0.070744 \n", - "13 6.5 0.0 1.0 NaN NaN 0.917862 0.341815 \n", - "14 7.0 0.0 1.0 NaN NaN 1.016928 1.977647 \n", - "15 7.5 0.0 1.0 NaN NaN 1.029570 0.270348 \n", - "16 8.0 0.0 1.0 NaN NaN 1.259499 0.037083 \n", - "17 8.5 0.0 1.0 NaN NaN 0.220483 0.017146 \n", - "18 9.0 0.0 1.0 NaN NaN 1.261125 0.475724 \n", - "19 9.5 0.0 1.0 NaN NaN 0.421576 0.045959 \n", - "20 10.0 0.0 1.0 NaN NaN 0.497384 1.714701 \n", + "0 0.0 0.0 1.0 NaN NaN 1.918394 0.076250 \n", + "1 0.5 0.0 1.0 NaN NaN 0.826073 0.797220 \n", + "2 1.0 0.0 1.0 NaN NaN 0.692564 0.748152 \n", + "3 1.5 0.0 1.0 NaN NaN 0.266340 1.159657 \n", + "4 2.0 0.0 1.0 NaN NaN 0.326667 1.247234 \n", + "5 2.5 0.0 1.0 NaN NaN 0.362526 0.710908 \n", + "6 3.0 0.0 1.0 NaN NaN 0.372895 0.441686 \n", + "7 3.5 0.0 1.0 NaN NaN 0.374727 0.583920 \n", + "8 4.0 0.0 1.0 NaN NaN 0.102518 0.656904 \n", + "9 4.5 0.0 1.0 NaN NaN 0.343553 1.120148 \n", + "10 5.0 0.0 1.0 NaN NaN 0.121310 0.467665 \n", + "11 5.5 0.0 1.0 NaN NaN 0.772284 0.260980 \n", + "12 6.0 0.0 1.0 NaN NaN 2.419382 1.365294 \n", + "13 6.5 0.0 1.0 NaN NaN 0.041028 0.124470 \n", + "14 7.0 0.0 1.0 NaN NaN 0.534293 1.640434 \n", + "15 7.5 0.0 1.0 NaN NaN 1.130277 1.044380 \n", + "16 8.0 0.0 1.0 NaN NaN 0.823108 0.484711 \n", + "17 8.5 0.0 1.0 NaN NaN 0.383893 0.276453 \n", + "18 9.0 0.0 1.0 NaN NaN 0.952520 1.049056 \n", + "19 9.5 0.0 1.0 NaN NaN 0.996087 1.432980 \n", + "20 10.0 0.0 1.0 NaN NaN 1.333280 0.328698 \n", "\n", " observable_x3 observable_x1_scaled observable_x2_offsetted \\\n", - "0 0.527374 2.644445 0.829697 \n", - "1 1.890310 0.159396 1.198465 \n", - "2 1.894163 0.871327 1.419854 \n", - "3 0.375309 0.094792 1.312732 \n", - "4 1.482260 0.780350 0.121320 \n", - "5 1.169758 0.673553 0.811504 \n", - "6 0.855471 2.124931 0.155462 \n", - "7 0.064725 0.390211 1.851578 \n", - "8 1.284974 0.422031 0.002277 \n", - "9 1.494402 0.767217 0.551295 \n", - "10 0.012657 0.404401 0.821524 \n", - "11 0.570145 0.425698 0.674008 \n", - "12 1.166961 0.924822 1.250828 \n", - "13 0.995366 0.634604 1.303114 \n", - "14 0.195737 0.671411 1.738663 \n", - "15 2.187025 0.613702 0.233507 \n", - "16 0.805247 0.267410 0.797446 \n", - "17 0.981206 0.945712 0.249686 \n", - "18 0.397297 0.453729 0.572759 \n", - "19 0.050022 1.252809 0.598425 \n", - "20 0.254816 1.335222 2.181662 \n", + "0 1.830396 0.435845 0.396733 \n", + "1 0.382144 0.693896 0.243874 \n", + "2 0.085469 0.677618 0.338545 \n", + "3 0.779226 0.255229 0.096162 \n", + "4 0.425859 0.221299 0.652261 \n", + "5 0.314667 0.665919 1.060136 \n", + "6 0.051562 1.021041 0.430593 \n", + "7 0.309506 1.493077 1.334118 \n", + "8 1.575355 0.289360 1.843696 \n", + "9 0.269241 0.919762 0.995190 \n", + "10 0.524276 0.181064 2.435522 \n", + "11 0.174355 0.472509 2.764016 \n", + "12 2.170329 1.429517 0.633370 \n", + "13 1.534095 1.273643 0.747386 \n", + "14 0.896389 1.282679 1.081766 \n", + "15 1.126667 1.038584 1.633180 \n", + "16 1.854798 0.252607 1.538954 \n", + "17 0.484237 0.870126 0.691797 \n", + "18 1.326394 0.814400 0.377074 \n", + "19 0.105097 0.528210 0.571568 \n", + "20 0.345096 1.389723 0.199970 \n", "\n", " observable_x1withsigma \n", - "0 10.573821 \n", - "1 1.773556 \n", - "2 12.670683 \n", - "3 12.421583 \n", - "4 4.131129 \n", - "5 15.429952 \n", - "6 3.564042 \n", - "7 19.218570 \n", - "8 8.721648 \n", - "9 4.034688 \n", - "10 9.279264 \n", - "11 3.429569 \n", - "12 12.253422 \n", - "13 13.024050 \n", - "14 7.041457 \n", - "15 4.154744 \n", - "16 8.135988 \n", - "17 11.495145 \n", - "18 2.302771 \n", - "19 2.080936 \n", - "20 9.060495 " + "0 13.498166 \n", + "1 2.168002 \n", + "2 0.330408 \n", + "3 7.703818 \n", + "4 18.788001 \n", + "5 14.458795 \n", + "6 10.930802 \n", + "7 27.257116 \n", + "8 5.139764 \n", + "9 7.970237 \n", + "10 22.750521 \n", + "11 19.955992 \n", + "12 0.324669 \n", + "13 10.590418 \n", + "14 5.478118 \n", + "15 2.666993 \n", + "16 12.717218 \n", + "17 4.817458 \n", + "18 3.532245 \n", + "19 3.569704 \n", + "20 17.042249 " ] }, "execution_count": 27, @@ -3685,9 +3747,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (AMICI)", + "display_name": "Python 3", "language": "python", - "name": "amici" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -3699,7 +3761,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.7" }, "toc": { "base_numbering": 1, diff --git a/deps/AMICI/python/sdist/amici/swig.py b/deps/AMICI/python/sdist/amici/swig.py deleted file mode 100644 index 42bd9aac8..000000000 --- a/deps/AMICI/python/sdist/amici/swig.py +++ /dev/null @@ -1,77 +0,0 @@ -"""Functions for downloading/building/finding SWIG""" - -from typing import Tuple -import os -import subprocess -import re - - -def find_swig() -> str: - """Get name and version of SWIG executable - - We need version >=3.0. Probably we should try some default paths and names, - but this should do the trick for now. - - Debian/Ubuntu systems have swig3.0 ('swig' is older versions), - OSX has swig 3.0 as 'swig'. - """ - - candidates = ['swig4.0', 'swig3.0', 'swig'] - # Environment variable has priority - if 'SWIG' in os.environ: - candidates.insert(0, os.environ['SWIG']) - - for candidate in candidates: - if swig_works(candidate): - return candidate - - raise RuntimeError("Unable to find SWIG executable with default names. " - "Ensure you have SWIG installed, e.g. by " - "`sudo apt install swig3.0` or `brew install swig`. " - "As non-root user, you can install SWIG using " - "https://github.com/ICB-DCM/AMICI/blob/master/scripts/" - "downloadAndBuildSwig.sh, or by following the " - "instructions at http://www.swig.org/Doc4.0/" - "SWIGDocumentation.html#Preface_installation. " - "If was not found despite being installed, set the SWIG" - " environment variable to the full path of the correct " - "executable.") - - -def swig_works(swig: str, verbose: bool = True) -> bool: - """Test if `swig` looks like a working SWIG executable.""" - - try: - # For python3.6 compatibility no `capture_output=True` - result = subprocess.run([swig, '-version'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - except (FileNotFoundError, PermissionError): - if verbose: - print(f'Testing SWIG executable {swig}... FAILED.') - return False - - if verbose: - if result.returncode == 0: - print(f'Testing SWIG executable {swig}... SUCCEEDED.') - else: - print(f'Testing SWIG executable {swig}... FAILED.') - - return result.returncode == 0 - - -def get_swig_version(swig_exe: str) -> Tuple: - """Determine version of the given SWIG executable - - Returns: - Version tuple - """ - result = subprocess.run([swig_exe, '-version'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - assert result.returncode == 0 - - version = re.sub(r'(?s).*Version\s+([\S]+).*', r'\1', - result.stdout.decode('utf-8')) - - return tuple(int(x) for x in version.split('.')) diff --git a/deps/AMICI/python/sdist/amici/swig.py b/deps/AMICI/python/sdist/amici/swig.py new file mode 120000 index 000000000..638f8c3b3 --- /dev/null +++ b/deps/AMICI/python/sdist/amici/swig.py @@ -0,0 +1 @@ +../../amici/swig.py \ No newline at end of file diff --git a/deps/AMICI/python/sdist/setup.py b/deps/AMICI/python/sdist/setup.py index 090fd61f8..0b22313b3 100755 --- a/deps/AMICI/python/sdist/setup.py +++ b/deps/AMICI/python/sdist/setup.py @@ -12,39 +12,33 @@ - hdf5 libraries and headers """ -from setuptools import find_packages, setup, Extension - import os -import sys import subprocess +import sys + import setup_clibs # Must run from within containing directory -# Add current directory to path, as we need some modules from the AMICI -# package already for installation -sys.path.insert(0, os.getcwd()) - -from amici import __version__ -from amici.custom_commands import ( - AmiciInstall, AmiciBuildCLib, AmiciDevelop, - AmiciInstallLib, AmiciBuildExt, AmiciSDist) -from amici.setuptools import ( - get_blas_config, - get_hdf5_config, - add_coverage_flags_if_required, - add_debug_flags_if_required, -) +from distutils import log -def try_install(package): +def try_install(package: str) -> None: """Try installing the given package using pip. Exit on error.""" + + log.info(f"Missing required package {package}. Trying to install...") errno = subprocess.call([sys.executable, "-m", "pip", "install", package]) if errno: - print(f"Failed trying to install {package}. Please install manually.") + log.error(f"Failed trying to install {package}. " + "Please install manually before installing AMICI.") raise SystemExit(errno) + import importlib + importlib.invalidate_caches() + globals()[package] = importlib.import_module(package) + try: - # required for include directory + # Required for numpy include directory, and for importing anything from + # the `amici` package. Therefore, try before any amici import. import numpy as np except ImportError: # We need numpy, but setup_requires fires too late @@ -52,6 +46,31 @@ def try_install(package): # retry import numpy as np +try: + # Required for customizing installation, but setup_requires fires too late + from setuptools import find_packages, setup, Extension +except ImportError: + try_install('setuptools') + from setuptools import find_packages, setup, Extension + + +# Add current directory to path, as we need some modules from the AMICI +# package already for installation +sys.path.insert(0, os.getcwd()) + +from amici import __version__ +from amici.custom_commands import ( + AmiciInstall, AmiciBuildCLib, AmiciDevelop, + AmiciInstallLib, AmiciBuildExt, AmiciSDist) +from amici.setuptools import ( + get_blas_config, + get_hdf5_config, + add_coverage_flags_if_required, + add_debug_flags_if_required, + add_openmp_flags, +) + + # Python version check. We need >= 3.6 due to e.g. f-strings if sys.version_info < (3, 6): sys.exit('amici requires at least Python version 3.6') @@ -63,6 +82,8 @@ def main(): amici_module_linker_flags = [] define_macros = [] + add_openmp_flags(cxx_flags=cxx_flags, ldflags=amici_module_linker_flags) + blaspkgcfg = get_blas_config() amici_module_linker_flags.extend(blaspkgcfg['extra_link_args']) amici_module_linker_flags.extend( @@ -116,7 +137,8 @@ def main(): # Readme as long package description to go on PyPi # (https://pypi.org/project/amici/) - with open("README.md", "r", encoding="utf-8") as fh: + with open(os.path.join(os.path.dirname(__file__), "README.md"), + "r", encoding="utf-8") as fh: long_description = fh.read() # Build shared object @@ -184,7 +206,7 @@ def main(): 'amici_import_petab.py = amici.petab_import:main' ] }, - install_requires=['sympy', + install_requires=['sympy>=1.6.0', 'python-libsbml', 'h5py', 'pandas', diff --git a/deps/AMICI/python/sdist/setup_clibs.py b/deps/AMICI/python/sdist/setup_clibs.py index d64c7f0af..52b513a08 100644 --- a/deps/AMICI/python/sdist/setup_clibs.py +++ b/deps/AMICI/python/sdist/setup_clibs.py @@ -15,6 +15,22 @@ PackageInfo = Dict[str, List[Union[str, Tuple[str, Any]]]] Library = Tuple[str, PackageInfo] +# suite sparse include directories +suite_sparse_include_dirs = [ + 'amici/ThirdParty/SuiteSparse/KLU/Include/', + 'amici/ThirdParty/SuiteSparse/AMD/Include/', + 'amici/ThirdParty/SuiteSparse/COLAMD/Include/', + 'amici/ThirdParty/SuiteSparse/BTF/Include/', + 'amici/ThirdParty/SuiteSparse/SuiteSparse_config', + 'amici/ThirdParty/SuiteSparse/include' +] + +# sundials include directories +sundials_include_dirs = [ + 'amici/ThirdParty/sundials/include', + 'amici/ThirdParty/sundials/src', +] + def get_sundials_sources() -> List[str]: """Get list of Sundials source files""" @@ -43,23 +59,17 @@ def get_sundials_sources() -> List[str]: os.path.join('src', 'idas', 'idas_nls_sim.c'), os.path.join('src', 'idas', 'idaa_io.c'), os.path.join('src', 'sundials', 'sundials_math.c'), - os.path.join('src', 'sundials', 'sundials_mpi.c'), - os.path.join('src', 'sundials', 'sundials_sptfqmr.c'), os.path.join('src', 'sundials', 'sundials_matrix.c'), - os.path.join('src', 'sundials', 'sundials_pcg.c'), os.path.join('src', 'sundials', 'sundials_direct.c'), - os.path.join('src', 'sundials', 'sundials_spgmr.c'), - os.path.join('src', 'sundials', 'sundials_spbcgs.c'), os.path.join('src', 'sundials', 'sundials_nvector_senswrapper.c'), os.path.join('src', 'sundials', 'sundials_dense.c'), os.path.join('src', 'sundials', 'sundials_nvector.c'), os.path.join('src', 'sundials', 'sundials_version.c'), - os.path.join('src', 'sundials', 'sundials_spfgmr.c'), - os.path.join('src', 'sundials', 'sundials_sparse.c'), os.path.join('src', 'sundials', 'sundials_iterative.c'), os.path.join('src', 'sundials', 'sundials_nonlinearsolver.c'), os.path.join('src', 'sundials', 'sundials_linearsolver.c'), os.path.join('src', 'sundials', 'sundials_band.c'), + os.path.join('src', 'sundials', 'sundials_futils.c'), os.path.join('src', 'sunnonlinsol', 'newton', 'sunnonlinsol_newton.c'), os.path.join('src', 'sunnonlinsol', 'fixedpoint', 'sunnonlinsol_fixedpoint.c'), @@ -135,9 +145,9 @@ def get_amici_base_sources(with_hdf5: bool = True) -> List[str]: with_hdf5: compile with HDF5 support """ - amici_base_sources = glob.glob('amici{s}src{s}*.cpp'.format(s=os.sep)) - amici_base_sources = [src for src in amici_base_sources if not re.search( - r'(matlab)|(\.template\.)', src)] + amici_base_sources = glob.glob(os.path.join('amici', 'src', '*.cpp')) + amici_base_sources = [src for src in amici_base_sources + if not re.search(r'(matlab)|(\.(ODE_)?template\.)', src)] if not with_hdf5: hdf5_cpp = os.path.join('amici', 'src', 'hdf5.cpp') @@ -164,14 +174,9 @@ def get_lib_sundials(extra_compiler_flags: Optional[List[str]] = None) -> \ libsundials = ('sundials', { 'sources': get_sundials_sources(), - 'include_dirs': ['amici/ThirdParty/sundials/include', - 'amici/ThirdParty/sundials/src', - 'amici/ThirdParty/SuiteSparse/KLU/Include/', - 'amici/ThirdParty/SuiteSparse/AMD/Include/', - 'amici/ThirdParty/SuiteSparse/COLAMD/Include/', - 'amici/ThirdParty/SuiteSparse/BTF/Include/', - 'amici/ThirdParty/SuiteSparse/SuiteSparse_config', - 'amici/ThirdParty/SuiteSparse/include'], + 'include_dirs': [*sundials_include_dirs, + *suite_sparse_include_dirs, + ], 'cflags': [*extra_compiler_flags], 'cflags_mingw32': ['-Wno-misleading-indentation'], 'cflags_unix': ['-Wno-misleading-indentation'] @@ -192,13 +197,7 @@ def get_lib_suite_sparse(extra_compiler_flags: Optional[List[str]] = None) -> \ libsuitesparse = ('suitesparse', { 'sources': get_suite_sparse_sources(), - 'include_dirs': ['amici/ThirdParty/SuiteSparse/KLU/Include/', - 'amici/ThirdParty/SuiteSparse/AMD/Include/', - 'amici/ThirdParty/SuiteSparse/COLAMD/Include/', - 'amici/ThirdParty/SuiteSparse/BTF/Include/', - 'amici/ThirdParty/SuiteSparse/SuiteSparse_config', - 'amici/ThirdParty/SuiteSparse/include' - ], + 'include_dirs': suite_sparse_include_dirs, 'cflags': [*extra_compiler_flags], 'cflags_mingw32': ['-Wno-unused-but-set-variable'], 'cflags_unix': ['-Wno-unused-but-set-variable'] @@ -233,14 +232,8 @@ def get_lib_amici(extra_compiler_flags: List[str] = None, and h5pkgcfg['include_dirs']) ), 'include_dirs': ['amici/include', - 'amici/ThirdParty/SuiteSparse/KLU/Include/', - 'amici/ThirdParty/SuiteSparse/AMD/Include/', - 'amici/ThirdParty/SuiteSparse/COLAMD/Include/', - 'amici/ThirdParty/SuiteSparse/BTF/Include/', - 'amici/ThirdParty/SuiteSparse/SuiteSparse_config/', - 'amici/ThirdParty/SuiteSparse/include', - 'amici/ThirdParty/sundials/include', - 'amici/ThirdParty/sundials/src', + *suite_sparse_include_dirs, + *sundials_include_dirs, 'amici/ThirdParty/gsl/', ], 'cflags': [*extra_compiler_flags], diff --git a/deps/AMICI/python/tests/conftest.py b/deps/AMICI/python/tests/conftest.py index 16c2cf6ef..83b435130 100644 --- a/deps/AMICI/python/tests/conftest.py +++ b/deps/AMICI/python/tests/conftest.py @@ -66,7 +66,7 @@ def pysb_example_presimulation_module(): model.name = 'test_model_presimulation_pysb' outdir = model.name - pysb2amici(model, outdir, verbose=False, + pysb2amici(model, outdir, verbose=True, observables=['pPROT_obs'], constant_parameters=constant_parameters) diff --git a/deps/AMICI/python/tests/solverSettings.hdf5 b/deps/AMICI/python/tests/solverSettings.hdf5 new file mode 100644 index 000000000..6f3d655af Binary files /dev/null and b/deps/AMICI/python/tests/solverSettings.hdf5 differ diff --git a/deps/AMICI/python/tests/test_compare_conservation_laws_sbml.py b/deps/AMICI/python/tests/test_compare_conservation_laws_sbml.py new file mode 100644 index 000000000..2a7f207ef --- /dev/null +++ b/deps/AMICI/python/tests/test_compare_conservation_laws_sbml.py @@ -0,0 +1,211 @@ +import amici +import os +import sys +import pytest +import numpy as np +import warnings + + +@pytest.fixture +def edata_fixture(): + """edata is generated to test pre- and postequilibration""" + edata_pre = amici.ExpData(2, 0, 0, + np.array([0., 0.1, 0.2, 0.5, 1., 2., 5., 10.])) + edata_pre.setObservedData([1.5] * 16) + edata_pre.fixedParameters = np.array([5., 20.]) + edata_pre.fixedParametersPreequilibration = np.array([0., 10.]) + edata_pre.reinitializeFixedParameterInitialStates = True + + # edata for postequilibration + edata_post = amici.ExpData(2, 0, 0, + np.array([float('inf')] * 3)) + edata_post.setObservedData([0.75] * 6) + edata_post.fixedParameters = np.array([7.5, 30.]) + + # edata with both equilibrations + edata_full = amici.ExpData(2, 0, 0, + np.array([0., 0., 0., 1., 2., 2., 4., float('inf'), float('inf')])) + edata_full.setObservedData([3.14] * 18) + edata_full.fixedParameters = np.array([1., 2.]) + edata_full.fixedParametersPreequilibration = np.array([3., 4.]) + edata_full.reinitializeFixedParameterInitialStates = True + + return edata_pre, edata_post, edata_full + + +def generate_models(): + # SBML model we want to import + sbml_file = os.path.join(os.path.dirname(__file__), '..', + 'examples', 'example_constant_species', + 'model_constant_species.xml') + sbml_importer = amici.SbmlImporter(sbml_file) + + # Name of the model that will also be the name of the python module + model_name = model_output_dir ='model_constant_species' + model_name_cl = model_output_dir_cl = 'model_constant_species_cl' + + # Define constants, observables, sigmas + constant_parameters = ['synthesis_substrate', 'init_enzyme'] + observables = { + 'observable_product': {'name': '', 'formula': 'product'}, + 'observable_substrate': {'name': '', 'formula': 'substrate'}, + } + sigmas = {'observable_product': 1.0, 'observable_substrate': 1.0} + + # wrap models with and without conservations laws + sbml_importer.sbml2amici(model_name_cl, + model_output_dir_cl, + observables=observables, + constant_parameters=constant_parameters, + sigmas=sigmas) + sbml_importer.sbml2amici(model_name, + model_output_dir, + observables=observables, + constant_parameters=constant_parameters, + sigmas=sigmas, + compute_conservation_laws=False) + + # load both models + model_without_cl_module = amici.import_model_module(model_name, + module_path=os.path.abspath(model_name)) + model_with_cl_module = amici.import_model_module(model_name_cl, + module_path=os.path.abspath(model_name_cl)) + + # get the models and return + model_without_cl = model_without_cl_module.getModel() + model_with_cl = model_with_cl_module.getModel() + return model_with_cl, model_without_cl + + +def get_results(model, edata=None, sensi_order=0, + sensi_meth=amici.SensitivityMethod.forward, + sensi_meth_preeq=amici.SensitivityMethod.forward, + reinitialize_states=False): + + # set model and data properties + model.setReinitializeFixedParameterInitialStates(reinitialize_states) + + # get the solver, set the properties + solver = model.getSolver() + solver.setNewtonMaxSteps(20) + solver.setSensitivityOrder(sensi_order) + solver.setSensitivityMethodPreequilibration(sensi_meth_preeq) + solver.setSensitivityMethod(sensi_meth) + if edata is None: + model.setTimepoints(np.linspace(0, 5, 101)) + else: + edata.reinitializeFixedParameterInitialStates = reinitialize_states + + # return simulation results + return amici.runAmiciSimulation(model, solver, edata) + + +def test_compare_conservation_laws_sbml(edata_fixture): + # first, create the modek + model_with_cl, model_without_cl = generate_models() + + # ----- compare simulations wo edata, sensi = 0, states ------------------ + # run simulations + rdata_cl = get_results(model_with_cl) + assert rdata_cl['status'] == amici.AMICI_SUCCESS + rdata = get_results(model_without_cl) + assert rdata['status'] == amici.AMICI_SUCCESS + + # compare state trajectories + assert np.isclose(rdata['x'], rdata_cl['x']).all() + + # ----- compare simulations wo edata, sensi = 1, states and sensis ------- + # run simulations + rdata_cl = get_results(model_with_cl, sensi_order=1) + assert rdata_cl['status'] == amici.AMICI_SUCCESS + rdata = get_results(model_without_cl, sensi_order=1) + assert rdata['status'] == amici.AMICI_SUCCESS + + # compare state trajectories + for field in ['x', 'sx']: + assert np.isclose(rdata[field], rdata_cl[field]).all(), field + + # ----- compare simulations wo edata, sensi = 0, states and sensis ------- + model_without_cl.setSteadyStateSensitivityMode( + amici.SteadyStateSensitivityMode.simulationFSA + ) + + # run simulations + edata, _, _ = edata_fixture + rdata_cl = get_results(model_with_cl, edata=edata) + assert rdata_cl['status'] == amici.AMICI_SUCCESS + rdata = get_results(model_without_cl, edata=edata) + assert rdata['status'] == amici.AMICI_SUCCESS + + # compare preequilibrated states + for field in ['x', 'x_ss', 'llh']: + assert np.isclose(rdata[field], rdata_cl[field]).all(), field + + # ----- compare simulations wo edata, sensi = 1, states and sensis ------- + + # run simulations + rdata_cl = get_results(model_with_cl, edata=edata, sensi_order=1) + assert rdata_cl['status'] == amici.AMICI_SUCCESS + rdata = get_results(model_without_cl, edata=edata, sensi_order=1) + assert rdata['status'] == amici.AMICI_SUCCESS + # check that steady state computation succeeded only by sim in full model + assert (rdata['preeq_status'] == np.array([-3, 1, 0])).all() + # check that steady state computation succeeded by Newton in reduced model + assert (rdata_cl['preeq_status'] == np.array([1, 0, 0])).all() + + # compare state sensitivities with edata and preequilibration + for field in ['x', 'x_ss', 'sx', 'llh', 'sllh']: + assert np.isclose(rdata[field], rdata_cl[field]).all(), field + + # ----- check failure st.st. sensi computation if run wo CLs ------------- + # check failure of steady state senistivity computation if run wo CLs + model_without_cl.setSteadyStateSensitivityMode( + amici.SteadyStateSensitivityMode.newtonOnly + ) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + rdata = get_results(model_without_cl, edata=edata, sensi_order=1) + assert rdata['status'] == amici.AMICI_ERROR + +def test_adjoint_pre_and_post_equilibration(edata_fixture): + # get both models + model_module = amici.import_model_module('model_constant_species', + module_path=os.path.abspath('model_constant_species')) + model = model_module.getModel() + model_module_cl = amici.import_model_module('model_constant_species_cl', + module_path=os.path.abspath('model_constant_species_cl')) + model_cl = model_module_cl.getModel() + + # check gradient with and without state reinitialization + for edata in edata_fixture: + for reinit in [False, True]: + # --- compare different ways of preequilibration, full rank Jacobian --------- + # forward preequilibration, forward simulation + rff_cl = get_results(model_cl, edata=edata, sensi_order=1, + sensi_meth=amici.SensitivityMethod.forward, + sensi_meth_preeq=amici.SensitivityMethod.forward, + reinitialize_states=reinit) + # forward preequilibration, adjoint simulation + rfa_cl = get_results(model_cl, edata=edata, sensi_order=1, + sensi_meth=amici.SensitivityMethod.adjoint, + sensi_meth_preeq=amici.SensitivityMethod.forward, + reinitialize_states=reinit) + # adjoint preequilibration, adjoint simulation + raa_cl = get_results(model_cl, edata=edata, sensi_order=1, + sensi_meth=amici.SensitivityMethod.adjoint, + sensi_meth_preeq=amici.SensitivityMethod.adjoint, + reinitialize_states=reinit) + + # assert all are close + assert np.isclose(rff_cl['sllh'], rfa_cl['sllh']).all() + assert np.isclose(rfa_cl['sllh'], raa_cl['sllh']).all() + assert np.isclose(raa_cl['sllh'], rff_cl['sllh']).all() + + # --- compare fully adjoint approach to simulation with singular Jacobian ---- + raa = get_results(model, edata=edata, sensi_order=1, + sensi_meth=amici.SensitivityMethod.adjoint, + sensi_meth_preeq=amici.SensitivityMethod.adjoint, + reinitialize_states=reinit) + + # assert gradients are close (quadrature tolerances are laxer) + assert np.isclose(raa_cl['sllh'], raa['sllh'], 1e-5, 1e-5).all() diff --git a/deps/AMICI/python/tests/test_hdf5.py b/deps/AMICI/python/tests/test_hdf5.py index aa35e8c9f..76d63176d 100644 --- a/deps/AMICI/python/tests/test_hdf5.py +++ b/deps/AMICI/python/tests/test_hdf5.py @@ -19,6 +19,8 @@ def _modify_solver_attrs(solver): cval = not val elif attr == 'setStabilityLimitFlag': cval = 0 + elif attr == 'setReturnDataReportingMode': + cval = amici.RDataReporting.likelihood elif isinstance(val, int): cval = val + 1 else: diff --git a/deps/AMICI/python/tests/test_misc.py b/deps/AMICI/python/tests/test_misc.py index bda95ecb9..6cb302513 100644 --- a/deps/AMICI/python/tests/test_misc.py +++ b/deps/AMICI/python/tests/test_misc.py @@ -15,14 +15,14 @@ def test_parameter_scaling_from_int_vector(): scale_vector = amici.parameterScalingFromIntVector( [ - amici.ParameterScaling_log10, - amici.ParameterScaling_ln, - amici.ParameterScaling_none + amici.ParameterScaling.log10, + amici.ParameterScaling.ln, + amici.ParameterScaling.none ]) - assert scale_vector[0] == amici.ParameterScaling_log10 - assert scale_vector[1] == amici.ParameterScaling_ln - assert scale_vector[2] == amici.ParameterScaling_none + assert scale_vector[0] == amici.ParameterScaling.log10 + assert scale_vector[1] == amici.ParameterScaling.ln + assert scale_vector[2] == amici.ParameterScaling.none def test_sbml2amici_no_observables(): @@ -47,7 +47,8 @@ def test_sbml2amici_no_observables(): tmpdir = TemporaryDirectory() sbml_importer.sbml2amici(modelName="test", output_dir=tmpdir.name, - observables=None) + observables=None, + compute_conservation_laws=False) def test_hill_function_dwdx(): @@ -55,7 +56,7 @@ def test_hill_function_dwdx(): if involved states are zero if not properly arranged symbolically. Test that what we are applying the right sympy simplification.""" - w = sp.sympify('Pow(x1, p1) / (Pow(x1, p1) + a)') + w = sp.Matrix([[sp.sympify('Pow(x1, p1) / (Pow(x1, p1) + a)')]]) dwdx = w.diff(sp.Symbol('x1')) # Verify that without simplification we fail @@ -65,7 +66,7 @@ def test_hill_function_dwdx(): _ = str(res) # Test that powsimp does the job - dwdx = sp.powsimp(dwdx) + dwdx = dwdx.applyfunc(lambda x: sp.powsimp(x, deep=True)) with sp.evaluate(False): res = dwdx.subs({'x1': 0.0}) _ = str(res) @@ -79,4 +80,6 @@ def test_cmake_compilation(sbml_example_presimulation_module): cmd = f"set -e; cd {source_dir}; mkdir -p build; cd build; "\ "cmake ..; make" - subprocess.run(cmd, shell=True, capture_output=True, check=True) + + subprocess.run(cmd, shell=True, check=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) diff --git a/deps/AMICI/python/tests/test_pandas.py b/deps/AMICI/python/tests/test_pandas.py index 8e5e762d4..80ee45735 100644 --- a/deps/AMICI/python/tests/test_pandas.py +++ b/deps/AMICI/python/tests/test_pandas.py @@ -42,7 +42,7 @@ def test_pandas_import_export(sbml_example_presimulation_module, case): for fp in ['fixedParameters', 'fixedParametersPreequilibration', 'fixedParametersPresimulation']: - if fp != 'fixedParameters' or case[fp] is not (): + if fp != 'fixedParameters' or case[fp] != (): assert getattr(edata[0], fp) == getattr(edata_reconstructed[0], fp) assert case[fp] == getattr(edata_reconstructed[0], fp) diff --git a/deps/AMICI/python/tests/test_preequilibration.py b/deps/AMICI/python/tests/test_preequilibration.py index d9b0aa99e..6f5dd62ed 100644 --- a/deps/AMICI/python/tests/test_preequilibration.py +++ b/deps/AMICI/python/tests/test_preequilibration.py @@ -14,8 +14,8 @@ def preeq_fixture(pysb_example_presimulation_module): model.setReinitializeFixedParameterInitialStates(True) solver = model.getSolver() - solver.setSensitivityOrder(amici.SensitivityOrder_first) - solver.setSensitivityMethod(amici.SensitivityMethod_forward) + solver.setSensitivityOrder(amici.SensitivityOrder.first) + solver.setSensitivityMethod(amici.SensitivityMethod.forward) edata = get_data(model) edata.t_presim = 2 @@ -49,12 +49,12 @@ def preeq_fixture(pysb_example_presimulation_module): edata_sim.fixedParametersPreequilibration = () pscales = [ - amici.ParameterScaling_log10, amici.ParameterScaling_ln, - amici.ParameterScaling_none, + amici.ParameterScaling.log10, amici.ParameterScaling.ln, + amici.ParameterScaling.none, amici.parameterScalingFromIntVector([ - amici.ParameterScaling_log10, amici.ParameterScaling_ln, - amici.ParameterScaling_none, amici.ParameterScaling_log10, - amici.ParameterScaling_ln, amici.ParameterScaling_none + amici.ParameterScaling.log10, amici.ParameterScaling.ln, + amici.ParameterScaling.none, amici.ParameterScaling.log10, + amici.ParameterScaling.ln, amici.ParameterScaling.none ]) ] @@ -84,9 +84,11 @@ def test_manual_preequilibration(preeq_fixture): # combined rdata_auto = amici.runAmiciSimulation(model, solver, edata) + assert rdata_auto.status == amici.AMICI_SUCCESS # manual preequilibration rdata_preeq = amici.runAmiciSimulation(model, solver, edata_preeq) + assert rdata_preeq.status == amici.AMICI_SUCCESS # manual reinitialization + presimulation x0 = rdata_preeq['x'][0, :] @@ -98,6 +100,7 @@ def test_manual_preequilibration(preeq_fixture): model.setInitialStates(x0) model.setInitialStateSensitivities(sx0.flatten()) rdata_presim = amici.runAmiciSimulation(model, solver, edata_presim) + assert rdata_presim.status == amici.AMICI_SUCCESS # manual reinitialization + simulation x0 = rdata_presim['x'][0, :] @@ -109,6 +112,7 @@ def test_manual_preequilibration(preeq_fixture): model.setInitialStates(x0) model.setInitialStateSensitivities(sx0.flatten()) rdata_sim = amici.runAmiciSimulation(model, solver, edata_sim) + assert rdata_sim.status == amici.AMICI_SUCCESS for variable in ['x', 'sx']: assert np.isclose( @@ -138,6 +142,43 @@ def test_parameter_reordering(preeq_fixture): ).all(), plist +def test_data_replicates(preeq_fixture): + """Test data replicates""" + + model, solver, edata, edata_preeq, \ + edata_presim, edata_sim, pscales, plists = preeq_fixture + + sensi_meth = amici.SensitivityMethod.forward + solver.setSensitivityMethod(sensi_meth) + + # add infty timepoint + y = edata.getObservedData() + stdy = edata.getObservedDataStdDev() + ts = np.hstack([*edata.getTimepoints(), np.inf]) + edata.setTimepoints(sorted(ts)) + edata.setObservedData(np.hstack([y, y[0]])) + edata.setObservedDataStdDev(np.hstack([stdy, stdy[0]])) + rdata_single = amici.runAmiciSimulation(model, solver, edata) + + # duplicate data and timepoints + y = edata.getObservedData() + stdy = edata.getObservedDataStdDev() + ts = np.hstack([*edata.getTimepoints(), *edata.getTimepoints()]) + idx = np.argsort(ts) + edata.setTimepoints(sorted(ts)) + edata.setObservedData(np.hstack([y, y])[idx]) + edata.setObservedDataStdDev(np.hstack([stdy, stdy])[idx]) + + rdata_double = amici.runAmiciSimulation(model, solver, edata) + + for variable in ['llh', 'sllh']: + assert np.isclose( + 2*rdata_single[variable], + rdata_double[variable], + 1e-6, 1e-6 + ).all(), dict(variable=variable, sensi_meth=sensi_meth) + + def test_parameter_in_expdata(preeq_fixture): """Test parameter in ExpData""" @@ -146,6 +187,18 @@ def test_parameter_in_expdata(preeq_fixture): rdata = amici.runAmiciSimulation(model, solver, edata) + # get initial states will compute initial states if nothing is set, + # this needs go first as we need unmodified model. Also set to + # preequilibration fixpars first as this is where initial states would be + # computed otherwise + model.setFixedParameters(edata.fixedParametersPreequilibration) + edata.x0 = model.getInitialStates() + edata.sx0 = model.getInitialStateSensitivities() + + # perturb model initial states + model.setInitialStates(rdata['x_ss'] * 4) + model.setInitialStateSensitivities(rdata['sx_ss'].flatten() / 2) + # set ExpData plist edata.plist = model.getParameterList() # perturb model parameter list @@ -165,19 +218,12 @@ def test_parameter_in_expdata(preeq_fixture): # perturb model pscale, needs to be done after getting parameters, # otherwise we will mess up parameter value model.setParameterScale(amici.parameterScalingFromIntVector([ - amici.ParameterScaling_log10 - if scaling == amici.ParameterScaling_none - else amici.ParameterScaling_none + amici.ParameterScaling.log10 + if scaling == amici.ParameterScaling.none + else amici.ParameterScaling.none for scaling in model.getParameterScale() ])) - edata.x0 = rdata['x_ss'] - edata.sx0 = rdata['sx_ss'].flatten() - - # perturb model initial states - model.setInitialStates(rdata['x_ss'] * 4) - model.setInitialStateSensitivities(rdata['sx_ss'].flatten() / 2) - rdata_edata = amici.runAmiciSimulation( model, solver, edata ) @@ -187,3 +233,145 @@ def test_parameter_in_expdata(preeq_fixture): rdata_edata[variable][0, :], 1e-6, 1e-6 ).all(), variable + + +def test_raise_presimulation_with_adjoints(preeq_fixture): + """Test data replicates""" + + model, solver, edata, edata_preeq, \ + edata_presim, edata_sim, pscales, plists = preeq_fixture + + # preequilibration and presimulation with adjoints: + # this needs to fail unless we remove presimulation + solver.setSensitivityMethod(amici.SensitivityMethod.adjoint) + + rdata = amici.runAmiciSimulation(model, solver, edata) + assert rdata['status'] == amici.AMICI_ERROR + + # presimulation and postequilibration with adjoints: + # this also needs to fail + y = edata.getObservedData() + stdy = edata.getObservedDataStdDev() + + # add infty timepoint + ts = np.hstack([*edata.getTimepoints(), np.inf]) + edata.setTimepoints(sorted(ts)) + edata.setObservedData(np.hstack([y, y[0]])) + edata.setObservedDataStdDev(np.hstack([stdy, stdy[0]])) + edata.t_presim = 0 + edata.fixedParametersPresimulation = () + + # no presim any more, this should work + rdata = amici.runAmiciSimulation(model, solver, edata) + assert rdata['status'] == amici.AMICI_SUCCESS + + +def test_equilibration_methods_with_adjoints(preeq_fixture): + """Test data replicates""" + + model, solver, edata, edata_preeq, \ + edata_presim, edata_sim, pscales, plists = preeq_fixture + + # we don't want presim + edata.t_presim = 0.0 + edata.fixedParametersPresimulation = () + + # add infty timepoint + y = edata.getObservedData() + stdy = edata.getObservedDataStdDev() + ts = np.hstack([*edata.getTimepoints(), np.inf]) + edata.setTimepoints(sorted(ts)) + edata.setObservedData(np.hstack([y, y[0]])) + edata.setObservedDataStdDev(np.hstack([stdy, stdy[0]])) + + rdatas = {} + equil_meths = [amici.SteadyStateSensitivityMode.newtonOnly, + amici.SteadyStateSensitivityMode.simulationFSA] + sensi_meths = [amici.SensitivityMethod.forward, + amici.SensitivityMethod.adjoint] + settings = itertools.product(equil_meths, sensi_meths) + + for setting in settings: + # unpack, solver settings + equil_meth, sensi_meth = setting + model.setSteadyStateSensitivityMode(equil_meth) + solver.setSensitivityMethod(sensi_meth) + solver.setNewtonMaxSteps(0) + + # add rdatas + rdatas[setting] = amici.runAmiciSimulation(model, solver, edata) + # assert successful simulation + + assert rdatas[setting]['status'] == amici.AMICI_SUCCESS + + for setting1, setting2 in itertools.product(settings, settings): + # assert correctness of result + for variable in ['llh', 'sllh']: + assert np.isclose( + rdatas[setting1][variable], + rdatas[setting2][variable], + 1e-6, 1e-6 + ).all(), variable + + +def test_newton_solver_equilibration(preeq_fixture): + """Test data replicates""" + + model, solver, edata, edata_preeq, \ + edata_presim, edata_sim, pscales, plists = preeq_fixture + + # we don't want presim + edata.t_presim = 0.0 + edata.fixedParametersPresimulation = () + + # add infty timepoint + y = edata.getObservedData() + stdy = edata.getObservedDataStdDev() + ts = np.hstack([*edata.getTimepoints(), np.inf]) + edata.setTimepoints(sorted(ts)) + edata.setObservedData(np.hstack([y, y[0]])) + edata.setObservedDataStdDev(np.hstack([stdy, stdy[0]])) + + rdatas = {} + settings = [amici.SteadyStateSensitivityMode.simulationFSA, + amici.SteadyStateSensitivityMode.newtonOnly] + + for equil_meth in settings: + # set sensi method + sensi_meth = amici.SensitivityMethod.forward + solver.setSensitivityMethod(sensi_meth) + model.setSteadyStateSensitivityMode(equil_meth) + if equil_meth == amici.SteadyStateSensitivityMode.newtonOnly: + solver.setNewtonMaxSteps(10) + else: + solver.setNewtonMaxSteps(0) + + # add rdatas + rdatas[equil_meth] = amici.runAmiciSimulation(model, solver, edata) + + # assert successful simulation + assert rdatas[equil_meth]['status'] == amici.AMICI_SUCCESS + + # assert correct results + for variable in ['llh', 'sllh', 'sx0', 'sx_ss', 'x_ss']: + assert np.isclose( + rdatas[settings[0]][variable], + rdatas[settings[1]][variable], + 1e-6, 1e-6 + ).all(), variable + + # test failure for iterative linear solver with sensitivities + edata.fixedParametersPreequilibration = () + edata.t_presim = 0.0 + edata.fixedParametersPresimulation = () + + solver.setLinearSolver(amici.LinearSolver.SPBCG) + solver.setSensitivityMethod(amici.SensitivityMethod.adjoint) + solver.setSensitivityOrder(amici.SensitivityOrder.first) + model.setSteadyStateSensitivityMode( + amici.SteadyStateSensitivityMode.newtonOnly) + solver.setNewtonMaxSteps(10) + solver.setNewtonMaxLinearSteps(10) + rdata_spbcg = amici.runAmiciSimulation(model, solver, edata) + + assert rdata_spbcg['status'] == amici.AMICI_ERROR diff --git a/deps/AMICI/python/tests/test_pregenerated_models.py b/deps/AMICI/python/tests/test_pregenerated_models.py index 53715b99f..653af09a6 100755 --- a/deps/AMICI/python/tests/test_pregenerated_models.py +++ b/deps/AMICI/python/tests/test_pregenerated_models.py @@ -81,8 +81,8 @@ def test_pregenerated_model(sub_test, case): and len(model.getParameterList()) \ and not model_name.startswith('model_neuron') \ and not case.endswith('byhandpreeq'): - check_derivatives(model, solver, edata, - assert_fun, **check_derivative_opts) + check_derivatives(model, solver, edata, assert_fun, + **check_derivative_opts) verify_simulation_opts = dict() @@ -97,19 +97,19 @@ def test_pregenerated_model(sub_test, case): verify_simulation_results( rdata, expected_results[sub_test][case]['results'], - assert_fun, **verify_simulation_opts + **verify_simulation_opts ) if model_name == 'model_steadystate' and \ case == 'sensiforwarderrorint': edata = amici.amici.ExpData(model.get()) + # Test runAmiciSimulations: ensure running twice + # with same ExpData yields same results if edata and model_name != 'model_neuron_o2' and not ( model_name == 'model_robertson' and case == 'sensiforwardSPBCG' ): - # Test runAmiciSimulations: ensure running twice - # with same ExpData yields same results if isinstance(edata, amici.amici.ExpData): edatas = [edata, edata] else: @@ -120,33 +120,70 @@ def test_pregenerated_model(sub_test, case): failfast=False ) verify_simulation_results( - rdatas[0], - expected_results[sub_test][case]['results'], - assert_fun, **verify_simulation_opts + rdatas[0], expected_results[sub_test][case]['results'], + **verify_simulation_opts ) verify_simulation_results( - rdatas[1], - expected_results[sub_test][case]['results'], - assert_fun, **verify_simulation_opts + rdatas[1], expected_results[sub_test][case]['results'], + **verify_simulation_opts ) + # test residuals mode + if solver.getSensitivityMethod() == amici.SensitivityMethod.adjoint: + with pytest.raises(RuntimeError): + solver.setReturnDataReportingMode(amici.RDataReporting.residuals) + else: + solver.setReturnDataReportingMode(amici.RDataReporting.residuals) + rdata = amici.runAmiciSimulation(model, solver, edata) + verify_simulation_results( + rdata, expected_results[sub_test][case]['results'], + fields=['t', 'res', 'sres', 'y', 'sy', 'sigmay', 'ssigmay'], + **verify_simulation_opts + ) + with pytest.raises(RuntimeError): + solver.setSensitivityMethod(amici.SensitivityMethod.adjoint) + + # test likelihood mode + solver.setReturnDataReportingMode(amici.RDataReporting.likelihood) + rdata = amici.runAmiciSimulation(model, solver, edata) + verify_simulation_results( + rdata, expected_results[sub_test][case]['results'], + fields=['t', 'llh', 'sllh', 's2llh', 'FIM'], **verify_simulation_opts + ) + with pytest.raises(RuntimeError): model.getParameterByName('thisParameterDoesNotExist') -def verify_simulation_results(rdata, expected_results, assert_fun, +def verify_simulation_results(rdata, expected_results, fields=None, atol=1e-8, rtol=1e-4): """ compares all fields of the simulation results in rdata against the expectedResults using the provided tolerances - Arguments: - rdata: simulation results as returned by amici.runAmiciSimulation - expected_results: stored test results - atol: absolute tolerance - rtol: relative tolerance + :param rdata: simulation results as returned by amici.runAmiciSimulation + :param expected_results: stored test results + :param fields: subsetting of expected results to check + :param atol: absolute tolerance + :param rtol: relative tolerance """ + subfields = [] + if fields is None: + attrs = expected_results.attrs.keys() + fields = expected_results.keys() + if 'diagnosis' in expected_results.keys(): + subfields = expected_results['diagnosis'].keys() + + else: + attrs = [field for field in fields + if field in expected_results.attrs.keys()] + if 'diagnosis' in expected_results.keys(): + subfields = [field for field in fields + if field in expected_results['diagnosis'].keys()] + fields = [field for field in fields + if field in expected_results.keys()] + if expected_results.attrs['status'][0] != 0: assert rdata['status'] == expected_results.attrs['status'][0] return @@ -154,10 +191,16 @@ def verify_simulation_results(rdata, expected_results, assert_fun, for field in expected_results.keys(): if field == 'diagnosis': for subfield in ['J', 'xdot']: + if subfield not in subfields: + assert rdata[subfield] is None, field + continue check_results(rdata, subfield, expected_results[field][subfield][()], assert_fun, 1e-8, 1e-8) else: + if field not in fields: + assert rdata[field] is None, field + continue if field == 's2llh': check_results(rdata, field, expected_results[field][()], assert_fun, 1e-4, 1e-3) @@ -165,6 +208,6 @@ def verify_simulation_results(rdata, expected_results, assert_fun, check_results(rdata, field, expected_results[field][()], assert_fun, atol, rtol) - for attr in expected_results.attrs.keys(): + for attr in attrs: check_results(rdata, attr, expected_results.attrs[attr], assert_fun, atol, rtol) diff --git a/deps/AMICI/python/tests/test_pysb.py b/deps/AMICI/python/tests/test_pysb.py index 888b0dd4e..4c799f6c3 100644 --- a/deps/AMICI/python/tests/test_pysb.py +++ b/deps/AMICI/python/tests/test_pysb.py @@ -37,10 +37,7 @@ def test_compare_to_sbml_import(pysb_example_presimulation_module, ['sbml', 'pysb']): # check equilibrium fixed parameters assert np.isclose( - [ - sum(rdata["x_ss"][[1, 3]]), - sum(rdata["x_ss"][[2, 4]]) - ], + [sum(rdata["x_ss"][[1, 3]]), sum(rdata["x_ss"][[2, 4]])], edata.fixedParametersPreequilibration, atol=1e-6, rtol=1e-6 ).all(), f'{importer} preequilibration' @@ -60,9 +57,9 @@ def test_compare_to_sbml_import(pysb_example_presimulation_module, atol=1e-6, rtol=1e-6 ).all(), f'{importer} presimulation' - skip_attrs = ['ptr', 't_steadystate', 'numsteps', 'newton_numsteps', + skip_attrs = ['ptr', 'preeq_t', 'numsteps', 'preeq_numsteps', 'numrhsevals', 'numerrtestfails', 'order', 'J', 'xdot', - 'wrms_steadystate', 'newton_cpu_time', 'cpu_time', + 'preeq_wrms', 'preeq_cpu_time', 'cpu_time', 'cpu_timeB', 'w'] for field in rdata_pysb: @@ -73,6 +70,10 @@ def test_compare_to_sbml_import(pysb_example_presimulation_module, assert rdata_sbml[field] is None, field elif rdata_sbml[field] is None: assert rdata_pysb[field] is None, field + elif np.isnan(rdata_sbml[field]).all(): + assert np.isnan(rdata_pysb[field]).all(), field + elif np.isnan(rdata_pysb[field]).all(): + assert np.isnan(rdata_sbml[field]).all(), field else: assert np.isclose( rdata_sbml[field], rdata_pysb[field], @@ -173,7 +174,7 @@ def get_data(model): solver = model.getSolver() model.setTimepoints(np.linspace(0, 60, 61)) model.setSteadyStateSensitivityMode( - amici.SteadyStateSensitivityMode_simulationFSA + amici.SteadyStateSensitivityMode.simulationFSA ) rdata = amici.runAmiciSimulation(model, solver) @@ -192,6 +193,6 @@ def get_results(model, edata): edata.reinitializeFixedParameterInitialStates = True model.setTimepoints(np.linspace(0, 60, 61)) model.setSteadyStateSensitivityMode( - amici.SteadyStateSensitivityMode_simulationFSA + amici.SteadyStateSensitivityMode.simulationFSA ) return amici.runAmiciSimulation(model, solver, edata) diff --git a/deps/AMICI/python/tests/test_sbml_import.py b/deps/AMICI/python/tests/test_sbml_import.py index b32ea3d37..27c6d6de0 100644 --- a/deps/AMICI/python/tests/test_sbml_import.py +++ b/deps/AMICI/python/tests/test_sbml_import.py @@ -42,7 +42,8 @@ def test_sbml2amici_no_observables(simple_sbml_model): with TemporaryDirectory() as tmpdir: sbml_importer.sbml2amici(model_name="test", output_dir=tmpdir, - observables=None) + observables=None, + compute_conservation_laws=False) def assert_fun(x): @@ -87,9 +88,9 @@ def test_presimulation(sbml_example_presimulation_module): solver.setNewtonMaxSteps(0) model.setTimepoints(np.linspace(0, 60, 61)) model.setSteadyStateSensitivityMode( - amici.SteadyStateSensitivityMode_simulationFSA + amici.SteadyStateSensitivityMode.simulationFSA ) - solver.setSensitivityOrder(amici.SensitivityOrder_first) + solver.setSensitivityOrder(amici.SensitivityOrder.first) model.setReinitializeFixedParameterInitialStates(True) rdata = amici.runAmiciSimulation(model, solver) @@ -110,7 +111,7 @@ def test_steadystate_simulation(model_steadystate_module): model = model_steadystate_module.getModel() model.setTimepoints(np.linspace(0, 60, 60)) solver = model.getSolver() - solver.setSensitivityOrder(amici.SensitivityOrder_first) + solver.setSensitivityOrder(amici.SensitivityOrder.first) rdata = amici.runAmiciSimulation(model, solver) edata = [amici.ExpData(rdata, 1, 0)] rdata = amici.runAmiciSimulations(model, solver, edata) @@ -214,7 +215,7 @@ def test_likelihoods(model_test_likelihoods): model = model_test_likelihoods.getModel() model.setTimepoints(np.linspace(0, 60, 60)) solver = model.getSolver() - solver.setSensitivityOrder(amici.SensitivityOrder_first) + solver.setSensitivityOrder(amici.SensitivityOrder.first) # run model once to create an edata rdata = amici.runAmiciSimulation(model, solver) diff --git a/deps/AMICI/python/tests/test_swig_interface.py b/deps/AMICI/python/tests/test_swig_interface.py index fe738ef77..daef6db99 100644 --- a/deps/AMICI/python/tests/test_swig_interface.py +++ b/deps/AMICI/python/tests/test_swig_interface.py @@ -18,7 +18,6 @@ def test_copy_constructors(pysb_example_presimulation_module): model = pysb_example_presimulation_module.getModel() solver = model.getSolver() - # TODO: expand this to serialization for obj in [model, solver]: for attr in dir(obj): if attr.startswith('__') \ @@ -73,10 +72,18 @@ def get_val(obj, attr): def get_mod_val(val, attr): if attr == 'getStabilityLimitFlag': return val - 1 + elif attr == 'getReturnDataReportingMode': + return amici.RDataReporting.likelihood + elif attr == 'getParameterList': + return tuple(get_mod_val(val[0], '') for _ in val) + elif attr == 'getStateIsNonNegative': + raise ValueError('Cannot modify value') elif isinstance(val, bool): return not val elif isinstance(val, numbers.Number): return val + 1 + elif isinstance(val, tuple): + return tuple(get_mod_val(v, attr) for v in val) raise ValueError('Cannot modify value') diff --git a/deps/AMICI/scripts/buildAmici.sh b/deps/AMICI/scripts/buildAmici.sh index 6cc95105a..cc2ba1603 100755 --- a/deps/AMICI/scripts/buildAmici.sh +++ b/deps/AMICI/scripts/buildAmici.sh @@ -8,13 +8,13 @@ make=${MAKE:-make} script_path=$(dirname "$BASH_SOURCE") amici_path=$(cd "$script_path/.." && pwd) +amici_build_dir="${amici_path}/build" +mkdir -p "${amici_build_dir}" +cd "${amici_build_dir}" -mkdir -p "${amici_path}/build" -cd "${amici_path}/build" +cpputest_build_dir="${amici_path}/ThirdParty/cpputest-master/build/" -cpputest_build_dir="${amici_path}"/ThirdParty/cpputest-master/build/ - -if [[ $TRAVIS = true ]]; then +if [[ $TRAVIS = true ]] || [[ $GITHUB_ACTIONS = true ]]; then # Running on CI server build_type="Debug" else @@ -22,9 +22,19 @@ else fi CppUTest_DIR=${cpputest_build_dir} \ - ${cmake} -DCMAKE_BUILD_TYPE=$build_type -DPython3_EXECUTABLE="$(command -v python3)" .. - -${make} + ${cmake} \ + -DCMAKE_BUILD_TYPE=$build_type \ + -DPython3_EXECUTABLE="$(command -v python3)" .. -${make} python-sdist -set -x +# build, with or without sonarcloud wrapper +if [[ "$CI_SONARCLOUD" == "TRUE" ]]; then + build-wrapper-linux-x86-64 \ + --out-dir "${amici_path}/bw-output" \ + cmake --build . --parallel +elif [[ "$TRAVIS" == "true" ]]; then + cmake --build . + ${make} python-sdist +else + cmake --build . --parallel + ${make} python-sdist +fi diff --git a/deps/AMICI/scripts/installAmiciSource.sh b/deps/AMICI/scripts/installAmiciSource.sh index b07c792d1..ea129b3dd 100755 --- a/deps/AMICI/scripts/installAmiciSource.sh +++ b/deps/AMICI/scripts/installAmiciSource.sh @@ -21,7 +21,7 @@ if [[ $? ]]; then python3 -m venv ${AMICI_PATH}/build/venv --clear --without-pip source ${AMICI_PATH}/build/venv/bin/activate curl https://bootstrap.pypa.io/get-pip.py -o ${AMICI_PATH}/build/get-pip.py - python ${AMICI_PATH}/build/get-pip.py + python3 ${AMICI_PATH}/build/get-pip.py else set -e source ${AMICI_PATH}/build/venv/bin/activate @@ -29,6 +29,7 @@ fi # install wheel separately to prevent build_wheel fail in next step pip install --upgrade wheel -pip install --upgrade pip setuptools pkgconfig scipy matplotlib pysb coverage +pip install --upgrade pip setuptools pkgconfig scipy matplotlib coverage pytest pytest-cov +pip install git+https://github.com/pysb/pysb # pin to develop to fix sympy compatibility pip install --verbose -e ${AMICI_PATH}/python/sdist[petab] deactivate diff --git a/deps/AMICI/sonar-project.properties b/deps/AMICI/sonar-project.properties new file mode 100644 index 000000000..912de4d43 --- /dev/null +++ b/deps/AMICI/sonar-project.properties @@ -0,0 +1,21 @@ +# SonarScanner configuration +# https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/ +# https://docs.sonarqube.org/latest/analysis/analysis-parameters/ +# https://sonarcloud.io/documentation/analysis/languages/cfamily/ + +sonar.host.url=https://sonarcloud.io +sonar.login=af35cb17710485d21c8e453a77f1f008eae1f7a4 +sonar.organization=icb-dcm +sonar.projectKey=ICB-DCM_AMICI + +sonar.sources=. +sonar.exclusions=build/**,ThirdParty/**,doc/**,models/**,python/sdist/amici/**,**/*.html,**/*.m,model_*/** + +sonar.sourceEncoding=UTF-8 + +sonar.cfamily.threads=2 +sonar.cfamily.gcov.reportsPath=build +sonar.cfamily.cache.enabled=true +sonar.cfamily.cache.path=sonar_cache + +sonar.python.coverage.reportPaths=build/coverage_py.xml diff --git a/deps/AMICI/src/abstract_model.cpp b/deps/AMICI/src/abstract_model.cpp index 6b1076e20..ca978a4a2 100644 --- a/deps/AMICI/src/abstract_model.cpp +++ b/deps/AMICI/src/abstract_model.cpp @@ -2,313 +2,569 @@ namespace amici { -const std::string AbstractModel::getAmiciVersion() const { +const std::string +AbstractModel::getAmiciVersion() const +{ throw AmiException("Version not set during code generation"); } -const std::string AbstractModel::getAmiciCommit() const { +const std::string +AbstractModel::getAmiciCommit() const +{ throw AmiException("Commit not set during code generation"); } -void AbstractModel::fx0(realtype * /*x0*/, const realtype /*t*/, const realtype * /*p*/, - const realtype * /*k*/) { +void +AbstractModel::fx0(realtype* /*x0*/, + const realtype /*t*/, + const realtype* /*p*/, + const realtype* /*k*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -bool AbstractModel::isFixedParameterStateReinitializationAllowed() const { +bool +AbstractModel::isFixedParameterStateReinitializationAllowed() const +{ return false; } -void AbstractModel::fx0_fixedParameters(realtype *x0, const realtype t, - const realtype *p, const realtype *k) {} - -void AbstractModel::fsx0_fixedParameters(realtype *sx0, const realtype t, - const realtype *x0, const realtype *p, - const realtype *k, const int ip) {} - -void AbstractModel::fsx0(realtype * /*sx0*/, const realtype /*t*/, const realtype * /*x0*/, - const realtype * /*p*/, const realtype * /*k*/, const int /*ip*/) { +void +AbstractModel::fx0_fixedParameters(realtype* /*x0*/, + const realtype /*t*/, + const realtype* /*p*/, + const realtype* /*k*/) +{ + // no-op default implementation +} + +void +AbstractModel::fsx0_fixedParameters(realtype* /*sx0*/, + const realtype /*t*/, + const realtype* /*x0*/, + const realtype* /*p*/, + const realtype* /*k*/, + const int /*ip*/) +{ + // no-op default implementation +} + +void +AbstractModel::fsx0(realtype* /*sx0*/, + const realtype /*t*/, + const realtype* /*x0*/, + const realtype* /*p*/, + const realtype* /*k*/, + const int /*ip*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdx0(AmiVector &x0, AmiVector &dx0) {} +void +AbstractModel::fdx0(AmiVector& /*x0*/, AmiVector& /*dx0*/) +{ + // no-op default implementation +} -void AbstractModel::fstau(realtype * /*stau*/, const realtype /*t*/, const realtype * /*x*/, - const realtype * /*p*/, const realtype * /*k*/, - const realtype * /*h*/, const realtype * /*sx*/, const int /*ip*/, - const int /*ie*/) { +void +AbstractModel::fstau(realtype* /*stau*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const realtype* /*sx*/, + const int /*ip*/, + const int /*ie*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fy(realtype * /*y*/, const realtype /*t*/, const realtype * /*x*/, - const realtype * /*p*/, const realtype * /*k*/, const realtype * /*h*/, - const realtype * /*w*/) { +void +AbstractModel::fy(realtype* /*y*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const realtype* /*w*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdydp(realtype * /*dydp*/, const realtype /*t*/, const realtype * /*x*/, - const realtype * /*p*/, const realtype * /*k*/, - const realtype * /*h*/, const int /*ip*/, const realtype * /*w*/, - const realtype * /*dwdp*/) { +void +AbstractModel::fdydp(realtype* /*dydp*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const int /*ip*/, + const realtype* /*w*/, + const realtype* /*dwdp*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdydx(realtype * /*dydx*/, const realtype /*t*/, const realtype * /*x*/, - const realtype * /*p*/, const realtype * /*k*/, - const realtype * /*h*/, const realtype * /*w*/, - const realtype * /*dwdx*/) { +void +AbstractModel::fdydx(realtype* /*dydx*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const realtype* /*w*/, + const realtype* /*dwdx*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fz(realtype * /*z*/, const int /*ie*/, const realtype /*t*/, - const realtype * /*x*/, const realtype * /*p*/, const realtype * /*k*/, - const realtype * /*h*/) { +void +AbstractModel::fz(realtype* /*z*/, + const int /*ie*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fsz(realtype * /*sz*/, const int /*ie*/, const realtype /*t*/, - const realtype * /*x*/, const realtype * /*p*/, const realtype * /*k*/, - const realtype * /*h*/, const realtype * /*sx*/, const int /*ip*/) { +void +AbstractModel::fsz(realtype* /*sz*/, + const int /*ie*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const realtype* /*sx*/, + const int /*ip*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::frz(realtype * /*rz*/, const int /*ie*/, const realtype /*t*/, - const realtype * /*x*/, const realtype * /*p*/, const realtype * /*k*/, - const realtype * /*h*/) { +void +AbstractModel::frz(realtype* /*rz*/, + const int /*ie*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fsrz(realtype * /*srz*/, const int /*ie*/, const realtype /*t*/, - const realtype * /*x*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*h*/, - const realtype * /*sx*/, const int /*ip*/) { +void +AbstractModel::fsrz(realtype* /*srz*/, + const int /*ie*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const realtype* /*sx*/, + const int /*ip*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdzdp(realtype * /*dzdp*/, const int /*ie*/, const realtype /*t*/, - const realtype * /*x*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*h*/, const int /*ip*/) { +void +AbstractModel::fdzdp(realtype* /*dzdp*/, + const int /*ie*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const int /*ip*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdzdx(realtype * /*dzdx*/, const int /*ie*/, const realtype /*t*/, - const realtype * /*x*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*h*/) { +void +AbstractModel::fdzdx(realtype* /*dzdx*/, + const int /*ie*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdrzdp(realtype * /*drzdp*/, const int /*ie*/, const realtype /*t*/, - const realtype * /*x*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*h*/, const int /*ip*/) { +void +AbstractModel::fdrzdp(realtype* /*drzdp*/, + const int /*ie*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const int /*ip*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdrzdx(realtype * /*drzdx*/, const int /*ie*/, const realtype /*t*/, - const realtype * /*x*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*h*/) { +void +AbstractModel::fdrzdx(realtype* /*drzdx*/, + const int /*ie*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdeltax(realtype * /*deltax*/, const realtype /*t*/, - const realtype * /*x*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*h*/, const int /*ie*/, - const realtype * /*xdot*/, const realtype * /*xdot_old*/) { +void +AbstractModel::fdeltax(realtype* /*deltax*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const int /*ie*/, + const realtype* /*xdot*/, + const realtype* /*xdot_old*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdeltasx(realtype * /*deltasx*/, const realtype /*t*/, - const realtype * /*x*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*h*/, - const realtype * /*w*/, const int /*ip*/, const int /*ie*/, - const realtype * /*xdot*/, const realtype * /*xdot_old*/, - const realtype * /*sx*/, const realtype * /*stau*/) { +void +AbstractModel::fdeltasx(realtype* /*deltasx*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const realtype* /*w*/, + const int /*ip*/, + const int /*ie*/, + const realtype* /*xdot*/, + const realtype* /*xdot_old*/, + const realtype* /*sx*/, + const realtype* /*stau*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdeltaxB(realtype * /*deltaxB*/, const realtype /*t*/, - const realtype * /*x*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*h*/, const int /*ie*/, - const realtype * /*xdot*/, const realtype * /*xdot_old*/, - const realtype * /*xB*/) { +void +AbstractModel::fdeltaxB(realtype* /*deltaxB*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const int /*ie*/, + const realtype* /*xdot*/, + const realtype* /*xdot_old*/, + const realtype* /*xB*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdeltaqB(realtype * /*deltaqB*/, const realtype /*t*/, - const realtype * /*x*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*h*/, const int /*ip*/, - const int /*ie*/, const realtype * /*xdot*/, - const realtype * /*xdot_old*/, const realtype * /*xB*/) { +void +AbstractModel::fdeltaqB(realtype* /*deltaqB*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const int /*ip*/, + const int /*ie*/, + const realtype* /*xdot*/, + const realtype* /*xdot_old*/, + const realtype* /*xB*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fsigmay(realtype * /*sigmay*/, const realtype /*t*/, - const realtype * /*p*/, const realtype * /*k*/) { +void +AbstractModel::fsigmay(realtype* /*sigmay*/, + const realtype /*t*/, + const realtype* /*p*/, + const realtype* /*k*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdsigmaydp(realtype * /*dsigmaydp*/, const realtype /*t*/, - const realtype * /*p*/, const realtype * /*k*/, - const int /*ip*/) { +void +AbstractModel::fdsigmaydp(realtype* /*dsigmaydp*/, + const realtype /*t*/, + const realtype* /*p*/, + const realtype* /*k*/, + const int /*ip*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fsigmaz(realtype * /*sigmaz*/, const realtype /*t*/, - const realtype * /*p*/, const realtype * /*k*/) { +void +AbstractModel::fsigmaz(realtype* /*sigmaz*/, + const realtype /*t*/, + const realtype* /*p*/, + const realtype* /*k*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdsigmazdp(realtype * /*dsigmazdp*/, const realtype /*t*/, - const realtype * /*p*/, const realtype * /*k*/, - const int /*ip*/) { +void +AbstractModel::fdsigmazdp(realtype* /*dsigmazdp*/, + const realtype /*t*/, + const realtype* /*p*/, + const realtype* /*k*/, + const int /*ip*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fJy(realtype * /*nllh*/, const int /*iy*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*y*/, - const realtype * /*sigmay*/, const realtype * /*my*/) { +void +AbstractModel::fJy(realtype* /*nllh*/, + const int /*iy*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*y*/, + const realtype* /*sigmay*/, + const realtype* /*my*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fJz(realtype * /*nllh*/, const int /*iz*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*z*/, - const realtype * /*sigmaz*/, const realtype * /*mz*/) { +void +AbstractModel::fJz(realtype* /*nllh*/, + const int /*iz*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*z*/, + const realtype* /*sigmaz*/, + const realtype* /*mz*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fJrz(realtype * /*nllh*/, const int /*iz*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*z*/, - const realtype * /*sigmaz*/) { +void +AbstractModel::fJrz(realtype* /*nllh*/, + const int /*iz*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*z*/, + const realtype* /*sigmaz*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdJydy(realtype * /*dJydy*/, const int /*iy*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*y*/, - const realtype * /*sigmay*/, const realtype * /*my*/) { +void +AbstractModel::fdJydy(realtype* /*dJydy*/, + const int /*iy*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*y*/, + const realtype* /*sigmay*/, + const realtype* /*my*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdJydsigma(realtype * /*dJydsigma*/, const int /*iy*/, - const realtype * /*p*/, const realtype * /*k*/, - const realtype * /*y*/, const realtype * /*sigmay*/, - const realtype * /*my*/) { +void +AbstractModel::fdJydsigma(realtype* /*dJydsigma*/, + const int /*iy*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*y*/, + const realtype* /*sigmay*/, + const realtype* /*my*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdJzdz(realtype * /*dJzdz*/, const int /*iz*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*z*/, - const realtype * /*sigmaz*/, const realtype * /*mz*/) { +void +AbstractModel::fdJzdz(realtype* /*dJzdz*/, + const int /*iz*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*z*/, + const realtype* /*sigmaz*/, + const realtype* /*mz*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdJzdsigma(realtype * /*dJzdsigma*/, const int /*iz*/, - const realtype * /*p*/, const realtype * /*k*/, - const realtype * /*z*/, const realtype * /*sigmaz*/, - const realtype * /*mz*/) { +void +AbstractModel::fdJzdsigma(realtype* /*dJzdsigma*/, + const int /*iz*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*z*/, + const realtype* /*sigmaz*/, + const realtype* /*mz*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdJrzdz(realtype * /*dJrzdz*/, const int /*iz*/, const realtype * /*p*/, - const realtype * /*k*/, const realtype * /*rz*/, - const realtype * /*sigmaz*/) { +void +AbstractModel::fdJrzdz(realtype* /*dJrzdz*/, + const int /*iz*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*rz*/, + const realtype* /*sigmaz*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fdJrzdsigma(realtype * /*dJrzdsigma*/, const int /*iz*/, - const realtype * /*p*/, const realtype * /*k*/, - const realtype * /*rz*/, const realtype * /*sigmaz*/) { +void +AbstractModel::fdJrzdsigma(realtype* /*dJrzdsigma*/, + const int /*iz*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*rz*/, + const realtype* /*sigmaz*/) +{ throw AmiException("Requested functionality is not supported as (%s) is " "not implemented for this model!", __func__); } -void AbstractModel::fw(realtype *w, const realtype t, const realtype *x, - const realtype *p, const realtype *k, const realtype *h, - const realtype *tcl) {} - -void AbstractModel::fdwdp(realtype *dwdp, const realtype t, const realtype *x, - const realtype *p, const realtype *k, - const realtype *h, const realtype *w, - const realtype *tcl, const realtype *stcl) { +void +AbstractModel::fw(realtype* /*w*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const realtype* /*tcl*/) +{ + // no-op default implementation +} + +void +AbstractModel::fdwdp(realtype* /*dwdp*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const realtype* /*w*/, + const realtype* /*tcl*/, + const realtype* /*stcl*/) +{ + // no-op default implementation +} + +void +AbstractModel::fdwdp_colptrs(sunindextype* /*indexptrs*/) +{ + // no-op default implementation +} + +void +AbstractModel::fdwdp_rowvals(sunindextype* /*indexvals*/) +{ + // no-op default implementation +} + +void +AbstractModel::fdwdp(realtype* /*dwdp*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const realtype* /*w*/, + const realtype* /*tcl*/, + const realtype* /*stcl*/, + const int /*ip*/) +{ + // no-op default implementation +} + +void +AbstractModel::fdwdx(realtype* /*dwdx*/, + const realtype /*t*/, + const realtype* /*x*/, + const realtype* /*p*/, + const realtype* /*k*/, + const realtype* /*h*/, + const realtype* /*w*/, + const realtype* /*tcl*/) +{ + // no-op default implementation +} + +void +AbstractModel::fdwdx_colptrs(sunindextype* /*indexptrs*/) +{ + // no-op default implementation +} + +void +AbstractModel::fdwdx_rowvals(sunindextype* /*indexvals*/) +{ + // no-op default implementation } -void AbstractModel::fdwdp_colptrs(sunindextype *indexptrs) {} - -void AbstractModel::fdwdp_rowvals(sunindextype *indexvals) {} - -void AbstractModel::fdwdp(realtype *dwdp, const realtype t, const realtype *x, - const realtype *p, const realtype *k, - const realtype *h, const realtype *w, - const realtype *tcl, const realtype *stcl, - const int ip) { -} - -void AbstractModel::fdwdx(realtype *dwdx, const realtype t, const realtype *x, - const realtype *p, const realtype *k, - const realtype *h, const realtype *w, - const realtype *tcl) {} - -void AbstractModel::fdwdx_colptrs(sunindextype *indexptrs) {} - -void AbstractModel::fdwdx_rowvals(sunindextype *indexvals) {} - } // namespace amici diff --git a/deps/AMICI/src/amici.cpp b/deps/AMICI/src/amici.cpp index 39423f2c1..4e381e6aa 100644 --- a/deps/AMICI/src/amici.cpp +++ b/deps/AMICI/src/amici.cpp @@ -5,6 +5,7 @@ #include "amici/amici.h" +#include "amici/steadystateproblem.h" #include "amici/backwardproblem.h" #include "amici/forwardproblem.h" #include "amici/misc.h" @@ -21,15 +22,18 @@ #include // ensure definitions are in sync -static_assert(AMICI_SUCCESS == CV_SUCCESS, "AMICI_SUCCESS != CV_SUCCESS"); -static_assert(AMICI_DATA_RETURN == CV_TSTOP_RETURN, +static_assert(amici::AMICI_SUCCESS == CV_SUCCESS, + "AMICI_SUCCESS != CV_SUCCESS"); +static_assert(amici::AMICI_DATA_RETURN == CV_TSTOP_RETURN, "AMICI_DATA_RETURN != CV_TSTOP_RETURN"); -static_assert(AMICI_ROOT_RETURN == CV_ROOT_RETURN, +static_assert(amici::AMICI_ROOT_RETURN == CV_ROOT_RETURN, "AMICI_ROOT_RETURN != CV_ROOT_RETURN"); -static_assert(AMICI_ILL_INPUT == CV_ILL_INPUT, +static_assert(amici::AMICI_ILL_INPUT == CV_ILL_INPUT, "AMICI_ILL_INPUT != CV_ILL_INPUT"); -static_assert(AMICI_NORMAL == CV_NORMAL, "AMICI_NORMAL != CV_NORMAL"); -static_assert(AMICI_ONE_STEP == CV_ONE_STEP, "AMICI_ONE_STEP != CV_ONE_STEP"); +static_assert(amici::AMICI_NORMAL == CV_NORMAL, + "AMICI_NORMAL != CV_NORMAL"); +static_assert(amici::AMICI_ONE_STEP == CV_ONE_STEP, + "AMICI_ONE_STEP != CV_ONE_STEP"); static_assert(std::is_same::value, "Definition of realtype does not match"); @@ -96,30 +100,70 @@ AmiciApplication::runAmiciSimulation(Solver& solver, Model& model, bool rethrow) { - std::unique_ptr rdata; - /* Applies condition-specific model settings and restores them when going * out of scope */ - ConditionContext conditionContext(&model, edata); + ConditionContext cc1(&model, edata, FixedParameterContext::simulation); + + std::unique_ptr rdata = std::make_unique(solver, + model); + + if (model.nx_solver <= 0) { + return rdata; + } + + std::unique_ptr preeq {}; + std::unique_ptr fwd {}; + std::unique_ptr bwd {}; + std::unique_ptr posteq {}; try { - rdata = std::unique_ptr(new ReturnData(solver, model)); + if (solver.getPreequilibration() || + (edata && !edata->fixedParametersPreequilibration.empty())) { + ConditionContext cc2( + &model, edata, FixedParameterContext::preequilibration + ); - if (model.nx_solver <= 0) { - return rdata; + preeq = std::make_unique(solver, model); + preeq->workSteadyStateProblem(&solver, &model, -1); } - auto fwd = std::unique_ptr( - new ForwardProblem(rdata.get(), edata, &model, &solver)); + + fwd = std::make_unique(edata, &model, &solver, + preeq.get()); fwd->workForwardProblem(); - auto bwd = - std::unique_ptr(new BackwardProblem(fwd.get())); - bwd->workBackwardProblem(); + + if (fwd->getCurrentTimeIteration() < model.nt()) { + posteq = std::make_unique(solver, model); + posteq->workSteadyStateProblem(&solver, &model, + fwd->getCurrentTimeIteration()); + } + + + if (edata && solver.computingASA()) { + fwd->getAdjointUpdates(model, *edata); + if (posteq) { + posteq->getAdjointUpdates(model, *edata); + posteq->workSteadyStateBackwardProblem(&solver, &model, + bwd.get()); + } + + + bwd = std::make_unique(*fwd, posteq.get()); + bwd->workBackwardProblem(); + + + if (preeq) { + ConditionContext cc2(&model, edata, + FixedParameterContext::preequilibration); + preeq->workSteadyStateBackwardProblem(&solver, &model, + bwd.get()); + } + } rdata->status = AMICI_SUCCESS; + } catch (amici::IntegrationFailure const& ex) { - rdata->invalidate(ex.time); rdata->status = ex.error_code; if (rethrow) throw; @@ -128,7 +172,6 @@ AmiciApplication::runAmiciSimulation(Solver& solver, ex.time, ex.what()); } catch (amici::IntegrationFailureB const& ex) { - rdata->invalidateSLLH(); rdata->status = ex.error_code; if (rethrow) throw; @@ -139,7 +182,6 @@ AmiciApplication::runAmiciSimulation(Solver& solver, ex.time, ex.what()); } catch (amici::AmiException const& ex) { - rdata->invalidate(model.t0()); rdata->status = AMICI_ERROR; if (rethrow) throw; @@ -149,8 +191,8 @@ AmiciApplication::runAmiciSimulation(Solver& solver, ex.getBacktrace()); } - rdata->applyChainRuleFactorToSimulationResults(&model); - + rdata->processSimulationObjects(preeq.get(), fwd.get(), bwd.get(), + posteq.get(), model, solver, edata); return rdata; } @@ -196,7 +238,7 @@ AmiciApplication::runAmiciSimulations(const Solver& solver, } void -AmiciApplication::warningF(const char* identifier, const char* format, ...) +AmiciApplication::warningF(const char* identifier, const char* format, ...) const { va_list argptr; va_start(argptr, format); @@ -206,7 +248,7 @@ AmiciApplication::warningF(const char* identifier, const char* format, ...) } void -AmiciApplication::errorF(const char* identifier, const char* format, ...) +AmiciApplication::errorF(const char* identifier, const char* format, ...) const { va_list argptr; va_start(argptr, format); diff --git a/deps/AMICI/src/backwardproblem.cpp b/deps/AMICI/src/backwardproblem.cpp index 564517252..6e4b1a598 100644 --- a/deps/AMICI/src/backwardproblem.cpp +++ b/deps/AMICI/src/backwardproblem.cpp @@ -4,37 +4,58 @@ #include "amici/solver.h" #include "amici/exception.h" #include "amici/edata.h" -#include "amici/rdata.h" #include "amici/forwardproblem.h" +#include "amici/steadystateproblem.h" +#include "amici/misc.h" #include namespace amici { -BackwardProblem::BackwardProblem(const ForwardProblem *fwd) : - model(fwd->model), - rdata(fwd->rdata), - solver(fwd->solver), - t(fwd->getTime()), - llhS0(static_cast(fwd->model->nJ * fwd->model->nplist()), 0.0), - xB(fwd->model->nx_solver), - dxB(fwd->model->nx_solver), - xQB(fwd->model->nJ*fwd->model->nplist()), - x_disc(fwd->getStatesAtDiscontinuities()), - xdot_disc(fwd->getRHSAtDiscontinuities()), - xdot_old_disc(fwd->getRHSBeforeDiscontinuities()), - sx0(fwd->getStateSensitivity()), - nroots(fwd->getNumberOfRoots()), - discs(fwd->getDiscontinuities()), - irdiscs(fwd->getDiscontinuities()), - iroot(fwd->getRootCounter()), - rootidx(fwd->getRootIndexes()), - dJydx(fwd->getDJydx()), - dJzdx(fwd->getDJzdx()) {} +BackwardProblem::BackwardProblem(const ForwardProblem &fwd, + const SteadystateProblem *posteq): + model(fwd.model), + solver(fwd.solver), + edata(fwd.edata), + t(fwd.getTime()), + xB(fwd.model->nx_solver), + dxB(fwd.model->nx_solver), + xQB(fwd.model->nJ*fwd.model->nplist()), + x_disc(fwd.getStatesAtDiscontinuities()), + xdot_disc(fwd.getRHSAtDiscontinuities()), + xdot_old_disc(fwd.getRHSBeforeDiscontinuities()), + sx0(fwd.getStateSensitivity()), + nroots(fwd.getNumberOfRoots()), + discs(fwd.getDiscontinuities()), + rootidx(fwd.getRootIndexes()), + dJydx(fwd.getDJydx()), + dJzdx(fwd.getDJzdx()) { + /* complement dJydx from postequilibration. This should overwrite + * anything but only fill in previously 0 values, as only non-inf + * timepoints are filled from fwd. + */ + for (int it = 0; it < fwd.model->nt(); it++) { + if (std::isinf(fwd.model->getTimepoint(it))) { + if (!posteq) + throw AmiException("Model has non-finite timpoint but, " + "postequilibration did not run"); + + /* copy adjoint update to postequilibration */ + writeSlice(slice(posteq->getDJydx(), it, + fwd.model->nx_solver * fwd.model->nJ), + slice(this->dJydx, it, + fwd.model->nx_solver * fwd.model->nJ)); + + /* If adjoint sensis were computed, copy also quadratures */ + xQB.reset(); + xQB = posteq->getEquilibrationQuadratures(); + } + } + } -void BackwardProblem::workBackwardProblem() { +void BackwardProblem::workBackwardProblem() { if (model->nx_solver <= 0 || solver->getSensitivityOrder() < SensitivityOrder::first || @@ -42,43 +63,46 @@ void BackwardProblem::workBackwardProblem() { model->nplist() == 0) { return; } - - int it = rdata->nt - 1; - model->initializeB(xB, dxB, xQB); - handleDataPointB(it); - solver->setupB(&which, rdata->ts[it], model, xB, dxB, xQB); - - --it; - --iroot; - - while (it >= 0 || iroot >= 0) { - - /* check if next timepoint is a discontinuity or a data-point */ - double tnext = getTnext(discs, iroot, it); - - if (tnext < t) { - solver->runB(tnext); - solver->writeSolutionB(&t, xB, dxB, xQB, this->which); - solver->getDiagnosisB(it, rdata, this->which); - } - /* handle discontinuity */ - if (model->ne > 0 && rdata->nmaxevent > 0 && iroot >= 0) { - if (tnext == discs.at(iroot)) { - handleEventB(iroot); - --iroot; + int it = model->nt() - 1; + /* If we have posteq, infty timepoints were already treated */ + for (int jt = model->nt() - 1; jt >= 0; jt--) + if (std::isinf(model->getTimepoint(jt))) + --it; + + /* initialize state vectors, depending on postequilibration */ + model->initializeB(xB, dxB, xQB, it < model->nt() - 1); + + if ((it >= 0 || !discs.empty()) && model->getTimepoint(it) > model->t0()) + { + handleDataPointB(it); + solver->setupB(&which, model->getTimepoint(it), model, xB, dxB, xQB); + --it; + + while (it >= 0 || discs.size() > 0) { + /* check if next timepoint is a discontinuity or a data-point */ + double tnext = getTnext(it); + + if (tnext < t) { + solver->runB(tnext); + solver->writeSolutionB(&t, xB, dxB, xQB, this->which); } - } - /* handle data-point */ - if (tnext == rdata->ts[it]) { - handleDataPointB(it); - it--; - } + /* handle discontinuity */ + if (tnext > model->getTimepoint(it)) { + handleEventB(); + } + + /* handle data-point */ + if (tnext == model->getTimepoint(it)) { + handleDataPointB(it); + it--; + } - /* reinit states */ - solver->reInitB(which, t, xB, dxB); - solver->quadReInitB(which, xQB); + /* reinit states */ + solver->reInitB(which, t, xB, dxB); + solver->quadReInitB(which, xQB); + } } /* we still need to integrate from first datapoint to tstart */ @@ -86,47 +110,61 @@ void BackwardProblem::workBackwardProblem() { /* solve for backward problems */ solver->runB(model->t0()); solver->writeSolutionB(&t, xB, dxB, xQB, this->which); - solver->getDiagnosisB(0, rdata, this->which); } - computeLikelihoodSensitivities(); - rdata->cpu_timeB = solver->getCpuTimeB(); + if (edata && edata->t_presim > 0) { + ConditionContext cc(model, edata, FixedParameterContext::presimulation); + solver->runB(model->t0() - edata->t_presim); + solver->writeSolutionB(&t, xB, dxB, xQB, this->which); + } } -void BackwardProblem::handleEventB(const int iroot) { +void BackwardProblem::handleEventB() { + auto rootidx = this->rootidx.back(); + this->rootidx.pop_back(); + + auto x_disc = this->x_disc.back(); + this->x_disc.pop_back(); + + auto xdot_disc = this->xdot_disc.back(); + this->xdot_disc.pop_back(); + + auto xdot_old_disc = this->xdot_old_disc.back(); + this->xdot_old_disc.pop_back(); + for (int ie = 0; ie < model->ne; ie++) { - if (rootidx[iroot * model->ne + ie] == 0) { + if (rootidx[ie] == 0) { continue; } - model->addAdjointQuadratureEventUpdate(xQB, ie, t, x_disc[iroot], xB, - xdot_disc[iroot], - xdot_old_disc[iroot]); - model->addAdjointStateEventUpdate(xB, ie, t, x_disc[iroot], - xdot_disc[iroot], - xdot_old_disc[iroot]); + model->addAdjointQuadratureEventUpdate(xQB, ie, t, x_disc, xB, + xdot_disc, + xdot_old_disc); + model->addAdjointStateEventUpdate(xB, ie, t, x_disc, + xdot_disc, + xdot_old_disc); - for (int ix = 0; ix < model->nxtrue_solver; ++ix) { - for (int iJ = 0; iJ < model->nJ; ++iJ) { - if (model->nz > 0) { + if (model->nz > 0) { + for (int ix = 0; ix < model->nxtrue_solver; ++ix) { + for (int iJ = 0; iJ < model->nJ; ++iJ) { xB[ix + iJ * model->nxtrue_solver] += - dJzdx[iJ + ( ix + nroots[ie] * model->nx_solver ) * model->nJ]; + dJzdx[iJ + ( ix + nroots[ie] * model->nx_solver ) + * model->nJ]; } } } - - nroots[ie]--; } - model->updateHeavisideB(&rootidx[iroot * model->ne]); + model->updateHeavisideB(rootidx.data()); } - void BackwardProblem::handleDataPointB(const int it) { + solver->storeDiagnosisB(this->which); + for (int ix = 0; ix < model->nxtrue_solver; ix++) { for (int iJ = 0; iJ < model->nJ; iJ++) // we only need the 1:nxtrue_solver (not the nx_true) slice here! @@ -135,50 +173,14 @@ void BackwardProblem::handleDataPointB(const int it) { } } -realtype BackwardProblem::getTnext(std::vector const& troot, - const int iroot, const int it) { - if (it < 0 - || (iroot >= 0 && model->ne > 0 && troot.at(iroot) > rdata->ts[it])) { - return troot.at(iroot); +realtype BackwardProblem::getTnext(const int it) { + if (discs.size() > 0 && discs.back() > model->getTimepoint(it)) { + double tdisc = discs.back(); + discs.pop_back(); + return tdisc; } - return rdata->ts[it]; -} - - -void BackwardProblem::computeLikelihoodSensitivities() -{ - for (int iJ = 0; iJ < model->nJ; iJ++) { - if (iJ == 0) { - for (int ip = 0; ip < model->nplist(); ++ip) { - llhS0[ip] = 0.0; - for (int ix = 0; ix < model->nxtrue_solver; ++ix) { - llhS0[ip] += xB[ix] * sx0.at(ix,ip); - } - } - } else { - for (int ip = 0; ip < model->nplist(); ++ip) { - llhS0[ip + iJ * model->nplist()] = 0.0; - for (int ix = 0; ix < model->nxtrue_solver; ++ix) { - llhS0[ip + iJ * model->nplist()] += - xB[ix + iJ * model->nxtrue_solver] * sx0.at(ix,ip)+ - xB[ix] * sx0.at(ix + iJ * model->nxtrue_solver,ip); - } - } - } - } - - for (int iJ = 0; iJ < model->nJ; iJ++) { - for (int ip = 0; ip < model->nplist(); ip++) { - if (iJ == 0) { - rdata->sllh.at(ip) -= llhS0[ip] + xQB[ip*model->nJ]; - } else { - rdata->s2llh.at(iJ - 1 + ip * (model->nJ - 1)) -= - llhS0[ip + iJ * model->nplist()] + - xQB[iJ + ip*model->nJ]; - } - } - } + return model->getTimepoint(it); } } // namespace amici diff --git a/deps/AMICI/src/edata.cpp b/deps/AMICI/src/edata.cpp index 851eb9e02..2ade1ea29 100644 --- a/deps/AMICI/src/edata.cpp +++ b/deps/AMICI/src/edata.cpp @@ -48,9 +48,12 @@ ExpData::ExpData(int nytrue, int nztrue, int nmaxevent, setObservedEventsStdDev(observedEventsStdDev); } -ExpData::ExpData(Model const& model) +ExpData::ExpData(Model const &model) : ExpData(model.nytrue, model.nztrue, model.nMaxEvent(), - model.getTimepoints(), model.getFixedParameters()) {} + model.getTimepoints(), model.getFixedParameters()) { + reinitializeFixedParameterInitialStates = + model.getReinitializeFixedParameterInitialStates(); +} ExpData::ExpData(ReturnData const& rdata, realtype sigma_y, realtype sigma_z) : ExpData(rdata, std::vector(rdata.nytrue*rdata.nt, sigma_y), std::vector(rdata.nztrue*rdata.nmaxevent, sigma_z)) {} @@ -104,7 +107,7 @@ std::vector const& ExpData::getTimepoints() const { } int ExpData::nt() const { - return ts.size(); + return static_cast(ts.size()); } realtype ExpData::getTimepoint(int it) const { @@ -320,7 +323,8 @@ int ExpData::nmaxevent() const return nmaxevent_; } -ConditionContext::ConditionContext(Model *model, const ExpData *edata) +ConditionContext::ConditionContext(Model *model, const ExpData *edata, + FixedParameterContext fpc) : model(model), originalParameters(model->getParameters()), originalFixedParameters(model->getFixedParameters()), @@ -336,7 +340,7 @@ ConditionContext::ConditionContext(Model *model, const ExpData *edata) if(model->hasCustomInitialStateSensitivities()) originalsx0 = model->getInitialStateSensitivities(); - applyCondition(edata); + applyCondition(edata, fpc); } ConditionContext::~ConditionContext() @@ -344,7 +348,8 @@ ConditionContext::~ConditionContext() restore(); } -void ConditionContext::applyCondition(const ExpData *edata) +void ConditionContext::applyCondition(const ExpData *edata, + FixedParameterContext fpc) { if(!edata) return; @@ -389,13 +394,45 @@ void ConditionContext::applyCondition(const ExpData *edata) model->setParameters(edata->parameters); } - if(!edata->fixedParameters.empty()) { - // fixed parameter in model are superseded by those provided in edata - if(edata->fixedParameters.size() != (unsigned) model->nk()) - throw AmiException("Number of fixed parameters (%d) in model does" - " not match ExpData (%zd).", - model->nk(), edata->fixedParameters.size()); - model->setFixedParameters(edata->fixedParameters); + switch (fpc) { + case FixedParameterContext::simulation: + if (!edata->fixedParameters.empty()) { + // fixed parameter in model are superseded by those provided in + // edata + if (edata->fixedParameters.size() + != (unsigned)model->nk()) + throw AmiException("Number of fixed parameters (%d) in model does" + "not match ExpData (%zd).", + model->nk(), edata->fixedParameters.size()); + model->setFixedParameters(edata->fixedParameters); + } + break; + case FixedParameterContext::preequilibration: + if (!edata->fixedParametersPreequilibration.empty()) { + // fixed parameter in model are superseded by those provided in + // edata + if (edata->fixedParametersPreequilibration.size() != + (unsigned)model->nk()) + throw AmiException("Number of fixed parameters (%d) in model does" + "not match ExpData (preequilibration) (%zd).", + model->nk(), + edata->fixedParametersPreequilibration.size()); + model->setFixedParameters(edata->fixedParametersPreequilibration); + } + break; + case FixedParameterContext::presimulation: + if (!edata->fixedParametersPresimulation.empty()) { + // fixed parameter in model are superseded by those provided in + // edata + if (edata->fixedParametersPresimulation.size() + != (unsigned)model->nk()) + throw AmiException("Number of fixed parameters (%d) in model does" + " not match ExpData (presimulation) (%zd).", + model->nk(), + edata->fixedParametersPresimulation.size()); + model->setFixedParameters(edata->fixedParametersPresimulation); + } + break; } if(edata->nt()) { diff --git a/deps/AMICI/src/exception.cpp b/deps/AMICI/src/exception.cpp index e2ea1e9b1..024d0a105 100644 --- a/deps/AMICI/src/exception.cpp +++ b/deps/AMICI/src/exception.cpp @@ -11,26 +11,22 @@ namespace amici { AmiException::AmiException(const char *fmt, ...) { va_list ap; va_start(ap, fmt); - vsnprintf(msg, sizeof(msg), fmt, ap); + vsnprintf(msg.data(), msg.size(), fmt, ap); va_end(ap); storeBacktrace(12); } -AmiException::AmiException(const amici::AmiException &old) { - snprintf(msg, sizeof(msg), "%s", old.msg); - snprintf(trace, sizeof(trace), "%s", old.trace); -} - const char *AmiException::what() const noexcept { - return msg; + return msg.data(); } const char *AmiException::getBacktrace() const { - return trace; + return trace.data(); } void AmiException::storeBacktrace(const int nMaxFrames) { - snprintf(trace, sizeof(trace), "%s", backtraceString(nMaxFrames).c_str()); + snprintf(trace.data(), trace.size(), "%s", + backtraceString(nMaxFrames).c_str()); } CvodeException::CvodeException(const int error_code, const char *function) : diff --git a/deps/AMICI/src/forwardproblem.cpp b/deps/AMICI/src/forwardproblem.cpp index a5ad78b27..8fa06efea 100644 --- a/deps/AMICI/src/forwardproblem.cpp +++ b/deps/AMICI/src/forwardproblem.cpp @@ -6,7 +6,6 @@ #include "amici/solver.h" #include "amici/exception.h" #include "amici/edata.h" -#include "amici/rdata.h" #include "amici/steadystateproblem.h" #include @@ -15,101 +14,106 @@ namespace amici { -ForwardProblem::ForwardProblem(ReturnData *rdata, const ExpData *edata, - Model *model, Solver *solver) +ForwardProblem::ForwardProblem(const ExpData *edata, Model *model, + Solver *solver, const SteadystateProblem *preeq) : model(model), - rdata(rdata), solver(solver), edata(edata), - rootidx(static_cast(model->ne * model->ne * model->nMaxEvent()), 0), nroots(static_cast(model->ne), 0), rootvals(static_cast(model->ne), 0.0), rvaltmp(static_cast(model->ne), 0.0), - discs(static_cast(model->nMaxEvent() * model->ne), 0.0), - irdiscs(model->nMaxEvent() * model->ne, 0.0), - x_disc(model->nx_solver, model->nMaxEvent()*model->ne), - xdot_disc(model->nx_solver, model->nMaxEvent()*model->ne), - xdot_old_disc(model->nx_solver, model->nMaxEvent()*model->ne), dJydx(model->nJ * model->nx_solver * model->nt(), 0.0), dJzdx(model->nJ * model->nx_solver * model->nMaxEvent(), 0.0), t(model->t0()), rootsfound(model->ne, 0), - Jtmp(SUNMatrixWrapper(model->nx_solver,model->nx_solver)), x(model->nx_solver), - x_rdata(model->nx_rdata), x_old(model->nx_solver), dx(model->nx_solver), dx_old(model->nx_solver), xdot(model->nx_solver), xdot_old(model->nx_solver), sx(model->nx_solver,model->nplist()), - sx_rdata(model->nx_rdata,model->nplist()), sdx(model->nx_solver,model->nplist()), stau(model->nplist()) { + if (preeq) { + x = preeq->getState(); + sx = preeq->getStateSensitivity(); + preequilibrated = true; + } } - void ForwardProblem::workForwardProblem() { - if(edata){ - rdata->initializeObjectiveFunction(); - } - + FinalStateStorer fss(this); if(model->nx_solver == 0){ return; } - /* if preequilibration is necessary, start Newton solver */ - if (solver->getPreequilibration() || - (edata && !edata->fixedParametersPreequilibration.empty())) { - handlePreequilibration(); - } else { + auto presimulate = edata && edata->t_presim > 0; + + /* if preequilibration was done, model was already initialized */ + if (!preequilibrated) model->initialize(x, dx, sx, sdx, solver->getSensitivityOrder() >= SensitivityOrder::first); - // handlePreequilibration will setup the solver on its own. - solver->setup(model->t0(), model, x, dx, sx, sdx); - // update x0 after computing consistence IC, only important for DAEs - x.copy(solver->getState(model->t0())); - - model->fx_rdata(x_rdata, x); - rdata->x0 = x_rdata.getVector(); - if (solver->getSensitivityMethod() == SensitivityMethod::forward && - solver->getSensitivityOrder() >= SensitivityOrder::first) { - model->fsx_rdata(sx_rdata, sx); - for (int ix = 0; ix < rdata->nx; ix++) { - for (int ip = 0; ip < model->nplist(); ip++) - rdata->sx0[ip*rdata->nx + ix] = sx_rdata.at(ix,ip); - } - } - } + + /* compute initial time and setup solver for (pre-)simulation */ + auto t0 = model->t0(); + if (presimulate) + t0 -= edata->t_presim; + solver->setup(t0, model, x, dx, sx, sdx); /* perform presimulation if necessary */ - if (edata && edata->t_presim > 0) + if (presimulate) { + if (solver->computingASA()) + throw AmiException("Presimulation with adjoint sensitivities" + " is currently not implemented."); handlePresimulation(); + t = model->t0(); + } + /* when computing adjoint sensitivity analysis with presimulation, + we need to store sx after the reinitialization after preequilibration + but before reinitialization after presimulation. As presimulation with ASA + will not update sx, we can simply extract the values here.*/ + if (solver->computingASA() && presimulate) + sx = solver->getStateSensitivity(model->t0()); + + if (presimulate || preequilibrated) + solver->updateAndReinitStatesAndSensitivities(model); + + // update x0 after computing consistence IC/reinitialization + x = solver->getState(model->t0()); + /* when computing forward sensitivities, we generally want to update sx + after presimulation/preequilibration, and if we didn't do either this also + wont harm. when computing ASA, we only want to update here, if we didn't + update before presimulation (if applicable). + */ + if (solver->computingFSA() || (solver->computingASA() && !presimulate )) + sx = solver->getStateSensitivity(model->t0()); + + + /* store initial state and sensitivity*/ + initial_state = getSimulationState(); /* loop over timepoints */ - for (int it = 0; it < model->nt(); it++) { + for (it = 0; it < model->nt(); it++) { auto nextTimepoint = model->getTimepoint(it); + if (std::isinf(nextTimepoint)) + break; + if (nextTimepoint > model->t0()) { // Solve for nextTimepoint while (t < nextTimepoint) { - if (std::isinf(nextTimepoint)) { - SteadystateProblem sstate = SteadystateProblem(solver, x); - sstate.workSteadyStateProblem(rdata, solver, model, it); - sstate.writeSolution(&t, x, sx); - } else { - int status = solver->run(nextTimepoint); - solver->writeSolution(&t, x, dx, sx); - /* sx will be copied from solver on demand if sensitivities - are computed */ - if (status == AMICI_ILL_INPUT) { - /* clustering of roots => turn off rootfinding */ - solver->turnOffRootFinding(); - } else if (status == AMICI_ROOT_RETURN) { - handleEvent(&tlastroot, false); - } + int status = solver->run(nextTimepoint); + solver->writeSolution(&t, x, dx, sx, dx); + /* sx will be copied from solver on demand if sensitivities + are computed */ + if (status == AMICI_ILL_INPUT) { + /* clustering of roots => turn off rootfinding */ + solver->turnOffRootFinding(); + } else if (status == AMICI_ROOT_RETURN) { + handleEvent(&tlastroot, false); } } } @@ -117,115 +121,19 @@ void ForwardProblem::workForwardProblem() { } /* fill events */ - if (model->nz > 0) { - getEventOutput(); - } - - // set likelihood - if (!edata) { - rdata->invalidateLLH(); - rdata->invalidateSLLH(); - } - - storeJacobianAndDerivativeInReturnData(); - rdata->cpu_time = solver->getCpuTime(); -} - -void ForwardProblem::handlePreequilibration() { - // Are there dedicated condition preequilibration parameters provided? - bool overrideFixedParameters = - edata && !edata->fixedParametersPreequilibration.empty(); - - std::vector - originalFixedParameters; // to restore after pre-equilibration - - if (overrideFixedParameters) { - if (edata->fixedParametersPreequilibration.size() != - (unsigned)model->nk()) - throw AmiException( - "Number of fixed parameters (%d) in model does not match " - "preequilibration parameters in ExpData (%zd).", - model->nk(), edata->fixedParametersPreequilibration.size()); - originalFixedParameters = model->getFixedParameters(); - model->setFixedParameters(edata->fixedParametersPreequilibration); - model->initialize(x, dx, sx, sdx, - solver->getSensitivityOrder() >= - SensitivityOrder::first); - solver->setup(model->t0(), model, x, dx, sx, sdx); - // update x0 after computing consistence IC, only important for DAEs - x.copy(solver->getState(model->t0())); - } - - // pre-equilibrate - SteadystateProblem sstate = SteadystateProblem(solver, x); - - sstate.workSteadyStateProblem(rdata, solver, model, -1); - sstate.writeSolution(&t, x, sx); - - if (overrideFixedParameters) { - // Restore - model->setFixedParameters(originalFixedParameters); - } - - updateAndReinitStatesAndSensitivities(true); -} - -void ForwardProblem::updateAndReinitStatesAndSensitivities(bool isSteadystate) { - - if (isSteadystate) { - model->fx_rdata(x_rdata, x); - rdata->x_ss = x_rdata.getVector(); - } - - model->fx0_fixedParameters(x); - solver->reInit(t, x, dx); - model->fx_rdata(x_rdata, x); - - rdata->x0 = x_rdata.getVector(); - if (solver->getSensitivityOrder() >= SensitivityOrder::first) { - if (isSteadystate) { - model->fsx_rdata(sx_rdata, sx); - for (int ip = 0; ip < model->nplist(); ip++) - std::copy_n(sx_rdata.data(ip), rdata->nx, - &rdata->sx_ss.at(ip * rdata->nx)); - } - - model->fsx0_fixedParameters(sx, x); - model->fsx_rdata(sx_rdata, sx); - - for (int ip = 0; ip < model->nplist(); ip++) - std::copy_n(sx_rdata.data(ip), rdata->nx, - &rdata->sx0.at(ip * rdata->nx)); - - if (solver->getSensitivityMethod() == SensitivityMethod::forward) - solver->sensReInit(sx, sdx); + if (model->nz > 0 && model->nt() > 0) { + fillEvents(model->nMaxEvent()); } } void ForwardProblem::handlePresimulation() { // Are there dedicated condition preequilibration parameters provided? - bool overrideFixedParameters = edata && !edata->fixedParametersPresimulation.empty(); - - std::vector originalFixedParameters; // to restore after pre-equilibration - - if(overrideFixedParameters) { - if(edata->fixedParametersPresimulation.size() != (unsigned) model->nk()) - throw AmiException("Number of fixed parameters (%d) in model does not match presimulation parameters in ExpData (%zd).", - model->nk(), edata->fixedParametersPresimulation.size()); - originalFixedParameters = model->getFixedParameters(); - model->setFixedParameters(edata->fixedParametersPresimulation); - } - t = model->t0() - edata->t_presim; - updateAndReinitStatesAndSensitivities(false); + ConditionContext cond(model, edata, FixedParameterContext::presimulation); + solver->updateAndReinitStatesAndSensitivities(model); solver->run(model->t0()); - solver->writeSolution(&t, x, dx, sx); - if(overrideFixedParameters) { - model->setFixedParameters(originalFixedParameters); - } - t = model->t0(); - updateAndReinitStatesAndSensitivities(false); + solver->writeSolution(&t, x, dx, sx, dx); } @@ -233,24 +141,18 @@ void ForwardProblem::handleEvent(realtype *tlastroot, const bool seflag) { /* store heaviside information at event occurence */ model->froot(t, x, dx, rootvals); + /* store timepoint at which the event occured*/ + discs.push_back(t); + + /* extract and store which events occured */ if (!seflag) { solver->getRootInfo(rootsfound.data()); } - - if (iroot < model->nMaxEvent() * model->ne) { - std::copy(rootsfound.begin(), rootsfound.end(), - &rootidx[iroot * model->ne]); - } + rootidx.push_back(rootsfound); rvaltmp = rootvals; if (!seflag) { - /* only extract in the first event fired */ - if (solver->getSensitivityOrder() >= SensitivityOrder::first && - solver->getSensitivityMethod() == SensitivityMethod::forward) { - sx.copy(solver->getStateSensitivity(t)); - } - /* only check this in the first event fired, otherwise this will always * be true */ if (t == *tlastroot) { @@ -262,60 +164,42 @@ void ForwardProblem::handleEvent(realtype *tlastroot, const bool seflag) { } if(model->nz>0) - getEventOutput(); + storeEvent(); /* if we need to do forward sensitivities later on we need to store the old * x and the old xdot */ if (solver->getSensitivityOrder() >= SensitivityOrder::first) { /* store x and xdot to compute jump in sensitivities */ - x_old = solver->getState(t); - if (solver->getSensitivityMethod() == SensitivityMethod::forward) { - model->fxdot(t, x, dx, xdot); - xdot_old = xdot; - dx_old = dx; - - /* compute event-time derivative only for primary events, we get - * into trouble with multiple simultaneously firing events here (but - * is this really well defined then?), in that case just use the - * last ie and hope for the best. */ - if (!seflag) { - for (int ie = 0; ie < model->ne; ie++) { - if (rootsfound.at(ie) == 1) { - /* only consider transitions false -> true */ - model->getEventTimeSensitivity(stau, t, ie, x, sx); - } + x_old = x; + } + if (solver->computingFSA()) { + model->fxdot(t, x, dx, xdot); + xdot_old = xdot; + dx_old = dx; + /* compute event-time derivative only for primary events, we get + * into trouble with multiple simultaneously firing events here (but + * is this really well defined then?), in that case just use the + * last ie and hope for the best. */ + if (!seflag) { + for (int ie = 0; ie < model->ne; ie++) { + if (rootsfound.at(ie) == 1) { + /* only consider transitions false -> true */ + model->getEventTimeSensitivity(stau, t, ie, x, sx); } } - } else if (solver->getSensitivityMethod() == SensitivityMethod::adjoint) { - /* store x to compute jump in discontinuity */ - if (iroot < model->nMaxEvent() * model->ne) { - x_disc[iroot] = x; - xdot_disc[iroot] = xdot; - xdot_old_disc[iroot] = xdot_old; - } } + } else if (solver->computingASA()) { + /* store x to compute jump in discontinuity */ + x_disc.push_back(x); + xdot_disc.push_back(xdot); + xdot_old_disc.push_back(xdot_old); } model->updateHeaviside(rootsfound); applyEventBolus(); - if (iroot < model->nMaxEvent() * model->ne) { - discs[iroot] = t; - ++iroot; - } else { - solver->app->warning( - "AMICI:TOO_MUCH_EVENT", - "Event was recorded but not reported as the number of " - "occured events exceeded (nmaxevents)*(number of " - "events in model definition)!"); - /* reinitialise so that we can continue in peace */ - solver->reInit(t, x, dx); - return; - } - - if (solver->getSensitivityOrder() >= SensitivityOrder::first - && solver->getSensitivityMethod() == SensitivityMethod::forward) { + if (solver->computingFSA()) { /* compute the new xdot */ model->fxdot(t, x, dx, xdot); applyEventSensiBolusFSA(); @@ -346,39 +230,34 @@ void ForwardProblem::handleEvent(realtype *tlastroot, const bool seflag) { } /* fire the secondary event */ if (secondevent > 0) { - handleEvent(tlastroot, TRUE); + handleEvent(tlastroot, true); } /* only reinitialise in the first event fired */ if (!seflag) { solver->reInit(t, x, dx); - - if (solver->getSensitivityOrder() >= SensitivityOrder::first) { - if (solver->getSensitivityMethod() == SensitivityMethod::forward) { - solver->sensReInit(sx, sdx); - } - } - } -} - -void ForwardProblem::storeJacobianAndDerivativeInReturnData() { - model->fxdot(t, x, dx, xdot); - rdata->xdot = xdot.getVector(); - - model->fJ(t, 0.0, x, dx, xdot, Jtmp.get()); - // CVODES uses colmajor, so we need to transform to rowmajor - for (int ix = 0; ix < model->nx_solver; ix++) { - for (int jx = 0; jx < model->nx_solver; jx++) { - rdata->J[ix * model->nx_solver + jx] = - Jtmp.data()[ix + model->nx_solver * jx]; + if (solver->computingFSA()) { + solver->sensReInit(sx, sdx); } } } -void ForwardProblem::getEventOutput() { +void ForwardProblem::storeEvent() { if (t == model->getTimepoint(model->nt() - 1)) { // call from fillEvent at last timepoint model->froot(t, x, dx, rootvals); + for (int ie = 0; ie < model->ne; ie++) { + rootsfound.at(ie) = (nroots.at(ie) < model->nMaxEvent()) ? 1 : 0; + } + rootidx.push_back(rootsfound); + } + + if (getRootCounter() < getEventCounter()) { + /* update stored state (sensi) */ + event_states.at(getRootCounter()) = getSimulationState(); + } else { + /* add stored state (sensi) */ + event_states.push_back(getSimulationState()); } /* EVENT OUTPUT */ @@ -393,42 +272,10 @@ void ForwardProblem::getEventOutput() { continue; } - /* get event output */ - model->getEvent(slice(rdata->z, nroots.at(ie), rdata->nz), ie, t, x); - /* if called from fillEvent at last timepoint, - then also get the root function value */ - if (t == model->getTimepoint(model->nt() - 1)) - model->getEventRegularization(slice(rdata->rz, nroots.at(ie), - rdata->nz), ie, t, x); - - if (edata) { - model->getEventSigma(slice(rdata->sigmaz, nroots.at(ie), rdata->nz), - ie, nroots.at(ie), t, edata); - model->addEventObjective(rdata->llh, ie, nroots.at(ie), t, x, - *edata); - - /* if called from fillEvent at last timepoint, - add regularization based on rz */ - if (t == model->getTimepoint(model->nt() - 1)) - model->addEventObjectiveRegularization( - rdata->llh, ie, nroots.at(ie), t, x, *edata); - } - - if (solver->getSensitivityOrder() >= SensitivityOrder::first) { - if (solver->getSensitivityMethod() == SensitivityMethod::forward) { - getEventSensisFSA(ie); - } else { - if (edata) { - model->getAdjointStateEventUpdate(slice(dJzdx, nroots.at(ie), - model->nx_solver * model->nJ), - ie, nroots.at(ie), t, x, *edata); - model->addPartialEventObjectiveSensitivity(rdata->sllh, - rdata->s2llh, - ie, nroots.at(ie), - t, x, *edata); - } - } - } + if (edata && solver->computingASA()) + model->getAdjointStateEventUpdate(slice(dJzdx, nroots.at(ie), + model->nx_solver * model->nJ), + ie, nroots.at(ie), t, x, *edata); nroots.at(ie)++; } @@ -436,98 +283,17 @@ void ForwardProblem::getEventOutput() { if (t == model->getTimepoint(model->nt() - 1)) { // call from fillEvent at last timepoint // loop until all events are filled - if (std::any_of(nroots.cbegin(), nroots.cend(), [&](int curNRoots) { - return curNRoots < model->nMaxEvent(); - })) - getEventOutput(); - } -} - -void ForwardProblem::getEventSensisFSA(int ie) { - if (t == model->getTimepoint(model->nt() - 1)) { - // call from fillEvent at last timepoint - model->getUnobservedEventSensitivity(slice(rdata->sz, nroots.at(ie), - rdata->nz * rdata->nplist), - ie); - model->getEventRegularizationSensitivity(slice(rdata->srz, - nroots.at(ie), - rdata->nz * rdata->nplist), - ie, t, x, sx); - } else { - model->getEventSensitivity(slice(rdata->sz, nroots.at(ie), - rdata->nz * rdata->nplist), - ie, t, x, sx); - } - - if (edata) { - model->addEventObjectiveSensitivity(rdata->sllh, rdata->s2llh, ie, - nroots.at(ie), t, x, sx, *edata); + fillEvents(model->nMaxEvent()); } } void ForwardProblem::handleDataPoint(int it) { - model->fx_rdata(x_rdata, x); - std::copy_n(x_rdata.data(), rdata->nx, &rdata->x.at(it * rdata->nx)); - model->getExpression(slice(rdata->w, it, model->nw), - model->getTimepoint(it), x); - if (model->getTimepoint(it) > model->t0()) { - solver->getDiagnosis(it, rdata); - } - - getDataOutput(it); -} - -void ForwardProblem::getDataOutput(int it) { - model->getObservable(slice(rdata->y, it, rdata->ny), rdata->ts[it], x); - model->getObservableSigma(slice(rdata->sigmay, it, rdata->ny), it, - edata); - if (edata) { - model->addObservableObjective(rdata->llh, it, x, *edata); - rdata->fres(it, *edata); - rdata->fchi2(it); - } - - if (solver->getSensitivityOrder() >= SensitivityOrder::first && - model->nplist() > 0) { - - model->getObservableSigmaSensitivity(slice(rdata->ssigmay, it, - model->nplist() * model->ny), - it, edata); - - if (solver->getSensitivityMethod() == SensitivityMethod::forward) { - getDataSensisFSA(it); - } else { - if (edata) { - model->getAdjointStateObservableUpdate(slice(dJydx, it, - model->nx_solver * model->nJ), - it, x, *edata); - model->addPartialObservableObjectiveSensitivity(rdata->sllh, - rdata->s2llh, - it, x, *edata); - } - } - } -} - -void ForwardProblem::getDataSensisFSA(int it) { - model->fsx_rdata(sx_rdata, sx); - for (int ix = 0; ix < rdata->nx; ix++) { - for (int ip = 0; ip < model->nplist(); ip++) { - rdata->sx[(it * model->nplist() + ip) * rdata->nx + ix] = - sx_rdata.at(ix, ip); - } - } - - model->getObservableSensitivity(slice(rdata->sy, it, - model->nplist() * model->ny), - t, x, sx); - - if (edata) { - model->addObservableObjectiveSensitivity(rdata->sllh, rdata->s2llh, - it, x, sx, *edata); - rdata->fsres(it, *edata); - rdata->fFIM(it); - } + /* We only store the simulation state if it's not the initial state, as the + initial state is stored anyway and we want to avoid storing it twice */ + if (t != model->t0() && timepoint_states.count(t) == 0) + timepoint_states[t] = getSimulationState(); + /* store diagnosis information for debugging */ + solver->storeDiagnosis(); } void ForwardProblem::applyEventBolus() { @@ -544,4 +310,27 @@ void ForwardProblem::applyEventSensiBolusFSA() { xdot_old, stau); } +void ForwardProblem::getAdjointUpdates(Model &model, + const ExpData &edata) { + for (int it = 0; it < model.nt(); it++) { + if (std::isinf(model.getTimepoint(it))) + return; + model.getAdjointStateObservableUpdate( + slice(dJydx, it, model.nx_solver * model.nJ), it, + getSimulationStateTimepoint(it).x, edata + ); + } +} + +SimulationState ForwardProblem::getSimulationState() const { + auto state = SimulationState(); + state.t = t; + state.x = x; + state.dx = dx; + if (solver->computingFSA() || t == model->t0()) + state.sx = sx; + state.state = model->getModelState(); + return state; +} + } // namespace amici diff --git a/deps/AMICI/src/hdf5.cpp b/deps/AMICI/src/hdf5.cpp index ef574a982..c7fa945e5 100644 --- a/deps/AMICI/src/hdf5.cpp +++ b/deps/AMICI/src/hdf5.cpp @@ -367,20 +367,69 @@ void writeReturnDataDiagnosis(const ReturnData &rdata, file, hdf5Location + "/numnonlinsolvconvfailsB", rdata.numnonlinsolvconvfailsB); - H5LTset_attribute_int(file.getId(), (hdf5Location + "").c_str(), - "newton_status", &rdata.newton_status, 1); + if (!rdata.preeq_status.empty()) { + std::vector preeq_status_int (rdata.preeq_status.size()); + for (int i = 0; (unsigned)i < rdata.preeq_status.size(); i++) + preeq_status_int[i] = static_cast(rdata.preeq_status[i]); + createAndWriteInt1DDataset(file, hdf5Location + "/preeq_status", + preeq_status_int); + } + + if (!rdata.preeq_numsteps.empty()) + createAndWriteInt1DDataset(file, hdf5Location + "/preeq_numsteps", + rdata.preeq_numsteps); + + if (!rdata.preeq_numlinsteps.empty()) + createAndWriteInt2DDataset(file, hdf5Location + "/preeq_numlinsteps", + rdata.preeq_numlinsteps, + rdata.newton_maxsteps, 2); + + H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), + "preeq_numstepsB", &rdata.preeq_numstepsB, 1); + + H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), + "preeq_cpu_time", &rdata.preeq_cpu_time, 1); + + H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), + "preeq_cpu_timeB", &rdata.preeq_cpu_timeB, 1); + + H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "preeq_t", + &rdata.preeq_t, 1); - if (!rdata.newton_numsteps.empty()) - createAndWriteInt1DDataset(file, hdf5Location + "/newton_numsteps", - rdata.newton_numsteps); + H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "preeq_wrms", + &rdata.preeq_wrms, 1); - if (!rdata.newton_numlinsteps.empty()) - createAndWriteInt2DDataset(file, hdf5Location + "/newton_numlinsteps", - rdata.newton_numlinsteps, + if (!rdata.posteq_status.empty()) { + std::vector posteq_status_int (rdata.posteq_status.size()); + for (int i = 0; (unsigned)i < rdata.posteq_status.size(); i++) + posteq_status_int[i] = static_cast(rdata.posteq_status[i]); + createAndWriteInt1DDataset(file, hdf5Location + "/posteq_status", + posteq_status_int); + } + + if (!rdata.posteq_numsteps.empty()) + createAndWriteInt1DDataset(file, hdf5Location + "/posteq_numsteps", + rdata.posteq_numsteps); + + if (!rdata.posteq_numlinsteps.empty()) + createAndWriteInt2DDataset(file, hdf5Location + "/posteq_numlinsteps", + rdata.posteq_numlinsteps, rdata.newton_maxsteps, 2); + H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), + "posteq_numstepsB", &rdata.posteq_numstepsB, 1); + H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), - "newton_cpu_time", &rdata.newton_cpu_time, 1); + "posteq_cpu_time", &rdata.posteq_cpu_time, 1); + + H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), + "posteq_cpu_timeB", &rdata.posteq_cpu_timeB, 1); + + H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "posteq_t", + &rdata.posteq_t, 1); + + H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "posteq_wrms", + &rdata.posteq_wrms, 1); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "cpu_time", &rdata.cpu_time, 1); @@ -517,7 +566,7 @@ void writeSolverSettingsToHDF5(Solver const& solver, std::string const& hdf5Filename, std::string const& hdf5Location) { auto file = createOrOpenForWriting(hdf5Filename); - + writeSolverSettingsToHDF5(solver, file, hdf5Location); } @@ -526,38 +575,38 @@ void writeSolverSettingsToHDF5(Solver const& solver, const std::string& hdf5Location) { if(!locationExists(file, hdf5Location)) createGroup(file, hdf5Location); - + double dbuffer; int ibuffer; - + dbuffer = solver.getAbsoluteTolerance(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "atol", &dbuffer, 1); - + dbuffer = solver.getRelativeTolerance(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "rtol", &dbuffer, 1); - + dbuffer = solver.getAbsoluteToleranceFSA(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "atol_fsa", &dbuffer, 1); - + dbuffer = solver.getRelativeToleranceFSA(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "rtol_fsa", &dbuffer, 1); - + dbuffer = solver.getAbsoluteToleranceB(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "atolB", &dbuffer, 1); - + dbuffer = solver.getRelativeToleranceB(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "rtolB", &dbuffer, 1); - + dbuffer = solver.getAbsoluteToleranceQuadratures(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "quad_atol", &dbuffer, 1); - + dbuffer = solver.getRelativeToleranceQuadratures(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "quad_rtol", &dbuffer, 1); @@ -565,82 +614,90 @@ void writeSolverSettingsToHDF5(Solver const& solver, dbuffer = solver.getAbsoluteToleranceSteadyState(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "ss_atol", &dbuffer, 1); - + dbuffer = solver.getRelativeToleranceSteadyState(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "ss_rtol", &dbuffer, 1); - + dbuffer = solver.getAbsoluteToleranceSteadyStateSensi(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "ss_atol_sensi", &dbuffer, 1); - + dbuffer = solver.getRelativeToleranceSteadyStateSensi(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "ss_rtol_sensi", &dbuffer, 1); - + ibuffer = static_cast(solver.getMaxSteps()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "maxsteps", &ibuffer, 1); - + ibuffer = static_cast(solver.getMaxStepsBackwardProblem()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "maxstepsB", &ibuffer, 1); - + ibuffer = static_cast(solver.getLinearMultistepMethod()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "lmm", &ibuffer, 1); - + ibuffer = static_cast(solver.getNonlinearSolverIteration()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "iter", &ibuffer, 1); - + ibuffer = static_cast(solver.getStabilityLimitFlag()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "stldet", &ibuffer, 1); - + ibuffer = static_cast(solver.getStateOrdering()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "ordering", &ibuffer, 1); - + ibuffer = static_cast(solver.getInterpolationType()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "interpType", &ibuffer, 1); - + ibuffer = static_cast(solver.getSensitivityMethod()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "sensi_meth", &ibuffer, 1); - + + ibuffer = static_cast(solver.getSensitivityMethodPreequilibration()); + H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), + "sensi_meth_preeq", &ibuffer, 1); + ibuffer = static_cast(solver.getSensitivityOrder()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "sensi", &ibuffer, 1); - + ibuffer = static_cast(solver.getNewtonMaxSteps()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "newton_maxsteps", &ibuffer, 1); - + ibuffer = static_cast(solver.getPreequilibration()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "newton_preeq", &ibuffer, 1); - + ibuffer = static_cast(solver.getNewtonDampingFactorMode()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "newton_damping_factor_mode", &ibuffer, 1); - + dbuffer = solver.getNewtonDampingFactorLowerBound(); H5LTset_attribute_double(file.getId(), hdf5Location.c_str(), "newton_damping_factor_lower_bound", &dbuffer, 1); - + ibuffer = static_cast(solver.getNewtonMaxLinearSteps()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "newton_maxlinsteps", &ibuffer, 1); - + ibuffer = static_cast(solver.getLinearSolver()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "linsol", &ibuffer, 1); - + ibuffer = static_cast(solver.getInternalSensitivityMethod()); H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), "ism", &ibuffer, 1); + + ibuffer = static_cast(solver.getReturnDataReportingMode()); + H5LTset_attribute_int(file.getId(), hdf5Location.c_str(), + "rdrm", &ibuffer, 1); } void readSolverSettingsFromHDF5(H5::H5File const& file, Solver &solver, @@ -754,6 +811,12 @@ void readSolverSettingsFromHDF5(H5::H5File const& file, Solver &solver, getIntScalarAttribute(file, datasetPath, "sensi_meth"))); } + if(attributeExists(file, datasetPath, "sensi_meth_preeq")) { + solver.setSensitivityMethodPreequilibration( + static_cast( + getIntScalarAttribute(file, datasetPath, "sensi_meth_preeq"))); + } + if(attributeExists(file, datasetPath, "sensi")) { solver.setSensitivityOrder( static_cast( @@ -798,6 +861,12 @@ void readSolverSettingsFromHDF5(H5::H5File const& file, Solver &solver, static_cast( getIntScalarAttribute(file, datasetPath, "ism"))); } + + if(attributeExists(file, datasetPath, "rdrm")) { + solver.setReturnDataReportingMode( + static_cast( + getIntScalarAttribute(file, datasetPath, "rdrm"))); + } } void readSolverSettingsFromHDF5(const std::string &hdffile, Solver &solver, diff --git a/deps/AMICI/src/interface_matlab.cpp b/deps/AMICI/src/interface_matlab.cpp index 800bbc061..a4fff0834 100644 --- a/deps/AMICI/src/interface_matlab.cpp +++ b/deps/AMICI/src/interface_matlab.cpp @@ -227,6 +227,11 @@ std::unique_ptr expDataFromMatlabCall(const mxArray *prhs[], } } + // preequilibration condition parameters + if (mxGetProperty(prhs[RHS_DATA], 0, "reinitializeStates")) + edata->reinitializeFixedParameterInitialStates = + static_cast(mxGetScalar(mxGetProperty(prhs[RHS_DATA], 0, "reinitializeStates"))); + return edata; } @@ -303,6 +308,11 @@ void setSolverOptions(const mxArray *prhs[], int nrhs, Solver &solver) solver.setSensitivityMethod(static_cast(dbl2int(mxGetScalar(mxGetProperty(prhs[RHS_OPTIONS], 0, "sensi_meth"))))); } + if (mxGetProperty(prhs[RHS_OPTIONS], 0, "sensi_meth_preeq")) { + solver.setSensitivityMethodPreequilibration( + static_cast(dbl2int(mxGetScalar(mxGetProperty(prhs[RHS_OPTIONS], 0, "sensi_meth_preeq"))))); + } + if (mxGetProperty(prhs[RHS_OPTIONS], 0, "ordering")) { solver.setStateOrdering(dbl2int(mxGetScalar(mxGetProperty(prhs[RHS_OPTIONS], 0, "ordering")))); } @@ -444,6 +454,10 @@ void setModelData(const mxArray *prhs[], int nrhs, Model &model) mxGetPr(sx0) + mxGetM(sx0) * mxGetN(sx0))); } } + // preequilibration condition parameters + if (mxGetPr(prhs[RHS_DATA]) && mxGetProperty(prhs[RHS_DATA], 0, "reinitializeStates")) + model.setReinitializeFixedParameterInitialStates( + static_cast(mxGetScalar(mxGetProperty(prhs[RHS_DATA], 0, "reinitializeStates")))); } } // namespace amici @@ -482,7 +496,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { "Incorrect number of input arguments (must be at least 7)!"); }; - auto model = getModel(); + auto model = amici::generic_model::getModel(); model->app = &amiciApp; auto solver = model->getSolver(); diff --git a/deps/AMICI/src/main.template.cpp b/deps/AMICI/src/main.template.cpp index 07ff62a32..f957df9ad 100644 --- a/deps/AMICI/src/main.template.cpp +++ b/deps/AMICI/src/main.template.cpp @@ -54,7 +54,7 @@ int main(int argc, char **argv) { hdffile = argv[1]; } - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); // Read AMICI settings and model parameters from HDF5 file diff --git a/deps/AMICI/src/misc.cpp b/deps/AMICI/src/misc.cpp index 731559c96..60e9d3ea1 100644 --- a/deps/AMICI/src/misc.cpp +++ b/deps/AMICI/src/misc.cpp @@ -21,15 +21,9 @@ namespace amici { -gsl::span slice(std::vector &data, const int index, - const unsigned size) { - if ((index + 1) * size > data.size()) - throw std::out_of_range("requested slice is out of data range"); - if (size > 0) - return gsl::make_span(&data.at(index*size), size); - else - return gsl::make_span(static_cast(nullptr), 0); -} +void writeSlice(const AmiVector &s, gsl::span b) { + writeSlice(s.getVector(), b); +}; double getUnscaledParameter(double scaledParameter, ParameterScaling scaling) { diff --git a/deps/AMICI/src/model.ODE_template.cpp b/deps/AMICI/src/model.ODE_template.cpp new file mode 100644 index 000000000..1f444ae6d --- /dev/null +++ b/deps/AMICI/src/model.ODE_template.cpp @@ -0,0 +1,43 @@ +#include "TPL_MODELNAME.h" +#include + +namespace amici { + +namespace model_TPL_MODELNAME { + +std::array parameterNames = { + TPL_PARAMETER_NAMES_INITIALIZER_LIST +}; + +std::array fixedParameterNames = { + TPL_FIXED_PARAMETER_NAMES_INITIALIZER_LIST +}; + +std::array stateNames = { + TPL_STATE_NAMES_INITIALIZER_LIST +}; + +std::array observableNames = { + TPL_OBSERVABLE_NAMES_INITIALIZER_LIST +}; + +std::array parameterIds = { + TPL_PARAMETER_IDS_INITIALIZER_LIST +}; + +std::array fixedParameterIds = { + TPL_FIXED_PARAMETER_IDS_INITIALIZER_LIST +}; + +std::array stateIds = { + TPL_STATE_IDS_INITIALIZER_LIST +}; + +std::array observableIds = { + TPL_OBSERVABLE_IDS_INITIALIZER_LIST +}; + + +} // namespace model_TPL_MODELNAME + +} // namespace amici diff --git a/deps/AMICI/src/model.cpp b/deps/AMICI/src/model.cpp index dbe21b38a..ea9d39035 100644 --- a/deps/AMICI/src/model.cpp +++ b/deps/AMICI/src/model.cpp @@ -14,30 +14,6 @@ namespace amici { -/** - * @brief local helper to check whether the provided buffer has the expected - * size - * @param buffer buffer to which values are to be written - * @param expected_size expected size of the buffer - */ -static void checkBufferSize(gsl::span buffer, - unsigned expected_size) { - if (buffer.size() != expected_size) - throw AmiException("Incorrect buffer size! Was %u, expected %u.", - buffer.size(), expected_size); -} - -/** - * @brief local helper function to write computed slice to provided buffer - * @param slice computed value - * @param buffer buffer to which values are to be written - */ -static void writeSlice(gsl::span slice, - gsl::span buffer) { - checkBufferSize(buffer, slice.size()); - std::copy(slice.begin(), slice.end(), buffer.data()); -} - /** * @brief local helper function to get parameters * @param ids vector of name/ids of (fixed)Parameters @@ -96,17 +72,7 @@ static int setValueByIdRegex(std::vector const &ids, std::string const ®ex, const char *variable_name, const char *id_name) { try { - /* For unknown reasons, the Intel compiler fails to compile patterns - * such as p[\d]+, which work with g++ and clang. - * Using std::regex_constants::extended fixes Intel issues, but g++ - * seems to not match the pattern correctly. - * This is the best solution I was able to come up with... - */ -#ifdef __INTEL_COMPILER - std::regex pattern(regex, std::regex_constants::extended); -#else std::regex pattern(regex); -#endif int n_found = 0; for (const auto &id : ids) { if (std::regex_match(id, pattern)) { @@ -128,49 +94,59 @@ static int setValueByIdRegex(std::vector const &ids, } } -Model::Model() : dxdotdp(0, 0), x_pos_tmp(0) {} - Model::Model(const int nx_rdata, const int nxtrue_rdata, const int nx_solver, - const int nxtrue_solver, const int ny, const int nytrue, - const int nz, const int nztrue, const int ne, const int nJ, - const int nw, const int ndwdx, const int ndwdp, const int ndxdotdw, - std::vector ndJydy, const int nnz, const int ubw, - const int lbw, SecondOrderMode o2mode, + const int nxtrue_solver, const int nx_solver_reinit, const int ny, + const int nytrue, const int nz, const int nztrue, const int ne, + const int nJ, const int nw, const int ndwdx, const int ndwdp, + const int ndxdotdw, std::vector ndJydy, const int nnz, + const int ubw, const int lbw, SecondOrderMode o2mode, const std::vector &p, std::vector k, const std::vector &plist, std::vector idlist, std::vector z2event, const bool pythonGenerated, const int ndxdotdp_explicit, const int ndxdotdp_implicit) : nx_rdata(nx_rdata), nxtrue_rdata(nxtrue_rdata), nx_solver(nx_solver), - nxtrue_solver(nxtrue_solver), ny(ny), nytrue(nytrue), nz(nz), - nztrue(nztrue), ne(ne), nw(nw), ndwdx(ndwdx), ndwdp(ndwdp), - ndxdotdw(ndxdotdw), ndJydy(std::move(ndJydy)), - nnz(nnz), nJ(nJ), ubw(ubw), lbw(lbw), pythonGenerated(pythonGenerated), - ndxdotdp_explicit(ndxdotdp_explicit), ndxdotdp_implicit(ndxdotdp_implicit), - o2mode(o2mode), idlist(std::move(idlist)), - J(nx_solver, nx_solver, nnz, CSC_MAT), - dxdotdw(nx_solver, nw, ndxdotdw, CSC_MAT), dwdp(nw, p.size(), ndwdp, CSC_MAT), - dwdx(nw, nx_solver, ndwdx, CSC_MAT), M(nx_solver, nx_solver), w(nw), - x_rdata(nx_rdata, 0.0), sx_rdata(nx_rdata, 0.0), h(ne, 0.0), - total_cl(nx_rdata - nx_solver), - stotal_cl((nx_rdata - nx_solver) * p.size()), x_pos_tmp(nx_solver), - unscaledParameters(p), originalParameters(p), - fixedParameters(std::move(k)), z2event(std::move(z2event)), plist_(plist), + nxtrue_solver(nxtrue_solver), nx_solver_reinit(nx_solver_reinit), ny(ny), + nytrue(nytrue), nz(nz), nztrue(nztrue), ne(ne), nw(nw), ndwdx(ndwdx), + ndwdp(ndwdp), ndxdotdw(ndxdotdw), ndJydy(std::move(ndJydy)), nnz(nnz), + nJ(nJ), ubw(ubw), lbw(lbw), pythonGenerated(pythonGenerated), + ndxdotdp_explicit(ndxdotdp_explicit), + ndxdotdp_implicit(ndxdotdp_implicit), o2mode(o2mode), + idlist(std::move(idlist)), J(nx_solver, nx_solver, nnz, CSC_MAT), + dxdotdw(nx_solver, nw, ndxdotdw, CSC_MAT), + dwdp(nw, static_cast(p.size()), ndwdp, CSC_MAT), + dwdx(nw, nx_solver, ndwdx, CSC_MAT), + w(nw), x_rdata(nx_rdata, 0.0), sx_rdata(nx_rdata, 0.0), + x_pos_tmp(nx_solver), originalParameters(p), z2event(std::move(z2event)), stateIsNonNegative(nx_solver, false), pscale(std::vector(p.size(), ParameterScaling::none)) { - /* If Matlab wrapped: dxdotdp is a full AmiVector, - if Python wrapped: dxdotdp_explicit and dxdotdp_implicit are CSC matrices */ + state.h.resize(ne, 0.0); + state.total_cl.resize(nx_rdata - nx_solver, 0.0); + state.stotal_cl.resize((nx_rdata - nx_solver) * p.size(), 0.0); + state.unscaledParameters = p; + state.fixedParameters = k; + state.plist = plist; + + /* If Matlab wrapped: dxdotdp is a full AmiVector, + if Python wrapped: dxdotdp_explicit and dxdotdp_implicit are CSC matrices + */ if (pythonGenerated) { - dxdotdp_explicit = SUNMatrixWrapper(nx_solver, p.size(), ndxdotdp_explicit, CSC_MAT); - dxdotdp_implicit = SUNMatrixWrapper(nx_solver, p.size(), ndxdotdp_implicit, CSC_MAT); + dxdotdp_explicit = + SUNMatrixWrapper(nx_solver, static_cast(p.size()), + ndxdotdp_explicit, CSC_MAT); + dxdotdp_implicit = + SUNMatrixWrapper(nx_solver, static_cast(p.size()), + ndxdotdp_implicit, CSC_MAT); // also dJydy depends on the way of wrapping if (static_cast(nytrue) != this->ndJydy.size()) - throw std::runtime_error("Number of elements in ndJydy is not equal " - " nytrue."); + throw std::runtime_error( + "Number of elements in ndJydy is not equal " + " nytrue."); for (int iytrue = 0; iytrue < nytrue; ++iytrue) - dJydy.emplace_back(SUNMatrixWrapper(nJ, ny, this->ndJydy[iytrue], CSC_MAT)); + dJydy.emplace_back( + SUNMatrixWrapper(nJ, ny, this->ndJydy[iytrue], CSC_MAT)); } else { dJydy_matlab = std::vector(nJ * nytrue * ny, 0.0); } @@ -190,22 +166,24 @@ bool operator==(const Model &a, const Model &b) { return (a.nx_rdata == b.nx_rdata) && (a.nxtrue_rdata == b.nxtrue_rdata) && (a.nx_solver == b.nx_solver) && - (a.nxtrue_solver == b.nxtrue_solver) && (a.ny == b.ny) && + (a.nxtrue_solver == b.nxtrue_solver) && + (a.nx_solver_reinit == b.nx_solver_reinit) && (a.ny == b.ny) && (a.nytrue == b.nytrue) && (a.nz == b.nz) && (a.nztrue == b.nztrue) && (a.ne == b.ne) && (a.nw == b.nw) && (a.ndwdx == b.ndwdx) && (a.ndwdp == b.ndwdp) && (a.ndxdotdw == b.ndxdotdw) && (a.nnz == b.nnz) && (a.nJ == b.nJ) && (a.ubw == b.ubw) && (a.lbw == b.lbw) && (a.o2mode == b.o2mode) && - (a.z2event == b.z2event) && (a.idlist == b.idlist) && (a.h == b.h) && - (a.unscaledParameters == b.unscaledParameters) && + (a.z2event == b.z2event) && (a.idlist == b.idlist) && + (a.state.h == b.state.h) && + (a.state.unscaledParameters == b.state.unscaledParameters) && (a.originalParameters == b.originalParameters) && - (a.fixedParameters == b.fixedParameters) && (a.plist_ == b.plist_) && - (a.x0data == b.x0data) && (a.sx0data == b.sx0data) && - (a.ts == b.ts) && (a.nmaxevent == b.nmaxevent) && - (a.pscale == b.pscale) && + (a.state.fixedParameters == b.state.fixedParameters) && + (a.state.plist == b.state.plist) && (a.x0data == b.x0data) && + (a.sx0data == b.sx0data) && (a.ts == b.ts) && + (a.nmaxevent == b.nmaxevent) && (a.pscale == b.pscale) && (a.stateIsNonNegative == b.stateIsNonNegative) && - (a.reinitializeFixedParameterInitialStates - == b.reinitializeFixedParameterInitialStates) && + (a.reinitializeFixedParameterInitialStates == + b.reinitializeFixedParameterInitialStates) && (a.tstart == b.tstart) && bool_dxdotdp; } @@ -223,10 +201,12 @@ void Model::initialize(AmiVector &x, AmiVector &dx, AmiVectorArray &sx, initHeaviside(x, dx); } -void Model::initializeB(AmiVector &xB, AmiVector &dxB, AmiVector &xQB) { +void Model::initializeB(AmiVector &xB, AmiVector &dxB, AmiVector &xQB, + bool posteq) const { xB.reset(); dxB.reset(); - xQB.reset(); + if (!posteq) + xQB.reset(); } void Model::initializeStates(AmiVector &x) { @@ -234,11 +214,9 @@ void Model::initializeStates(AmiVector &x) { fx0(x); } else { std::vector x0_solver(nx_solver, 0.0); - ftotal_cl(total_cl.data(), x0data.data()); + ftotal_cl(state.total_cl.data(), x0data.data()); fx_solver(x0_solver.data(), x0data.data()); - for (int ix = 0; ix < nx_solver; ix++) { - x[ix] = (realtype)x0_solver.at(ix); - } + std::copy(x0_solver.cbegin(), x0_solver.cend(), x.data()); } } @@ -251,11 +229,11 @@ void Model::initializeStateSensitivities(AmiVectorArray &sx, std::vector sx0_solver_slice(nx_solver, 0.0); for (int ip = 0; ip < nplist(); ip++) { if (ncl() > 0) - stcl = &stotal_cl.at(plist(ip) * ncl()); + stcl = &state.stotal_cl.at(plist(ip) * ncl()); fstotal_cl(stcl, &sx0data.at(ip * nx_rdata), plist(ip)); fsx_solver(sx0_solver_slice.data(), &sx0data.at(ip * nx_rdata)); for (int ix = 0; ix < nx_solver; ix++) { - sx.at(ix, ip) = (realtype)sx0_solver_slice.at(ix); + sx.at(ix, ip) = sx0_solver_slice.at(ix); } } } @@ -266,7 +244,7 @@ void Model::initHeaviside(AmiVector const &x, AmiVector const &dx) { froot(tstart, x, dx, rootvals); for (int ie = 0; ie < ne; ie++) { if (rootvals.at(ie) < 0) { - h.at(ie) = 0.0; + state.h.at(ie) = 0.0; } else if (rootvals.at(ie) == 0) { throw AmiException( "Simulation started in an event. This could lead to " @@ -274,26 +252,28 @@ void Model::initHeaviside(AmiVector const &x, AmiVector const &dx) { "specify an earlier simulation start via " "options.t0"); } else { - h.at(ie) = 1.0; + state.h.at(ie) = 1.0; } } } -int Model::nplist() const { return plist_.size(); } +int Model::nplist() const { return static_cast(state.plist.size()); } -int Model::np() const { return originalParameters.size(); } +int Model::np() const { return static_cast(originalParameters.size()); } -int Model::nk() const { return fixedParameters.size(); } +int Model::nk() const { return static_cast(state.fixedParameters.size()); } int Model::ncl() const { return nx_rdata - nx_solver; } -const double *Model::k() const { return fixedParameters.data(); } +int Model::nx_reinit() const { return nx_solver_reinit; } + +const double *Model::k() const { return state.fixedParameters.data(); } int Model::nMaxEvent() const { return nmaxevent; } void Model::setNMaxEvent(int nmaxevent) { this->nmaxevent = nmaxevent; } -int Model::nt() const { return ts.size(); } +int Model::nt() const { return static_cast(ts.size()); } const std::vector &Model::getParameterScale() const { return pscale; @@ -301,7 +281,7 @@ const std::vector &Model::getParameterScale() const { void Model::setParameterScale(ParameterScaling pscale) { this->pscale.assign(this->pscale.size(), pscale); - scaleParameters(unscaledParameters, this->pscale, originalParameters); + scaleParameters(state.unscaledParameters, this->pscale, originalParameters); sx0data.clear(); } @@ -310,12 +290,12 @@ void Model::setParameterScale(std::vector const &pscaleVec) { throw AmiException("Dimension mismatch. Size of parameter scaling does " "not match number of model parameters."); this->pscale = pscaleVec; - scaleParameters(unscaledParameters, this->pscale, originalParameters); + scaleParameters(state.unscaledParameters, this->pscale, originalParameters); sx0data.clear(); } const std::vector &Model::getUnscaledParameters() const { - return unscaledParameters; + return state.unscaledParameters; } std::vector const &Model::getParameters() const { @@ -343,8 +323,8 @@ void Model::setParameters(const std::vector &p) { throw AmiException("Dimension mismatch. Size of parameters does not " "match number of model parameters."); this->originalParameters = p; - this->unscaledParameters.resize(originalParameters.size()); - unscaleParameters(originalParameters, pscale, unscaledParameters); + this->state.unscaledParameters.resize(originalParameters.size()); + unscaleParameters(originalParameters, pscale, state.unscaledParameters); } void Model::setParameterById(const std::map &p, @@ -353,7 +333,7 @@ void Model::setParameterById(const std::map &p, for (auto& kv : p) { try { setParameterById(kv.first, kv.second); - } catch (AmiException&) { + } catch (AmiException const&) { if(!ignoreErrors) throw; } @@ -367,7 +347,7 @@ void Model::setParameterById(std::string const &par_id, realtype value) { setValueById(getParameterIds(), originalParameters, value, par_id, "parameter", "id"); - unscaleParameters(originalParameters, pscale, unscaledParameters); + unscaleParameters(originalParameters, pscale, state.unscaledParameters); } int Model::setParametersByIdRegex(std::string const &par_id_regex, @@ -377,7 +357,7 @@ int Model::setParametersByIdRegex(std::string const &par_id_regex, "Could not access parameters by id as they are not set"); int n_found = setValueByIdRegex(getParameterIds(), originalParameters, value, par_id_regex, "parameter", "id"); - unscaleParameters(originalParameters, pscale, unscaledParameters); + unscaleParameters(originalParameters, pscale, state.unscaledParameters); return n_found; } @@ -388,7 +368,7 @@ void Model::setParameterByName(std::string const &par_name, realtype value) { setValueById(getParameterNames(), originalParameters, value, par_name, "parameter", "name"); - unscaleParameters(originalParameters, pscale, unscaledParameters); + unscaleParameters(originalParameters, pscale, state.unscaledParameters); } void Model::setParameterByName(const std::map &p, @@ -397,7 +377,7 @@ void Model::setParameterByName(const std::map &p, for (auto& kv : p) { try { setParameterByName(kv.first, kv.second); - } catch (AmiException&) { + } catch (AmiException const&) { if(!ignoreErrors) throw; } @@ -410,15 +390,16 @@ int Model::setParametersByNameRegex(std::string const &par_name_regex, throw AmiException( "Could not access parameters by name as they are not set"); - int n_found = setValueByIdRegex(getParameterNames(), originalParameters, + int n_found = setValueByIdRegex(getParameterNames(), + originalParameters, value, par_name_regex, "parameter", "name"); - unscaleParameters(originalParameters, pscale, unscaledParameters); + unscaleParameters(originalParameters, pscale, state.unscaledParameters); return n_found; } const std::vector &Model::getFixedParameters() const { - return fixedParameters; + return state.fixedParameters; } realtype Model::getFixedParameterById(std::string const &par_id) const { @@ -426,8 +407,8 @@ realtype Model::getFixedParameterById(std::string const &par_id) const { throw AmiException( "Could not access fixed parameters by id as they are not set"); - return getValueById(getFixedParameterIds(), fixedParameters, par_id, - "fixedParameters", "id"); + return getValueById(getFixedParameterIds(), state.fixedParameters, + par_id, "fixedParameters", "id"); } realtype Model::getFixedParameterByName(std::string const &par_name) const { @@ -435,15 +416,15 @@ realtype Model::getFixedParameterByName(std::string const &par_name) const { throw AmiException( "Could not access fixed parameters by name as they are not set"); - return getValueById(getFixedParameterNames(), fixedParameters, par_name, - "fixedParameters", "name"); + return getValueById(getFixedParameterNames(), state.fixedParameters, + par_name, "fixedParameters", "name"); } void Model::setFixedParameters(const std::vector &k) { if (k.size() != (unsigned)nk()) throw AmiException("Dimension mismatch. Size of fixedParameters does " "not match number of fixed model parameters."); - this->fixedParameters = k; + this->state.fixedParameters = k; } void Model::setFixedParameterById(std::string const &par_id, realtype value) { @@ -451,7 +432,7 @@ void Model::setFixedParameterById(std::string const &par_id, realtype value) { throw AmiException( "Could not access fixed parameters by id as they are not set"); - setValueById(getFixedParameterIds(), fixedParameters, value, par_id, + setValueById(getFixedParameterIds(), state.fixedParameters, value, par_id, "fixedParameters", "id"); } @@ -461,8 +442,8 @@ int Model::setFixedParametersByIdRegex(std::string const &par_id_regex, throw AmiException( "Could not access fixed parameters by id as they are not set"); - return setValueByIdRegex(getFixedParameterIds(), fixedParameters, value, - par_id_regex, "fixedParameters", "id"); + return setValueByIdRegex(getFixedParameterIds(), state.fixedParameters, + value, par_id_regex, "fixedParameters", "id"); } void Model::setFixedParameterByName(std::string const &par_name, @@ -471,8 +452,8 @@ void Model::setFixedParameterByName(std::string const &par_name, throw AmiException( "Could not access fixed parameters by name as they are not set"); - setValueById(getFixedParameterNames(), fixedParameters, value, par_name, - "fixedParameters", "name"); + setValueById(getFixedParameterNames(), state.fixedParameters, value, + par_name, "fixedParameters", "name"); } int Model::setFixedParametersByNameRegex(std::string const &par_name_regex, @@ -481,8 +462,8 @@ int Model::setFixedParametersByNameRegex(std::string const &par_name_regex, throw AmiException( "Could not access fixed parameters by name as they are not set"); - return setValueByIdRegex(getFixedParameterIds(), fixedParameters, value, - par_name_regex, "fixedParameters", "name"); + return setValueByIdRegex(getFixedParameterIds(), state.fixedParameters, + value, par_name_regex, "fixedParameters", "name"); } std::string Model::getName() const { @@ -593,9 +574,9 @@ void Model::setAllStatesNonNegative() { setStateIsNonNegative(std::vector(nx_solver, true)); } -const std::vector &Model::getParameterList() const { return plist_; } +const std::vector &Model::getParameterList() const { return state.plist; } -int Model::plist(int pos) const { return plist_.at(pos); } +int Model::plist(int pos) const { return state.plist.at(pos); } void Model::setParameterList(const std::vector &plist) { int np = this->np(); // cannot capture 'this' in lambda expression @@ -603,7 +584,7 @@ void Model::setParameterList(const std::vector &plist) { [&np](int idx) { return idx < 0 || idx >= np; })) { throw AmiException("Indices in plist must be in [0..np]"); } - this->plist_ = plist; + this->state.plist = plist; initializeVectors(); } @@ -618,7 +599,8 @@ std::vector Model::getInitialStates() { * changing parameters etc. */ std::vector x0(nx_rdata, 0.0); - fx0(x0.data(), tstart, unscaledParameters.data(), fixedParameters.data()); + fx0(x0.data(), tstart, state.unscaledParameters.data(), + state.fixedParameters.data()); return x0; } @@ -652,8 +634,8 @@ std::vector Model::getInitialStateSensitivities() { std::vector sx0(nx_rdata * nplist(), 0.0); auto x0 = getInitialStates(); for (int ip = 0; ip < nplist(); ip++) { - fsx0(sx0.data(), tstart, x0.data(), unscaledParameters.data(), - fixedParameters.data(), plist(ip)); + fsx0(sx0.data(), tstart, x0.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), plist(ip)); } return sx0; @@ -677,10 +659,10 @@ void Model::setInitialStateSensitivities(const std::vector &sx0) { // revert chainrule switch (pscale.at(plist(ip))) { case ParameterScaling::log10: - chainrulefactor = unscaledParameters.at(plist(ip)) * log(10); + chainrulefactor = state.unscaledParameters.at(plist(ip)) * log(10); break; case ParameterScaling::ln: - chainrulefactor = unscaledParameters.at(plist(ip)); + chainrulefactor = state.unscaledParameters.at(plist(ip)); break; case ParameterScaling::none: chainrulefactor = 1.0; @@ -739,8 +721,8 @@ bool Model::getReinitializeFixedParameterInitialStates() const { } void Model::requireSensitivitiesForAllParameters() { - plist_.resize(np()); - std::iota(plist_.begin(), plist_.end(), 0); + state.plist.resize(np()); + std::iota(state.plist.begin(), state.plist.end(), 0); initializeVectors(); } @@ -765,7 +747,7 @@ void Model::getObservableSensitivity(gsl::span sy, const realtype t, fdydx(t, x); fdydp(t, x); - this->sx.assign(nx_solver * nplist(), 0.0); + this->sx.resize(nx_solver * nplist()); sx.flatten_to_vector(this->sx); // compute sy = 1.0*dydx*sx + 1.0*sy @@ -804,8 +786,8 @@ void Model::addObservableObjective(realtype &Jy, const int it, for (int iyt = 0; iyt < nytrue; iyt++) { if (edata.isSetObservedData(it, iyt)) { std::fill(nllh.begin(), nllh.end(), 0.0); - fJy(nllh.data(), iyt, unscaledParameters.data(), - fixedParameters.data(), y.data(), sigmay.data(), + fJy(nllh.data(), iyt, state.unscaledParameters.data(), + state.fixedParameters.data(), y.data(), sigmay.data(), edata.getObservedDataPtr(it)); Jy -= nllh.at(0); } @@ -826,6 +808,7 @@ void Model::addObservableObjectiveSensitivity(std::vector &sllh, // Compute dJydx*sx for current 'it' // dJydx rdata->nt x nJ x nx_solver // sx rdata->nt x nx_solver x nplist() + this->sx.resize(nx_solver * nplist()); sx.flatten_to_vector(this->sx); // C := alpha*op(A)*op(B) + beta*C, @@ -865,8 +848,9 @@ void Model::getEventSensitivity(gsl::span sz, const int ie, const realtype t, const AmiVector &x, const AmiVectorArray &sx) { for (int ip = 0; ip < nplist(); ip++) { - fsz(&sz.at(ip * nz), ie, t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data(), sx.data(ip), plist(ip)); + fsz(&sz.at(ip * nz), ie, t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), sx.data(ip), + plist(ip)); } } @@ -891,8 +875,9 @@ void Model::getEventRegularizationSensitivity(gsl::span srz, const AmiVector &x, const AmiVectorArray &sx) { for (int ip = 0; ip < nplist(); ip++) { - fsrz(&srz.at(ip * nz), ie, t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data(), sx.data(ip), plist(ip)); + fsrz(&srz.at(ip * nz), ie, t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), sx.data(ip), + plist(ip)); } } @@ -920,8 +905,8 @@ void Model::addEventObjective(realtype &Jz, const int ie, const int nroots, for (int iztrue = 0; iztrue < nztrue; iztrue++) { if (edata.isSetObservedEvents(nroots, iztrue)) { std::fill(nllh.begin(), nllh.end(), 0.0); - fJz(nllh.data(), iztrue, unscaledParameters.data(), - fixedParameters.data(), z.data(), sigmaz.data(), + fJz(nllh.data(), iztrue, state.unscaledParameters.data(), + state.fixedParameters.data(), z.data(), sigmaz.data(), edata.getObservedEventsPtr(nroots)); Jz -= nllh.at(0); } @@ -939,8 +924,8 @@ void Model::addEventObjectiveRegularization(realtype &Jrz, const int ie, for (int iztrue = 0; iztrue < nztrue; iztrue++) { if (edata.isSetObservedEvents(nroots, iztrue)) { std::fill(nllh.begin(), nllh.end(), 0.0); - fJrz(nllh.data(), iztrue, unscaledParameters.data(), - fixedParameters.data(), rz.data(), sigmaz.data()); + fJrz(nllh.data(), iztrue, state.unscaledParameters.data(), + state.fixedParameters.data(), rz.data(), sigmaz.data()); Jrz -= nllh.at(0); } } @@ -1009,8 +994,9 @@ void Model::getEventTimeSensitivity(std::vector &stau, std::fill(stau.begin(), stau.end(), 0.0); for (int ip = 0; ip < nplist(); ip++) { - fstau(&stau.at(ip), t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data(), sx.data(ip), plist(ip), ie); + fstau(&stau.at(ip), t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), sx.data(ip), + plist(ip), ie); } } @@ -1021,8 +1007,9 @@ void Model::addStateEventUpdate(AmiVector &x, const int ie, const realtype t, deltax.assign(nx_solver, 0.0); // compute update - fdeltax(deltax.data(), t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data(), ie, xdot.data(), xdot_old.data()); + fdeltax(deltax.data(), t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), ie, xdot.data(), + xdot_old.data()); if (alwaysCheckFinite) { app->checkFinite(deltax, "deltax"); @@ -1045,9 +1032,10 @@ void Model::addStateSensitivityEventUpdate(AmiVectorArray &sx, const int ie, deltasx.assign(nx_solver, 0.0); // compute update - fdeltasx(deltasx.data(), t, x_old.data(), unscaledParameters.data(), - fixedParameters.data(), h.data(), w.data(), plist(ip), ie, - xdot.data(), xdot_old.data(), sx.data(ip), &stau.at(ip)); + fdeltasx(deltasx.data(), t, x_old.data(), + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), w.data(), plist(ip), ie, xdot.data(), + xdot_old.data(), sx.data(ip), &stau.at(ip)); if (alwaysCheckFinite) { app->checkFinite(deltasx, "deltasx"); @@ -1065,9 +1053,9 @@ void Model::addAdjointStateEventUpdate(AmiVector &xB, const int ie, deltaxB.assign(nx_solver, 0.0); // compute update - fdeltaxB(deltaxB.data(), t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data(), ie, xdot.data(), xdot_old.data(), - xB.data()); + fdeltaxB(deltaxB.data(), t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), ie, xdot.data(), + xdot_old.data(), xB.data()); if (alwaysCheckFinite) { app->checkFinite(deltaxB, "deltaxB"); @@ -1086,9 +1074,9 @@ void Model::addAdjointQuadratureEventUpdate( for (int ip = 0; ip < nplist(); ip++) { deltaqB.assign(nJ, 0.0); - fdeltaqB(deltaqB.data(), t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data(), plist(ip), ie, xdot.data(), - xdot_old.data(), xB.data()); + fdeltaqB(deltaqB.data(), t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), plist(ip), ie, + xdot.data(), xdot_old.data(), xB.data()); for (int iJ = 0; iJ < nJ; ++iJ) xQB.at(iJ) += deltaqB.at(iJ); @@ -1101,22 +1089,23 @@ void Model::addAdjointQuadratureEventUpdate( void Model::updateHeaviside(const std::vector &rootsfound) { for (int ie = 0; ie < ne; ie++) { - h.at(ie) += rootsfound.at(ie); + state.h.at(ie) += rootsfound.at(ie); } } void Model::updateHeavisideB(const int *rootsfound) { for (int ie = 0; ie < ne; ie++) { - h.at(ie) -= rootsfound[ie]; + state.h.at(ie) -= rootsfound[ie]; } } + int Model::checkFinite(gsl::span array, const char *fun) const { auto result = app->checkFinite(array, fun); if (result != AMICI_SUCCESS) { - app->checkFinite(fixedParameters, "k"); - app->checkFinite(unscaledParameters, "p"); + app->checkFinite(state.fixedParameters, "k"); + app->checkFinite(state.unscaledParameters, "p"); app->checkFinite(w, "w"); } @@ -1132,10 +1121,10 @@ bool Model::getAlwaysCheckFinite() const { return alwaysCheckFinite; } void Model::fx0(AmiVector &x) { std::fill(x_rdata.begin(), x_rdata.end(), 0.0); /* this function also computes initial total abundances */ - fx0(x_rdata.data(), tstart, unscaledParameters.data(), - fixedParameters.data()); + fx0(x_rdata.data(), tstart, state.unscaledParameters.data(), + state.fixedParameters.data()); fx_solver(x.data(), x_rdata.data()); - ftotal_cl(total_cl.data(), x_rdata.data()); + ftotal_cl(state.total_cl.data(), x_rdata.data()); if (alwaysCheckFinite) { checkFinite(x_rdata, "x0 x_rdata"); @@ -1150,12 +1139,12 @@ void Model::fx0_fixedParameters(AmiVector &x) { x0_fixedparameters to (i) enable updates to states that were removed from conservation laws and (ii) be able to correctly compute total abundances after updating the state variables */ - fx_rdata(x_rdata.data(), x.data(), total_cl.data()); - fx0_fixedParameters(x_rdata.data(), tstart, unscaledParameters.data(), - fixedParameters.data()); + fx_rdata(x_rdata.data(), x.data(), state.total_cl.data()); + fx0_fixedParameters(x_rdata.data(), tstart, state.unscaledParameters.data(), + state.fixedParameters.data()); fx_solver(x.data(), x_rdata.data()); /* update total abundances */ - ftotal_cl(total_cl.data(), x_rdata.data()); + ftotal_cl(state.total_cl.data(), x_rdata.data()); } void Model::fsx0(AmiVectorArray &sx, const AmiVector &x) { @@ -1163,10 +1152,10 @@ void Model::fsx0(AmiVectorArray &sx, const AmiVector &x) { realtype *stcl = nullptr; for (int ip = 0; ip < nplist(); ip++) { if (ncl() > 0) - stcl = &stotal_cl.at(plist(ip) * ncl()); + stcl = &state.stotal_cl.at(plist(ip) * ncl()); std::fill(sx_rdata.begin(), sx_rdata.end(), 0.0); - fsx0(sx_rdata.data(), tstart, x.data(), unscaledParameters.data(), - fixedParameters.data(), plist(ip)); + fsx0(sx_rdata.data(), tstart, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), plist(ip)); fsx_solver(sx.data(ip), sx_rdata.data()); fstotal_cl(stcl, sx_rdata.data(), plist(ip)); } @@ -1178,10 +1167,11 @@ void Model::fsx0_fixedParameters(AmiVectorArray &sx, const AmiVector &x) { realtype *stcl = nullptr; for (int ip = 0; ip < nplist(); ip++) { if (ncl() > 0) - stcl = &stotal_cl.at(plist(ip) * ncl()); + stcl = &state.stotal_cl.at(plist(ip) * ncl()); fsx_rdata(sx_rdata.data(), sx.data(ip), stcl, plist(ip)); fsx0_fixedParameters(sx_rdata.data(), tstart, x.data(), - unscaledParameters.data(), fixedParameters.data(), + state.unscaledParameters.data(), + state.fixedParameters.data(), plist(ip)); fsx_solver(sx.data(ip), sx_rdata.data()); fstotal_cl(stcl, sx_rdata.data(), plist(ip)); @@ -1191,7 +1181,7 @@ void Model::fsx0_fixedParameters(AmiVectorArray &sx, const AmiVector &x) { void Model::fsdx0() {} void Model::fx_rdata(AmiVector &x_rdata, const AmiVector &x) { - fx_rdata(x_rdata.data(), x.data(), total_cl.data()); + fx_rdata(x_rdata.data(), x.data(), state.total_cl.data()); if (alwaysCheckFinite) checkFinite(x_rdata.getVector(), "x_rdata"); } @@ -1200,7 +1190,7 @@ void Model::fsx_rdata(AmiVectorArray &sx_rdata, const AmiVectorArray &sx) { realtype *stcl = nullptr; for (int ip = 0; ip < nplist(); ip++) { if (ncl() > 0) - stcl = &stotal_cl.at(plist(ip) * ncl()); + stcl = &state.stotal_cl.at(plist(ip) * ncl()); fsx_rdata(sx_rdata.data(ip), sx.data(ip), stcl, ip); } } @@ -1236,8 +1226,8 @@ void Model::writeLLHSensitivitySlice(const std::vector &dLLhdp, nJ - 1); } -void Model::checkLLHBufferSize(std::vector &sllh, - std::vector &s2llh) { +void Model::checkLLHBufferSize(std::vector const &sllh, + std::vector const &s2llh) const { if (sllh.size() != static_cast(nplist())) throw AmiException("Incorrect sllh buffer size! Was %u, expected %i.", sllh.size(), nplist()); @@ -1260,8 +1250,9 @@ void Model::fy(const realtype t, const AmiVector &x) { y.assign(ny, 0.0); fw(t, x.data()); - fy(y.data(), t, x.data(), unscaledParameters.data(), fixedParameters.data(), - h.data(), w.data()); + fy(y.data(), t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), + state.h.data(), w.data()); if (alwaysCheckFinite) { app->checkFinite(gsl::make_span(y.data(), ny), "y"); @@ -1278,8 +1269,8 @@ void Model::fdydp(const realtype t, const AmiVector &x) { /* get dydp slice (ny) for current time and parameter */ for (int ip = 0; ip < nplist(); ip++) - fdydp(&dydp.at(ip * ny), t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data(), plist(ip), w.data(), + fdydp(&dydp.at(ip * ny), t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), plist(ip), w.data(), dwdp.data()); if (alwaysCheckFinite) { @@ -1295,8 +1286,8 @@ void Model::fdydx(const realtype t, const AmiVector &x) { fw(t, x.data()); fdwdx(t, x.data()); - fdydx(dydx.data(), t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data(), w.data(), dwdx.data()); + fdydx(dydx.data(), t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), w.data(), dwdx.data()); if (alwaysCheckFinite) { app->checkFinite(dydx, "dydx"); @@ -1309,8 +1300,8 @@ void Model::fsigmay(const int it, const ExpData *edata) { sigmay.assign(ny, 0.0); - fsigmay(sigmay.data(), getTimepoint(it), unscaledParameters.data(), - fixedParameters.data()); + fsigmay(sigmay.data(), getTimepoint(it), state.unscaledParameters.data(), + state.fixedParameters.data()); if (edata) { auto sigmay_edata = edata->getObservedDataStdDevPtr(it); @@ -1341,7 +1332,8 @@ void Model::fdsigmaydp(const int it, const ExpData *edata) { for (int ip = 0; ip < nplist(); ip++) // get dsigmaydp slice (ny) for current timepoint and parameter fdsigmaydp(&dsigmaydp.at(ip * ny), getTimepoint(it), - unscaledParameters.data(), fixedParameters.data(), + state.unscaledParameters.data(), + state.fixedParameters.data(), plist(ip)); // sigmas in edata override model-sigma -> for those sigmas, set dsigmaydp @@ -1388,8 +1380,8 @@ void Model::fdJydy(const int it, const AmiVector &x, const ExpData &edata) { continue; // get dJydy slice (ny) for current timepoint and observable - fdJydy(dJydy[iyt].data(), iyt, unscaledParameters.data(), - fixedParameters.data(), y.data(), sigmay.data(), + fdJydy(dJydy[iyt].data(), iyt, state.unscaledParameters.data(), + state.fixedParameters.data(), y.data(), sigmay.data(), edata.getObservedDataPtr(it)); if (alwaysCheckFinite) { @@ -1402,8 +1394,9 @@ void Model::fdJydy(const int it, const AmiVector &x, const ExpData &edata) { if (!edata.isSetObservedData(it, iyt)) continue; fdJydy(&dJydy_matlab.at(iyt * ny * nJ), iyt, - unscaledParameters.data(), fixedParameters.data(), y.data(), - sigmay.data(), edata.getObservedDataPtr(it)); + state.unscaledParameters.data(), + state.fixedParameters.data(), y.data(), sigmay.data(), + edata.getObservedDataPtr(it)); } if (alwaysCheckFinite) { // get dJydy slice (ny) for current timepoint and observable @@ -1423,8 +1416,9 @@ void Model::fdJydsigma(const int it, const AmiVector &x, const ExpData &edata) { if (edata.isSetObservedData(it, iyt)) // get dJydsigma slice (ny) for current timepoint and observable fdJydsigma(&dJydsigma.at(iyt * ny * nJ), iyt, - unscaledParameters.data(), fixedParameters.data(), - y.data(), sigmay.data(), edata.getObservedDataPtr(it)); + state.unscaledParameters.data(), + state.fixedParameters.data(), y.data(), sigmay.data(), + edata.getObservedDataPtr(it)); } if (alwaysCheckFinite) { @@ -1512,8 +1506,8 @@ void Model::fz(const int ie, const realtype t, const AmiVector &x) { z.assign(nz, 0.0); - fz(z.data(), ie, t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data()); + fz(z.data(), ie, t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data()); } void Model::fdzdp(const int ie, const realtype t, const AmiVector &x) { @@ -1521,8 +1515,8 @@ void Model::fdzdp(const int ie, const realtype t, const AmiVector &x) { dzdp.assign(nz * nplist(), 0.0); for (int ip = 0; ip < nplist(); ip++) { - fdzdp(dzdp.data(), ie, t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data(), plist(ip)); + fdzdp(dzdp.data(), ie, t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), plist(ip)); } if (alwaysCheckFinite) { @@ -1534,8 +1528,8 @@ void Model::fdzdx(const int ie, const realtype t, const AmiVector &x) { dzdx.assign(nz * nx_solver, 0.0); - fdzdx(dzdx.data(), ie, t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data()); + fdzdx(dzdx.data(), ie, t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data()); if (alwaysCheckFinite) { app->checkFinite(dzdx, "dzdx"); @@ -1546,8 +1540,8 @@ void Model::frz(const int ie, const realtype t, const AmiVector &x) { rz.assign(nz, 0.0); - frz(rz.data(), ie, t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data()); + frz(rz.data(), ie, t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data()); } void Model::fdrzdp(const int ie, const realtype t, const AmiVector &x) { @@ -1555,8 +1549,8 @@ void Model::fdrzdp(const int ie, const realtype t, const AmiVector &x) { drzdp.assign(nz * nplist(), 0.0); for (int ip = 0; ip < nplist(); ip++) { - fdrzdp(drzdp.data(), ie, t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data(), plist(ip)); + fdrzdp(drzdp.data(), ie, t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), plist(ip)); } if (alwaysCheckFinite) { @@ -1568,8 +1562,8 @@ void Model::fdrzdx(const int ie, const realtype t, const AmiVector &x) { drzdx.assign(nz * nx_solver, 0.0); - fdrzdx(drzdx.data(), ie, t, x.data(), unscaledParameters.data(), - fixedParameters.data(), h.data()); + fdrzdx(drzdx.data(), ie, t, x.data(), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data()); if (alwaysCheckFinite) { app->checkFinite(drzdx, "drzdx"); @@ -1582,8 +1576,8 @@ void Model::fsigmaz(const int ie, const int nroots, const realtype t, return; sigmaz.assign(nz, 0.0); - fsigmaz(sigmaz.data(), t, unscaledParameters.data(), - fixedParameters.data()); + fsigmaz(sigmaz.data(), t, state.unscaledParameters.data(), + state.fixedParameters.data()); if (edata) { for (int iztrue = 0; iztrue < nztrue; iztrue++) { @@ -1614,8 +1608,8 @@ void Model::fdsigmazdp(const int ie, const int nroots, const realtype t, for (int ip = 0; ip < nplist(); ip++) { // get dsigmazdp slice (nz) for current event and parameter - fdsigmazdp(&dsigmazdp.at(ip * nz), t, unscaledParameters.data(), - fixedParameters.data(), plist(ip)); + fdsigmazdp(&dsigmazdp.at(ip * nz), t, state.unscaledParameters.data(), + state.fixedParameters.data(), plist(ip)); } // sigmas in edata override model-sigma -> for those sigmas, set dsigmazdp @@ -1646,8 +1640,9 @@ void Model::fdJzdz(const int ie, const int nroots, const realtype t, for (int iztrue = 0; iztrue < nztrue; iztrue++) { if (edata.isSetObservedEvents(nroots, iztrue)) { fdJzdz(&dJzdz.at(iztrue * nz * nJ), iztrue, - unscaledParameters.data(), fixedParameters.data(), z.data(), - sigmaz.data(), edata.getObservedEventsPtr(nroots)); + state.unscaledParameters.data(), + state.fixedParameters.data(), z.data(), sigmaz.data(), + edata.getObservedEventsPtr(nroots)); } } @@ -1667,8 +1662,8 @@ void Model::fdJzdsigma(const int ie, const int nroots, const realtype t, for (int iztrue = 0; iztrue < nztrue; iztrue++) { if (edata.isSetObservedEvents(nroots, iztrue)) { fdJzdsigma(&dJzdsigma.at(iztrue * nz * nJ), iztrue, - unscaledParameters.data(), fixedParameters.data(), - z.data(), sigmaz.data(), + state.unscaledParameters.data(), + state.fixedParameters.data(), z.data(), sigmaz.data(), edata.getObservedEventsPtr(nroots)); } } @@ -1771,8 +1766,8 @@ void Model::fdJrzdz(const int ie, const int nroots, const realtype t, for (int iztrue = 0; iztrue < nztrue; iztrue++) { if (edata.isSetObservedEvents(nroots, iztrue)) { fdJrzdz(&dJrzdz.at(iztrue * nz * nJ), iztrue, - unscaledParameters.data(), fixedParameters.data(), - rz.data(), sigmaz.data()); + state.unscaledParameters.data(), + state.fixedParameters.data(), rz.data(), sigmaz.data()); } } @@ -1792,8 +1787,8 @@ void Model::fdJrzdsigma(const int ie, const int nroots, const realtype t, for (int iztrue = 0; iztrue < nztrue; iztrue++) { if (edata.isSetObservedEvents(nroots, iztrue)) { fdJrzdsigma(&dJrzdsigma.at(iztrue * nz * nJ), iztrue, - unscaledParameters.data(), fixedParameters.data(), - rz.data(), sigmaz.data()); + state.unscaledParameters.data(), + state.fixedParameters.data(), rz.data(), sigmaz.data()); } } @@ -1804,8 +1799,8 @@ void Model::fdJrzdsigma(const int ie, const int nroots, const realtype t, void Model::fw(const realtype t, const realtype *x) { std::fill(w.begin(), w.end(), 0.0); - fw(w.data(), t, x, unscaledParameters.data(), fixedParameters.data(), - h.data(), total_cl.data()); + fw(w.data(), t, x, state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), state.total_cl.data()); if (alwaysCheckFinite) { app->checkFinite(w, "w"); @@ -1823,14 +1818,15 @@ void Model::fdwdp(const realtype t, const realtype *x) { fdwdp_colptrs(dwdp.indexptrs()); fdwdp_rowvals(dwdp.indexvals()); - fdwdp(dwdp.data(), t, x, unscaledParameters.data(), fixedParameters.data(), - h.data(), w.data(), total_cl.data(), stotal_cl.data()); + fdwdp(dwdp.data(), t, x, state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), w.data(), + state.total_cl.data(), state.stotal_cl.data()); } else { // matlab generated - fdwdp(dwdp.data(), t, x, unscaledParameters.data(), - fixedParameters.data(), h.data(), w.data(), total_cl.data(), - stotal_cl.data()); + fdwdp(dwdp.data(), t, x, state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), w.data(), + state.total_cl.data(), state.stotal_cl.data()); } if (alwaysCheckFinite) { @@ -1844,8 +1840,9 @@ void Model::fdwdx(const realtype t, const realtype *x) { fdwdx_colptrs(dwdx.indexptrs()); fdwdx_rowvals(dwdx.indexvals()); - fdwdx(dwdx.data(), t, x, unscaledParameters.data(), fixedParameters.data(), - h.data(), w.data(), total_cl.data()); + fdwdx(dwdx.data(), t, x, state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), w.data(), + state.total_cl.data()); if (alwaysCheckFinite) { app->checkFinite(gsl::make_span(dwdx.get()), "dwdx"); diff --git a/deps/AMICI/src/model_dae.cpp b/deps/AMICI/src/model_dae.cpp index d0384ae0b..0169d6c5d 100644 --- a/deps/AMICI/src/model_dae.cpp +++ b/deps/AMICI/src/model_dae.cpp @@ -13,9 +13,9 @@ void Model_DAE::fJ(realtype t, realtype cj, N_Vector x, N_Vector dx, auto x_pos = computeX_pos(x); fdwdx(t, N_VGetArrayPointer(x_pos)); SUNMatZero(J); - fJ(SM_DATA_D(J), t, N_VGetArrayPointer(x_pos), unscaledParameters.data(), - fixedParameters.data(), h.data(), cj, N_VGetArrayPointer(dx), w.data(), - dwdx.data()); + fJ(SM_DATA_D(J), t, N_VGetArrayPointer(x_pos), + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), cj, N_VGetArrayPointer(dx), w.data(), dwdx.data()); } void Model_DAE::fJSparse(const realtype t, const realtype cj, @@ -30,9 +30,9 @@ void Model_DAE::fJSparse(realtype t, realtype cj, N_Vector x, N_Vector dx, fdwdx(t, N_VGetArrayPointer(x_pos)); SUNMatZero(J); fJSparse(static_cast(SM_CONTENT_S(J)), t, - N_VGetArrayPointer(x_pos), unscaledParameters.data(), - fixedParameters.data(), h.data(), cj, N_VGetArrayPointer(dx), - w.data(), dwdx.data()); + N_VGetArrayPointer(x_pos), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), cj, + N_VGetArrayPointer(dx), w.data(), dwdx.data()); } void Model_DAE::fJSparseB(SUNMatrixContent_Sparse /*JSparseB*/, @@ -70,8 +70,9 @@ void Model_DAE::froot(realtype t, N_Vector x, N_Vector dx, gsl::span root) { std::fill(root.begin(), root.end(), 0.0); auto x_pos = computeX_pos(x); - froot(root.data(), t, N_VGetArrayPointer(x_pos), unscaledParameters.data(), - fixedParameters.data(), h.data(), N_VGetArrayPointer(dx)); + froot(root.data(), t, N_VGetArrayPointer(x_pos), + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), N_VGetArrayPointer(dx)); } void Model_DAE::fxdot(const realtype t, const AmiVector &x, const AmiVector &dx, @@ -84,8 +85,8 @@ void Model_DAE::fxdot(realtype t, N_Vector x, N_Vector dx, N_Vector xdot) { fw(t, N_VGetArrayPointer(x)); N_VConst(0.0, xdot); fxdot(N_VGetArrayPointer(xdot), t, N_VGetArrayPointer(x_pos), - unscaledParameters.data(), fixedParameters.data(), h.data(), - N_VGetArrayPointer(dx), w.data()); + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), N_VGetArrayPointer(dx), w.data()); } void Model_DAE::fJDiag(const realtype t, AmiVector &JDiag, @@ -95,8 +96,8 @@ void Model_DAE::fJDiag(const realtype t, AmiVector &JDiag, fdwdx(t, N_VGetArrayPointer(x_pos)); JDiag.set(0.0); fJDiag(JDiag.data(), t, N_VGetArrayPointer(x_pos), - unscaledParameters.data(), fixedParameters.data(), h.data(), 0.0, - dx.data(), w.data(), dwdx.data()); + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), 0.0, dx.data(), w.data(), dwdx.data()); if (!checkFinite(JDiag.getVector(), "Jacobian")) throw AmiException("Evaluation of fJDiag failed!"); } @@ -110,13 +111,14 @@ void Model_DAE::fdxdotdp(const realtype t, const N_Vector x, throw AmiException("Wrapping of DAEs is not yet implemented from Python"); } else { // matlab generated - fdwdp(t, N_VGetArrayPointer(x_pos)); // Why is it x_pos here and x ind model_ode.cpp? + fdwdp(t, N_VGetArrayPointer(x_pos)); for (int ip = 0; ip < nplist(); ip++) { N_VConst(0.0, dxdotdp.getNVector(ip)); fdxdotdp(dxdotdp.data(ip), t, N_VGetArrayPointer(x_pos), - unscaledParameters.data(), fixedParameters.data(), h.data(), - plist_[ip], N_VGetArrayPointer(dx), w.data(), dwdp.data()); + state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), plist(ip), + N_VGetArrayPointer(dx), w.data(), dwdp.data()); } } } @@ -124,8 +126,8 @@ void Model_DAE::fdxdotdp(const realtype t, const N_Vector x, void Model_DAE::fM(realtype t, const N_Vector x) { SUNMatZero(M.get()); auto x_pos = computeX_pos(x); - fM(M.data(), t, N_VGetArrayPointer(x_pos), unscaledParameters.data(), - fixedParameters.data()); + fM(M.data(), t, N_VGetArrayPointer(x_pos), state.unscaledParameters.data(), + state.fixedParameters.data()); } std::unique_ptr Model_DAE::getSolver() { @@ -182,14 +184,30 @@ void Model_DAE::fdxdotdp(realtype * /*dxdotdp*/, const realtype /*t*/, __func__); } +void Model_DAE::fJB(const realtype t, realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xB, + const AmiVector &dxB, const AmiVector & /*xBdot*/, + SUNMatrix JB) { + fJB(t, cj, x.getNVector(), dx.getNVector(), xB.getNVector(), dx.getNVector(), JB); +} + + void Model_DAE::fJB(realtype t, realtype cj, N_Vector x, N_Vector dx, N_Vector xB, N_Vector dxB, SUNMatrix JB) { auto x_pos = computeX_pos(x); fdwdx(t, N_VGetArrayPointer(x_pos)); SUNMatZero(JB); - fJB(SM_DATA_D(JB), t, N_VGetArrayPointer(x_pos), unscaledParameters.data(), - fixedParameters.data(), h.data(), cj, N_VGetArrayPointer(xB), - N_VGetArrayPointer(dx), N_VGetArrayPointer(dxB), w.data(), dwdx.data()); + fJB(SM_DATA_D(JB), t, N_VGetArrayPointer(x_pos), + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), cj, N_VGetArrayPointer(xB), N_VGetArrayPointer(dx), + N_VGetArrayPointer(dxB), w.data(), dwdx.data()); +} + +void Model_DAE::fJSparseB(const realtype t, realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xB, + const AmiVector &dxB, const AmiVector & /*xBdot*/, + SUNMatrix JB) { + fJSparseB(t, cj, x.getNVector(), dx.getNVector(), xB.getNVector(), dxB.getNVector(), JB); } void Model_DAE::fJSparseB(realtype t, realtype cj, N_Vector x, N_Vector dx, @@ -198,10 +216,10 @@ void Model_DAE::fJSparseB(realtype t, realtype cj, N_Vector x, N_Vector dx, fdwdx(t, N_VGetArrayPointer(x_pos)); SUNMatZero(JB); fJSparseB(static_cast(SM_CONTENT_S(JB)), t, - N_VGetArrayPointer(x_pos), unscaledParameters.data(), - fixedParameters.data(), h.data(), cj, N_VGetArrayPointer(xB), - N_VGetArrayPointer(dx), N_VGetArrayPointer(dxB), w.data(), - dwdx.data()); + N_VGetArrayPointer(x_pos), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), cj, + N_VGetArrayPointer(xB), N_VGetArrayPointer(dx), + N_VGetArrayPointer(dxB), w.data(), dwdx.data()); } void Model_DAE::fJvB(realtype t, N_Vector x, N_Vector dx, N_Vector xB, @@ -235,6 +253,44 @@ void Model_DAE::fqBdot(realtype t, N_Vector x, N_Vector dx, N_Vector xB, } } +void Model_DAE::fxBdot_ss(const realtype t, const AmiVector &xB, + const AmiVector &dxB, AmiVector &xBdot) { + fxBdot_ss(t, xB.getNVector(), dxB.getNVector(), xBdot.getNVector()); +} + +void Model_DAE::fxBdot_ss(realtype /*t*/, N_Vector xB, N_Vector /*dxB*/, + N_Vector xBdot) const { + /* Right hande side of the adjoint state for steady state computations. + J is fixed (as x remeins in steady state), so the RHS becomes simple. */ + N_VConst(0.0, xBdot); + J.multiply(xBdot, xB); + /* Mind the minus sign... */ + N_VScale(-1.0, xBdot, xBdot); +} + +void Model_DAE::fqBdot_ss(realtype /*t*/, N_Vector xB, N_Vector /*dxB*/, + N_Vector qBdot) const { + /* Quadratures when computing adjoints for steady state. The integrand is + just the adjoint state itself. */ + N_VScale(1.0, xB, qBdot); +} + +void Model_DAE::fJSparseB_ss(SUNMatrix JB) { + /* Just pass the model Jacobian on to JB */ + SUNMatCopy(J.get(), JB); +} + +void Model_DAE::writeSteadystateJB(const realtype t, realtype cj, + const AmiVector &x, const AmiVector & dx, + const AmiVector &xB, const AmiVector & dxB, + const AmiVector &xBdot) { + /* Get backward Jacobian */ + fJSparseB(t, cj, x.getNVector(), dx.getNVector(), xB.getNVector(), + dxB.getNVector(), J.get()); + /* Switch sign, as we integrate forward in time, not backward */ + J.scale(-1); +} + void Model_DAE::fsxdot(const realtype t, const AmiVector &x, const AmiVector &dx, const int ip, const AmiVector &sx, const AmiVector &sdx, AmiVector &sxdot) { diff --git a/deps/AMICI/src/model_header.ODE_template.h b/deps/AMICI/src/model_header.ODE_template.h index 48ae0028b..3b5b37263 100644 --- a/deps/AMICI/src/model_header.ODE_template.h +++ b/deps/AMICI/src/model_header.ODE_template.h @@ -9,14 +9,21 @@ #include "sundials/sundials_types.h" namespace amici { + class Solver; -} -/** - * @brief Wrapper function to instantiate the linked Amici model without knowing - * the name at compile time. - * @return - */ +namespace model_TPL_MODELNAME { + +extern std::array parameterNames; +extern std::array fixedParameterNames; +extern std::array stateNames; +extern std::array observableNames; +extern std::array parameterIds; +extern std::array fixedParameterIds; +extern std::array stateIds; +extern std::array observableIds; + + extern void J_TPL_MODELNAME(realtype *J, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, @@ -112,6 +119,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { TPL_NXTRUE_RDATA, // nxtrue_rdata TPL_NX_SOLVER, // nx_solver TPL_NXTRUE_SOLVER, // nxtrue_solver + TPL_NX_SOLVER_REINIT, // nx_solver_reinit TPL_NY, // ny TPL_NYTRUE, // nytrue TPL_NZ, // nz @@ -151,7 +159,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x Vector with the states * @param p parameter vector * @param k constants vector - * @param h heavyside vector + * @param h heaviside vector * @param w vector with helper variables * @param dwdx derivative of w wrt x **/ @@ -167,7 +175,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x Vector with the states * @param p parameter vector * @param k constants vector - * @param h heavyside vector + * @param h heaviside vector * @param xB Vector with the adjoint states * @param w vector with helper variables * @param dwdx derivative of w wrt x @@ -185,7 +193,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x Vector with the states * @param p parameter vector * @param k constants vector - * @param h heavyside vector + * @param h heaviside vector * @param w vector with helper variables * @param dwdx derivative of w wrt x **/ @@ -326,7 +334,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector * @param ip sensitivity index * @param ie event index * @param xdot new model right hand side @@ -346,7 +354,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector * @param w repeating elements vector * @param ip sensitivity index * @param ie event index @@ -368,7 +376,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector * @param ie event index * @param xdot new model right hand side * @param xdot_old previous model right hand side @@ -384,7 +392,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector * @param ie event index * @param xdot new model right hand side * @param xdot_old previous model right hand side @@ -404,7 +412,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector * @param ip parameter index w.r.t. which the derivative is requested **/ virtual void fdrzdp(realtype *drzdp, const int ie, const realtype t, @@ -418,7 +426,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector **/ virtual void fdrzdx(realtype *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, @@ -454,38 +462,38 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { TPL_DJYDY_ROWVALS_IMPL TPL_DWDP_IMPL - + TPL_DWDP_COLPTRS_IMPL - + TPL_DWDP_ROWVALS_IMPL TPL_DWDX_IMPL TPL_DWDX_COLPTRS_IMPL - + TPL_DWDX_ROWVALS_IMPL - + TPL_DXDOTDW_IMPL TPL_DXDOTDW_COLPTRS_IMPL TPL_DXDOTDW_ROWVALS_IMPL TPL_DXDOTDP_EXPLICIT_IMPL - + TPL_DXDOTDP_EXPLICIT_COLPTRS_IMPL - + TPL_DXDOTDP_EXPLICIT_ROWVALS_IMPL TPL_DXDOTDP_IMPLICIT_COLPTRS_IMPL - + TPL_DXDOTDP_IMPLICIT_ROWVALS_IMPL - + /** model specific implementation of fdydx * @param dydx partial derivative of observables y w.r.t. model states x * @param t current time * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector **/ virtual void fdydx(realtype *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, @@ -499,7 +507,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector * @param ip parameter index w.r.t. which the derivative is requested **/ virtual void fdydp(realtype *dydp, const realtype t, const realtype *x, @@ -517,7 +525,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector * @param ip parameter index w.r.t. which the derivative is requested **/ virtual void fdzdp(realtype *dzdp, const int ie, const realtype t, @@ -532,7 +540,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector **/ virtual void fdzdx(realtype *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, @@ -544,7 +552,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x Vector with the states * @param p parameter vector * @param k constants vector - * @param h heavyside vector + * @param h heaviside vector **/ virtual void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, @@ -558,7 +566,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector **/ virtual void frz(realtype *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, @@ -592,7 +600,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param p parameter vector * @param k constant vector * @param sx current state sensitivity - * @param h heavyside vector + * @param h heaviside vector * @param ip sensitivity index **/ virtual void fsrz(realtype *srz, const int ie, const realtype t, @@ -606,7 +614,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector * @param sx current state sensitivity * @param ip sensitivity index * @param ie event index @@ -652,7 +660,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector * @param sx current state sensitivity * @param ip sensitivity index **/ @@ -692,7 +700,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x Vector with the states * @param p parameter vector * @param k constants vector - * @param h heavyside vector + * @param h heaviside vector * @param w vector with helper variables **/ virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, @@ -707,7 +715,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector **/ virtual void fy(realtype *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, @@ -722,7 +730,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @param x current state * @param p parameter vector * @param k constant vector - * @param h heavyside vector + * @param h heaviside vector **/ virtual void fz(realtype *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, @@ -733,7 +741,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { TPL_X_SOLVER_IMPL TPL_TOTAL_CL_IMPL - + std::string getName() const override { return "TPL_MODELNAME"; } @@ -743,7 +751,8 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @return the names */ virtual std::vector getParameterNames() const override { - return std::vector{TPL_PARAMETER_NAMES_INITIALIZER_LIST}; + return std::vector(parameterNames.begin(), + parameterNames.end()); } /** @@ -751,7 +760,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @return the names */ virtual std::vector getStateNames() const override { - return std::vector{TPL_STATE_NAMES_INITIALIZER_LIST}; + return std::vector(stateNames.begin(), stateNames.end()); } /** @@ -759,8 +768,8 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @return the names */ virtual std::vector getFixedParameterNames() const override { - return std::vector{ - TPL_FIXED_PARAMETER_NAMES_INITIALIZER_LIST}; + return std::vector(fixedParameterNames.begin(), + fixedParameterNames.end()); } /** @@ -768,7 +777,8 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @return the names */ virtual std::vector getObservableNames() const override { - return std::vector{TPL_OBSERVABLE_NAMES_INITIALIZER_LIST}; + return std::vector(observableNames.begin(), + observableNames.end()); } /** @@ -776,7 +786,8 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @return the ids */ virtual std::vector getParameterIds() const override { - return std::vector{TPL_PARAMETER_IDS_INITIALIZER_LIST}; + return std::vector(parameterIds.begin(), + parameterIds.end()); } /** @@ -784,7 +795,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @return the ids */ virtual std::vector getStateIds() const override { - return std::vector{TPL_STATE_IDS_INITIALIZER_LIST}; + return std::vector(stateIds.begin(), stateIds.end()); } /** @@ -792,8 +803,8 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @return the ids */ virtual std::vector getFixedParameterIds() const override { - return std::vector{ - TPL_FIXED_PARAMETER_IDS_INITIALIZER_LIST}; + return std::vector(fixedParameterIds.begin(), + fixedParameterIds.end()); } /** @@ -801,7 +812,8 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { * @return the ids */ virtual std::vector getObservableIds() const override { - return std::vector{TPL_OBSERVABLE_IDS_INITIALIZER_LIST}; + return std::vector(observableIds.begin(), + observableIds.end()); } /** @@ -831,4 +843,9 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { } }; + +} // namespace model_TPL_MODELNAME + +} // namespace amici + #endif /* _amici_TPL_MODELNAME_h */ diff --git a/deps/AMICI/src/model_ode.cpp b/deps/AMICI/src/model_ode.cpp index 02389c534..e37246baa 100644 --- a/deps/AMICI/src/model_ode.cpp +++ b/deps/AMICI/src/model_ode.cpp @@ -14,8 +14,9 @@ void Model_ODE::fJ(realtype t, N_Vector x, N_Vector /*xdot*/, SUNMatrix J) { auto x_pos = computeX_pos(x); fdwdx(t, N_VGetArrayPointer(x_pos)); SUNMatZero(J); - fJ(SM_DATA_D(J), t, N_VGetArrayPointer(x_pos), unscaledParameters.data(), - fixedParameters.data(), h.data(), w.data(), dwdx.data()); + fJ(SM_DATA_D(J), t, N_VGetArrayPointer(x_pos), + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), w.data(), dwdx.data()); } void Model_ODE::fJSparse(const realtype t, const realtype /*cj*/, @@ -30,14 +31,15 @@ void Model_ODE::fJSparse(realtype t, N_Vector x, SUNMatrix J) { SUNMatZero(J); if (pythonGenerated) { fJSparse(SM_DATA_S(J), t, N_VGetArrayPointer(x_pos), - unscaledParameters.data(), fixedParameters.data(), h.data(), - w.data(), dwdx.data()); + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), w.data(), dwdx.data()); fJSparse_colptrs(SM_INDEXPTRS_S(J)); fJSparse_rowvals(SM_INDEXVALS_S(J)); } else { fJSparse(static_cast(SM_CONTENT_S(J)), t, - N_VGetArrayPointer(x_pos), unscaledParameters.data(), - fixedParameters.data(), h.data(), w.data(), dwdx.data()); + N_VGetArrayPointer(x_pos), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), w.data(), + dwdx.data()); } } @@ -61,8 +63,9 @@ void Model_ODE::froot(const realtype t, const AmiVector &x, void Model_ODE::froot(realtype t, N_Vector x, gsl::span root) { auto x_pos = computeX_pos(x); std::fill(root.begin(), root.end(), 0.0); - froot(root.data(), t, N_VGetArrayPointer(x_pos), unscaledParameters.data(), - fixedParameters.data(), h.data()); + froot(root.data(), t, N_VGetArrayPointer(x_pos), + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data()); } void Model_ODE::fxdot(const realtype t, const AmiVector &x, @@ -75,8 +78,8 @@ void Model_ODE::fxdot(realtype t, N_Vector x, N_Vector xdot) { fw(t, N_VGetArrayPointer(x_pos)); N_VConst(0.0, xdot); fxdot(N_VGetArrayPointer(xdot), t, N_VGetArrayPointer(x_pos), - unscaledParameters.data(), fixedParameters.data(), h.data(), - w.data()); + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), w.data()); } void Model_ODE::fJDiag(const realtype t, AmiVector &JDiag, @@ -94,8 +97,8 @@ void Model_ODE::fdxdotdw(const realtype t, const N_Vector x) { fdxdotdw_colptrs(dxdotdw.indexptrs()); fdxdotdw_rowvals(dxdotdw.indexvals()); fdxdotdw(dxdotdw.data(), t, N_VGetArrayPointer(x_pos), - unscaledParameters.data(), fixedParameters.data(), h.data(), - w.data()); + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), w.data()); } } @@ -110,11 +113,10 @@ void Model_ODE::fdxdotdp(const realtype t, const N_Vector x) { dxdotdp_explicit.reset(); fdxdotdp_explicit_colptrs(dxdotdp_explicit.indexptrs()); fdxdotdp_explicit_rowvals(dxdotdp_explicit.indexvals()); - fdxdotdp_explicit(dxdotdp_explicit.data(), - t, N_VGetArrayPointer(x_pos), - unscaledParameters.data(), - fixedParameters.data(), - h.data(), w.data()); + fdxdotdp_explicit( + dxdotdp_explicit.data(), t, N_VGetArrayPointer(x_pos), + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), w.data()); } if (nw > 0 && ndxdotdp_implicit > 0) { /* Sparse matrix multiplication @@ -129,8 +131,9 @@ void Model_ODE::fdxdotdp(const realtype t, const N_Vector x) { for (int ip = 0; ip < nplist(); ip++) { N_VConst(0.0, dxdotdp.getNVector(ip)); fdxdotdp(dxdotdp.data(ip), t, N_VGetArrayPointer(x_pos), - unscaledParameters.data(), fixedParameters.data(), - h.data(), plist_[ip], w.data(), dwdp.data()); + state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), plist(ip), + w.data(), dwdp.data()); } } } @@ -298,14 +301,28 @@ void Model_ODE::fdxdotdw_rowvals(sunindextype * /*indexvals*/) { __func__); // not implemented } +void Model_ODE::fJB(const realtype t, realtype /*cj*/, const AmiVector &x, + const AmiVector & /*dx*/, const AmiVector &xB, + const AmiVector & /*dxB*/, const AmiVector &xBdot, + SUNMatrix JB) { + fJB(t, x.getNVector(), xB.getNVector(), xBdot.getNVector(), JB); +} + void Model_ODE::fJB(realtype t, N_Vector x, N_Vector xB, N_Vector /*xBdot*/, SUNMatrix JB) { auto x_pos = computeX_pos(x); fdwdx(t, N_VGetArrayPointer(x_pos)); SUNMatZero(JB); - fJB(SM_DATA_D(JB), t, N_VGetArrayPointer(x_pos), unscaledParameters.data(), - fixedParameters.data(), h.data(), N_VGetArrayPointer(xB), w.data(), - dwdx.data()); + fJB(SM_DATA_D(JB), t, N_VGetArrayPointer(x_pos), + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), N_VGetArrayPointer(xB), w.data(), dwdx.data()); +} + +void Model_ODE::fJSparseB(const realtype t, realtype /*cj*/, const AmiVector &x, + const AmiVector & /*dx*/, const AmiVector &xB, + const AmiVector & /*dxB*/, const AmiVector &xBdot, + SUNMatrix JB) { + fJSparseB(t, x.getNVector(), xB.getNVector(), xBdot.getNVector(), JB); } void Model_ODE::fJSparseB(realtype t, N_Vector x, N_Vector xB, @@ -315,15 +332,16 @@ void Model_ODE::fJSparseB(realtype t, N_Vector x, N_Vector xB, SUNMatZero(JB); if (pythonGenerated) { fJSparseB(SM_DATA_S(JB), t, N_VGetArrayPointer(x_pos), - unscaledParameters.data(), fixedParameters.data(), h.data(), - N_VGetArrayPointer(xB), w.data(), dwdx.data()); + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), N_VGetArrayPointer(xB), w.data(), + dwdx.data()); fJSparseB_colptrs(SM_INDEXPTRS_S(JB)); fJSparseB_rowvals(SM_INDEXVALS_S(JB)); } else { fJSparseB(static_cast(SM_CONTENT_S(JB)), t, - N_VGetArrayPointer(x_pos), unscaledParameters.data(), - fixedParameters.data(), h.data(), N_VGetArrayPointer(xB), - w.data(), dwdx.data()); + N_VGetArrayPointer(x_pos), state.unscaledParameters.data(), + state.fixedParameters.data(), state.h.data(), + N_VGetArrayPointer(xB), w.data(), dwdx.data()); } } @@ -332,8 +350,8 @@ void Model_ODE::fJDiag(realtype t, N_Vector JDiag, N_Vector x) { fdwdx(t, N_VGetArrayPointer(x_pos)); N_VConst(0.0, JDiag); fJDiag(N_VGetArrayPointer(JDiag), t, N_VGetArrayPointer(x_pos), - unscaledParameters.data(), fixedParameters.data(), h.data(), - w.data(), dwdx.data()); + state.unscaledParameters.data(), state.fixedParameters.data(), + state.h.data(), w.data(), dwdx.data()); } void Model_ODE::fJvB(N_Vector vB, N_Vector JvB, realtype t, N_Vector x, @@ -357,9 +375,9 @@ void Model_ODE::fqBdot(realtype t, N_Vector x, N_Vector xB, N_Vector qBdot) { if (pythonGenerated) { /* call multiplication */ if (ndxdotdp_explicit > 0) - dxdotdp_explicit.multiply(qBdot, xB, plist_, true); + dxdotdp_explicit.multiply(qBdot, xB, state.plist, true); if (ndxdotdp_implicit > 0) - dxdotdp_implicit.multiply(qBdot, xB, plist_, true); + dxdotdp_implicit.multiply(qBdot, xB, state.plist, true); N_VScale(-1.0, qBdot, qBdot); } else { /* was matlab generated */ @@ -376,6 +394,39 @@ void Model_ODE::fqBdot(realtype t, N_Vector x, N_Vector xB, N_Vector qBdot) { } } +void Model_ODE::fxBdot_ss(const realtype t, const AmiVector &xB, + const AmiVector & /*dx*/, AmiVector &xBdot) { + fxBdot_ss(t, xB.getNVector(), xBdot.getNVector()); +} + +void Model_ODE::fxBdot_ss(realtype /*t*/, N_Vector xB, N_Vector xBdot) const { + /* Right hande side of the adjoint state for steady state computations. + J is fixed (as x remeins in steady state), so the RHS becomes simple. */ + N_VConst(0.0, xBdot); + J.multiply(xBdot, xB); +} + +void Model_ODE::fqBdot_ss(realtype /*t*/, N_Vector xB, N_Vector qBdot) const { + /* Quadratures when computing adjoints for steady state. The integrand is + just the adjoint state itself. */ + N_VScale(1.0, xB, qBdot); +} + +void Model_ODE::fJSparseB_ss(SUNMatrix JB) { + /* Just copy the model Jacobian */ + SUNMatCopy(J.get(), JB); +} + +void Model_ODE::writeSteadystateJB(const realtype t, realtype /*cj*/, + const AmiVector &x, const AmiVector & /*dx*/, + const AmiVector &xB, const AmiVector & /*dxB*/, + const AmiVector &xBdot) { + /* Get backward Jacobian */ + fJSparseB(t, x.getNVector(), xB.getNVector(), xBdot.getNVector(), J.get()); + /* Switch sign, as we integrate forward in time, not backward */ + J.scale(-1); +} + void Model_ODE::fsxdot(const realtype t, const AmiVector &x, const AmiVector & /*dx*/, const int ip, const AmiVector &sx, const AmiVector & /*sdx*/, diff --git a/deps/AMICI/src/newton_solver.cpp b/deps/AMICI/src/newton_solver.cpp index 198a4a1c9..a73234c44 100644 --- a/deps/AMICI/src/newton_solver.cpp +++ b/deps/AMICI/src/newton_solver.cpp @@ -4,7 +4,6 @@ #include "amici/solver.h" #include "amici/steadystateproblem.h" #include "amici/forwardproblem.h" -#include "amici/rdata.h" #include "amici/edata.h" #include "sunlinsol/sunlinsol_klu.h" // sparse solver @@ -16,28 +15,26 @@ namespace amici { -NewtonSolver::NewtonSolver(realtype *t, AmiVector *x, Model *model, - ReturnData *rdata) - : model(model), rdata(rdata), xdot(model->nx_solver), dx(model->nx_solver) - { +NewtonSolver::NewtonSolver(realtype *t, AmiVector *x, Model *model) + : model(model), xdot(model->nx_solver), dx(model->nx_solver), + xB(model->nx_solver), dxB(model->nx_solver) { this->t = t; this->x = x; } /* ------------------------------------------------------------------------- */ -std::unique_ptr NewtonSolver::getSolver( - realtype *t, AmiVector *x, LinearSolver linsolType, Model *model, - ReturnData *rdata, int maxlinsteps, int maxsteps, double atol, double rtol, - NewtonDampingFactorMode dampingFactorMode, double dampingFactorLowerBound) { +std::unique_ptr NewtonSolver::getSolver(realtype *t, AmiVector *x, + Solver &simulationSolver, + Model *model) { std::unique_ptr solver; - switch (linsolType) { + switch (simulationSolver.getLinearSolver()) { /* DIRECT SOLVERS */ case LinearSolver::dense: - solver.reset(new NewtonSolverDense(t, x, model, rdata)); + solver.reset(new NewtonSolverDense(t, x, model)); break; case LinearSolver::band: @@ -57,7 +54,7 @@ std::unique_ptr NewtonSolver::getSolver( throw NewtonFailure(AMICI_NOT_IMPLEMENTED, "getSolver"); case LinearSolver::SPBCG: - solver.reset(new NewtonSolverIterative(t, x, model, rdata)); + solver.reset(new NewtonSolverIterative(t, x, model)); break; case LinearSolver::SPTFQMR: @@ -67,18 +64,20 @@ std::unique_ptr NewtonSolver::getSolver( case LinearSolver::SuperLUMT: throw NewtonFailure(AMICI_NOT_IMPLEMENTED, "getSolver"); case LinearSolver::KLU: - solver.reset(new NewtonSolverSparse(t, x, model, rdata)); + solver.reset(new NewtonSolverSparse(t, x, model)); break; default: throw NewtonFailure(AMICI_NOT_IMPLEMENTED, "getSolver"); } - - solver->atol = atol; - solver->rtol = rtol; - solver->maxlinsteps = maxlinsteps; - solver->maxsteps = maxsteps; - solver->dampingFactorMode = dampingFactorMode; - solver->dampingFactorLowerBound = dampingFactorLowerBound; + solver->atol = simulationSolver.getAbsoluteTolerance(); + solver->rtol = simulationSolver.getRelativeTolerance(); + solver->maxlinsteps = simulationSolver.getNewtonMaxLinearSteps(); + solver->maxsteps = simulationSolver.getNewtonMaxSteps(); + solver->dampingFactorMode = simulationSolver.getNewtonDampingFactorMode(); + solver->dampingFactorLowerBound = + simulationSolver.getNewtonDampingFactorLowerBound(); + if (simulationSolver.getLinearSolver() == LinearSolver::SPBCG) + solver->numlinsteps.resize(simulationSolver.getNewtonMaxSteps(), 0); return solver; } @@ -109,7 +108,7 @@ void NewtonSolver::computeNewtonSensis(AmiVectorArray &sx) { auto data_ptr = model->dxdotdp_explicit.data(); for (sunindextype iCol = col[model->plist(ip)]; iCol < col[model->plist(ip) + 1]; ++iCol) - sx.at(row[iCol], ip) -= data_ptr[iCol]; + sx.at(static_cast(row[iCol]), ip) -= data_ptr[iCol]; } // copy implicit version @@ -119,7 +118,7 @@ void NewtonSolver::computeNewtonSensis(AmiVectorArray &sx) { auto data_ptr = model->dxdotdp_implicit.data(); for (sunindextype iCol = col[model->plist(ip)]; iCol < col[model->plist(ip) + 1]; ++iCol) - sx.at(row[iCol], ip) -= data_ptr[iCol]; + sx.at(static_cast(row[iCol]), ip) -= data_ptr[iCol]; } solveLinearSystem(sx[ip]); @@ -133,17 +132,15 @@ void NewtonSolver::computeNewtonSensis(AmiVectorArray &sx) { } } } + /* ------------------------------------------------------------------------- */ /* - Dense linear solver --------------------------------------------------- */ /* ------------------------------------------------------------------------- */ /* Derived class for dense linear solver */ -NewtonSolverDense::NewtonSolverDense(realtype *t, AmiVector *x, Model *model, - ReturnData *rdata) - : NewtonSolver(t, x, model, rdata), - Jtmp(model->nx_solver, model->nx_solver), - linsol(SUNLinSol_Dense(x->getNVector(), Jtmp.get())) -{ +NewtonSolverDense::NewtonSolverDense(realtype *t, AmiVector *x, Model *model) + : NewtonSolver(t, x, model), Jtmp(model->nx_solver, model->nx_solver), + linsol(SUNLinSol_Dense(x->getNVector(), Jtmp.get())) { int status = SUNLinSolInitialize_Dense(linsol); if(status != AMICI_SUCCESS) throw NewtonFailure(status, "SUNLinSolInitialize_Dense"); @@ -158,6 +155,16 @@ void NewtonSolverDense::prepareLinearSystem(int /*ntry*/, int /*nnewt*/) { throw NewtonFailure(status, "SUNLinSolSetup_Dense"); } +/* ------------------------------------------------------------------------- */ + +void NewtonSolverDense::prepareLinearSystemB(int /*ntry*/, int /*nnewt*/) { + model->fJB(*t, 0.0, *x, dx, xB, dxB, xdot, Jtmp.get()); + int status = SUNLinSolSetup_Dense(linsol, Jtmp.get()); + if(status != AMICI_SUCCESS) + throw NewtonFailure(status, "SUNLinSolSetup_Dense"); +} + + /* ------------------------------------------------------------------------- */ void NewtonSolverDense::solveLinearSystem(AmiVector &rhs) { @@ -182,12 +189,10 @@ NewtonSolverDense::~NewtonSolverDense() { /* ------------------------------------------------------------------------- */ /* Derived class for sparse linear solver */ -NewtonSolverSparse::NewtonSolverSparse(realtype *t, AmiVector *x, Model *model, - ReturnData *rdata) - : NewtonSolver(t, x, model, rdata), +NewtonSolverSparse::NewtonSolverSparse(realtype *t, AmiVector *x, Model *model) + : NewtonSolver(t, x, model), Jtmp(model->nx_solver, model->nx_solver, model->nnz, CSC_MAT), - linsol(SUNKLU(x->getNVector(), Jtmp.get())) -{ + linsol(SUNKLU(x->getNVector(), Jtmp.get())) { int status = SUNLinSolInitialize_KLU(linsol); if(status != AMICI_SUCCESS) throw NewtonFailure(status, "SUNLinSolInitialize_KLU"); @@ -205,6 +210,16 @@ void NewtonSolverSparse::prepareLinearSystem(int /*ntry*/, int /*nnewt*/) { /* ------------------------------------------------------------------------- */ +void NewtonSolverSparse::prepareLinearSystemB(int /*ntry*/, int /*nnewt*/) { + /* Get sparse Jacobian */ + model->fJSparseB(*t, 0.0, *x, dx, xB, dxB, xdot, Jtmp.get()); + int status = SUNLinSolSetup_KLU(linsol, Jtmp.get()); + if(status != AMICI_SUCCESS) + throw NewtonFailure(status, "SUNLinSolSetup_KLU"); +} + +/* ------------------------------------------------------------------------- */ + void NewtonSolverSparse::solveLinearSystem(AmiVector &rhs) { /* Pass pointer to the linear solver */ int status = SUNLinSolSolve_KLU(linsol, Jtmp.get(), @@ -212,7 +227,7 @@ void NewtonSolverSparse::solveLinearSystem(AmiVector &rhs) { // last argument is tolerance and does not have any influence on result if(status != AMICI_SUCCESS) - throw NewtonFailure(status, "SUNLinSolSolve_Dense"); + throw NewtonFailure(status, "SUNLinSolSolve_KLU"); } /* ------------------------------------------------------------------------- */ @@ -227,24 +242,62 @@ NewtonSolverSparse::~NewtonSolverSparse() { /* ------------------------------------------------------------------------- */ NewtonSolverIterative::NewtonSolverIterative(realtype *t, AmiVector *x, - Model *model, ReturnData *rdata) - : NewtonSolver(t, x, model, rdata), ns_p(model->nx_solver), + Model *model) + : NewtonSolver(t, x, model), ns_p(model->nx_solver), ns_h(model->nx_solver), ns_t(model->nx_solver), ns_s(model->nx_solver), ns_r(model->nx_solver), ns_rt(model->nx_solver), ns_v(model->nx_solver), ns_Jv(model->nx_solver), ns_tmp(model->nx_solver), - ns_Jdiag(model->nx_solver) + ns_Jdiag(model->nx_solver), ns_J(model->nx_solver, model->nx_solver) { } /* ------------------------------------------------------------------------- */ void NewtonSolverIterative::prepareLinearSystem(int ntry, int nnewt) { + newton_try = ntry; + i_newton = nnewt; + if (nnewt == -1) { + throw NewtonFailure(AMICI_NOT_IMPLEMENTED, + "Linear solver SPBCG does not support sensitivity " + "computation for steady state problems."); + } + + // Get the Jacobian and its diagonal for preconditioning + model->fJ(*t, 0.0, *x, dx, xdot, ns_J.get()); + model->fJDiag(*t, ns_Jdiag, 0.0, *x, dx); + + // Ensure positivity of entries in ns_Jdiag + ns_p.set(1.0); + N_VAbs(ns_Jdiag.getNVector(), ns_Jdiag.getNVector()); + N_VCompare(1e-15, ns_Jdiag.getNVector(), ns_tmp.getNVector()); + N_VLinearSum(-1.0, ns_tmp.getNVector(), 1.0, ns_p.getNVector(), ns_tmp.getNVector()); + N_VLinearSum(1.0, ns_Jdiag.getNVector(), 1.0, ns_tmp.getNVector(), ns_Jdiag.getNVector()); +} + +/* ------------------------------------------------------------------------- */ + +void NewtonSolverIterative::prepareLinearSystemB(int ntry, int nnewt) { newton_try = ntry; i_newton = nnewt; if (nnewt == -1) { throw AmiException("Linear solver SPBCG does not support sensitivity " "computation for steady state problems."); } + + // Get the Jacobian and its diagonal for preconditioning + model->fJB(*t, 0.0, *x, dx, xB, dxB, xdot, ns_J.get()); + + // Get the diagonal and ensure negativity of entries is ns_J. Note that diag(JB) = -diag(J). + model->fJDiag(*t, ns_Jdiag, 0.0, *x, dx); + + ns_p.set(1.0); + N_VAbs(ns_Jdiag.getNVector(), ns_Jdiag.getNVector()); + N_VCompare(1e-15, ns_Jdiag.getNVector(), ns_tmp.getNVector()); + N_VLinearSum(-1.0, ns_tmp.getNVector(), 1.0, ns_p.getNVector(), ns_tmp.getNVector()); + N_VLinearSum(1.0, ns_Jdiag.getNVector(), 1.0, ns_tmp.getNVector(), ns_Jdiag.getNVector()); + + std::transform(ns_Jdiag.data(), ns_Jdiag.data()+ns_Jdiag.getLength(), + ns_Jdiag.data(), std::negate()); } /* ------------------------------------------------------------------------- */ @@ -254,22 +307,13 @@ void NewtonSolverIterative::solveLinearSystem(AmiVector &rhs) { rhs.minus(); } +/* ------------------------------------------------------------------------- */ void NewtonSolverIterative::linsolveSPBCG(int ntry, int nnewt, AmiVector &ns_delta) { xdot = ns_delta; xdot.minus(); - // Get the diagonal of the Jacobian for preconditioning - model->fJDiag(*t, ns_Jdiag, 0.0, *x, dx); - - // Ensure positivity of entries in ns_Jdiag - ns_p.set(1.0); - N_VAbs(ns_Jdiag.getNVector(), ns_Jdiag.getNVector()); - N_VCompare(1e-15, ns_Jdiag.getNVector(), ns_tmp.getNVector()); - N_VLinearSum(-1.0, ns_tmp.getNVector(), 1.0, ns_p.getNVector(), ns_tmp.getNVector()); - N_VLinearSum(1.0, ns_Jdiag.getNVector(), 1.0, ns_tmp.getNVector(), ns_Jdiag.getNVector()); - // Initialize for linear solve ns_p.reset(); ns_v.reset(); @@ -279,8 +323,7 @@ void NewtonSolverIterative::linsolveSPBCG(int ntry, int nnewt, double omega = 1.0; double alpha = 1.0; - // can be set to 0 at the moment - model->fJv(*t, *x, dx, xdot, ns_delta, ns_Jv, 0.0); + ns_J.multiply(ns_Jv.getNVector(), ns_delta.getNVector()); // ns_r = xdot - ns_Jv; N_VLinearSum(-1.0, ns_Jv.getNVector(), 1.0, xdot.getNVector(), ns_r.getNVector()); @@ -299,7 +342,8 @@ void NewtonSolverIterative::linsolveSPBCG(int ntry, int nnewt, N_VLinearSum(1.0, ns_r.getNVector(), beta, ns_p.getNVector(), ns_p.getNVector()); // ns_v = J * ns_p - model->fJv(*t, *x, dx, xdot, ns_p, ns_v, 0.0); + ns_v.reset(); + ns_J.multiply(ns_v.getNVector(), ns_p.getNVector()); N_VDiv(ns_v.getNVector(), ns_Jdiag.getNVector(), ns_v.getNVector()); // Compute factor @@ -312,7 +356,8 @@ void NewtonSolverIterative::linsolveSPBCG(int ntry, int nnewt, N_VLinearSum(1.0, ns_r.getNVector(), -alpha, ns_v.getNVector(), ns_s.getNVector()); // ns_t = J * ns_s - model->fJv(*t, *x, dx, xdot, ns_s, ns_t, 0.0); + ns_t.reset(); + ns_J.multiply(ns_t.getNVector(), ns_s.getNVector()); N_VDiv(ns_t.getNVector(), ns_Jdiag.getNVector(), ns_t.getNVector()); // Compute factor @@ -331,8 +376,7 @@ void NewtonSolverIterative::linsolveSPBCG(int ntry, int nnewt, // Test convergence if (res < atol) { // Write number of steps needed - rdata->newton_numlinsteps[(ntry - 1) * maxsteps + - nnewt] = i_linstep + 1; + numlinsteps.at(nnewt) = i_linstep + 1; // Return success return; diff --git a/deps/AMICI/src/rdata.cpp b/deps/AMICI/src/rdata.cpp index aff0b7b40..976ab3f59 100644 --- a/deps/AMICI/src/rdata.cpp +++ b/deps/AMICI/src/rdata.cpp @@ -1,41 +1,92 @@ #include "amici/rdata.h" +#include "amici/backwardproblem.h" +#include "amici/edata.h" +#include "amici/exception.h" +#include "amici/forwardproblem.h" #include "amici/misc.h" #include "amici/model.h" -#include "amici/edata.h" -#include "amici/symbolic_functions.h" #include "amici/solver.h" -#include "amici/exception.h" +#include "amici/steadystateproblem.h" +#include "amici/symbolic_functions.h" #include namespace amici { -ReturnData::ReturnData(Solver const& solver, const Model &model) - : ReturnData(model.getTimepoints(), model.np(), model.nk(), - model.nx_rdata, model.nx_solver, model.nxtrue_rdata, - model.ny, model.nytrue, model.nz, model.nztrue, model.ne, model.nJ, - model.nplist(), model.nMaxEvent(), model.nt(), - solver.getNewtonMaxSteps(), model.nw, model.getParameterScale(), - model.o2mode, solver.getSensitivityOrder(), - static_cast(solver.getSensitivityMethod())) { +ReturnData::ReturnData(Solver const &solver, const Model &model) + : ReturnData(model.getTimepoints(), model.np(), model.nk(), model.nx_rdata, + model.nx_solver, model.nxtrue_rdata, model.nx_solver_reinit, + model.ny, model.nytrue, model.nz, model.nztrue, model.ne, + model.nJ, model.nplist(), model.nMaxEvent(), model.nt(), + solver.getNewtonMaxSteps(), model.nw, + model.getParameterScale(), model.o2mode, + solver.getSensitivityOrder(), solver.getSensitivityMethod(), + solver.getReturnDataReportingMode()) {} + +ReturnData::ReturnData(std::vector ts, int np, int nk, int nx, + int nx_solver, int nxtrue, int nx_solver_reinit, int ny, int nytrue, int nz, + int nztrue, int ne, int nJ, int nplist, int nmaxevent, + int nt, int newton_maxsteps, int nw, + std::vector pscale, + SecondOrderMode o2mode, SensitivityOrder sensi, + SensitivityMethod sensi_meth, RDataReporting rdrm) + : ts(std::move(ts)), np(np), nk(nk), nx(nx), nx_solver(nx_solver), + nxtrue(nxtrue), nx_solver_reinit(nx_solver_reinit), ny(ny), nytrue(nytrue), nz(nz), nztrue(nztrue), ne(ne), + nJ(nJ), nplist(nplist), nmaxevent(nmaxevent), nt(nt), nw(nw), + newton_maxsteps(newton_maxsteps), pscale(std::move(pscale)), + o2mode(o2mode), sensi(sensi), sensi_meth(sensi_meth), + rdata_reporting(rdrm), x_solver(nx_solver), sx_solver(nx_solver, nplist), + x_rdata(nx), sx_rdata(nx, nplist), nroots(ne) { + + switch (rdata_reporting) { + case RDataReporting::full: + initializeFullReporting(); + break; + + case RDataReporting::residuals: + initializeResidualReporting(); + break; + + case RDataReporting::likelihood: + initializeLikelihoodReporting(); + break; + } } +void ReturnData::initializeLikelihoodReporting() { + llh = getNaN(); + chi2 = getNaN(); + if (sensi >= SensitivityOrder::first) { + sllh.resize(nplist, getNaN()); + if (sensi >= SensitivityOrder::second) + s2llh.resize(nplist * (nJ - 1), getNaN()); + + if (sensi_meth == SensitivityMethod::forward || + sensi >= SensitivityOrder::second) + FIM.resize(nplist * nplist, 0.0); + } +} + +void ReturnData::initializeResidualReporting() { + y.resize(nt * ny, 0.0); + sigmay.resize(nt * ny, 0.0); + res.resize(nt * nytrue, 0.0); + if ((sensi_meth == SensitivityMethod::forward && + sensi >= SensitivityOrder::first) + || sensi >= SensitivityOrder::second) { + + sy.resize(nt * ny * nplist, 0.0); + ssigmay.resize(nt * ny * nplist, 0.0); + sres.resize(nt * nytrue * nplist, 0.0); + } +} + +void ReturnData::initializeFullReporting() { + + initializeLikelihoodReporting(); + initializeResidualReporting(); -ReturnData::ReturnData( - std::vector ts, - int np, int nk, int nx, int nx_solver, int nxtrue, int ny, int nytrue, - int nz, int nztrue, int ne, int nJ, int nplist, int nmaxevent, - int nt, int newton_maxsteps, int nw, std::vector pscale, - SecondOrderMode o2mode, SensitivityOrder sensi, SensitivityMethod sensi_meth) - : ts(std::move(ts)), np(np), nk(nk), nx(nx), nx_solver(nx_solver), nxtrue(nxtrue), - ny(ny), nytrue(nytrue), nz(nz), - nztrue(nztrue), ne(ne), nJ(nJ), - nplist(nplist), nmaxevent(nmaxevent), nt(nt), nw(nw), - newton_maxsteps(newton_maxsteps), pscale(std::move(pscale)), - o2mode(o2mode), sensi(sensi), - sensi_meth(sensi_meth) - { xdot.resize(nx_solver, getNaN()); J.resize(nx_solver * nx_solver, getNaN()); @@ -46,21 +97,22 @@ ReturnData::ReturnData( rz.resize(nmaxevent * nz, 0.0); x.resize(nt * nx, 0.0); - y.resize(nt * ny, 0.0); - sigmay.resize(nt * ny, 0.0); w.resize(nt * nw, 0.0); - newton_numsteps.resize(3, 0); - newton_numlinsteps.resize(newton_maxsteps*2, 0); + preeq_numsteps.resize(3, 0); + preeq_status.resize(3, SteadyStateStatus::not_run); + posteq_numsteps.resize(3, 0); + posteq_status.resize(3, SteadyStateStatus::not_run); - if(nt>0) { + if (nt > 0) { numsteps.resize(nt, 0); numrhsevals.resize(nt, 0); numerrtestfails.resize(nt, 0); numnonlinsolvconvfails.resize(nt, 0); order.resize(nt, 0); - if (sensi_meth == SensitivityMethod::adjoint && sensi >= SensitivityOrder::first) { + if (sensi_meth == SensitivityMethod::adjoint && + sensi >= SensitivityOrder::first) { numstepsB.resize(nt, 0); numrhsevalsB.resize(nt, 0); numerrtestfailsB.resize(nt, 0); @@ -69,95 +121,432 @@ ReturnData::ReturnData( } x0.resize(nx, getNaN()); - x_ss.resize(nx, getNaN()); - res.resize(nt * nytrue, 0.0); - - llh = getNaN(); - chi2 = getNaN(); - if (sensi >= SensitivityOrder::first){ - sllh.resize(nplist, getNaN()); + if (sensi >= SensitivityOrder::first) { sx0.resize(nx * nplist, getNaN()); sx_ss.resize(nx * nplist, getNaN()); - if (sensi_meth == SensitivityMethod::forward || sensi >= SensitivityOrder::second){ + if (sensi_meth == SensitivityMethod::forward || + sensi >= SensitivityOrder::second) { // for second order we can fill in from the augmented states sx.resize(nt * nx * nplist, 0.0); - sy.resize(nt * ny * nplist, 0.0); sz.resize(nmaxevent * nz * nplist, 0.0); srz.resize(nmaxevent * nz * nplist, 0.0); - - FIM.resize(nplist * nplist, 0.0); - sres.resize(nt * nytrue * nplist, 0.0); } ssigmay.resize(nt * ny * nplist, 0.0); ssigmaz.resize(nmaxevent * nz * nplist, 0.0); - if (sensi >= SensitivityOrder::second) { - s2llh.resize(nplist * (nJ - 1), getNaN()); - if (sensi_meth == SensitivityMethod::forward) - s2rz.resize(nmaxevent * nztrue * nplist * nplist, 0.0); + if (sensi >= SensitivityOrder::second && + sensi_meth == SensitivityMethod::forward) + s2rz.resize(nmaxevent * nztrue * nplist * nplist, 0.0); + } +} + +void ReturnData::processSimulationObjects(SteadystateProblem const *preeq, + ForwardProblem const *fwd, + BackwardProblem const *bwd, + SteadystateProblem const *posteq, + Model &model, Solver const &solver, + ExpData const *edata) { + ModelContext mc(&model); + + processSolver(solver); + + if (preeq) + processPreEquilibration(*preeq, model); + + if (fwd) + processForwardProblem(*fwd, model, edata); + else + invalidate(0); + + if (posteq) + processPostEquilibration(*posteq, model, edata); + + if (fwd && !posteq) + storeJacobianAndDerivativeInReturnData(*fwd, model); + else if (posteq) + storeJacobianAndDerivativeInReturnData(*posteq, model); + + if (fwd && bwd) + processBackwardProblem(*fwd, *bwd, preeq, model); + else if (solver.computingASA()) + invalidateSLLH(); + + applyChainRuleFactorToSimulationResults(model); +} + +void ReturnData::processPreEquilibration(SteadystateProblem const &preeq, + Model &model) { + readSimulationState(preeq.getFinalSimulationState(), model); + + if (!x_ss.empty()) { + model.fx_rdata(x_rdata, x_solver); + writeSlice(x_rdata, x_ss); + } + if (!sx_ss.empty() && sensi >= SensitivityOrder::first) { + model.fsx_rdata(sx_rdata, sx_solver); + for (int ip = 0; ip < nplist; ip++) + writeSlice(sx_rdata[ip], slice(sx_ss, ip, nx)); + } + /* Get cpu time for Newton solve in milliseconds */ + preeq_cpu_time = preeq.getCPUTime(); + preeq_cpu_timeB = preeq.getCPUTimeB(); + preeq_numstepsB = preeq.getNumStepsB(); + preeq_wrms = preeq.getResidualNorm(); + preeq_status = preeq.getSteadyStateStatus(); + if (preeq_status[1] == SteadyStateStatus::success) + preeq_t = preeq.getSteadyStateTime(); + if (!preeq_numsteps.empty()) + writeSlice(preeq.getNumSteps(), preeq_numsteps); + if (!preeq.getNumLinSteps().empty() && !preeq_numlinsteps.empty()) { + preeq_numlinsteps.resize(newton_maxsteps * 2, 0); + writeSlice(preeq.getNumLinSteps(), preeq_numlinsteps); + } +} + +void ReturnData::processPostEquilibration(SteadystateProblem const &posteq, + Model &model, ExpData const *edata) { + for (int it = 0; it < nt; it++) { + auto t = model.getTimepoint(it); + if (std::isinf(t)) { + readSimulationState(posteq.getFinalSimulationState(), model); + getDataOutput(it, model, edata); } } + /* Get cpu time for Newton solve in milliseconds */ + posteq_cpu_time = posteq.getCPUTime(); + posteq_cpu_timeB = posteq.getCPUTimeB(); + posteq_numstepsB = posteq.getNumStepsB(); + posteq_wrms = posteq.getResidualNorm(); + posteq_status = posteq.getSteadyStateStatus(); + if (posteq_status[1] == SteadyStateStatus::success) + posteq_t = posteq.getSteadyStateTime(); + if (!posteq_numsteps.empty()) + writeSlice(posteq.getNumSteps(), posteq_numsteps); + if (!posteq.getNumLinSteps().empty() && !posteq_numlinsteps.empty()) { + posteq_numlinsteps.resize(newton_maxsteps * 2, 0); + writeSlice(posteq.getNumLinSteps(), posteq_numlinsteps); + } +} +void ReturnData::processForwardProblem(ForwardProblem const &fwd, Model &model, + ExpData const *edata) { + if (edata) + initializeObjectiveFunction(); + + auto initialState = fwd.getInitialSimulationState(); + if (initialState.x.getLength() == 0) + return; // if x wasn't set forward problem failed during initialization + readSimulationState(initialState, model); + + if (!x0.empty()) { + model.fx_rdata(x_rdata, x_solver); + writeSlice(x_rdata, x0); + } + + if (!sx0.empty()) { + model.fsx_rdata(sx_rdata, sx_solver); + for (int ip = 0; ip < nplist; ip++) + writeSlice(sx_rdata[ip], slice(sx0, ip, nx)); + } + + // process timpoint data + realtype tf = fwd.getFinalTime(); + for (int it = 0; it < model.nt(); it++) { + if (model.getTimepoint(it) <= tf) { + readSimulationState(fwd.getSimulationStateTimepoint(it), model); + getDataOutput(it, model, edata); + } else { + // check for integration failure but consider postequilibration + if (!std::isinf(model.getTimepoint(it))) + invalidate(it); + } + } + + // process event data + if (nz > 0) { + auto rootidx = fwd.getRootIndexes(); + for (int iroot = 0; iroot <= fwd.getEventCounter(); iroot++) { + readSimulationState(fwd.getSimulationStateEvent(iroot), model); + getEventOutput(iroot, t, rootidx.at(iroot), model, edata); + } + } } -void ReturnData::invalidate(const realtype t) { - invalidateLLH(); - invalidateSLLH(); +void ReturnData::getDataOutput(int it, Model &model, ExpData const *edata) { + if (!x.empty()) { + model.fx_rdata(x_rdata, x_solver); + writeSlice(x_rdata, slice(x, it, nx)); + } + if (!w.empty()) + model.getExpression(slice(w, it, nw), ts[it], x_solver); + if (!y.empty()) + model.getObservable(slice(y, it, ny), ts[it], x_solver); + if (!sigmay.empty()) + model.getObservableSigma(slice(sigmay, it, ny), it, edata); + + if (edata) { + if (!isNaN(llh)) + model.addObservableObjective(llh, it, x_solver, *edata); + fres(it, model, *edata); + fchi2(it); + } - // find it corresponding to datapoint after integration failure - int it_start; - for (it_start = 0; it_start < nt; it_start++) - if(ts.at(it_start)>t) - break; + if (sensi >= SensitivityOrder::first && nplist > 0) { + + if (!ssigmay.empty()) + model.getObservableSigmaSensitivity(slice(ssigmay, it, nplist * ny), + it, edata); - for (int it = it_start; it < nt; it++){ - for (int ix = 0; ix < nx; ix++) - x.at(ix + nx * it) = getNaN(); - for (int iy = 0; iy < ny; iy++) - y.at(iy + ny * it) = getNaN(); - for (int iw = 0; iw < nw; iw++) - w.at(iw + nw * it) = getNaN(); + if (sensi_meth == SensitivityMethod::forward) { + getDataSensisFSA(it, model, edata); + } else if (edata && !sllh.empty()) { + model.addPartialObservableObjectiveSensitivity( + sllh, s2llh, it, x_solver, *edata); + } } +} +void ReturnData::getDataSensisFSA(int it, Model &model, ExpData const *edata) { if (!sx.empty()) { - for (int it = it_start; it < nt; it++){ - for (int ip = 0; ip < nplist; ip++) { - for (int ix = 0; ix < nx; ix++) - sx.at(ix + nx*(ip + it*nplist)) = getNaN(); + model.fsx_rdata(sx_rdata, sx_solver); + for (int ip = 0; ip < nplist; ip++) { + writeSlice(sx_rdata[ip], + slice(sx, it * nplist + ip, nx)); + } + } + + if (!sy.empty()) { + model.getObservableSensitivity(slice(sy, it, nplist * ny), ts[it], + x_solver, sx_solver); + } + + if (edata) { + if (!sllh.empty()) + model.addObservableObjectiveSensitivity(sllh, s2llh, it, x_solver, + sx_solver, *edata); + fsres(it, model, *edata); + fFIM(it, model, *edata); + } +} + +void ReturnData::getEventOutput(int iroot, realtype t, std::vector rootidx, + Model &model, ExpData const *edata) { + + for (int ie = 0; ie < ne; ie++) { + if (rootidx.at(ie) != 1 || nroots.at(ie) >= nmaxevent) + continue; + + /* get event output */ + if (!z.empty()) + model.getEvent(slice(z, nroots.at(ie), nz), ie, t, x_solver); + /* if called from fillEvent at last timepoint, + then also get the root function value */ + if (t == model.getTimepoint(nt - 1)) + if (!rz.empty()) + model.getEventRegularization(slice(rz, nroots.at(ie), nz), ie, + t, x_solver); + + if (edata) { + if (!sigmaz.empty()) + model.getEventSigma(slice(sigmaz, nroots.at(ie), nz), ie, + nroots.at(ie), t, edata); + if (!isNaN(llh)) + model.addEventObjective(llh, ie, nroots.at(ie), t, x_solver, + *edata); + + /* if called from fillEvent at last timepoint, + add regularization based on rz */ + if (t == model.getTimepoint(nt - 1) && !isNaN(llh)) { + model.addEventObjectiveRegularization( + llh, ie, nroots.at(ie), t, x_solver, *edata); } } + + if (sensi >= SensitivityOrder::first) { + if (sensi_meth == SensitivityMethod::forward) { + getEventSensisFSA(iroot, ie, t, model, edata); + } else if (edata && !sllh.empty()) { + model.addPartialEventObjectiveSensitivity( + sllh, s2llh, ie, nroots.at(ie), t, x_solver, *edata); + } + } + nroots.at(ie)++; + } +} + +void ReturnData::getEventSensisFSA(int iroot, int ie, realtype t, Model &model, + ExpData const *edata) { + if (t == model.getTimepoint(nt - 1)) { + // call from fillEvent at last timepoint + if (!sz.empty()) + model.getUnobservedEventSensitivity( + slice(sz, nroots.at(ie), nz * nplist), ie); + if (!srz.empty()) + model.getEventRegularizationSensitivity( + slice(srz, nroots.at(ie), nz * nplist), ie, t, x_solver, + sx_solver); + } else if (!sz.empty()) { + model.getEventSensitivity(slice(sz, nroots.at(ie), nz * nplist), ie, + t, x_solver, sx_solver); } - if(!sy.empty()) { - for (int it = it_start; it < nt; it++){ - for (int ip = 0; ip < nplist; ip++) { - for (int iy = 0; iy < ny; iy++) - sy.at(iy + ny*(ip + it*nplist)) = getNaN(); + + if (edata && !sllh.empty()) { + model.addEventObjectiveSensitivity(sllh, s2llh, ie, nroots.at(ie), + t, x_solver, sx_solver, *edata); + } +} + +void ReturnData::processBackwardProblem(ForwardProblem const &fwd, + BackwardProblem const &bwd, + SteadystateProblem const *preeq, + Model &model) { + if (sllh.empty()) + return; + readSimulationState(fwd.getInitialSimulationState(), model); + + std::vector llhS0(model.nJ * model.nplist(), 0.0); + auto xB = bwd.getAdjointState(); + auto xQB = bwd.getAdjointQuadrature(); + + if (preeq && preeq->hasQuadrature()) { + handleSx0Backward(model, *preeq, xQB); + } else { + handleSx0Forward(model, llhS0, xB); + } + + for (int iJ = 0; iJ < model.nJ; iJ++) { + for (int ip = 0; ip < model.nplist(); ip++) { + if (iJ == 0) { + sllh.at(ip) -= llhS0[ip] + xQB[ip * model.nJ]; + } else { + s2llh.at(iJ - 1 + ip * (model.nJ - 1)) -= + llhS0[ip + iJ * model.nplist()] + xQB[iJ + ip * model.nJ]; } } } } -void ReturnData::invalidateLLH() -{ +void ReturnData::handleSx0Backward(const Model &model, + SteadystateProblem const &preeq, + AmiVector &xQB) const { + /* If preequilibration is run in adjoint mode, the scalar product of sx0 + with its adjoint counterpart (see handleSx0Forward()) is not necessary: + the actual simulation is "extended" by the preequilibration time. + At initialization (at t=-inf), the adjoint state is in steady state (= 0) + and so is the scalar product. Instead of the scalar product, the + quadratures xQB from preequilibration contribute to the gradient + (see example notebook on equilibration for further documentation). */ + auto xQBpreeq = preeq.getAdjointQuadrature(); + for (int ip = 0; ip < model.nplist(); ++ip) + xQB[ip] += xQBpreeq[ip]; +} + +void ReturnData::handleSx0Forward(const Model &model, + std::vector &llhS0, + AmiVector &xB) const { + /* If preequilibration is run in forward mode or is not needed, then adjoint + sensitivity analysis still needs the state sensitivities at t=0 (sx0), + to compute the gradient. For each parameter, the scalar product of sx0 + with its adjoint counterpart contributes to the gradient. */ + for (int iJ = 0; iJ < model.nJ; iJ++) { + if (iJ == 0) { + for (int ip = 0; ip < model.nplist(); ++ip) { + llhS0[ip] = 0.0; + for (int ix = 0; ix < model.nxtrue_solver; ++ix) { + llhS0[ip] += xB[ix] * sx_solver.at(ix, ip); + } + } + } else { + for (int ip = 0; ip < model.nplist(); ++ip) { + llhS0[ip + iJ * model.nplist()] = 0.0; + for (int ix = 0; ix < model.nxtrue_solver; ++ix) { + llhS0[ip + iJ * model.nplist()] += + xB[ix + iJ * model.nxtrue_solver] * sx_solver.at(ix, ip) + + xB[ix] * sx_solver.at(ix + iJ * model.nxtrue_solver, ip); + } + } + } + } +} + +void ReturnData::processSolver(Solver const &solver) { + + cpu_time = solver.getCpuTime(); + if (!numsteps.empty()) + numsteps = solver.getNumSteps(); + if (!numrhsevals.empty()) + numrhsevals = solver.getNumRhsEvals(); + if (!numerrtestfails.empty()) + numerrtestfails = solver.getNumErrTestFails(); + if (!numnonlinsolvconvfails.empty()) + numnonlinsolvconvfails = solver.getNumNonlinSolvConvFails(); + if (!order.empty()) + order = solver.getLastOrder(); + + cpu_timeB = solver.getCpuTimeB(); + if (!numstepsB.empty()) + numstepsB = solver.getNumStepsB(); + if (!numrhsevalsB.empty()) + numrhsevalsB = solver.getNumRhsEvalsB(); + if (!numerrtestfailsB.empty()) + numerrtestfailsB = solver.getNumErrTestFailsB(); + if (!numnonlinsolvconvfailsB.empty()) + numnonlinsolvconvfailsB = solver.getNumNonlinSolvConvFailsB(); +} + +void ReturnData::readSimulationState(SimulationState const &state, + Model &model) { + x_solver = state.x; + dx_solver = state.dx; + if (computingFSA() || state.t == model.t0()) + sx_solver = state.sx; + t = state.t; + model.setModelState(state.state); +} + +void ReturnData::invalidate(const int it_start) { + if (it_start >= nt) + return; + + invalidateLLH(); + invalidateSLLH(); + + if (!x.empty()) + std::fill(x.begin() + nx * it_start, x.end(), getNaN()); + if (!y.empty()) + std::fill(y.begin() + ny * it_start, y.end(), getNaN()); + if (!w.empty()) + std::fill(w.begin() + nw * it_start, w.end(), getNaN()); + + if (!sx.empty()) + std::fill(sx.begin() + nx * nplist * it_start, sx.end(), getNaN()); + if (!sy.empty()) + std::fill(sy.begin() + ny * nplist * it_start, sy.end(), getNaN()); +} + +void ReturnData::invalidateLLH() { llh = getNaN(); chi2 = getNaN(); } void ReturnData::invalidateSLLH() { - std::fill(sllh.begin(), sllh.end(), getNaN()); - std::fill(s2llh.begin(), s2llh.end(), getNaN()); + if (!sllh.empty()) { + std::fill(sllh.begin(), sllh.end(), getNaN()); + std::fill(s2llh.begin(), s2llh.end(), getNaN()); + } } -void ReturnData::applyChainRuleFactorToSimulationResults(const Model *model) { +void ReturnData::applyChainRuleFactorToSimulationResults(const Model &model) { // chain-rule factor: multiplier for am_p std::vector coefficient(nplist, 1.0); std::vector pcoefficient(nplist, 1.0); - std::vector unscaledParameters = model->getParameters(); - unscaleParameters(unscaledParameters, model->getParameterScale(), unscaledParameters); + std::vector unscaledParameters = model.getParameters(); + unscaleParameters(unscaledParameters, model.getParameterScale(), + unscaledParameters); std::vector augcoefficient(np, 1.0); @@ -177,13 +566,14 @@ void ReturnData::applyChainRuleFactorToSimulationResults(const Model *model) { } for (int ip = 0; ip < nplist; ++ip) { - switch (pscale[model->plist(ip)]) { + switch (pscale[model.plist(ip)]) { case ParameterScaling::log10: coefficient.at(ip) = log(10.0); - pcoefficient.at(ip) = unscaledParameters.at(model->plist(ip)) * log(10); + pcoefficient.at(ip) = + unscaledParameters.at(model.plist(ip)) * log(10); break; case ParameterScaling::ln: - pcoefficient.at(ip) = unscaledParameters.at(model->plist(ip)); + pcoefficient.at(ip) = unscaledParameters.at(model.plist(ip)); break; case ParameterScaling::none: break; @@ -193,48 +583,55 @@ void ReturnData::applyChainRuleFactorToSimulationResults(const Model *model) { if (sensi >= SensitivityOrder::first) { // recover first order sensitivies from states for adjoint sensitivity // analysis - if (sensi == SensitivityOrder::second && o2mode == SecondOrderMode::full) { - if (sensi_meth == SensitivityMethod::adjoint) { + if (sensi == SensitivityOrder::second + && o2mode == SecondOrderMode::full + && sensi_meth == SensitivityMethod::adjoint) { + if (!sx.empty() && !x.empty()) for (int ip = 0; ip < nplist; ++ip) for (int ix = 0; ix < nxtrue; ++ix) for (int it = 0; it < nt; ++it) - sx.at(ix + nxtrue*(ip + it*nplist)) = + sx.at(ix + nxtrue * (ip + it * nplist)) = x.at(it * nx + nxtrue + ip * nxtrue + ix); + if (!sy.empty() && !y.empty()) for (int ip = 0; ip < nplist; ++ip) for (int iy = 0; iy < nytrue; ++iy) for (int it = 0; it < nt; ++it) - sy.at(iy + nytrue*(ip + it*nplist)) = + sy.at(iy + nytrue * (ip + it * nplist)) = y.at(it * ny + nytrue + ip * nytrue + iy); + if (!sz.empty() && !z.empty()) for (int ip = 0; ip < nplist; ++ip) for (int iz = 0; iz < nztrue; ++iz) for (int it = 0; it < nt; ++it) - sz.at(iz + nztrue*(ip + it*nplist)) = + sz.at(iz + nztrue * (ip + it * nplist)) = z.at(it * nz + nztrue + ip * nztrue + iz); - } + } - for (int ip = 0; ip < nplist; ++ip) - sllh.at(ip) *= pcoefficient.at(ip); + if (!sllh.empty()) + for (int ip = 0; ip < nplist; ++ip) + sllh.at(ip) *= pcoefficient.at(ip); + - if(!sres.empty()) - for (int iyt = 0; iyt < nytrue*nt; ++iyt) + if (!sres.empty()) + for (int iyt = 0; iyt < nytrue * nt; ++iyt) for (int ip = 0; ip < nplist; ++ip) sres.at((iyt * nplist + ip)) *= pcoefficient.at(ip); if(!FIM.empty()) for (int ip = 0; ip < nplist; ++ip) for (int jp = 0; jp < nplist; ++jp) - FIM.at(jp + ip * nplist) *= pcoefficient.at(ip)*pcoefficient.at(jp); - -#define chainRule(QUANT, IND1, N1T, N1, IND2, N2) \ - if (!s##QUANT.empty()) \ - for (int IND1 = 0; (IND1) < (N1T); ++(IND1)) \ - for (int ip = 0; ip < nplist; ++ip) \ - for (int IND2 = 0; (IND2) < (N2); ++(IND2)) { \ - s##QUANT.at(((IND2)*nplist + ip)*(N1) + (IND1)) *= \ - pcoefficient.at(ip); \ + FIM.at(jp + ip * nplist) *= + pcoefficient.at(ip)*pcoefficient.at(jp); + +#define chainRule(QUANT, IND1, N1T, N1, IND2, N2) \ + if (!s##QUANT.empty()) \ + for (int IND1 = 0; (IND1) < (N1T); ++(IND1)) \ + for (int ip = 0; ip < nplist; ++ip) \ + for (int IND2 = 0; (IND2) < (N2); ++(IND2)) { \ + s##QUANT.at(((IND2)*nplist + ip) * (N1) + (IND1)) *= \ + pcoefficient.at(ip); \ } chainRule(x, ix, nxtrue, nx, it, nt); @@ -251,28 +648,30 @@ void ReturnData::applyChainRuleFactorToSimulationResults(const Model *model) { for (int ip = 0; ip < nplist; ++ip) { for (int iJ = 1; iJ < nJ; ++iJ) { s2llh[ip * nplist + (iJ - 1)] *= - pcoefficient.at(ip) * augcoefficient[iJ - 1]; - if (model->plist(ip) == iJ - 1) + pcoefficient.at(ip) * augcoefficient[iJ - 1]; + if (model.plist(ip) == iJ - 1) s2llh[ip * nplist + (iJ - 1)] += - sllh.at(ip) * coefficient.at(ip); + sllh.at(ip) * coefficient.at(ip); } } } #define s2ChainRule(QUANT, IND1, N1T, N1, IND2, N2) \ - if (!s##QUANT.empty()) \ + if (!s##QUANT.empty()) \ for (int ip = 0; ip < nplist; ++ip) \ for (int iJ = 1; iJ < nJ; ++iJ) \ for (int IND1 = 0; IND1 < N1T; ++IND1) \ for (int IND2 = 0; IND2 < N2; ++IND2) { \ - s##QUANT.at((IND2*nplist + ip)*N1 + IND1 + iJ*N1T) *= \ - pcoefficient.at(ip) * augcoefficient[iJ - 1]; \ - if (model->plist(ip) == iJ - 1) \ - s##QUANT.at((IND2*nplist + ip)*N1 + IND1 + iJ*N1T) += \ - s##QUANT.at((IND2*nplist + ip)*N1 + IND1) * \ - coefficient[ip]; \ -} - + s##QUANT.at((IND2 * nplist + ip) * N1 + IND1 + \ + iJ * N1T) *= \ + pcoefficient.at(ip) * augcoefficient[iJ - 1]; \ + if (model.plist(ip) == iJ - 1) \ + s##QUANT.at((IND2 * nplist + ip) * N1 + IND1 + \ + iJ * N1T) += \ + s##QUANT.at((IND2 * nplist + ip) * N1 + \ + IND1) * \ + coefficient[ip]; \ + } s2ChainRule(x, ix, nxtrue, nx, it, nt); s2ChainRule(y, iy, nytrue, ny, it, nt); @@ -283,23 +682,23 @@ void ReturnData::applyChainRuleFactorToSimulationResults(const Model *model) { } if (o2mode == SecondOrderMode::directional) { // directional - for (int ip = 0; ip < nplist; ++ip) { - s2llh.at(ip) *= pcoefficient.at(ip); - s2llh.at(ip) += model->k()[nk - nplist + ip] * sllh.at(ip) / - unscaledParameters[model->plist(ip)]; + for (int ip = 0; ip < nplist; ++ip) { + s2llh.at(ip) *= pcoefficient.at(ip); + s2llh.at(ip) += model.k()[nk - nplist + ip] * sllh.at(ip) / + unscaledParameters[model.plist(ip)]; } -#define s2vecChainRule(QUANT, IND1, N1T, N1, IND2, N2) \ - if (!s##QUANT.empty()) \ - for (int ip = 0; ip < nplist; ++ip) \ - for (int IND1 = 0; IND1 < N1T; ++IND1) \ - for (int IND2 = 0; IND2 < N2; ++IND2) { \ - s##QUANT.at((IND2*nplist + ip)*N1 + IND1 + N1T) *= \ - pcoefficient.at(ip); \ - s##QUANT.at((IND2*nplist + ip)*N1 + IND1 + N1T) += \ - model->k()[nk - nplist + ip] * \ - s##QUANT.at((IND2*nplist + ip)*N1 + IND1) / \ - unscaledParameters[model->plist(ip)]; \ +#define s2vecChainRule(QUANT, IND1, N1T, N1, IND2, N2) \ + if (!s##QUANT.empty()) \ + for (int ip = 0; ip < nplist; ++ip) \ + for (int IND1 = 0; IND1 < N1T; ++IND1) \ + for (int IND2 = 0; IND2 < N2; ++IND2) { \ + s##QUANT.at((IND2 * nplist + ip) * N1 + IND1 + N1T) *= \ + pcoefficient.at(ip); \ + s##QUANT.at((IND2 * nplist + ip) * N1 + IND1 + N1T) += \ + model.k()[nk - nplist + ip] * \ + s##QUANT.at((IND2 * nplist + ip) * N1 + IND1) / \ + unscaledParameters[model.plist(ip)]; \ } s2vecChainRule(x, ix, nxtrue, nx, it, nt); @@ -311,31 +710,52 @@ void ReturnData::applyChainRuleFactorToSimulationResults(const Model *model) { } } -void ReturnData::initializeObjectiveFunction() -{ - llh = 0.0; - chi2 = 0.0; - std::fill(sllh.begin(),sllh.end(), 0.0); - std::fill(s2llh.begin(),s2llh.end(), 0.0); +void ReturnData::initializeObjectiveFunction() { + if (rdata_reporting == RDataReporting::likelihood || + rdata_reporting == RDataReporting::full) { + llh = 0.0; + std::fill(sllh.begin(), sllh.end(), 0.0); + std::fill(s2llh.begin(), s2llh.end(), 0.0); + } + if (rdata_reporting == RDataReporting::residuals || + rdata_reporting == RDataReporting::full) + chi2 = 0.0; } -void ReturnData::fres(const int it, const ExpData &edata) { - if ( res.empty()) +static realtype fres(realtype y, realtype my, realtype sigma_y) { + return (y - my) / sigma_y; +} + +static realtype fsres(realtype y, realtype sy, realtype my, + realtype sigma_y, realtype ssigma_y) { + double r = fres(sy, 0.0, sigma_y); + if (ssigma_y > 0) + r += fres(y, my, sigma_y * sigma_y / ssigma_y); + return r; +} + +void ReturnData::fres(const int it, Model &model, const ExpData &edata) { + if (res.empty()) return; + std::vector y_it(ny, 0.0); + model.getObservable(y_it, ts[it], x_solver); + + std::vector sigmay_it(ny, 0.0); + model.getObservableSigma(sigmay_it, it, &edata); + auto observedData = edata.getObservedDataPtr(it); for (int iy = 0; iy < nytrue; ++iy) { - int iyt_true = iy + it * edata.nytrue(); - int iyt = iy + it * ny; + int iyt = iy + it * edata.nytrue(); if (!edata.isSetObservedData(it, iy)) continue; - res.at(iyt_true) = - (y.at(iyt) - observedData[iy]) / sigmay.at(iyt); + res.at(iyt) = amici::fres(y_it.at(iy), observedData[iy], + sigmay_it.at(iy)); } } void ReturnData::fchi2(const int it) { - if (res.empty()) + if (res.empty() || isNaN(chi2)) return; for (int iy = 0; iy < nytrue; ++iy) { @@ -344,37 +764,71 @@ void ReturnData::fchi2(const int it) { } } -void ReturnData::fsres(const int it, const ExpData &edata) { +void ReturnData::fsres(const int it, Model &model, const ExpData &edata) { if (sres.empty()) return; + std::vector y_it(ny, 0.0); + model.getObservable(y_it, ts[it], x_solver); + std::vector sy_it(ny * nplist, 0.0); + model.getObservableSensitivity(sy_it, ts[it], x_solver, sx_solver); + + std::vector sigmay_it(ny, 0.0); + model.getObservableSigma(sigmay_it, it, &edata); + std::vector ssigmay_it(ny * nplist, 0.0); + model.getObservableSigmaSensitivity(ssigmay_it, it, &edata); + + auto observedData = edata.getObservedDataPtr(it); for (int iy = 0; iy < nytrue; ++iy) { - int iyt_true = iy + it * edata.nytrue(); - int iyt = iy + it * ny; if (!edata.isSetObservedData(it, iy)) continue; for (int ip = 0; ip < nplist; ++ip) { - sres.at(iyt_true * nplist + ip) = - sy.at(iy + ny * (ip + it * nplist)) / - sigmay.at(iyt); + int idx = (iy + it * edata.nytrue()) * nplist + ip; + sres.at(idx) = amici::fsres(y_it.at(iy), sy_it.at(iy + ny * ip), + observedData[iy], sigmay_it.at(iy), + ssigmay_it.at(iy + ny * ip)); } } } -void ReturnData::fFIM(const int it) { - if (sres.empty()) +void ReturnData::fFIM(int it, Model &model, const ExpData &edata) { + if (FIM.empty()) return; + std::vector y_it(ny, 0.0); + model.getObservable(y_it, ts[it], x_solver); + std::vector sy_it(ny * nplist, 0.0); + model.getObservableSensitivity(sy_it, ts[it], x_solver, sx_solver); + + std::vector sigmay_it(ny, 0.0); + model.getObservableSigma(sigmay_it, it, &edata); + std::vector ssigmay_it(ny * nplist, 0.0); + model.getObservableSigmaSensitivity(ssigmay_it, it, &edata); + + auto observedData = edata.getObservedDataPtr(it); for (int iy = 0; iy < nytrue; ++iy) { - int iyt_true = iy + it * nytrue; + if (!edata.isSetObservedData(it, iy)) + continue; for (int ip = 0; ip < nplist; ++ip) { for (int jp = 0; jp < nplist; ++jp) { - FIM.at(ip + nplist * jp) += sres.at(iyt_true * nplist + ip) * - sres.at(iyt_true * nplist + jp); + FIM.at(ip + nplist * jp) += + amici::fsres(y_it.at(iy), sy_it.at(iy + ny * ip), + observedData[iy], sigmay_it.at(iy), + ssigmay_it.at(iy + ny * ip)) + * + amici::fsres(y_it.at(iy), sy_it.at(iy + ny * jp), + observedData[iy], sigmay_it.at(iy), + ssigmay_it.at(iy + ny * jp)); } } } } +ModelContext::ModelContext(Model *model) + : model(model), original_state(model->getModelState()) {} + +ModelContext::~ModelContext() { restore(); } + +void ModelContext::restore() { model->setModelState(original_state); } } // namespace amici diff --git a/deps/AMICI/src/returndata_matlab.cpp b/deps/AMICI/src/returndata_matlab.cpp index 2535cd740..58fe9cf68 100644 --- a/deps/AMICI/src/returndata_matlab.cpp +++ b/deps/AMICI/src/returndata_matlab.cpp @@ -33,17 +33,17 @@ mxArray *initMatlabReturnFields(ReturnData const *rdata) { "x0", "sx0", "diagnosis"}; - + checkFieldNames(field_names_sol,numFields); mxArray *matlabSolutionStruct = mxCreateStructMatrix(1, 1, numFields, field_names_sol); - + std::vector perm0 = {1, 0}; std::vector perm1 = {0, 1}; std::vector perm2 = {0, 2, 1}; std::vector perm3 = {0, 2, 3, 1}; - + writeMatlabField0(matlabSolutionStruct, "status", rdata->status); writeMatlabField1(matlabSolutionStruct, "t", rdata->ts, rdata->nt); @@ -96,12 +96,12 @@ mxArray *initMatlabReturnFields(ReturnData const *rdata) { mxArray *diagnosis = initMatlabDiagnosisFields(rdata); mxSetField(matlabSolutionStruct, 0, "diagnosis", diagnosis); - + return(matlabSolutionStruct); } mxArray *initMatlabDiagnosisFields(ReturnData const *rdata) { - const int numFields = 17; + const int numFields = 27; const char *field_names_sol[numFields] = {"xdot", "J", "numsteps", @@ -113,43 +113,74 @@ mxArray *initMatlabDiagnosisFields(ReturnData const *rdata) { "numrhsevalsB", "numerrtestfailsB", "numnonlinsolvconvfailsB", - "newton_status", - "newton_numsteps", - "newton_numlinsteps", - "newton_cpu_time", - "newton_t_steadystate", - "newton_wrms" - }; - + "preeq_status", + "preeq_numsteps", + "preeq_numstepsB", + "preeq_numlinsteps", + "preeq_cpu_time", + "preeq_cpu_timeB", + "preeq_t", + "preeq_wrms", + "posteq_status", + "posteq_numsteps", + "posteq_numstepsB", + "posteq_numlinsteps", + "posteq_cpu_time", + "posteq_cpu_timeB", + "posteq_t", + "posteq_wrms"}; + checkFieldNames(field_names_sol,numFields); - + mxArray *matlabDiagnosisStruct = mxCreateStructMatrix(1, 1, numFields, field_names_sol); - + std::vector perm1 = {0, 1}; - - writeMatlabField1(matlabDiagnosisStruct, "numsteps", rdata->numsteps, rdata->nt); - writeMatlabField1(matlabDiagnosisStruct, "numrhsevals", rdata->numrhsevals, rdata->nt); - writeMatlabField1(matlabDiagnosisStruct, "numerrtestfails", rdata->numerrtestfails, rdata->nt); - writeMatlabField1(matlabDiagnosisStruct, "numnonlinsolvconvfails", rdata->numnonlinsolvconvfails, rdata->nt); - writeMatlabField1(matlabDiagnosisStruct, "order", rdata->order, rdata->nt); + int finite_nt = 0; + for (int it = 0; it < rdata->nt; it++) + if (!std::isinf(rdata->ts[it])) + finite_nt++; + + writeMatlabField1(matlabDiagnosisStruct, "numsteps", rdata->numsteps, finite_nt); + writeMatlabField1(matlabDiagnosisStruct, "numrhsevals", rdata->numrhsevals, finite_nt); + writeMatlabField1(matlabDiagnosisStruct, "numerrtestfails", rdata->numerrtestfails, finite_nt); + writeMatlabField1(matlabDiagnosisStruct, "numnonlinsolvconvfails", rdata->numnonlinsolvconvfails, finite_nt); + writeMatlabField1(matlabDiagnosisStruct, "order", rdata->order, finite_nt); if (rdata->nx > 0) { - writeMatlabField1(matlabDiagnosisStruct, "xdot", rdata->xdot, rdata->nx); - writeMatlabField2(matlabDiagnosisStruct, "J", rdata->J, rdata->nx, rdata->nx, perm1); - writeMatlabField0(matlabDiagnosisStruct, "newton_status", rdata->newton_status); - writeMatlabField1(matlabDiagnosisStruct, "newton_numsteps", rdata->newton_numsteps, 3); - writeMatlabField2(matlabDiagnosisStruct, "newton_numlinsteps", rdata->newton_numlinsteps, rdata->newton_maxsteps, 2, perm1); - writeMatlabField0(matlabDiagnosisStruct, "newton_cpu_time", rdata->newton_cpu_time); - writeMatlabField0(matlabDiagnosisStruct, "newton_t_steadystate", rdata->t_steadystate); - writeMatlabField0(matlabDiagnosisStruct, "newton_wrms", rdata->wrms_steadystate); + writeMatlabField1(matlabDiagnosisStruct, "xdot", rdata->xdot, rdata->nx_solver); + writeMatlabField2(matlabDiagnosisStruct, "J", rdata->J, rdata->nx_solver, rdata->nx_solver, perm1); + + writeMatlabField1(matlabDiagnosisStruct, "preeq_status", rdata->preeq_status, 3); + writeMatlabField1(matlabDiagnosisStruct, "preeq_numsteps", rdata->preeq_numsteps, 3); + writeMatlabField2(matlabDiagnosisStruct, "preeq_numlinsteps", + rdata->preeq_numlinsteps, + rdata->preeq_numlinsteps.size() > 0 + ? rdata->newton_maxsteps : 0, 2, perm1); + writeMatlabField0(matlabDiagnosisStruct, "preeq_numstepsB", rdata->preeq_numstepsB); + writeMatlabField0(matlabDiagnosisStruct, "preeq_cpu_time", rdata->preeq_cpu_time); + writeMatlabField0(matlabDiagnosisStruct, "preeq_cpu_timeB", rdata->preeq_cpu_timeB); + writeMatlabField0(matlabDiagnosisStruct, "preeq_t", rdata->preeq_t); + writeMatlabField0(matlabDiagnosisStruct, "preeq_wrms", rdata->preeq_wrms); + + writeMatlabField1(matlabDiagnosisStruct, "posteq_status", rdata->posteq_status, 3); + writeMatlabField1(matlabDiagnosisStruct, "posteq_numsteps", rdata->posteq_numsteps, 3); + writeMatlabField2(matlabDiagnosisStruct, "posteq_numlinsteps", + rdata->posteq_numlinsteps, + rdata->posteq_numlinsteps.size() > 0 + ? rdata->newton_maxsteps : 0, 2, perm1); + writeMatlabField0(matlabDiagnosisStruct, "posteq_numstepsB", rdata->posteq_numstepsB); + writeMatlabField0(matlabDiagnosisStruct, "posteq_cpu_time", rdata->posteq_cpu_time); + writeMatlabField0(matlabDiagnosisStruct, "posteq_cpu_timeB", rdata->posteq_cpu_timeB); + writeMatlabField0(matlabDiagnosisStruct, "posteq_t", rdata->posteq_t); + writeMatlabField0(matlabDiagnosisStruct, "posteq_wrms", rdata->posteq_wrms); } if (rdata->sensi >= SensitivityOrder::first) { if (rdata->sensi_meth == SensitivityMethod::adjoint) { - writeMatlabField1(matlabDiagnosisStruct, "numstepsB", rdata->numstepsB, rdata->nt); - writeMatlabField1(matlabDiagnosisStruct, "numrhsevalsB", rdata->numrhsevalsB, rdata->nt); - writeMatlabField1(matlabDiagnosisStruct, "numerrtestfailsB", rdata->numerrtestfailsB, rdata->nt); - writeMatlabField1(matlabDiagnosisStruct, "numnonlinsolvconvfailsB", rdata->numnonlinsolvconvfailsB, rdata->nt); + writeMatlabField1(matlabDiagnosisStruct, "numstepsB", rdata->numstepsB, finite_nt); + writeMatlabField1(matlabDiagnosisStruct, "numrhsevalsB", rdata->numrhsevalsB, finite_nt); + writeMatlabField1(matlabDiagnosisStruct, "numerrtestfailsB", rdata->numerrtestfailsB, finite_nt); + writeMatlabField1(matlabDiagnosisStruct, "numnonlinsolvconvfailsB", rdata->numnonlinsolvconvfailsB, finite_nt); } } @@ -160,11 +191,11 @@ mxArray *initMatlabDiagnosisFields(ReturnData const *rdata) { template void writeMatlabField0(mxArray *matlabStruct, const char *fieldName, T fieldData) { - + std::vector dim = {(mwSize)(1), (mwSize)(1)}; - + double *array = initAndAttachArray(matlabStruct, fieldName, dim); - + array[0] = static_cast(fieldData); } @@ -173,11 +204,11 @@ void writeMatlabField1(mxArray *matlabStruct, const char *fieldName, std::vector const& fieldData, int dim0) { if(fieldData.size() != dim0) throw AmiException("Dimension mismatch when writing rdata->%s to matlab results",fieldName); - + std::vector dim = {(mwSize)(dim0), (mwSize)(1)}; - + double *array = initAndAttachArray(matlabStruct, fieldName, dim); - + for(int i = 0; i < dim0; i++) array[i] = static_cast(fieldData[i]); } @@ -187,15 +218,18 @@ void writeMatlabField2(mxArray *matlabStruct, const char *fieldName, std::vector const& fieldData, int dim0, int dim1, std::vector perm) { if(fieldData.size() != dim0*dim1) - throw AmiException("Dimension mismatch when writing rdata->%s to matlab results",fieldName); - + throw AmiException("Dimension mismatch when writing rdata->%s to " + "matlab results (expected: %d, actual: %d)", + fieldName, dim0 * dim1, + static_cast(fieldData.size())); + if(perm.size() != 2) throw AmiException("Dimension mismatch when applying permutation!"); - + std::vector dim = {(mwSize)(dim0), (mwSize)(dim1)}; - + double *array = initAndAttachArray(matlabStruct, fieldName, reorder(dim,perm)); - + std::vector index = {0,0}; /* transform rowmajor (c++) to colmajor (matlab) and apply permutation */ for (index[0] = 0; index[0] < dim[0]; index[0]++) { @@ -212,14 +246,14 @@ void writeMatlabField3(mxArray *matlabStruct, const char *fieldName, int dim2, std::vector perm) { if(fieldData.size() != dim0*dim1*dim2) throw AmiException("Dimension mismatch when writing rdata->%s to matlab results",fieldName); - + if(perm.size() != 3) throw AmiException("Dimension mismatch when applying permutation!"); - + std::vector dim = {(mwSize)(dim0), (mwSize)(dim1), (mwSize)(dim2)}; - + double *array = initAndAttachArray(matlabStruct, fieldName, reorder(dim,perm)); - + std::vector index = {0,0,0}; /* transform rowmajor (c++) to colmajor (matlab) and apply permutation */ for (index[0] = 0; index[0] < dim[0]; index[0]++) { @@ -238,14 +272,14 @@ void writeMatlabField4(mxArray *matlabStruct, const char *fieldName, int dim2, int dim3, std::vector perm) { if(fieldData.size() != dim0*dim1*dim2*dim3) throw AmiException("Dimension mismatch when writing rdata->%s to matlab results!",fieldName); - + if(perm.size() != 4) throw AmiException("Dimension mismatch when applying permutation!"); - + std::vector dim = {(mwSize)(dim0), (mwSize)(dim1), (mwSize)(dim2), (mwSize)(dim3)}; - + double *array = initAndAttachArray(matlabStruct, fieldName, reorder(dim,perm)); - + std::vector index = {0,0,0,0}; /* transform rowmajor (c++) to colmajor (matlab) and apply permutation */ for (index[0] = 0; index[0] < dim[0]; index[0]++) { @@ -263,7 +297,7 @@ void writeMatlabField4(mxArray *matlabStruct, const char *fieldName, double *initAndAttachArray(mxArray *matlabStruct, const char *fieldName, std::vector dim) { if(!mxIsStruct(matlabStruct)) throw AmiException("Passing non-struct mxArray to initAndAttachArray!",fieldName); - + int fieldNumber = mxGetFieldNumber(matlabStruct, fieldName); if(fieldNumber<0) throw AmiException("Trying to access non-existent field '%s'!",fieldName); diff --git a/deps/AMICI/src/solver.cpp b/deps/AMICI/src/solver.cpp index 023647f29..9d76e50c9 100644 --- a/deps/AMICI/src/solver.cpp +++ b/deps/AMICI/src/solver.cpp @@ -5,7 +5,6 @@ #include "amici/model.h" #include "amici/rdata.h" -#include #include #include #include @@ -20,18 +19,20 @@ Solver::Solver(AmiciApplication *app) : app(app) Solver::Solver(const Solver &other) : ism(other.ism), lmm(other.lmm), iter(other.iter), - interpType(other.interpType), maxsteps(other.maxsteps), t(nan("")), - sensi_meth(other.sensi_meth), stldet(other.stldet), - ordering(other.ordering), newton_maxsteps(other.newton_maxsteps), + interpType(other.interpType), maxsteps(other.maxsteps), + sensi_meth(other.sensi_meth), sensi_meth_preeq(other.sensi_meth_preeq), + stldet(other.stldet), ordering(other.ordering), + newton_maxsteps(other.newton_maxsteps), newton_maxlinsteps(other.newton_maxlinsteps), newton_damping_factor_mode(other.newton_damping_factor_mode), newton_damping_factor_lower_bound(other.newton_damping_factor_lower_bound), - requires_preequilibration(other.requires_preequilibration), linsol(other.linsol), - atol(other.atol), rtol(other.rtol), atol_fsa(other.atol_fsa), - rtol_fsa(other.rtol_fsa), atolB(other.atolB), rtolB(other.rtolB), - quad_atol(other.quad_atol), quad_rtol(other.quad_rtol), - ss_atol(other.ss_atol), ss_rtol(other.ss_rtol), - ss_atol_sensi(other.ss_atol_sensi), ss_rtol_sensi(other.ss_rtol_sensi), + requires_preequilibration(other.requires_preequilibration), + linsol(other.linsol), atol(other.atol), rtol(other.rtol), + atol_fsa(other.atol_fsa), rtol_fsa(other.rtol_fsa), + atolB(other.atolB), rtolB(other.rtolB), quad_atol(other.quad_atol), + quad_rtol(other.quad_rtol), ss_atol(other.ss_atol), + ss_rtol(other.ss_rtol), ss_atol_sensi(other.ss_atol_sensi), + ss_rtol_sensi(other.ss_rtol_sensi), rdata_mode(other.rdata_mode), maxstepsB(other.maxstepsB), sensi(other.sensi) {} @@ -81,11 +82,15 @@ void Solver::setup(const realtype t0, Model *model, const AmiVector &x0, /* Initialize CVodes/IDAs solver*/ init(t0, x0, dx0); + /* Clear diagnosis storage */ + resetDiagnosis(); + + /* Apply stored tolerances to sundials solver */ applyTolerances(); /* Set optional inputs */ setErrHandlerFn(); - /* attaches userdata*/ + /* Attaches userdata */ setUserData(model); /* specify maximal number of steps */ setMaxNumSteps(maxsteps); @@ -97,19 +102,19 @@ void Solver::setup(const realtype t0, Model *model, const AmiVector &x0, initializeLinearSolver(model); initializeNonLinearSolver(); - if (sensi >= SensitivityOrder::first && model->nx_solver > 0) { + if (sensi >= SensitivityOrder::first && + sensi_meth > SensitivityMethod::none && model->nx_solver > 0) { auto plist = model->getParameterList(); + sensInit1(sx0, sdx0); if (sensi_meth == SensitivityMethod::forward && !plist.empty()) { /* Set sensitivity analysis optional inputs */ auto par = model->getUnscaledParameters(); - /* Activate sensitivity calculations */ - sensInit1(sx0, sdx0); + /* Activate sensitivity calculations and apply tolerances */ initializeNonLinearSolverSens(model); setSensParams(par.data(), nullptr, plist.data()); - applyTolerancesFSA(); - } else if (sensi_meth == SensitivityMethod::adjoint) { + } else { /* Allocate space for the adjoint computation */ adjInit(); } @@ -153,43 +158,100 @@ void Solver::setupB(int *which, const realtype tf, Model *model, setStabLimDetB(*which, stldet); } -void Solver::getDiagnosis(const int it, ReturnData *rdata) const { - long int number; +void Solver::setupSteadystate(const realtype t0, Model *model, const AmiVector &x0, + const AmiVector &dx0, const AmiVector &xB0, + const AmiVector &dxB0, const AmiVector &xQ0) const { + /* Initialize CVodes/IDAs solver with steadystate RHS function */ + initSteadystate(t0, x0, dx0); - if (solverWasCalledF && solverMemory) { - getNumSteps(solverMemory.get(), &number); - rdata->numsteps[it] = number; + /* Allocate space for forward quadratures */ + quadInit(xQ0); - getNumRhsEvals(solverMemory.get(), &number); - rdata->numrhsevals[it] = number; + /* Apply tolerances */ + applyQuadTolerances(); - getNumErrTestFails(solverMemory.get(), &number); - rdata->numerrtestfails[it] = number; + /* Check linear solver (works only with KLU atm) */ + if (linsol != LinearSolver::KLU) + throw AmiException("Backward steady state computation via integration " + "is currently only implemented for KLU linear solver"); + /* Set Jacobian function and intialize values */ + setSparseJacFn_ss(); + model->writeSteadystateJB(t0, 0, x0, dx0, xB0, dxB0, xB0); +} - getNumNonlinSolvConvFails(solverMemory.get(), &number); - rdata->numnonlinsolvconvfails[it] = number; +void Solver::updateAndReinitStatesAndSensitivities(Model *model) { + model->fx0_fixedParameters(x); + reInit(t, x, dx); - getLastOrder(solverMemory.get(), &rdata->order[it]); + if (getSensitivityOrder() >= SensitivityOrder::first) { + model->fsx0_fixedParameters(sx, x); + if (getSensitivityMethod() == SensitivityMethod::forward) + sensReInit(sx, sdx); } } -void Solver::getDiagnosisB(const int it, ReturnData *rdata, - const int which) const { - long int number; +void Solver::resetDiagnosis() const { + ns.clear(); + nrhs.clear(); + netf.clear(); + nnlscf.clear(); + order.clear(); - if (solverWasCalledB && solverMemoryB.at(which)) { - getNumSteps(solverMemoryB.at(which).get(), &number); - rdata->numstepsB[it] = number; + nsB.clear(); + nrhsB.clear(); + netfB.clear(); + nnlscfB.clear(); +} - getNumRhsEvals(solverMemoryB.at(which).get(), &number); - rdata->numrhsevalsB[it] = number; +void Solver::storeDiagnosis() const { + if (!solverWasCalledF || !solverMemory) { + ns.push_back(0); + nrhs.push_back(0); + netf.push_back(0); + nnlscf.push_back(0); + order.push_back(0); + return; + } - getNumErrTestFails(solverMemoryB.at(which).get(), &number); - rdata->numerrtestfailsB[it] = number; + long int lnumber; + getNumSteps(solverMemory.get(), &lnumber); + ns.push_back(static_cast(lnumber)); - getNumNonlinSolvConvFails(solverMemoryB.at(which).get(), &number); - rdata->numnonlinsolvconvfailsB[it] = number; + getNumRhsEvals(solverMemory.get(), &lnumber); + nrhs.push_back(static_cast(lnumber)); + + getNumErrTestFails(solverMemory.get(), &lnumber); + netf.push_back(static_cast(lnumber)); + + getNumNonlinSolvConvFails(solverMemory.get(), &lnumber); + nnlscf.push_back(static_cast(lnumber)); + + int number; + getLastOrder(solverMemory.get(), &number); + order.push_back(number); +} + +void Solver::storeDiagnosisB(const int which) const { + if (!solverWasCalledB || !solverMemoryB.at(which)) { + nsB.push_back(0); + nrhsB.push_back(0); + netfB.push_back(0); + nnlscfB.push_back(0); + return; } + + long int number; + getNumSteps(solverMemoryB.at(which).get(), &number); + nsB.push_back(static_cast(number)); + + getNumRhsEvals(solverMemoryB.at(which).get(), &number); + nrhsB.push_back(static_cast(number)); + + getNumErrTestFails(solverMemoryB.at(which).get(), &number); + netfB.push_back(static_cast(number)); + + getNumNonlinSolvConvFails(solverMemoryB.at(which).get(), &number); + nnlscfB.push_back(static_cast(number)); } void Solver::initializeLinearSolver(const Model *model) const { @@ -404,21 +466,22 @@ bool operator==(const Solver &a, const Solver &b) { (isNaN(a.atol_fsa) && isNaN(b.atol_fsa))) && (a.rtolB == b.rtolB || (isNaN(a.rtolB) && isNaN(b.rtolB))) && (a.atolB == b.atolB || (isNaN(a.atolB) && isNaN(b.atolB))) && - (a.sensi == b.sensi) && (a.sensi_meth == b.sensi_meth); + (a.sensi == b.sensi) && (a.sensi_meth == b.sensi_meth) && + (a.rdata_mode == b.rdata_mode); } void Solver::applyTolerances() const { if (!getInitDone()) - throw AmiException(("Solver instance was not yet set up, the " - "tolerances cannot be applied yet!")); + throw AmiException("Solver instance was not yet set up, the " + "tolerances cannot be applied yet!"); setSStolerances(this->rtol, this->atol); } void Solver::applyTolerancesFSA() const { if (!getInitDone()) - throw AmiException(("Solver instance was not yet set up, the " - "tolerances cannot be applied yet!")); + throw AmiException("Solver instance was not yet set up, the " + "tolerances cannot be applied yet!"); if (sensi < SensitivityOrder::first) return; @@ -432,8 +495,8 @@ void Solver::applyTolerancesFSA() const { void Solver::applyTolerancesASA(const int which) const { if (!getAdjInitDone()) - throw AmiException(("Adjoint solver instance was not yet set up, the " - "tolerances cannot be applied yet!")); + throw AmiException("Adjoint solver instance was not yet set up, the " + "tolerances cannot be applied yet!"); if (sensi < SensitivityOrder::first) return; @@ -444,8 +507,8 @@ void Solver::applyTolerancesASA(const int which) const { void Solver::applyQuadTolerancesASA(const int which) const { if (!getAdjInitDone()) - throw AmiException(("Adjoint solver instance was not yet set up, the " - "tolerances cannot be applied yet!")); + throw AmiException("Adjoint solver instance was not yet set up, the " + "tolerances cannot be applied yet!"); if (sensi < SensitivityOrder::first) return; @@ -459,6 +522,23 @@ void Solver::applyQuadTolerancesASA(const int which) const { quadSStolerancesB(which, quad_rtol, quad_atol); } +void Solver::applyQuadTolerances() const { + if (!getQuadInitDone()) + throw AmiException("Quadratures were not intialized, the " + "tolerances cannot be applied yet!"); + + if (sensi < SensitivityOrder::first) + return; + + realtype quad_rtolF = isNaN(this->quad_rtol) ? rtol : this->quad_rtol; + realtype quad_atolF = isNaN(this->quad_atol) ? atol : this->quad_atol; + + /* Enable Quadrature Error Control */ + setQuadErrCon(!std::isinf(quad_atolF) && !std::isinf(quad_rtolF)); + + quadSStolerances(quad_rtolF, quad_atolF); +} + void Solver::applySensitivityTolerances() const { if (sensi < SensitivityOrder::first) return; @@ -473,12 +553,28 @@ void Solver::applySensitivityTolerances() const { SensitivityMethod Solver::getSensitivityMethod() const { return sensi_meth; } +SensitivityMethod Solver::getSensitivityMethodPreequilibration() const { return sensi_meth_preeq; } + void Solver::setSensitivityMethod(const SensitivityMethod sensi_meth) { - if (sensi_meth != this->sensi_meth) - resetMutableMemory(nx(), nplist(), nquad()); + checkSensitivityMethod(sensi_meth, false); this->sensi_meth = sensi_meth; } +void Solver::setSensitivityMethodPreequilibration(const SensitivityMethod sensi_meth_preeq) { + checkSensitivityMethod(sensi_meth_preeq, true); + this->sensi_meth_preeq = sensi_meth_preeq; +} + +void Solver::checkSensitivityMethod(const SensitivityMethod sensi_meth, + bool preequilibration) const { + if (rdata_mode == RDataReporting::residuals && + sensi_meth == SensitivityMethod::adjoint) + throw AmiException("Adjoint Sensitivity Analysis is not compatible with" + " only reporting residuals!"); + if (!preequilibration && sensi_meth != this->sensi_meth) + resetMutableMemory(nx(), nplist(), nquad()); +} + int Solver::getNewtonMaxSteps() const { return newton_maxsteps; } void Solver::setNewtonMaxSteps(const int newton_maxsteps) { @@ -770,9 +866,9 @@ void Solver::setStateOrdering(int ordering) { int Solver::getStabilityLimitFlag() const { return stldet; } void Solver::setStabilityLimitFlag(const int stldet) { - if (stldet != TRUE && stldet != FALSE) + if (stldet != static_cast(true) && stldet != static_cast(false)) throw AmiException("Invalid stldet flag, valid values are %i or %i", - TRUE, FALSE); + true, false); this->stldet = stldet; if (solverMemory) { @@ -803,6 +899,18 @@ void Solver::setInternalSensitivityMethod(const InternalSensitivityMethod ism) { this->ism = ism; } +RDataReporting Solver::getReturnDataReportingMode() const { + return rdata_mode; +}; + +void Solver::setReturnDataReportingMode(RDataReporting rdrm) { + if (rdrm == RDataReporting::residuals && + sensi_meth == SensitivityMethod::adjoint) + throw AmiException("Adjoint Sensitivity Analysis cannot report " + "residuals!"); + rdata_mode = rdrm; +} + void Solver::initializeNonLinearSolverSens(const Model *model) const { switch (iter) { case NonlinearSolverIteration::newton: @@ -867,10 +975,14 @@ bool Solver::getQuadInitDoneB(const int which) const { initializedQB.at(which); } +bool Solver::getQuadInitDone() const { return quadInitialized; } + void Solver::setInitDone() const { initialized = true; }; void Solver::setSensInitDone() const { sensInitialized = true; } +void Solver::setSensInitOff() const { sensInitialized = false; } + void Solver::setAdjInitDone() const { adjInitialized = true; } void Solver::setInitDoneB(const int which) const { @@ -885,6 +997,13 @@ void Solver::setQuadInitDoneB(const int which) const { initializedQB.at(which) = true; } +void Solver::setQuadInitDone() const { quadInitialized = true; } + +void Solver::switchForwardSensisOff() const { + sensToggleOff(); + setSensInitOff(); +} + realtype Solver::getCpuTime() const { return cpu_time; } @@ -899,6 +1018,7 @@ void Solver::resetMutableMemory(const int nx, const int nplist, initialized = false; adjInitialized = false; sensInitialized = false; + quadInitialized = false; solverWasCalledF = false; solverWasCalledB = false; @@ -910,6 +1030,7 @@ void Solver::resetMutableMemory(const int nx, const int nplist, xB = AmiVector(nx); dxB = AmiVector(nx); xQB = AmiVector(nquad); + xQ = AmiVector(nx); solverMemoryB.clear(); initializedB.clear(); @@ -917,13 +1038,14 @@ void Solver::resetMutableMemory(const int nx, const int nplist, } void Solver::writeSolution(realtype *t, AmiVector &x, AmiVector &dx, - AmiVectorArray &sx) const { + AmiVectorArray &sx, AmiVector &xQ) const { *t = gett(); + if (quadInitialized) + xQ.copy(getQuadrature(*t)); + if (sensInitialized) + sx.copy(getStateSensitivity(*t)); x.copy(getState(*t)); dx.copy(getDerivativeState(*t)); - if (sensInitialized) { - sx.copy(getStateSensitivity(*t)); - } } void Solver::writeSolutionB(realtype *t, AmiVector &xB, AmiVector &dxB, @@ -955,16 +1077,12 @@ const AmiVector &Solver::getDerivativeState(const realtype t) const { } const AmiVectorArray &Solver::getStateSensitivity(const realtype t) const { - if (sensInitialized) { - if (solverWasCalledF) { - if (t == this->t) { - getSens(); - } else { - getSensDky(t, 0); - } + if (sensInitialized && solverWasCalledF) { + if (t == this->t) { + getSens(); + } else { + getSensDky(t, 0); } - } else { - sx.reset(); } return sx; } @@ -1017,11 +1135,27 @@ const AmiVector &Solver::getAdjointQuadrature(const int which, return xQB; } +const AmiVector &Solver::getQuadrature(realtype t) const { + if (quadInitialized) { + if (solverWasCalledF) { + if (t == this->t) { + getQuad(t); + return xQ; + } + getQuadDky(t, 0); + } + } else { + xQ.reset(); + } + return xQ; +} + + realtype Solver::gett() const { return t; } void wrapErrHandlerFn(int error_code, const char *module, const char *function, char *msg, void * eh_data) { -#define BUF_SIZE 250 + constexpr int BUF_SIZE = 250; char buffer[BUF_SIZE]; char buffid[BUF_SIZE]; snprintf(buffer, BUF_SIZE, "AMICI ERROR: in module %s in function %s : %s ", module, diff --git a/deps/AMICI/src/solver_cvodes.cpp b/deps/AMICI/src/solver_cvodes.cpp index 34fbfe9ef..4c55d5c81 100644 --- a/deps/AMICI/src/solver_cvodes.cpp +++ b/deps/AMICI/src/solver_cvodes.cpp @@ -79,6 +79,14 @@ static int fxBdot(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, static int fqBdot(realtype t, N_Vector x, N_Vector xB, N_Vector qBdot, void *user_data); +static int fxBdot_ss(realtype t, N_Vector xB, N_Vector xBdot, void *user_data); + +static int fqBdot_ss(realtype t, N_Vector xB, N_Vector qBdot, void *user_data); + +static int fJSparseB_ss(realtype t, N_Vector x, N_Vector xBdot, + SUNMatrix JB, void *user_data, N_Vector tmp1, + N_Vector tmp2, N_Vector tmp3); + static int fsxdot(int Ns, realtype t, N_Vector x, N_Vector xdot, int ip, N_Vector sx, N_Vector sxdot, void *user_data, N_Vector tmp1, N_Vector tmp2); @@ -89,8 +97,9 @@ static int fsxdot(int Ns, realtype t, N_Vector x, N_Vector xdot, int ip, void CVodeSolver::init(const realtype t0, const AmiVector &x0, const AmiVector & /*dx0*/) const { solverWasCalledF = false; + forceReInitPostProcessF = false; t = t0; - x.copy(x0); + x = x0; int status; if (getInitDone()) { status = CVodeReInit(solverMemory.get(), t0, x.getNVector()); @@ -102,19 +111,32 @@ void CVodeSolver::init(const realtype t0, const AmiVector &x0, throw CvodeException(status, "CVodeInit"); } +void CVodeSolver::initSteadystate(const realtype t0, const AmiVector &x0, + const AmiVector &dx0) const { + /* We need to set the steadystate rhs function. SUndials doesn't have this + in its public api, so we have to change it in the solver memory, + as re-calling init would unset solver settings. */ + auto cv_mem = static_cast(solverMemory.get()); + cv_mem->cv_f = fxBdot_ss; +} + void CVodeSolver::sensInit1(const AmiVectorArray &sx0, const AmiVectorArray & /*sdx0*/) const { - int status; - sx.copy(sx0); - if (getSensInitDone()) { - status = CVodeSensReInit(solverMemory.get(), - static_cast(getSensitivityMethod()), - sx.getNVectorArray()); - } else { - status = CVodeSensInit1(solverMemory.get(), nplist(), - static_cast(getSensitivityMethod()), - fsxdot, sx.getNVectorArray()); - setSensInitDone(); + int status = CV_SUCCESS; + sx = sx0; + if (getSensitivityMethod() == SensitivityMethod::forward && nplist() > 0) { + if (getSensInitDone()) { + status = CVodeSensReInit( + solverMemory.get(), + static_cast(getInternalSensitivityMethod()), + sx.getNVectorArray()); + } else { + status = + CVodeSensInit1(solverMemory.get(), nplist(), + static_cast(getInternalSensitivityMethod()), + fsxdot, sx.getNVectorArray()); + setSensInitDone(); + } } if (status != CV_SUCCESS) throw CvodeException(status, "CVodeSensInit1"); @@ -124,7 +146,8 @@ void CVodeSolver::binit(const int which, const realtype tf, const AmiVector &xB0, const AmiVector & /*dxB0*/) const { solverWasCalledB = false; - xB.copy(xB0); + forceReInitPostProcessB = false; + xB = xB0; int status; if (getInitDoneB(which)) { status = CVodeReInitB(solverMemory.get(), which, tf, xB.getNVector()); @@ -138,7 +161,7 @@ void CVodeSolver::binit(const int which, const realtype tf, } void CVodeSolver::qbinit(const int which, const AmiVector &xQB0) const { - xQB.copy(xQB0); + xQB = xQB0; int status; if (getQuadInitDoneB(which)) { status = CVodeQuadReInitB(solverMemory.get(), which, xQB.getNVector()); @@ -205,6 +228,12 @@ void CVodeSolver::setJacTimesVecFnB(int which) const { throw CvodeException(status, "CVodeSetJacTimesB"); } +void CVodeSolver::setSparseJacFn_ss() const { + int status = CVodeSetJacFn(solverMemory.get(), fJSparseB_ss); + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeSetJacFn"); +} + Solver *CVodeSolver::clone() const { return new CVodeSolver(*this); } void CVodeSolver::allocateSolver() const { @@ -240,6 +269,12 @@ void CVodeSolver::setQuadErrConB(const int which, const bool flag) const { throw CvodeException(status, "CVodeSetQuadErrConB"); } +void CVodeSolver::setQuadErrCon(const bool flag) const { + int status = CVodeSetQuadErrCon(solverMemory.get(), flag); + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeSetQuadErrCon"); +} + void CVodeSolver::getRootInfo(int *rootsfound) const { int status = CVodeGetRootInfo(solverMemory.get(), rootsfound); if (status != CV_SUCCESS) @@ -344,7 +379,7 @@ void CVodeSolver::setStabLimDetB(const int which, const int stldet) const { throw CvodeException(status, "CVodeSetStabLimDetB"); } -void CVodeSolver::setId(const Model */*model*/) const {} +void CVodeSolver::setId(const Model * /*model*/) const {} void CVodeSolver::setSuppressAlg(const bool /*flag*/) const {} @@ -486,6 +521,12 @@ void CVodeSolver::reInitB(const int which, const realtype tB0, resetState(cv_memB, xB.getNVector()); } +void CVodeSolver::sensToggleOff() const { + auto status = CVodeSensToggleOff(solverMemory.get()); + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeSensToggleOff"); +} + void CVodeSolver::quadReInitB(int which, const AmiVector &yQB0) const { auto cv_memB = static_cast(CVodeGetAdjCVodeBmem(solverMemory.get(), which)); @@ -541,6 +582,12 @@ void CVodeSolver::getQuadB(int which) const { throw CvodeException(status, "CVodeGetQuadB"); } +void CVodeSolver::getQuad(realtype &t) const { + int status = CVodeGetQuad(solverMemory.get(), &t, xQ.getNVector()); + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeGetQuad"); +} + void CVodeSolver::getQuadDkyB(const realtype t, const int k, int which) const { int status = CVodeGetQuadDky(CVodeGetAdjCVodeBmem(solverMemory.get(), which), t, k, @@ -549,6 +596,13 @@ void CVodeSolver::getQuadDkyB(const realtype t, const int k, int which) const { throw CvodeException(status, "CVodeGetQuadDkyB"); } +void CVodeSolver::getQuadDky(const realtype t, const int k) const { + int status = + CVodeGetQuadDky(solverMemory.get(), t, k, xQ.getNVector()); + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeGetQuadDky"); +} + void CVodeSolver::adjInit() const { int status; if (getAdjInitDone()) { @@ -562,6 +616,19 @@ void CVodeSolver::adjInit() const { throw CvodeException(status, "CVodeAdjInit"); } +void CVodeSolver::quadInit(const AmiVector &xQ0) const { + int status; + xQ.copy(xQ0); + if (getQuadInitDone()) { + status = CVodeQuadReInit(solverMemory.get(), xQ0.getNVector()); + } else { + status = CVodeQuadInit(solverMemory.get(), fqBdot_ss, xQ.getNVector()); + setQuadInitDone(); + } + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeQuadInit"); +} + void CVodeSolver::allocateSolverB(int *which) const { if (!solverMemoryB.empty()) { *which = 0; @@ -572,7 +639,7 @@ void CVodeSolver::allocateSolverB(int *which) const { solverMemoryB.resize(*which + 1); solverMemoryB.at(*which) = std::unique_ptr>( - getAdjBmem(solverMemory.get(), *which), [](void */*ptr*/) {}); + getAdjBmem(solverMemory.get(), *which), [](void * /*ptr*/) {}); if (status != CV_SUCCESS) throw CvodeException(status, "CVodeCreateB"); } @@ -593,6 +660,14 @@ void CVodeSolver::quadSStolerancesB(const int which, const realtype reltolQB, throw CvodeException(status, "CVodeQuadSStolerancesB"); } +void CVodeSolver::quadSStolerances(const realtype reltolQB, + const realtype abstolQB) const { + int status = + CVodeQuadSStolerances(solverMemory.get(), reltolQB, abstolQB); + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeQuadSStolerances"); +} + void CVodeSolver::getB(const int which) const { realtype tDummy = 0; int status = CVodeGetB(solverMemory.get(), which, &tDummy, xB.getNVector()); @@ -698,12 +773,14 @@ void CVodeSolver::setStopTime(const realtype tstop) const { throw CvodeException(status, "CVodeSetStopTime"); } + void CVodeSolver::turnOffRootFinding() const { int status = CVodeRootInit(solverMemory.get(), 0, nullptr); if (status != CV_SUCCESS) throw CvodeException(status, "CVodeRootInit"); } + const Model *CVodeSolver::getModel() const { if (!solverMemory) throw AmiException("Solver has not been allocated, information is not " @@ -712,6 +789,7 @@ const Model *CVodeSolver::getModel() const { return static_cast(cv_mem->cv_user_data); } + /** * @brief Jacobian of xdot with respect to states x * @param N number of state variables @@ -725,7 +803,7 @@ const Model *CVodeSolver::getModel() const { * @param tmp3 temporary storage vector * @return status flag indicating successful execution **/ -int fJ(realtype t, N_Vector x, N_Vector xdot, SUNMatrix J, +static int fJ(realtype t, N_Vector x, N_Vector xdot, SUNMatrix J, void *user_data, N_Vector /*tmp1*/, N_Vector /*tmp2*/, N_Vector /*tmp3*/) { auto model = static_cast(user_data); @@ -733,6 +811,7 @@ int fJ(realtype t, N_Vector x, N_Vector xdot, SUNMatrix J, return model->checkFinite(gsl::make_span(J), "Jacobian"); } + /** * @brief Jacobian of xBdot with respect to adjoint state xB * @param NeqBdot number of adjoint state variables @@ -747,7 +826,7 @@ int fJ(realtype t, N_Vector x, N_Vector xdot, SUNMatrix J, * @param tmp3B temporary storage vector * @return status flag indicating successful execution **/ -int fJB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, +static int fJB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, SUNMatrix JB, void *user_data, N_Vector /*tmp1B*/, N_Vector /*tmp2B*/, N_Vector /*tmp3B*/) { auto model = static_cast(user_data); @@ -755,6 +834,7 @@ int fJB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, return model->checkFinite(gsl::make_span(JB), "Jacobian"); } + /** * @brief J in sparse form (for sparse solvers from the SuiteSparse Package) * @param t timepoint @@ -767,7 +847,7 @@ int fJB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, * @param tmp3 temporary storage vector * @return status flag indicating successful execution */ -int fJSparse(realtype t, N_Vector x, N_Vector /*xdot*/, +static int fJSparse(realtype t, N_Vector x, N_Vector /*xdot*/, SUNMatrix J, void *user_data, N_Vector /*tmp1*/, N_Vector /*tmp2*/, N_Vector /*tmp3*/) { auto model = static_cast(user_data); @@ -775,6 +855,7 @@ int fJSparse(realtype t, N_Vector x, N_Vector /*xdot*/, return model->checkFinite(gsl::make_span(J), "Jacobian"); } + /** * @brief JB in sparse form (for sparse solvers from the SuiteSparse Package) * @param t timepoint @@ -788,7 +869,7 @@ int fJSparse(realtype t, N_Vector x, N_Vector /*xdot*/, * @param tmp3B temporary storage vector * @return status flag indicating successful execution */ -int fJSparseB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, +static int fJSparseB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, SUNMatrix JB, void *user_data, N_Vector /*tmp1B*/, N_Vector /*tmp2B*/, N_Vector /*tmp3B*/) { auto model = static_cast(user_data); @@ -796,6 +877,7 @@ int fJSparseB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, return model->checkFinite(gsl::make_span(JB), "Jacobian"); } + /** * @brief J in banded form (for banded solvers) * @param N number of states @@ -811,11 +893,12 @@ int fJSparseB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, * @param tmp3 temporary storage vector * @return status flag indicating successful execution */ -int fJBand(realtype t, N_Vector x, N_Vector xdot, SUNMatrix J, +static int fJBand(realtype t, N_Vector x, N_Vector xdot, SUNMatrix J, void *user_data, N_Vector tmp1, N_Vector tmp2, N_Vector tmp3) { return fJ(t, x, xdot, J, user_data, tmp1, tmp2, tmp3); } + /** * @brief JB in banded form (for banded solvers) * @param NeqBdot number of states @@ -832,12 +915,13 @@ int fJBand(realtype t, N_Vector x, N_Vector xdot, SUNMatrix J, * @param tmp3B temporary storage vector * @return status flag indicating successful execution */ -int fJBandB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, +static int fJBandB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, SUNMatrix JB, void *user_data, N_Vector tmp1B, N_Vector tmp2B, N_Vector tmp3B) { return fJB(t, x, xB, xBdot, JB, user_data, tmp1B, tmp2B, tmp3B); } + /** * @brief Matrix vector product of J with a vector v (for iterative solvers) * @param t timepoint @@ -850,13 +934,14 @@ int fJBandB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, * @param tmp temporary storage vector * @return status flag indicating successful execution **/ -int fJv(N_Vector v, N_Vector Jv, realtype t, N_Vector x, +static int fJv(N_Vector v, N_Vector Jv, realtype t, N_Vector x, N_Vector /*xdot*/, void *user_data, N_Vector /*tmp*/) { auto model = static_cast(user_data); model->fJv(v, Jv, t, x); return model->checkFinite(gsl::make_span(Jv), "Jacobian"); } + /** * @brief Matrix vector product of JB with a vector v (for iterative solvers) * @param t timepoint @@ -870,7 +955,7 @@ int fJv(N_Vector v, N_Vector Jv, realtype t, N_Vector x, * @param tmpB temporary storage vector * @return status flag indicating successful execution **/ -int fJvB(N_Vector vB, N_Vector JvB, realtype t, N_Vector x, +static int fJvB(N_Vector vB, N_Vector JvB, realtype t, N_Vector x, N_Vector xB, N_Vector /*xBdot*/, void *user_data, N_Vector /*tmpB*/) { auto model = static_cast(user_data); @@ -878,6 +963,7 @@ int fJvB(N_Vector vB, N_Vector JvB, realtype t, N_Vector x, return model->checkFinite(gsl::make_span(JvB), "Jacobian"); } + /** * @brief Event trigger function for events * @param t timepoint @@ -886,7 +972,7 @@ int fJvB(N_Vector vB, N_Vector JvB, realtype t, N_Vector x, * @param user_data object with user input @type Model_ODE * @return status flag indicating successful execution */ -int froot(realtype t, N_Vector x, realtype *root, +static int froot(realtype t, N_Vector x, realtype *root, void *user_data) { auto model = static_cast(user_data); model->froot(t, x, gsl::make_span(root, model->ne)); @@ -894,6 +980,7 @@ int froot(realtype t, N_Vector x, realtype *root, "root function"); } + /** * @brief residual function of the ODE * @param t timepoint @@ -902,7 +989,7 @@ int froot(realtype t, N_Vector x, realtype *root, * @param user_data object with user input @type Model_ODE * @return status flag indicating successful execution */ -int fxdot(realtype t, N_Vector x, N_Vector xdot, void *user_data) { +static int fxdot(realtype t, N_Vector x, N_Vector xdot, void *user_data) { auto model = static_cast(user_data); if (t > 1e200 && !model->checkFinite(gsl::make_span(x), "fxdot")) { @@ -917,6 +1004,7 @@ int fxdot(realtype t, N_Vector x, N_Vector xdot, void *user_data) { return model->checkFinite(gsl::make_span(xdot), "fxdot"); } + /** * @brief Right hand side of differential equation for adjoint state xB * @param t timepoint @@ -926,13 +1014,14 @@ int fxdot(realtype t, N_Vector x, N_Vector xdot, void *user_data) { * @param user_data object with user input @type Model_ODE * @return status flag indicating successful execution */ -int fxBdot(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, +static int fxBdot(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, void *user_data) { auto model = static_cast(user_data); model->fxBdot(t, x, xB, xBdot); return model->checkFinite(gsl::make_span(xBdot), "fxBdot"); } + /** * @brief Right hand side of integral equation for quadrature states qB * @param t timepoint @@ -942,13 +1031,68 @@ int fxBdot(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, * @param user_data pointer to temp data object * @return status flag indicating successful execution */ -int fqBdot(realtype t, N_Vector x, N_Vector xB, N_Vector qBdot, +static int fqBdot(realtype t, N_Vector x, N_Vector xB, N_Vector qBdot, void *user_data) { auto model = static_cast(user_data); model->fqBdot(t, x, xB, qBdot); return model->checkFinite(gsl::make_span(qBdot), "qBdot"); } + +/** + * @brief Right hand side of differential equation for adjoint state xB + * when simulating in steadystate mode + * @param t timepoint + * @param xB Vector with the adjoint states + * @param xBdot Vector with the adjoint right hand side + * @param user_data object with user input @type Model_ODE + * @return status flag indicating successful execution + */ +static int fxBdot_ss(realtype t, N_Vector xB, N_Vector xBdot, + void *user_data) { + auto model = static_cast(user_data); + model->fxBdot_ss(t, xB, xBdot); + return model->checkFinite(gsl::make_span(xBdot), "fxBdot_ss"); +} + + +/** + * @brief Right hand side of integral equation for quadrature states qB + * when simulating in steadystate mode + * @param t timepoint + * @param xB Vector with the adjoint states + * @param qBdot Vector with the adjoint quadrature right hand side + * @param user_data pointer to temp data object + * @return status flag indicating successful execution + */ +static int fqBdot_ss(realtype t, N_Vector xB, N_Vector qBdot, + void *user_data) { + auto model = static_cast(user_data); + model->fqBdot_ss(t, xB, qBdot); + return model->checkFinite(gsl::make_span(qBdot), "qBdot_ss"); +} + +/** + * @brief JB in sparse form for steady state case + * @param t timepoint + * @param x Vector with the states + * @param xBdot Vector with the adjoint right hand side + * @param JB Matrix to which the Jacobian will be written + * @param user_data object with user input @type Model_ODE + * @param tmp1B temporary storage vector + * @param tmp2B temporary storage vector + * @param tmp3B temporary storage vector + * @return status flag indicating successful execution + */ +static int fJSparseB_ss(realtype /*t*/, N_Vector /*x*/, N_Vector xBdot, + SUNMatrix JB, void *user_data, N_Vector /*tmp1*/, + N_Vector /*tmp2*/, N_Vector /*tmp3*/) { + auto model = static_cast(user_data); + model->fJSparseB_ss(JB); + return model->checkFinite(gsl::make_span(xBdot), "JSparseB_ss"); +} + + /** * @brief Right hand side of differential equation for state sensitivities sx * @param Ns number of parameters @@ -964,7 +1108,7 @@ int fqBdot(realtype t, N_Vector x, N_Vector xB, N_Vector qBdot, * @param tmp3 temporary storage vector * @return status flag indicating successful execution */ -int fsxdot(int /*Ns*/, realtype t, N_Vector x, N_Vector /*xdot*/, +static int fsxdot(int /*Ns*/, realtype t, N_Vector x, N_Vector /*xdot*/, int ip, N_Vector sx, N_Vector sxdot, void *user_data, N_Vector /*tmp1*/, N_Vector /*tmp2*/) { auto model = static_cast(user_data); @@ -972,6 +1116,7 @@ int fsxdot(int /*Ns*/, realtype t, N_Vector x, N_Vector /*xdot*/, return model->checkFinite(gsl::make_span(sxdot), "sxdot"); } + bool operator==(const CVodeSolver &a, const CVodeSolver &b) { return static_cast(a) == static_cast(b); } diff --git a/deps/AMICI/src/solver_idas.cpp b/deps/AMICI/src/solver_idas.cpp index a8b9b51e4..20edc6001 100644 --- a/deps/AMICI/src/solver_idas.cpp +++ b/deps/AMICI/src/solver_idas.cpp @@ -70,6 +70,16 @@ static int fxBdot(realtype t, N_Vector x, N_Vector dx, N_Vector xB, static int fqBdot(realtype t, N_Vector x, N_Vector dx, N_Vector xB, N_Vector dxB, N_Vector qBdot, void *user_data); +static int fxBdot_ss(realtype t, N_Vector xB, N_Vector dxB, N_Vector xBdot, + void *user_data); + +static int fqBdot_ss(realtype t, N_Vector xB, N_Vector dxB, N_Vector qBdot, + void *user_data); + +static int fJSparseB_ss(realtype t, realtype cj, N_Vector x, N_Vector dx, + N_Vector xBdot, SUNMatrix JB, void *user_data, + N_Vector tmp1, N_Vector tmp2, N_Vector tmp3); + static int fsxdot(int Ns, realtype t, N_Vector x, N_Vector dx, N_Vector xdot, N_Vector *sx, N_Vector *sdx, N_Vector *sxdot, void *user_data, N_Vector tmp1, @@ -83,8 +93,8 @@ void IDASolver::init(const realtype t0, const AmiVector &x0, int status; solverWasCalledF = false; t = t0; - x.copy(x0); - dx.copy(dx0); + x = x0; + dx = dx0; if (getInitDone()) { status = IDAReInit(solverMemory.get(), t, x.getNVector(), dx.getNVector()); @@ -97,20 +107,33 @@ void IDASolver::init(const realtype t0, const AmiVector &x0, throw IDAException(status, "IDAInit"); } +void IDASolver::initSteadystate(const realtype t0, const AmiVector &x0, + const AmiVector &dx0) const { + /* We need to set the steadystate rhs function. SUndials doesn't have this + in its public api, so we have to change it in the solver memory, + as re-calling init would unset solver settings. */ + auto ida_mem = static_cast(solverMemory.get()); + ida_mem->ida_res = fxBdot_ss; +} + void IDASolver::sensInit1(const AmiVectorArray &sx0, const AmiVectorArray &sdx0) const { - int status; - sx.copy(sx0); - sdx.copy(sdx0); - if (getSensInitDone()) { - status = IDASensReInit(solverMemory.get(), - static_cast(getSensitivityMethod()), - sx.getNVectorArray(), sdx.getNVectorArray()); - } else { - status = IDASensInit(solverMemory.get(), nplist(), - static_cast(getSensitivityMethod()), fsxdot, - sx.getNVectorArray(), sdx.getNVectorArray()); - setSensInitDone(); + int status = IDA_SUCCESS; + sx = sx0; + sdx = sdx0; + if (getSensitivityMethod() == SensitivityMethod::forward && nplist() > 0) { + if (getSensInitDone()) { + status = + IDASensReInit(solverMemory.get(), + static_cast(getInternalSensitivityMethod()), + sx.getNVectorArray(), sdx.getNVectorArray()); + } else { + status = IDASensInit( + solverMemory.get(), nplist(), + static_cast(getInternalSensitivityMethod()), fsxdot, + sx.getNVectorArray(), sdx.getNVectorArray()); + setSensInitDone(); + } } if (status != IDA_SUCCESS) throw IDAException(status, "IDASensInit"); @@ -119,8 +142,8 @@ void IDASolver::sensInit1(const AmiVectorArray &sx0, void IDASolver::binit(const int which, const realtype tf, const AmiVector &xB0, const AmiVector &dxB0) const { int status; - xB.copy(xB0); - dxB.copy(dxB0); + xB = xB0; + dxB = dxB0; if (getInitDoneB(which)) status = IDAReInitB(solverMemory.get(), which, tf, xB.getNVector(), dxB.getNVector()); @@ -202,6 +225,12 @@ void IDASolver::setJacTimesVecFnB(const int which) const { throw IDAException(status, "IDASpilsSetJacTimesVecFnB"); } +void IDASolver::setSparseJacFn_ss() const { + int status = IDASetJacFn(solverMemory.get(), fJSparseB_ss); + if (status != IDA_SUCCESS) + throw IDAException(status, "IDASetJacFn"); +} + Solver *IDASolver::clone() const { return new IDASolver(*this); } void IDASolver::allocateSolver() const { @@ -236,6 +265,12 @@ void IDASolver::setQuadErrConB(const int which, const bool flag) const { throw IDAException(status, "IDASetQuadErrConB"); } +void IDASolver::setQuadErrCon(const bool flag) const { + int status = IDASetQuadErrCon(solverMemory.get(), flag); + if (status != IDA_SUCCESS) + throw IDAException(status, "IDASetQuadErrCon"); +} + void IDASolver::getRootInfo(int *rootsfound) const { int status = IDAGetRootInfo(solverMemory.get(), rootsfound); if (status != IDA_SUCCESS) @@ -412,6 +447,12 @@ void IDASolver::sensReInit(const AmiVectorArray &yyS0, throw IDAException(IDA_VECTOROP_ERR, "IDASensReInit"); } +void IDASolver::sensToggleOff() const { + auto status = IDASensToggleOff(solverMemory.get()); + if (status != IDA_SUCCESS) + throw IDAException(status, "IDASensToggleOff"); +} + void IDASolver::reInitB(const int which, const realtype tB0, const AmiVector &yyB0, const AmiVector &ypB0) const { @@ -484,6 +525,12 @@ void IDASolver::getQuadB(int which) const { throw IDAException(status, "IDAGetQuadB"); } +void IDASolver::getQuad(realtype &t) const { + int status = IDAGetQuad(solverMemory.get(), &t, xQ.getNVector()); + if (status != IDA_SUCCESS) + throw IDAException(status, "IDAGetQuad"); +} + void IDASolver::getQuadDkyB(const realtype t, int k, const int which) const { int status = IDAGetQuadDky(IDAGetAdjIDABmem(solverMemory.get(), which), t, k, xQB.getNVector()); @@ -491,6 +538,12 @@ void IDASolver::getQuadDkyB(const realtype t, int k, const int which) const { throw IDAException(status, "IDAGetB"); } +void IDASolver::getQuadDky(const realtype t, const int k) const { + int status = IDAGetQuadDky(solverMemory.get(), t, k, xQ.getNVector()); + if (status != IDA_SUCCESS) + throw IDAException(status, "IDAGetQuadDky"); +} + void IDASolver::adjInit() const { int status; if (getAdjInitDone()) { @@ -504,6 +557,19 @@ void IDASolver::adjInit() const { throw IDAException(status, "IDAAdjInit"); } +void IDASolver::quadInit(const AmiVector &xQ0) const { + int status; + xQ.copy(xQ0); + if (getQuadInitDone()) { + status = IDAQuadReInit(solverMemory.get(), xQ0.getNVector()); + } else { + status = IDAQuadInit(solverMemory.get(), fqBdot_ss, xQ.getNVector()); + setQuadInitDone(); + } + if (status != IDA_SUCCESS) + throw IDAException(status, "IDAQuadInit"); +} + void IDASolver::allocateSolverB(int *which) const { if (!solverMemoryB.empty()) { *which = 0; @@ -514,7 +580,7 @@ void IDASolver::allocateSolverB(int *which) const { solverMemoryB.resize(*which + 1); solverMemoryB.at(*which) = std::unique_ptr>( - getAdjBmem(solverMemory.get(), *which), [](void */*ptr*/) {}); + getAdjBmem(solverMemory.get(), *which), [](void * /*ptr*/) {}); if (status != IDA_SUCCESS) throw IDAException(status, "IDACreateB"); } @@ -534,6 +600,14 @@ void IDASolver::quadSStolerancesB(const int which, const realtype reltolQB, throw IDAException(status, "IDAQuadSStolerancesB"); } +void IDASolver::quadSStolerances(const realtype reltolQB, + const realtype abstolQB) const { + int status = IDAQuadSStolerances(solverMemory.get(), reltolQB, abstolQB); + if (status != IDA_SUCCESS) + throw IDAException(status, "IDAQuadSStolerances"); +} + + int IDASolver::solve(const realtype tout, const int itask) const { if (forceReInitPostProcessF) reInitPostProcessF(tout); @@ -965,7 +1039,7 @@ int fxdot(realtype t, N_Vector x, N_Vector dx, N_Vector xdot, * @return status flag indicating successful execution */ int fxBdot(realtype t, N_Vector x, N_Vector dx, N_Vector xB, - N_Vector dxB, N_Vector xBdot, void *user_data) { + N_Vector dxB, N_Vector xBdot, void *user_data) { auto model = static_cast(user_data); model->fxBdot(t, x, dx, xB, dxB, xBdot); @@ -992,6 +1066,65 @@ int fqBdot(realtype t, N_Vector x, N_Vector dx, N_Vector xB, } + +/** + * @brief Right hand side of differential equation for adjoint state xB + * when simulating in steadystate mode + * @param t timepoint + * @param xB Vector with the adjoint states + * @param dxB Vector with the adjoint derivative states + * @param xBdot Vector with the adjoint right hand side + * @param user_data object with user input @type Model_DAE + * @return status flag indicating successful execution + */ +static int fxBdot_ss(realtype t, N_Vector xB, N_Vector dxB, N_Vector xBdot, + void *user_data) { + auto model = static_cast(user_data); + model->fxBdot_ss(t, xB, dxB, xBdot); + return model->checkFinite(gsl::make_span(xBdot), "xBdot_ss"); +} + + +/** + * @brief Right hand side of integral equation for quadrature states qB + * when simulating in steadystate mode + * @param t timepoint + * @param xB Vector with the adjoint states + * @param dxB Vector with the adjoint derivative states + * @param qBdot Vector with the adjoint quadrature right hand side + * @param user_data pointer to temp data object + * @return status flag indicating successful execution + */ +static int fqBdot_ss(realtype t, N_Vector xB, N_Vector dxB, N_Vector qBdot, + void *user_data) { + auto model = static_cast(user_data); + model->fqBdot_ss(t, xB, dxB, qBdot); + return model->checkFinite(gsl::make_span(qBdot), "qBdot_ss"); +} + +/** + * @brief JB in sparse form for steady state case + * @param t timepoint + * @param cj scalar in Jacobian (inverse stepsize) + * @param x Vector with the states + * @param dx Vector with the derivative states + * @param xdot Vector with the right hand side + * @param J Matrix to which the Jacobian will be written + * @param user_data object with user input @type Model_DAE + * @param tmp1 temporary storage vector + * @param tmp2 temporary storage vector + * @param tmp3 temporary storage vector + * @return status flag indicating successful execution + */ + static int fJSparseB_ss(realtype /*t*/, realtype /*cj*/, N_Vector /*x*/, + N_Vector /*dx*/, N_Vector xBdot, SUNMatrix JB, + void *user_data, N_Vector /*tmp1*/, + N_Vector /*tmp2*/, N_Vector /*tmp3*/) { + auto model = static_cast(user_data); + model->fJSparseB_ss(JB); + return model->checkFinite(gsl::make_span(xBdot), "JSparseB_ss"); +} + /** * @brief Right hand side of differential equation for state sensitivities sx * @param Ns number of parameters diff --git a/deps/AMICI/src/steadystateproblem.cpp b/deps/AMICI/src/steadystateproblem.cpp index 3b3890d77..7a676e708 100644 --- a/deps/AMICI/src/steadystateproblem.cpp +++ b/deps/AMICI/src/steadystateproblem.cpp @@ -5,8 +5,9 @@ #include "amici/solver_cvodes.h" #include "amici/edata.h" #include "amici/forwardproblem.h" +#include "amici/backwardproblem.h" #include "amici/newton_solver.h" -#include "amici/rdata.h" +#include "amici/misc.h" #include #include @@ -17,99 +18,406 @@ namespace amici { -SteadystateProblem::SteadystateProblem(const Solver *solver, - const AmiVector &x0): - t(solver->gett()), delta(solver->nx()), ewt(solver->nx()), - rel_x_newton(solver->nx()), x_newton(solver->nx()), x(x0), - x_old(solver->nx()), dx(solver->nx()), xdot(solver->nx()), - xdot_old(solver->nx()), sx(solver->getStateSensitivity(solver->gett())), - sdx(solver->nx(), solver->nplist()) {} - -void SteadystateProblem::workSteadyStateProblem(ReturnData *rdata, - Solver *solver, Model *model, - int it) { - /** - * Tries to determine the steady state of the ODE system by a Newton - * solver, uses forward intergration, if the Newton solver fails, - * restarts Newton solver, if integration fails. - * Computes steady state sensitivities - * - * @param solver pointer to the AMICI solver object - * @param model pointer to the AMICI model object - * @param it integer with the index of the current time step - * @param rdata pointer to the return data object - */ - double run_time; - clock_t starttime; - - /* First, try to do Newton steps */ - starttime = clock(); - - auto newtonSolver = NewtonSolver::getSolver( - &t, &x, solver->getLinearSolver(), model, rdata, - solver->getNewtonMaxLinearSteps(), solver->getNewtonMaxSteps(), - solver->getAbsoluteTolerance(), solver->getRelativeTolerance(), - solver->getNewtonDampingFactorMode(), - solver->getNewtonDampingFactorLowerBound()); - - auto newton_status = NewtonStatus::failed; - try { - applyNewtonsMethod(rdata, model, newtonSolver.get(), - NewtonStatus::newt); - newton_status = NewtonStatus::newt; - } catch (NewtonFailure const &ex1) { +SteadystateProblem::SteadystateProblem(const Solver &solver, const Model &model) + : delta(model.nx_solver), ewt_(model.nx_solver), ewtQB_(model.nplist()), + rel_x_newton(model.nx_solver), x_newton(model.nx_solver), + x(model.nx_solver), x_old(model.nx_solver), dx(model.nx_solver), + xdot(model.nx_solver), xdot_old(model.nx_solver), + sx(model.nx_solver, model.nplist()), sdx(model.nx_solver, model.nplist()), + xB(model.nJ * model.nx_solver), xQ(model.nJ * model.nx_solver), + xQB(model.nplist()), xQBdot(model.nplist()), + dJydx(model.nJ * model.nx_solver * model.nt(), 0.0) { + /* maxSteps must be adapted if iterative linear solvers are used */ + if (solver.getLinearSolver() == LinearSolver::SPBCG) { + maxSteps = solver.getNewtonMaxSteps(); + numlinsteps.resize(2 * maxSteps, 0); + } + /* Check for compatibility of options */ + if (solver.getSensitivityMethod() == SensitivityMethod::forward && + solver.getSensitivityMethodPreequilibration() == SensitivityMethod::adjoint && + solver.getSensitivityOrder() > SensitivityOrder::none) + throw AmiException("Preequilibration using adjoint sensitivities " + "is not compatible with using forward " + "sensitivities during simulation"); + } + +void SteadystateProblem::workSteadyStateProblem(Solver *solver, Model *model, + int it) { + + /* process solver handling for pre- or postequilibration */ + if (it == -1) { + /* solver was not run before, set up everything */ + model->initialize(x, dx, sx, sdx, + solver->getSensitivityOrder() >= + SensitivityOrder::first); + t = model->t0(); + solver->setup(t, model, x, dx, sx, sdx); + } else { + /* solver was run before, extract current state from solver */ + solver->writeSolution(&t, x, dx, sx, xQ); + } + + /* create a Newton solver obejct */ + auto newtonSolver = NewtonSolver::getSolver(&t, &x, *solver, model); + + /* Compute steady state and get the computation time */ + clock_t starttime = clock(); + findSteadyState(solver, newtonSolver.get(), model, it); + cpu_time = (double)((clock() - starttime) * 1000) / CLOCKS_PER_SEC; + + /* Check whether state sensis still need to be computed */ + if (getSensitivityFlag(model, solver, it, SteadyStateContext::newtonSensi)) + { try { - /* Newton solver did not work, so try a simulation */ - if (it < 1) /* No previous time point computed, set t = t0 */ - t = model->t0(); - else /* Carry on simulating from last point */ - t = model->getTimepoint(it - 1); - if (it < 0) { - /* Preequilibration? -> Create a new CVode object for sim */ - auto newtonSimSolver = - createSteadystateSimSolver(solver, model); - getSteadystateSimulation(rdata, newtonSimSolver.get(), model); - } else { - /* Solver was already created, use this one */ - getSteadystateSimulation(rdata, solver, model); - } - newton_status = NewtonStatus::newt_sim; - } catch (AmiException const &ex2) { - /* may be integration failure from AmiSolve, so NewtonFailure - won't do for all cases */ - try { - applyNewtonsMethod(rdata, model, newtonSolver.get(), - NewtonStatus::newt_sim_newt); - newton_status = NewtonStatus::newt_sim_newt; - } catch (NewtonFailure const &ex3) { - if (ex3.error_code == AMICI_TOO_MUCH_WORK) - throw AmiException("Steady state computation failed to " - "converge within the allowed maximum " - "number of iterations"); - throw; - } + /* this might still fail, if the Jacobian is singular and + simulation did not find a steady state */ + newtonSolver->computeNewtonSensis(sx); + } catch (NewtonFailure const &) { + /* No steady state could be inferred. Store simulation state */ + storeSimulationState(model, solver->getSensitivityOrder() >= + SensitivityOrder::first); + throw AmiException("Steady state sensitvitiy computation failed due " + "to unsuccessful factorization of RHS Jacobian"); + } + } + + /* Get output of steady state solver, write it to x0 and reset time + if necessary */ + storeSimulationState(model, getSensitivityFlag(model, solver, it, + SteadyStateContext::sensiStorage)); +} + +void SteadystateProblem::workSteadyStateBackwardProblem(Solver *solver, + Model *model, + const BackwardProblem *bwd) { + /* initialize and check if there is something to be done */ + if (!initializeBackwardProblem(solver, model, bwd)) + return; + + /* Get the Newton solver */ + auto newtonSolver = NewtonSolver::getSolver(&t, &x, *solver, model); + + /* get the run time */ + clock_t starttime = clock(); + computeSteadyStateQuadrature(newtonSolver.get(), solver, model); + cpu_timeB = (double)((clock() - starttime) * 1000) / CLOCKS_PER_SEC; + + /* Finalize by setting addjoint state to zero (its steady state) */ + xB.reset(); +} + +void SteadystateProblem::findSteadyState(Solver *solver, + NewtonSolver *newtonSolver, + Model *model, int it) { + /* First, try to run the Newton solver */ + steady_state_status.resize(3, SteadyStateStatus::not_run); + findSteadyStateByNewtonsMethod(newtonSolver, model, false); + + /* Newton solver didn't work, so try to simulate to steady state */ + if (!checkSteadyStateSuccess()) + findSteadyStateBySimulation(solver, model, it); + + /* Simulation didn't work, retry the Newton solver from last sim state. */ + if (!checkSteadyStateSuccess()) + findSteadyStateByNewtonsMethod(newtonSolver, model, true); + + /* Nothing worked, throw an as informative error as possible */ + if (!checkSteadyStateSuccess()) + handleSteadyStateFailure(solver, model); +} + +void SteadystateProblem::findSteadyStateByNewtonsMethod(NewtonSolver *newtonSolver, + Model *model, + bool newton_retry) { + int ind = newton_retry ? 2 : 0; + try { + applyNewtonsMethod(model, newtonSolver, newton_retry); + steady_state_status[ind] = SteadyStateStatus::success; + } catch (NewtonFailure const &ex) { + /* nothing to be done */ + switch (ex.error_code) { + case AMICI_TOO_MUCH_WORK: + steady_state_status[ind] = + SteadyStateStatus::failed_convergence; + break; + case AMICI_NO_STEADY_STATE: + steady_state_status[ind] = + SteadyStateStatus::failed_too_long_simulation; + break; + case AMICI_SINGULAR_JACOBIAN: + steady_state_status[ind] = + SteadyStateStatus::failed_factorization; + break; + case AMICI_DAMPING_FACTOR_ERROR: + steady_state_status[ind] = SteadyStateStatus::failed_damping; + break; + default: + steady_state_status[ind] = SteadyStateStatus::failed; + break; + } + } + + /* copy number of linear steps used */ + if (maxSteps > 0) { + if (newton_retry) { + std::copy_n(newtonSolver->getNumLinSteps().begin(), + maxSteps, &numlinsteps.at(maxSteps)); + } else { + std::copy_n(newtonSolver->getNumLinSteps().begin(), + maxSteps, numlinsteps.begin()); } } - run_time = (double)((clock() - starttime) * 1000) / CLOCKS_PER_SEC; +} + +void SteadystateProblem::findSteadyStateBySimulation(const Solver *solver, + Model *model, + int it) { + /* set starting timepoint for the simulation solver */ + if (it < 1) /* No previous time point computed, set t = t0 */ + t = model->t0(); + else /* Carry on simulating from last point */ + t = model->getTimepoint(it - 1); + + try { + if (it < 0) { + /* Preequilibration? -> Create a new CVode object for sim */ + bool integrateSensis = getSensitivityFlag(model, solver, it, + SteadyStateContext::solverCreation); + auto newtonSimSolver = createSteadystateSimSolver(solver, model, + integrateSensis, + false); + runSteadystateSimulation(newtonSimSolver.get(), model, false); + } else { + /* Solver was already created, use this one */ + runSteadystateSimulation(solver, model, false); + } + steady_state_status[1] = SteadyStateStatus::success; + } catch (NewtonFailure const &ex) { + switch (ex.error_code) { + case AMICI_TOO_MUCH_WORK: + steady_state_status[1] = SteadyStateStatus::failed_convergence; + break; + case AMICI_NO_STEADY_STATE: + steady_state_status[1] = SteadyStateStatus::failed_too_long_simulation; + break; + default: + steady_state_status[1] = SteadyStateStatus::failed; + } + } catch (AmiException const &) { + steady_state_status[1] = SteadyStateStatus::failed; + } +} + +bool SteadystateProblem::initializeBackwardProblem(Solver *solver, + Model *model, + const BackwardProblem *bwd) { + if (bwd) { + /* If preequilibration but not adjoint mode, there's nothing to do */ + if (solver->getSensitivityMethodPreequilibration() != + SensitivityMethod::adjoint) + return false; + + /* If we need to reinitialize solver states, this won't work yet. */ + if (model->nx_reinit() > 0) + throw NewtonFailure(AMICI_NOT_IMPLEMENTED, + "Adjoint preequilibration with reinitialization of " + "non-constant states is not yet implemented. Stopping."); + + /* If we have a backward problem, we're in preequilibration. + Hence, quantities like t, x, and xB must be set. */ + solver->reInit(t, x, x); + solver->updateAndReinitStatesAndSensitivities(model); + xB.copy(bwd->getAdjointState()); + } + + /* Will need to write quadratures: set to 0 */ + xQ.reset(); + xQB.reset(); + xQBdot.reset(); + + return true; +} + +void SteadystateProblem::computeSteadyStateQuadrature(NewtonSolver *newtonSolver, + const Solver *solver, + Model *model) { + /* This routine computes the qudratures: + xQB = Integral[ xB(x(t), t, p) * dxdot/dp(x(t), t, p) | dt ] + As we're in steady state, we have x(t) = x_ss (x_steadystate), hence + xQB = Integral[ xB(x_ss, t, p) | dt ] * dxdot/dp(x_ss, t, p) + We therefore compute the integral over xB first and then do a + matrix-vector multiplication */ + + /* Try to compute the analytical solution for quadrature algebraically */ + getQuadratureByLinSolve(newtonSolver, model); + + /* Analytical solution didn't work, perform simulation instead */ + if (!hasQuadrature()) + getQuadratureBySimulation(solver, model); + + /* If analytic solution and integration did not work, throw an Exception */ + if (!hasQuadrature()) + throw AmiException("Steady state backward computation failed: Linear " + "system could not be solved (possibly due to singular Jacobian), " + "and numerical integration did not equilibrate within maxsteps"); +} + +void SteadystateProblem::getQuadratureByLinSolve(NewtonSolver *newtonSolver, + Model *model) { + /* Computes the integral over the adjoint state xB: + If the Jacobian has full rank, this has an anlytical solution, since + d/dt[ xB(t) ] = JB^T(x(t), p) xB(t) = JB^T(x_ss, p) xB(t) + This linear ODE system with time-constant matrix has the solution + xB(t) = exp( t * JB^T(x_ss, p) ) * xB(0) + This integral xQ over xB is given as the solution of + JB^T(x_ss, p) * xQ = xB(0) + So we first try to solve the linear system, if possible. */ + + /* copy content of xB into vector with integral */ + xQ.copy(xB); + + /* try to solve the linear system */ + try { + /* compute integral over xB and write to xQ */ + newtonSolver->prepareLinearSystemB(0, -1); + newtonSolver->solveLinearSystem(xQ); + /* Compute the quadrature as the inner product xQ * dxotdp */ + computeQBfromQ(model, xQ, xQB); + /* set flag that quadratures is available (for processing in rdata) */ + hasQuadrature_ = true; + } catch (NewtonFailure const &) { + hasQuadrature_ = false; + } +} + +void SteadystateProblem::getQuadratureBySimulation(const Solver *solver, + Model *model) { + /* If the Jacobian is singular, the integral over xB must be computed + by usual integration over time, but simplifications can be applied: + x is not time dependent, no forward trajectory is needed. */ + + /* set starting timepoint for the simulation solver */ + t = model->t0(); + /* xQ was written in getQuadratureByLinSolve() -> reset */ + xQ.reset(); + + /* create a new solver object */ + auto simSolver = createSteadystateSimSolver(solver, model, false, true); + + /* perform integration and qudrature */ + try { + runSteadystateSimulation(simSolver.get(), model, true); + hasQuadrature_ = true; + } catch (NewtonFailure const &) { + hasQuadrature_ = false; + } +} + +[[noreturn]] void SteadystateProblem::handleSteadyStateFailure(const Solver *solver, + Model *model) { + /* No steady state could be inferred. Store simulation state */ + storeSimulationState(model, solver->getSensitivityOrder() >= + SensitivityOrder::first); + + /* Throw error message according to error codes */ + std::string errorString = "Steady state computation failed. " + "First run of Newton solver failed"; + writeErrorString(&errorString, steady_state_status[0]); + errorString.append(" Simulation to steady state failed"); + writeErrorString(&errorString, steady_state_status[1]); + errorString.append(" Second run of Newton solver failed"); + writeErrorString(&errorString, steady_state_status[2]); + + throw AmiException(errorString.c_str()); +} - /* Compute steady state sensitvities */ +void SteadystateProblem::writeErrorString(std::string *errorString, + SteadyStateStatus status) const { + /* write error message according to steady state status */ + switch (status) { + case SteadyStateStatus::failed_too_long_simulation: + (*errorString).append(": System could not be equilibrated via" + " simulating to a late time point."); + break; + case SteadyStateStatus::failed_damping: + (*errorString).append(": Damping factor reached lower bound."); + break; + case SteadyStateStatus::failed_factorization: + (*errorString).append(": RHS could not be factorized."); + break; + case SteadyStateStatus::failed_convergence: + (*errorString).append(": No convergence was achieved."); + break; + case SteadyStateStatus::failed: + (*errorString).append("."); + break; + default: + break; + } +} - if (solver->getSensitivityOrder() >= SensitivityOrder::first && - (newton_status == NewtonStatus::newt || - newton_status == NewtonStatus::newt_sim_newt || - model->getSteadyStateSensitivityMode() != SteadyStateSensitivityMode::simulationFSA)) - // for newton_status == 2 the sensis were computed via FSA - newtonSolver->computeNewtonSensis(sx); +bool SteadystateProblem::getSensitivityFlag(const Model *model, + const Solver *solver, + int it, SteadyStateContext context) { + /* We need to check whether we need to compute forward sensitivities. + Depending on the situation (pre-/postequilibration) and the solver + settings, the logic may be involved and is handled here. + Most of these boolean operation could be simplified. However, + clarity is more important than brevity. */ + + /* Are we running in preequilibration (and hence create)? */ + bool preequilibration = (it == -1); + + /* Have we maybe already computed forward sensitivities? */ + bool forwardSensisAlreadyComputed = + solver->getSensitivityOrder() >= SensitivityOrder::first && + steady_state_status[1] == SteadyStateStatus::success && + model->getSteadyStateSensitivityMode() == SteadyStateSensitivityMode::simulationFSA; + + /* Do we need forward sensis for postequilibration? */ + bool needForwardSensisPosteq = !preequilibration && + !forwardSensisAlreadyComputed && + solver->getSensitivityOrder() >= SensitivityOrder::first && + solver->getSensitivityMethod() == SensitivityMethod::forward; + + /* Do we need forward sensis for preequilibration? */ + bool needForwardSensisPreeq = preequilibration && + !forwardSensisAlreadyComputed && + solver->getSensitivityMethodPreequilibration() == SensitivityMethod::forward && + solver->getSensitivityOrder() >= SensitivityOrder::first; + + /* Do we need to do the linear system solve to get forward sensitivities? */ + bool needForwardSensisNewton = + needForwardSensisPreeq || needForwardSensisPosteq; + + /* When we're creating a new solver object */ + bool needForwardSensiAtCreation = needForwardSensisPreeq && + model->getSteadyStateSensitivityMode() == SteadyStateSensitivityMode::simulationFSA; + + /* Check if we need to store sensis */ + switch (context) { + case SteadyStateContext::newtonSensi: + return needForwardSensisNewton; + + case SteadyStateContext::sensiStorage: + return needForwardSensisNewton || forwardSensisAlreadyComputed; + + case SteadyStateContext::solverCreation: + return needForwardSensiAtCreation; - /* Get output of steady state solver, write it to x0 and reset time if necessary */ - writeNewtonOutput(rdata, model, newton_status, run_time, it); + default: + throw AmiException("Requested invalid context in sensitivity " + "processing during steady state computation"); + } } realtype SteadystateProblem::getWrmsNorm(const AmiVector &x, const AmiVector &xdot, realtype atol, - realtype rtol - ) { + realtype rtol, + AmiVector &ewt) const { + /* Depending on what convergence we want to check (xdot, sxdot, xQBdot) + we need to pass ewt[QB], as xdot and xQBdot have different sizes */ N_VAbs(x.getNVector(), ewt.getNVector()); N_VScale(rtol, ewt.getNVector(), ewt.getNVector()); N_VAddConst(ewt.getNVector(), atol, ewt.getNVector()); @@ -117,45 +425,66 @@ realtype SteadystateProblem::getWrmsNorm(const AmiVector &x, return N_VWrmsNorm(xdot.getNVector(), ewt.getNVector()); } -bool SteadystateProblem::checkConvergence( - const Solver *solver, - Model *model - ) { - model->fxdot(t, x, dx, xdot); - wrms = getWrmsNorm(x, xdot, solver->getAbsoluteToleranceSteadyState(), solver->getRelativeToleranceSteadyState()); +bool SteadystateProblem::checkConvergence(const Solver *solver, + Model *model, + SensitivityMethod checkSensitivities) { + if (checkSensitivities == SensitivityMethod::adjoint) { + /* In the adjoint case, only xQB contributes to the gradient, the exact + steadystate is less important, as xB = xQdot may even not converge + to zero at all. So we need xQBdot, hence compute xQB first. */ + computeQBfromQ(model, xQ, xQB); + computeQBfromQ(model, xB, xQBdot); + wrms = getWrmsNorm(xQB, xQBdot, solver->getAbsoluteToleranceQuadratures(), + solver->getRelativeToleranceQuadratures(), ewtQB_); + } else { + /* If we're doing a forward simulation (with or without sensitivities: + Get RHS and compute weighted error norm */ + model->fxdot(t, x, dx, xdot); + wrms = getWrmsNorm(x, xdot, solver->getAbsoluteToleranceSteadyState(), + solver->getRelativeToleranceSteadyState(), ewt_); + } bool converged = wrms < RCONST(1.0); - if (solver->getSensitivityOrder()>SensitivityOrder::none && - solver->getSensitivityMethod() == SensitivityMethod::forward) { - for (int ip = 0; ip < model->nplist(); ++ip) { - if (converged) { - sx = solver->getStateSensitivity(t); - model->fsxdot(t, x, dx, ip, sx[ip], dx, xdot); - wrms = getWrmsNorm(x, xdot, - solver->getAbsoluteToleranceSteadyStateSensi(), - solver->getRelativeToleranceSteadyStateSensi()); - converged = wrms < RCONST(1.0); - } + + if (checkSensitivities != SensitivityMethod::forward) + return converged; + + /* Forward sensitivities: Compute weighted error norm for their RHS */ + for (int ip = 0; ip < model->nplist(); ++ip) { + if (converged) { + sx = solver->getStateSensitivity(t); + model->fsxdot(t, x, dx, ip, sx[ip], dx, xdot); + wrms = getWrmsNorm( + x, xdot, solver->getAbsoluteToleranceSteadyStateSensi(), + solver->getRelativeToleranceSteadyStateSensi(), ewt_); + converged = wrms < RCONST(1.0); } } return converged; } -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ +bool SteadystateProblem::checkSteadyStateSuccess() const { + /* Did one of the attempts yield s steady state? */ + if (std::any_of(steady_state_status.begin(), steady_state_status.end(), + [](SteadyStateStatus status) + {return status == SteadyStateStatus::success;})) { + return true; + } else { + return false; + } +} -void SteadystateProblem::applyNewtonsMethod(ReturnData *rdata, Model *model, +void SteadystateProblem::applyNewtonsMethod(Model *model, NewtonSolver *newtonSolver, - NewtonStatus steadystate_try) { + bool newton_retry) { int i_newtonstep = 0; int ix = 0; double gamma = 1.0; - bool compNewStep = TRUE; + bool compNewStep = true; /* initialize output of linear solver for Newton step */ delta.reset(); - model->fxdot(t, x, dx,xdot); + model->fxdot(t, x, dx, xdot); /* Check for relative error, but make sure not to divide by 0! Ensure positivity of the state */ @@ -163,8 +492,8 @@ void SteadystateProblem::applyNewtonsMethod(ReturnData *rdata, Model *model, x_old = x; xdot_old = xdot; - //rdata->newton_numsteps[newton_try - 1] = 0.0; - wrms = getWrmsNorm(x_newton, xdot, newtonSolver->atol, newtonSolver->rtol); + wrms = getWrmsNorm(x_newton, xdot, newtonSolver->atol, + newtonSolver->rtol, ewt_); bool converged = wrms < RCONST(1.0); while (!converged && i_newtonstep < newtonSolver->maxsteps) { @@ -172,20 +501,10 @@ void SteadystateProblem::applyNewtonsMethod(ReturnData *rdata, Model *model, if (compNewStep) { try { delta = xdot; - newtonSolver->getStep(steadystate_try == NewtonStatus::newt ? 1 - : 2, - i_newtonstep, delta); - } catch (NewtonFailure const &ex) { - rdata->newton_numsteps.at(steadystate_try == NewtonStatus::newt - ? 0 - : 2) = i_newtonstep; + newtonSolver->getStep(newton_retry ? 2 : 1, i_newtonstep, delta); + } catch (NewtonFailure const &) { + numsteps.at(newton_retry ? 2 : 0) = i_newtonstep; throw; - } catch (std::exception const &ex) { - rdata->newton_numsteps.at(steadystate_try == NewtonStatus::newt - ? 0 - : 2) = i_newtonstep; - throw AmiException("Newton solver failed to compute new step: " - "%s", ex.what()); } } @@ -196,7 +515,7 @@ void SteadystateProblem::applyNewtonsMethod(ReturnData *rdata, Model *model, /* Compute new xdot and residuals */ model->fxdot(t, x, dx, xdot); realtype wrms_tmp = getWrmsNorm(x_newton, xdot, newtonSolver->atol, - newtonSolver->rtol); + newtonSolver->rtol, ewt_); if (wrms_tmp < wrms) { /* If new residuals are smaller than old ones, update state */ @@ -204,7 +523,7 @@ void SteadystateProblem::applyNewtonsMethod(ReturnData *rdata, Model *model, x_old = x; xdot_old = xdot; /* New linear solve due to new state */ - compNewStep = TRUE; + compNewStep = true; /* Check residuals vs tolerances */ converged = wrms < RCONST(1.0); @@ -220,7 +539,8 @@ void SteadystateProblem::applyNewtonsMethod(ReturnData *rdata, Model *model, } if (recheck_convergence) { model->fxdot(t, x, dx, xdot); - wrms = getWrmsNorm(x_newton, xdot, newtonSolver->atol, newtonSolver->rtol); + wrms = getWrmsNorm(x_newton, xdot, newtonSolver->atol, + newtonSolver->rtol, ewt_); converged = wrms < RCONST(1.0); } } else if (newtonSolver->dampingFactorMode==NewtonDampingFactorMode::on) { @@ -231,118 +551,175 @@ void SteadystateProblem::applyNewtonsMethod(ReturnData *rdata, Model *model, /* Reduce dampening factor and raise an error when becomes too small */ gamma = gamma / 4.0; if (gamma < newtonSolver->dampingFactorLowerBound) - throw AmiException("Newton solver failed: a damping factor reached its lower bound"); + throw NewtonFailure(AMICI_DAMPING_FACTOR_ERROR, + "Newton solver failed: the damping factor " + "reached its lower bound"); /* No new linear solve, only try new dampening */ - compNewStep = FALSE; + compNewStep = false; } /* increase step counter */ i_newtonstep++; } /* Set return values */ - rdata->newton_numsteps.at(steadystate_try == NewtonStatus::newt ? 0 : 2) = - i_newtonstep; + numsteps.at(newton_retry ? 2 : 0) = i_newtonstep; if (!converged) throw NewtonFailure(AMICI_TOO_MUCH_WORK, "applyNewtonsMethod"); } -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ - -void SteadystateProblem::writeNewtonOutput(ReturnData *rdata, - const Model *model, - const NewtonStatus newton_status, - const double run_time, const int it) +void SteadystateProblem::runSteadystateSimulation(const Solver *solver, + Model *model, + bool backward) { - - /* Get cpu time for Newton solve in seconds */ - rdata->newton_cpu_time = run_time / 1000; - rdata->newton_status = static_cast(newton_status); - rdata->wrms_steadystate = wrms; - if (newton_status == NewtonStatus::newt_sim) { - rdata->t_steadystate = t; + /* Loop over steps and check for convergence + NB: This function is used for forward and backward simulation, and may + be called by workSteadyStateProblem and workSteadyStateBackwardProblem. + Whether we simulate forward or backward in time is reflected by the + flag "backward". */ + + /* Do we also have to check for convergence of sensitivities? */ + SensitivityMethod sensitivityFlag = SensitivityMethod::none; + if (solver->getSensitivityOrder() > SensitivityOrder::none && + solver->getSensitivityMethod() > SensitivityMethod::none) + sensitivityFlag = SensitivityMethod::forward; + /* If flag for forward sensitivity computation by simulation is not set, + disable forward sensitivity integration. Sensitivities will be combputed + by newonSolver->computeNewtonSensis then */ + if (model->getSteadyStateSensitivityMode() == SteadyStateSensitivityMode::newtonOnly) { + solver->switchForwardSensisOff(); + sensitivityFlag = SensitivityMethod::none; } + if (backward) + sensitivityFlag = SensitivityMethod::adjoint; - /* Steady state was found: set t to t0 if preeq, otherwise to inf */ - if (it == AMICI_PREEQUILIBRATE) { - t = model->t0(); - } else { - t = INFINITY; - } -} - -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ + bool converged = checkConvergence(solver, model, sensitivityFlag); + int sim_steps = 0; -void SteadystateProblem::getSteadystateSimulation(ReturnData *rdata, - Solver *solver, - Model *model) -{ - /* Loop over steps and check for convergence */ - bool converged = checkConvergence(solver, model); - - int steps_newton = 0; - while(!converged) { + while (!converged) { /* One step of ODE integration reason for tout specification: max with 1 ensures correct direction (any positive value would do) - multiplication with 10 ensures nonzero difference and should ensure stable computation - value is not important for AMICI_ONE_STEP mode, only direction w.r.t. current t + multiplication with 10 ensures nonzero difference and should ensure + stable computation value is not important for AMICI_ONE_STEP mode, + only direction w.r.t. current t */ solver->step(std::max(t, 1.0) * 10); - solver->writeSolution(&t, x, dx, sx); + if (backward) { + solver->writeSolution(&t, xB, dx, sx, xQ); + } else { + solver->writeSolution(&t, x, dx, sx, xQ); + } /* Check for convergence */ - converged = checkConvergence(solver, model); + converged = checkConvergence(solver, model, sensitivityFlag); /* increase counter, check for maxsteps */ - steps_newton++; - if (steps_newton >= solver->getMaxSteps() && !converged) { - rdata->newton_numsteps.at(static_cast(NewtonStatus::newt_sim) - 1) = - steps_newton; - throw NewtonFailure(AMICI_TOO_MUCH_WORK, "exceeded maximum number of steps"); + sim_steps++; + if (sim_steps >= solver->getMaxSteps() && !converged) { + numsteps.at(1) = sim_steps; + throw NewtonFailure(AMICI_TOO_MUCH_WORK, + "exceeded maximum number of steps"); + } + if (t >= 1e200 && !converged) { + numsteps.at(1) = sim_steps; + throw NewtonFailure(AMICI_NO_STEADY_STATE, "simulated to late time" + " point without convergence of RHS"); } } - rdata->newton_numsteps.at(static_cast(NewtonStatus::newt_sim) - 1) = - steps_newton; - if (solver->getSensitivityOrder()>SensitivityOrder::none) - sx = solver->getStateSensitivity(t); + + /* store information about steps and sensitivities, if necessary */ + if (backward) { + numstepsB = sim_steps; + } else { + numsteps.at(1) = sim_steps; + if (solver->getSensitivityOrder() > SensitivityOrder::none && + model->getSteadyStateSensitivityMode() == + SteadyStateSensitivityMode::simulationFSA) + sx = solver->getStateSensitivity(t); + } } std::unique_ptr SteadystateProblem::createSteadystateSimSolver( - const Solver *solver, Model *model) const + const Solver *solver, Model *model, bool forwardSensis, bool backward) const { /* Create new CVode solver object */ + auto sim_solver = std::unique_ptr(solver->clone()); - auto newton_solver = std::unique_ptr(solver->clone()); - - switch(solver->getLinearSolver()) { + switch (solver->getLinearSolver()) { case LinearSolver::dense: + break; case LinearSolver::KLU: - case LinearSolver::SuperLUMT: break; default: - throw NewtonFailure(AMICI_NOT_IMPLEMENTED, "invalid solver for steadystate simulation"); + throw NewtonFailure(AMICI_NOT_IMPLEMENTED, + "invalid solver for steadystate simulation"); + } + /* do we need sensitivities? */ + if (forwardSensis) { + /* need forward to compute sx0 */ + sim_solver->setSensitivityMethod(SensitivityMethod::forward); + } else { + sim_solver->setSensitivityMethod(SensitivityMethod::none); + sim_solver->setSensitivityOrder(SensitivityOrder::none); + } + /* use x and sx as dummies for dx and sdx + (they wont get touched in a CVodeSolver) */ + sim_solver->setup(model->t0(), model, x, x, sx, sx); + if (backward) { + sim_solver->setup(model->t0(), model, xB, xB, sx, sx); + sim_solver->setupSteadystate(model->t0(), model, x, x, xB, xB, xQ); + } else { + sim_solver->setup(model->t0(), model, x, x, sx, sx); } - if (solver->getSensitivityMethod() != SensitivityMethod::none - && model->getSteadyStateSensitivityMode() == SteadyStateSensitivityMode::simulationFSA) - newton_solver->setSensitivityMethod(SensitivityMethod::forward); //need forward to compute sx0 - else - newton_solver->setSensitivityMethod(SensitivityMethod::none); - // use x and sx as dummies for dx and sdx (they wont get touched in a CVodeSolver) - newton_solver->setup(model->t0(), model, x, x, sx, sx); + return sim_solver; +} - return newton_solver; +void SteadystateProblem::computeQBfromQ(Model *model, const AmiVector &yQ, + AmiVector &yQB) const { + /* Compute the quadrature as the inner product: yQB = dxotdp * yQ */ + + /* reset first, as multiplication add to existing value */ + yQB.reset(); + /* multiply */ + if (model->pythonGenerated) { + /* fill dxdotdp with current values */ + const auto& plist = model->getParameterList(); + model->fdxdotdp(t, x, x); + + if (model->ndxdotdp_explicit > 0) + model->dxdotdp_explicit.multiply(yQB.getNVector(), + yQ.getNVector(), plist, true); + if (model->ndxdotdp_implicit > 0) + model->dxdotdp_implicit.multiply(yQB.getNVector(), + yQ.getNVector(), plist, true); + } else { + for (int ip=0; ipnplist(); ++ip) + yQB[ip] = N_VDotProd(yQ.getNVector(), + model->dxdotdp.getNVector(ip)); + } +} + +void SteadystateProblem::getAdjointUpdates(Model &model, + const ExpData &edata) { + xB.reset(); + for (int it=0; it < model.nt(); it++) { + if (std::isinf(model.getTimepoint(it))) { + model.getAdjointStateObservableUpdate( + slice(dJydx, it, model.nx_solver * model.nJ), it, x, edata); + for (int ix = 0; ix < model.nxtrue_solver; ix++) + xB[ix] += dJydx[ix + it * model.nx_solver]; + } + } } -void SteadystateProblem::writeSolution(realtype *t, AmiVector &x, - AmiVectorArray &sx) const { - *t = this->t; - x.copy(this->x); - sx.copy(this->sx); +void SteadystateProblem::storeSimulationState(Model *model, bool storesensi) { + state.t = INFINITY; + state.x = x; + state.dx = xdot; + if (storesensi) + state.sx = sx; + state.state = model->getModelState(); } } // namespace amici diff --git a/deps/AMICI/src/sundials_linsol_wrapper.cpp b/deps/AMICI/src/sundials_linsol_wrapper.cpp index 84ace7e0a..00f3481fd 100644 --- a/deps/AMICI/src/sundials_linsol_wrapper.cpp +++ b/deps/AMICI/src/sundials_linsol_wrapper.cpp @@ -43,7 +43,9 @@ int SUNLinSolWrapper::Solve(SUNMatrix A, N_Vector x, N_Vector b, realtype tol) c return SUNLinSolSolve(solver, A, x, b, tol); } -long SUNLinSolWrapper::getLastFlag() const { return SUNLinSolLastFlag(solver); } +long SUNLinSolWrapper::getLastFlag() const { + return static_cast(SUNLinSolLastFlag(solver)); +} int SUNLinSolWrapper::space(long *lenrwLS, long *leniwLS) const { return SUNLinSolSpace(solver, lenrwLS, leniwLS); @@ -99,8 +101,9 @@ int SUNNonLinSolWrapper::setLSolveFn(SUNNonlinSolLSolveFn SolveFn) { return SUNNonlinSolSetLSolveFn(solver, SolveFn); } -int SUNNonLinSolWrapper::setConvTestFn(SUNNonlinSolConvTestFn CTestFn) { - return SUNNonlinSolSetConvTestFn(solver, CTestFn); +int SUNNonLinSolWrapper::setConvTestFn(SUNNonlinSolConvTestFn CTestFn, + void* ctest_data) { + return SUNNonlinSolSetConvTestFn(solver, CTestFn, ctest_data); } int SUNNonLinSolWrapper::setMaxIters(int maxiters) { diff --git a/deps/AMICI/src/sundials_matrix_wrapper.cpp b/deps/AMICI/src/sundials_matrix_wrapper.cpp index 496972f08..3bd99a125 100644 --- a/deps/AMICI/src/sundials_matrix_wrapper.cpp +++ b/deps/AMICI/src/sundials_matrix_wrapper.cpp @@ -174,6 +174,14 @@ void SUNMatrixWrapper::reset() { SUNMatZero(matrix); } +void SUNMatrixWrapper::scale(realtype a) { + if (matrix) { + int nonzeros_ = static_cast(nonzeros()); + for (int i = 0; i < nonzeros_; ++i) + data_ptr[i] *= a; + } +} + void SUNMatrixWrapper::multiply(N_Vector c, const_N_Vector b) const { multiply(gsl::make_span(NV_DATA_S(c), NV_LENGTH_S(c)), gsl::make_span(NV_DATA_S(b), NV_LENGTH_S(b))); @@ -201,8 +209,10 @@ void SUNMatrixWrapper::multiply(gsl::span c, switch (SUNMatGetID(matrix)) { case SUNMATRIX_DENSE: - amici_dgemv(BLASLayout::colMajor, BLASTranspose::noTrans, nrows, - ncols, 1.0, data(), nrows, b.data(), 1, 1.0, c.data(), 1); + amici_dgemv(BLASLayout::colMajor, BLASTranspose::noTrans, + static_cast(nrows), static_cast(ncols), + 1.0, data(), static_cast(nrows), + b.data(), 1, 1.0, c.data(), 1); break; case SUNMATRIX_SPARSE: @@ -230,7 +240,12 @@ void SUNMatrixWrapper::multiply(gsl::span c, case SUNMATRIX_CUSTOM: throw std::domain_error("Amici currently does not support custom" " matrix types."); + case SUNMATRIX_SLUNRLOC: + throw std::domain_error("Not Implemented."); + case SUNMATRIX_CUSPARSE: + throw std::domain_error("Not Implemented."); } + } void SUNMatrixWrapper::multiply(N_Vector c, @@ -392,6 +407,10 @@ void SUNMatrixWrapper::update_ptrs() { case SUNMATRIX_CUSTOM: throw std::domain_error("Amici currently does not support " "custom matrix types."); + case SUNMATRIX_SLUNRLOC: + throw std::domain_error("Not Implemented."); + case SUNMATRIX_CUSPARSE: + throw std::domain_error("Not Implemented."); } } diff --git a/deps/AMICI/src/symbolic_functions.cpp b/deps/AMICI/src/symbolic_functions.cpp index 10fdbcd2d..17dd2c4bd 100644 --- a/deps/AMICI/src/symbolic_functions.cpp +++ b/deps/AMICI/src/symbolic_functions.cpp @@ -239,7 +239,7 @@ double spline(double t, int num, ...) { /* clean memory reserved for valist */ va_end(valist); - spline(num, ss, 0, dudt, 0.0, ts, us, b, c, d); + spline(num, static_cast(ss), 0, dudt, 0.0, ts, us, b, c, d); uout = seval(num, t, ts, us, b, c, d); return uout; @@ -291,7 +291,7 @@ double spline_pos(double t, int num, ...) { /* clean memory reserved for valist */ va_end(valist); - spline(num, ss, 0, dudt, 0.0, ts, uslog, b, c, d); + spline(num, static_cast(ss), 0, dudt, 0.0, ts, uslog, b, c, d); uout = seval(num, t, ts, uslog, b, c, d); return exp(uout); @@ -348,7 +348,7 @@ double Dspline(int id, double t, int num, ...) { /* clean memory reserved for valist */ va_end(valist); - spline(num, ss, 0, dudt, 0.0, ts, us, b, c, d); + spline(num, static_cast(ss), 0, dudt, 0.0, ts, us, b, c, d); uout = seval(num, t, ts, us, b, c, d); return uout; @@ -409,10 +409,10 @@ double Dspline_pos(int id, double t, int num, ...) { /* clean memory reserved for valist */ va_end(valist); - spline(num, ss, 0, dudt, 0.0, ts, uslog, b, c, d); + spline(num, static_cast(ss), 0, dudt, 0.0, ts, uslog, b, c, d); uspline_pos = exp(seval(num, t, ts, uslog, b, c, d)); - spline(num, ss, 0, dudt, 0.0, ts, sus, b, c, d); + spline(num, static_cast(ss), 0, dudt, 0.0, ts, sus, b, c, d); suspline = seval(num, t, ts, sus, b, c, d); uout = suspline * uspline_pos / us[did]; @@ -501,13 +501,13 @@ double DDspline_pos(int id1, int id2, double t, int num, ...) { /* clean memory reserved for valist */ va_end(valist); - spline(num, ss, 0, dudt, 0.0, ts, uslog, b, c, d); + spline(num, static_cast(ss), 0, dudt, 0.0, ts, uslog, b, c, d); uspline_pos = exp(seval(num, t, ts, uslog, b, c, d)); - spline(num, ss, 0, dudt, 0.0, ts, sus1, b, c, d); + spline(num, static_cast(ss), 0, dudt, 0.0, ts, sus1, b, c, d); su1spline = seval(num, t, ts, sus1, b, c, d); - spline(num, ss, 0, dudt, 0.0, ts, sus2, b, c, d); + spline(num, static_cast(ss), 0, dudt, 0.0, ts, sus2, b, c, d); su2spline = seval(num, t, ts, sus2, b, c, d); if (id1 == id2) { diff --git a/deps/AMICI/src/vector.cpp b/deps/AMICI/src/vector.cpp index cefa78925..224d28bb2 100644 --- a/deps/AMICI/src/vector.cpp +++ b/deps/AMICI/src/vector.cpp @@ -18,7 +18,7 @@ N_Vector AmiVector::getNVector() { return nvec; } const_N_Vector AmiVector::getNVector() const { return nvec; } -std::vector const &AmiVector::getVector() { return vec; } +std::vector const &AmiVector::getVector() const { return vec; } int AmiVector::getLength() const { return static_cast(vec.size()); } @@ -58,7 +58,10 @@ void AmiVector::synchroniseNVector() { nvec = N_VMake_Serial(static_cast(vec.size()), vec.data()); } -AmiVector::~AmiVector() { N_VDestroy_Serial(nvec); } +AmiVector::~AmiVector() { + if (nvec) + N_VDestroy_Serial(nvec); +} AmiVectorArray::AmiVectorArray(long int length_inner, long int length_outer) : vec_array(length_outer, AmiVector(length_inner)) { @@ -119,7 +122,7 @@ void AmiVectorArray::reset() { } void AmiVectorArray::flatten_to_vector(std::vector &vec) const { - int n_outer = vec_array.size(); + int n_outer = static_cast(vec_array.size()); if (n_outer == 0) return; // nothing to do ... int n_inner = vec_array.at(0).getLength(); diff --git a/deps/AMICI/src/wrapfunctions.ODE_template.h b/deps/AMICI/src/wrapfunctions.ODE_template.h index b789f4360..33c8a9d81 100644 --- a/deps/AMICI/src/wrapfunctions.ODE_template.h +++ b/deps/AMICI/src/wrapfunctions.ODE_template.h @@ -1,11 +1,25 @@ #ifndef _amici_wrapfunctions_h #define _amici_wrapfunctions_h -#include "TPL_MODELNAME.h" + +#include + +#include "amici/model.h" + +namespace amici { +namespace generic_model { + /** - * @brief Wrapper function to instantiate the linked Amici model without knowing the name at compile time. - * @return + * @brief Wrapper function to instantiate the linked Amici model without knowing + * the name at compile time. + * @return Model instance */ std::unique_ptr getModel(); + +} // namespace generic_model + +} // namespace amici + + #endif /* _amici_wrapfunctions_h */ diff --git a/deps/AMICI/src/wrapfunctions.template.cpp b/deps/AMICI/src/wrapfunctions.template.cpp index 26f64f336..bb363c0c9 100644 --- a/deps/AMICI/src/wrapfunctions.template.cpp +++ b/deps/AMICI/src/wrapfunctions.template.cpp @@ -1,6 +1,16 @@ #include "amici/model.h" #include "wrapfunctions.h" +#include "TPL_MODELNAME.h" + +namespace amici { +namespace generic_model { std::unique_ptr getModel() { - return std::unique_ptr(new Model_TPL_MODELNAME()); + return std::unique_ptr( + new amici::model_TPL_MODELNAME::Model_TPL_MODELNAME()); } + + +} // namespace generic_model + +} // namespace amici diff --git a/deps/AMICI/swig/CMakeLists.txt b/deps/AMICI/swig/CMakeLists.txt index 786afa153..3705441e4 100644 --- a/deps/AMICI/swig/CMakeLists.txt +++ b/deps/AMICI/swig/CMakeLists.txt @@ -2,13 +2,23 @@ # Build additional AMICI interfaces via swig # -find_package(SWIG REQUIRED 3) +# Use most recent SWIG version available +SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC) +find_package(SWIG REQUIRED) + +set(SWIG_VERSION_MIN "3.0") +if (${SWIG_VERSION} VERSION_LESS ${SWIG_VERSION_MIN}) + message(FATAL_ERROR "Requiring SWIG>=${SWIG_VERSION_MIN} " + "but found only ${SWIG_VERSION}.") +endif() + include(${SWIG_USE_FILE}) set(AMICI_INTERFACE_LIST ${CMAKE_CURRENT_SOURCE_DIR}/amici.i ${CMAKE_CURRENT_SOURCE_DIR}/edata.i ${CMAKE_CURRENT_SOURCE_DIR}/rdata.i + ${CMAKE_CURRENT_SOURCE_DIR}/misc.i ${CMAKE_CURRENT_SOURCE_DIR}/model.i ${CMAKE_CURRENT_SOURCE_DIR}/model_ode.i ${CMAKE_CURRENT_SOURCE_DIR}/model_dae.i diff --git a/deps/AMICI/swig/abstract_model.i b/deps/AMICI/swig/abstract_model.i index bcdaa3fc2..d3d68dd8f 100644 --- a/deps/AMICI/swig/abstract_model.i +++ b/deps/AMICI/swig/abstract_model.i @@ -4,6 +4,11 @@ %ignore fJDiag; %ignore fJSparse; %ignore fJv; +%ignore fJB; +%ignore fJSparseB; +%ignore fxBdot_ss; +%ignore fJSparseB_ss; +%ignore writeSteadystateJB; %ignore fdx0; %ignore fdxdotdp; %ignore froot; diff --git a/deps/AMICI/swig/amici.i b/deps/AMICI/swig/amici.i index 0dd0ab647..0dd2c0630 100644 --- a/deps/AMICI/swig/amici.i +++ b/deps/AMICI/swig/amici.i @@ -63,6 +63,7 @@ wrap_unique_ptr(ExpDataPtr, amici::ExpData) %include "amici/defines.h" %include abstract_model.i +%include misc.i %include edata.i %include rdata.i %include solver.i @@ -142,6 +143,30 @@ namespace amici { bool compiledWithOpenMP(); } +%pythoncode %{ +from enum import IntEnum +def enum(prefix): + values = {k:v for k,v in globals().items() if k.startswith(prefix + '_')} + values = {k[len(prefix)+1:]:v for k,v in values.items()} + return IntEnum(prefix, values) +ParameterScaling = enum('ParameterScaling') +SecondOrderMode = enum('SecondOrderMode') +SensitivityOrder = enum('SensitivityOrder') +SensitivityMethod = enum('SensitivityMethod') +LinearSolver = enum('LinearSolver') +InternalSensitivityMethod = enum('InternalSensitivityMethod') +InterpolationType = enum('InterpolationType') +LinearMultistepMethod = enum('LinearMultistepMethod') +NonlinearSolverIteration = enum('NonlinearSolverIteration') +SteadyStateSensitivityMode = enum('SteadyStateSensitivityMode') +SteadyStateStatus = enum('SteadyStateStatus') +NewtonDampingFactorMode = enum('NewtonDampingFactorMode') +FixedParameterContext = enum('FixedParameterContext') +RDataReporting = enum('RDataReporting') +%} + +%template(SteadyStateStatusVector) std::vector; + // add module docstring and import additional types for typehints %pythonbegin %{ """ diff --git a/deps/AMICI/swig/misc.i b/deps/AMICI/swig/misc.i new file mode 100644 index 000000000..cdcca29af --- /dev/null +++ b/deps/AMICI/swig/misc.i @@ -0,0 +1,14 @@ +%module misc + +%ignore amici::printfToString; +%ignore amici::regexErrorToString; +%ignore amici::writeSlice; + +// Add necessary symbols to generated header +%{ +#include "amici/misc.h" +using namespace amici; +%} + +// Process symbols in header +%include "amici/misc.h" diff --git a/deps/AMICI/swig/model.i b/deps/AMICI/swig/model.i index e32c1bc8f..4631b184f 100644 --- a/deps/AMICI/swig/model.i +++ b/deps/AMICI/swig/model.i @@ -40,6 +40,9 @@ using namespace amici; %ignore dxdotdp; %ignore dxdotdp_implicit; %ignore dxdotdp_explicit; +%ignore ModelState; +%ignore getModelState; +%ignore setModelState; // Process symbols in header %include "amici/model.h" diff --git a/deps/AMICI/swig/rdata.i b/deps/AMICI/swig/rdata.i index efab480ca..2a1391e2a 100644 --- a/deps/AMICI/swig/rdata.i +++ b/deps/AMICI/swig/rdata.i @@ -6,5 +6,6 @@ using namespace amici; %} +%ignore processSimulationObjects; // Process symbols in header %include "amici/rdata.h" diff --git a/deps/AMICI/swig/solver.i b/deps/AMICI/swig/solver.i index ecc60c25b..271e5a86b 100644 --- a/deps/AMICI/swig/solver.i +++ b/deps/AMICI/swig/solver.i @@ -12,6 +12,7 @@ using namespace amici; // be exposed in swig %ignore getAdjointDerivativeState; %ignore getAdjointQuadrature; +%ignore getQuadrature; %ignore getAdjointState; %ignore getDerivativeState; %ignore getState; @@ -22,6 +23,7 @@ using namespace amici; %ignore sensReInit; %ignore setup; %ignore setupB; +%ignore setupSteadystate; %ignore writeSolution; %ignore writeSolutionB; diff --git a/deps/AMICI/tests/cpputest/calvetti/tests1.cpp b/deps/AMICI/tests/cpputest/calvetti/tests1.cpp index ae9b28c3c..dfde30fd9 100644 --- a/deps/AMICI/tests/cpputest/calvetti/tests1.cpp +++ b/deps/AMICI/tests/cpputest/calvetti/tests1.cpp @@ -1,26 +1,13 @@ #include "CppUTest/TestHarness.h" #include "CppUTestExt/MockSupport.h" -#include -#include #include "wrapfunctions.h" +#include +#include -TEST_GROUP(groupCalvetti) -{ - void setup() { - - } - - void teardown() { - - } -}; +TEST_GROUP(groupCalvetti){}; -TEST(groupCalvetti, testSimulation) { +TEST(groupCalvetti, testSimulation) +{ amici::simulateVerifyWrite("/model_calvetti/nosensi/"); } - - - - - diff --git a/deps/AMICI/tests/cpputest/dirac/tests1.cpp b/deps/AMICI/tests/cpputest/dirac/tests1.cpp index 4b3d6758c..89d71f1f9 100644 --- a/deps/AMICI/tests/cpputest/dirac/tests1.cpp +++ b/deps/AMICI/tests/cpputest/dirac/tests1.cpp @@ -3,38 +3,17 @@ #include -#include #include "wrapfunctions.h" +#include -TEST_GROUP(groupDirac) -{ - void setup() { - - } - - void teardown() { - - } -}; +TEST_GROUP(groupDirac){}; -TEST(groupDirac, testSimulation) { +TEST(groupDirac, testSimulation) +{ amici::simulateVerifyWrite("/model_dirac/nosensi/"); } -TEST(groupDirac, testSimulationExpData) { - -} - -TEST(groupDirac, testSensitivityForward) { +TEST(groupDirac, testSensitivityForward) +{ amici::simulateVerifyWrite("/model_dirac/sensiforward/"); } - -TEST(groupDirac, testSensitivityState) { - -} - -TEST(groupDirac, testSensitivityAdjoint) { - -} - - diff --git a/deps/AMICI/tests/cpputest/events/tests1.cpp b/deps/AMICI/tests/cpputest/events/tests1.cpp index f01bc9d10..f5ee53a7f 100644 --- a/deps/AMICI/tests/cpputest/events/tests1.cpp +++ b/deps/AMICI/tests/cpputest/events/tests1.cpp @@ -3,30 +3,22 @@ #include "testfunctions.h" -#include #include "wrapfunctions.h" +#include -TEST_GROUP(groupEvents) -{ - void setup() { - - } - - void teardown() { - - } -}; +TEST_GROUP(groupEvents){}; -TEST(groupEvents, testDefault) { +TEST(groupEvents, testDefault) +{ amici::simulateWithDefaultOptions(); } -TEST(groupEvents, testSimulation) { +TEST(groupEvents, testSimulation) +{ amici::simulateVerifyWrite("/model_events/nosensi/"); } -TEST(groupEvents, testSensitivityForward) { +TEST(groupEvents, testSensitivityForward) +{ amici::simulateVerifyWrite("/model_events/sensiforward/"); } - - diff --git a/deps/AMICI/tests/cpputest/expectedResults.h5 b/deps/AMICI/tests/cpputest/expectedResults.h5 index 673b46ab1..16394b088 100644 Binary files a/deps/AMICI/tests/cpputest/expectedResults.h5 and b/deps/AMICI/tests/cpputest/expectedResults.h5 differ diff --git a/deps/AMICI/tests/cpputest/jakstat_adjoint/tests1.cpp b/deps/AMICI/tests/cpputest/jakstat_adjoint/tests1.cpp index 6bf40b88b..a69ed24a5 100644 --- a/deps/AMICI/tests/cpputest/jakstat_adjoint/tests1.cpp +++ b/deps/AMICI/tests/cpputest/jakstat_adjoint/tests1.cpp @@ -3,57 +3,54 @@ #include "testfunctions.h" -#include #include "wrapfunctions.h" +#include -TEST_GROUP(groupJakstatAdjoint) -{ - void setup() { - - } - - void teardown() { - - } -}; +TEST_GROUP(groupJakstatAdjoint){}; -TEST(groupJakstatAdjoint, testSimulation) { +TEST(groupJakstatAdjoint, testSimulation) +{ amici::simulateVerifyWrite("/model_jakstat_adjoint/nosensi/"); } -TEST(groupJakstatAdjoint, testSensitivityForward) { +TEST(groupJakstatAdjoint, testSensitivityForward) +{ amici::simulateVerifyWrite("/model_jakstat_adjoint/sensiforward/"); } -TEST(groupJakstatAdjoint, testSensitivityForwardLogParam) { +TEST(groupJakstatAdjoint, testSensitivityForwardLogParam) +{ amici::simulateVerifyWrite("/model_jakstat_adjoint/sensiforwardlogparam/"); } -TEST(groupJakstatAdjoint, testSensitivityAdjoint) { +TEST(groupJakstatAdjoint, testSensitivityAdjoint) +{ amici::simulateVerifyWrite("/model_jakstat_adjoint/sensiadjoint/"); } -TEST(groupJakstatAdjoint, testSensitivityForwardEmptySensInd) { - amici::simulateVerifyWrite("/model_jakstat_adjoint/sensiforwardemptysensind/"); +TEST(groupJakstatAdjoint, testSensitivityForwardEmptySensInd) +{ + amici::simulateVerifyWrite( + "/model_jakstat_adjoint/sensiforwardemptysensind/"); } -TEST(groupJakstatAdjoint, testSensitivityAdjointEmptySensInd) { - amici::simulateVerifyWrite("/model_jakstat_adjoint/sensiadjointemptysensind/"); +TEST(groupJakstatAdjoint, testSensitivityAdjointEmptySensInd) +{ + amici::simulateVerifyWrite( + "/model_jakstat_adjoint/sensiadjointemptysensind/"); } -IGNORE_TEST(groupJakstatAdjoint, testSensitivityAdjointUnusedNanOutputs) { +IGNORE_TEST(groupJakstatAdjoint, testSensitivityAdjointUnusedNanOutputs) +{ /* UN-IGNORE ONCE THIS MODEL HAS BEEN IMPORTED VIA PYTHON INTERFACE */ - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); amici::hdf5::readModelDataFromHDF5( - NEW_OPTION_FILE, *model, - "/model_jakstat_adjoint/sensiadjoint/options"); + NEW_OPTION_FILE, *model, "/model_jakstat_adjoint/sensiadjoint/options"); amici::hdf5::readSolverSettingsFromHDF5( - NEW_OPTION_FILE, *solver, - "/model_jakstat_adjoint/sensiadjoint/options"); + NEW_OPTION_FILE, *solver, "/model_jakstat_adjoint/sensiadjoint/options"); auto edata = amici::hdf5::readSimulationExpData( - NEW_OPTION_FILE, "/model_jakstat_adjoint/sensiadjoint/data", - *model); + NEW_OPTION_FILE, "/model_jakstat_adjoint/sensiadjoint/data", *model); // Set output parameter p[10] to NaN and remove respective measurements // -> gradient should still be finite @@ -65,7 +62,7 @@ IGNORE_TEST(groupJakstatAdjoint, testSensitivityAdjointUnusedNanOutputs) { auto d = edata->getObservedData(); for (int it = 0; it < edata->nt(); ++it) { for (int iy = 0; iy < edata->nytrue(); ++iy) { - if(iy == 1) + if (iy == 1) d[it * edata->nytrue() + iy] = NAN; } } @@ -73,30 +70,28 @@ IGNORE_TEST(groupJakstatAdjoint, testSensitivityAdjointUnusedNanOutputs) { auto rdata = runAmiciSimulation(*solver, edata.get(), *model); - for(int i = 0; i < model->nplist(); ++i) + for (int i = 0; i < model->nplist(); ++i) CHECK_FALSE(std::isnan(rdata->sllh[i])); } - -TEST(groupJakstatAdjoint, testSensitivityReplicates) { +TEST(groupJakstatAdjoint, testSensitivityReplicates) +{ // Check that we can handle replicates correctly - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); amici::hdf5::readModelDataFromHDF5( - NEW_OPTION_FILE, *model, - "/model_jakstat_adjoint/sensiadjoint/options"); + NEW_OPTION_FILE, *model, "/model_jakstat_adjoint/sensiadjoint/options"); amici::hdf5::readSolverSettingsFromHDF5( - NEW_OPTION_FILE, *solver, - "/model_jakstat_adjoint/sensiadjoint/options"); + NEW_OPTION_FILE, *solver, "/model_jakstat_adjoint/sensiadjoint/options"); amici::ExpData edata(*model); // No replicate, no sensi - edata.setTimepoints({10.0}); + edata.setTimepoints({ 10.0 }); auto d = edata.getObservedData(); for (int it = 0; it < edata.nt(); ++it) { for (int iy = 0; iy < edata.nytrue(); ++iy) { - if(iy == 0) { + if (iy == 0) { d[it * edata.nytrue() + iy] = 1.0; } else { d[it * edata.nytrue() + iy] = NAN; @@ -111,11 +106,11 @@ TEST(groupJakstatAdjoint, testSensitivityReplicates) { auto llh1 = rdata1->llh; // forward + replicates - edata.setTimepoints({10.0, 10.0}); + edata.setTimepoints({ 10.0, 10.0 }); d = edata.getObservedData(); for (int it = 0; it < edata.nt(); ++it) { for (int iy = 0; iy < edata.nytrue(); ++iy) { - if(iy == 0) { + if (iy == 0) { d[it * edata.nytrue() + iy] = 1.0; } else { d[it * edata.nytrue() + iy] = NAN; diff --git a/deps/AMICI/tests/cpputest/jakstat_adjoint_o2/tests1.cpp b/deps/AMICI/tests/cpputest/jakstat_adjoint_o2/tests1.cpp index accd3c277..1331c0c36 100644 --- a/deps/AMICI/tests/cpputest/jakstat_adjoint_o2/tests1.cpp +++ b/deps/AMICI/tests/cpputest/jakstat_adjoint_o2/tests1.cpp @@ -3,33 +3,22 @@ #include "testfunctions.h" -#include #include "wrapfunctions.h" +#include -TEST_GROUP(groupJakstatAdjointO2) -{ - void setup() { - - } - - void teardown() { - - } -}; - +TEST_GROUP(groupJakstatAdjointO2){}; -TEST(groupJakstatAdjointO2, testSensitivityForward2) { +TEST(groupJakstatAdjointO2, testSensitivityForward2) +{ amici::simulateVerifyWrite("/model_jakstat_adjoint/sensi2forward/"); } -TEST(groupJakstatAdjointO2, testSensitivityForward2LogParam) { +TEST(groupJakstatAdjointO2, testSensitivityForward2LogParam) +{ amici::simulateVerifyWrite("/model_jakstat_adjoint/sensi2forwardlogparam/"); } -TEST(groupJakstatAdjointO2, testSensitivityAdjoint2) { +TEST(groupJakstatAdjointO2, testSensitivityAdjoint2) +{ amici::simulateVerifyWrite("/model_jakstat_adjoint/sensi2adjoint/"); } - - - - diff --git a/deps/AMICI/tests/cpputest/nested_events/tests1.cpp b/deps/AMICI/tests/cpputest/nested_events/tests1.cpp index 72a950c81..7208b713d 100644 --- a/deps/AMICI/tests/cpputest/nested_events/tests1.cpp +++ b/deps/AMICI/tests/cpputest/nested_events/tests1.cpp @@ -3,26 +3,17 @@ #include "testfunctions.h" -#include #include "wrapfunctions.h" +#include -TEST_GROUP(groupEvents) -{ - void setup() { - - } - - void teardown() { - - } -}; +TEST_GROUP(groupEvents){}; -TEST(groupEvents, testSimulation) { +TEST(groupEvents, testSimulation) +{ amici::simulateVerifyWrite("/model_nested_events/nosensi/"); } -TEST(groupEvents, testSensitivityForward) { +TEST(groupEvents, testSensitivityForward) +{ amici::simulateVerifyWrite("/model_nested_events/sensiforward/"); } - - diff --git a/deps/AMICI/tests/cpputest/neuron/tests1.cpp b/deps/AMICI/tests/cpputest/neuron/tests1.cpp index 82e003858..f5d645b7a 100644 --- a/deps/AMICI/tests/cpputest/neuron/tests1.cpp +++ b/deps/AMICI/tests/cpputest/neuron/tests1.cpp @@ -3,27 +3,19 @@ #include "testfunctions.h" -#include #include "wrapfunctions.h" +#include -TEST_GROUP(groupNeuron) -{ - void setup() { - - } - - void teardown() { - - } -}; - +TEST_GROUP(groupNeuron){}; -TEST(groupNeuron, testSimulation) { - amici::simulateVerifyWrite("/model_neuron/nosensi/", - 100*TEST_ATOL, 100*TEST_RTOL); +TEST(groupNeuron, testSimulation) +{ + amici::simulateVerifyWrite( + "/model_neuron/nosensi/", 100 * TEST_ATOL, 100 * TEST_RTOL); } -TEST(groupNeuron, testSensitivityForward) { - amici::simulateVerifyWrite("/model_neuron/sensiforward/", - 10*TEST_ATOL, 10*TEST_RTOL); +TEST(groupNeuron, testSensitivityForward) +{ + amici::simulateVerifyWrite( + "/model_neuron/sensiforward/", 10 * TEST_ATOL, 10 * TEST_RTOL); } diff --git a/deps/AMICI/tests/cpputest/neuron_o2/tests1.cpp b/deps/AMICI/tests/cpputest/neuron_o2/tests1.cpp index 958ff55b3..57b9ac47b 100644 --- a/deps/AMICI/tests/cpputest/neuron_o2/tests1.cpp +++ b/deps/AMICI/tests/cpputest/neuron_o2/tests1.cpp @@ -3,24 +3,13 @@ #include "testfunctions.h" -#include #include "wrapfunctions.h" +#include -TEST_GROUP(groupNeuronO2) -{ - void setup() { - - } - - void teardown() { - - } -}; - +TEST_GROUP(groupNeuronO2){}; -TEST(groupNeuronO2, testSensitivity2) { - amici::simulateVerifyWrite("/model_neuron/sensi2forward/", 10*TEST_ATOL, 10*TEST_RTOL); +TEST(groupNeuronO2, testSensitivity2) +{ + amici::simulateVerifyWrite( + "/model_neuron/sensi2forward/", 10 * TEST_ATOL, 10 * TEST_RTOL); } - - - diff --git a/deps/AMICI/tests/cpputest/robertson/tests1.cpp b/deps/AMICI/tests/cpputest/robertson/tests1.cpp index 5e31c36a8..441eac0b1 100644 --- a/deps/AMICI/tests/cpputest/robertson/tests1.cpp +++ b/deps/AMICI/tests/cpputest/robertson/tests1.cpp @@ -1,39 +1,31 @@ #include "CppUTest/TestHarness.h" #include "CppUTestExt/MockSupport.h" -#include -#include #include "wrapfunctions.h" +#include +#include -TEST_GROUP(groupRobertson) -{ - void setup() { - - } - - void teardown() { - - } -}; +TEST_GROUP(groupRobertson){}; -TEST(groupRobertson, testSimulation) { +TEST(groupRobertson, testSimulation) +{ amici::simulateVerifyWrite("/model_robertson/nosensi/"); } -TEST(groupRobertson, testSensitivityForward) { - amici::simulateVerifyWrite("/model_robertson/sensiforward/", 1e6*TEST_ATOL, 1e2*TEST_RTOL); +TEST(groupRobertson, testSensitivityForward) +{ + amici::simulateVerifyWrite( + "/model_robertson/sensiforward/", 1e6 * TEST_ATOL, 1e2 * TEST_RTOL); } -TEST(groupRobertson, testSensitivityForwardDense) { - amici::simulateVerifyWrite("/model_robertson/sensiforwarddense/", 1e6*TEST_ATOL, 1e2*TEST_RTOL); +TEST(groupRobertson, testSensitivityForwardDense) +{ + amici::simulateVerifyWrite( + "/model_robertson/sensiforwarddense/", 1e6 * TEST_ATOL, 1e2 * TEST_RTOL); } -TEST(groupRobertson, testSensitivityForwardSPBCG) { - amici::simulateVerifyWrite("/model_robertson/sensiforwardSPBCG/", 1e7*TEST_ATOL, 1e2*TEST_RTOL); +TEST(groupRobertson, testSensitivityForwardSPBCG) +{ + amici::simulateVerifyWrite( + "/model_robertson/sensiforwardSPBCG/", 1e7 * TEST_ATOL, 1e2 * TEST_RTOL); } - - - - - - diff --git a/deps/AMICI/tests/cpputest/steadystate/tests1.cpp b/deps/AMICI/tests/cpputest/steadystate/tests1.cpp index 7b857bf68..3c9992df8 100644 --- a/deps/AMICI/tests/cpputest/steadystate/tests1.cpp +++ b/deps/AMICI/tests/cpputest/steadystate/tests1.cpp @@ -3,97 +3,102 @@ #include "testfunctions.h" -#include #include "wrapfunctions.h" +#include -TEST_GROUP(groupSteadystate) -{ - void setup() { - - } - - void teardown() { - - } -}; +TEST_GROUP(groupSteadystate){}; -TEST(groupSteadystate, testDefault) { +TEST(groupSteadystate, testDefault) +{ amici::simulateWithDefaultOptions(); } - -TEST(groupSteadystate, testModelFromHDF5) { +TEST(groupSteadystate, testModelFromHDF5) +{ // Test reading some python-written options - std::vector pExp {1, 0.5, 0.4, 2, 0.1}; - std::vector kExp {0.1, 0.4, 0.7, 1.0}; + std::vector pExp{ 1, 0.5, 0.4, 2, 0.1 }; + std::vector kExp{ 0.1, 0.4, 0.7, 1.0 }; - auto model = getModel(); - amici::hdf5::readModelDataFromHDF5(NEW_OPTION_FILE, *model, "/model_steadystate/nosensi/options"); + auto model = amici::generic_model::getModel(); + amici::hdf5::readModelDataFromHDF5( + NEW_OPTION_FILE, *model, "/model_steadystate/nosensi/options"); - amici::checkEqualArray(kExp, model->getFixedParameters(), TEST_ATOL, TEST_RTOL, "k"); + amici::checkEqualArray( + kExp, model->getFixedParameters(), TEST_ATOL, TEST_RTOL, "k"); CHECK_EQUAL(51, model->nt()); CHECK_EQUAL(0.0, model->getTimepoint(0)); CHECK_EQUAL(100.0, model->getTimepoint(model->nt() - 2)); CHECK_EQUAL(INFINITY, model->getTimepoint(model->nt() - 1)); - for(int i = 0; i < model->np(); ++i) { + for (int i = 0; i < model->np(); ++i) { CHECK_EQUAL(pExp[i], model->getUnscaledParameters()[i]); CHECK_EQUAL(log10(pExp[i]), model->getParameters()[i]); } } -TEST(groupSteadystate, testInequality) { - auto modelA = getModel(); +TEST(groupSteadystate, testInequality) +{ + auto modelA = amici::generic_model::getModel(); auto modelB = std::unique_ptr(new amici::Model_Test()); CHECK_FALSE(*modelA == *modelB); } - -TEST(groupSteadystate, testCopyModel) { - auto modelA = getModel(); +TEST(groupSteadystate, testCopyModel) +{ + auto modelA = amici::generic_model::getModel(); auto modelB = std::unique_ptr(modelA->clone()); CHECK_TRUE(*modelA == *modelB); } - -TEST(groupSteadystate, testCloneModel) { - auto modelA = getModel(); - auto modelB = std::unique_ptr(new Model_model_steadystate()); +TEST(groupSteadystate, testCloneModel) +{ + auto modelA = amici::generic_model::getModel(); + auto modelB = std::unique_ptr( + new amici::model_model_steadystate::Model_model_steadystate()); CHECK_TRUE(*modelA == *modelB); } -TEST(groupSteadystate, testExpDataFromReturnData) { - auto model = getModel(); +TEST(groupSteadystate, testExpDataFromReturnData) +{ + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); - amici::hdf5::readModelDataFromHDF5(NEW_OPTION_FILE, *model, "/model_steadystate/nosensi/options"); - amici::hdf5::readSolverSettingsFromHDF5(NEW_OPTION_FILE, *solver, "/model_steadystate/nosensi/options"); + amici::hdf5::readModelDataFromHDF5( + NEW_OPTION_FILE, *model, "/model_steadystate/nosensi/options"); + amici::hdf5::readSolverSettingsFromHDF5( + NEW_OPTION_FILE, *solver, "/model_steadystate/nosensi/options"); auto rdata = runAmiciSimulation(*solver, nullptr, *model); auto edata = amici::ExpData(*rdata, 0.1, 0.1); runAmiciSimulation(*solver, &edata, *model); } -TEST(groupSteadystate, testReuseSolver) { - auto model = getModel(); +TEST(groupSteadystate, testReuseSolver) +{ + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); - amici::hdf5::readModelDataFromHDF5(NEW_OPTION_FILE, *model, "/model_steadystate/nosensi/options"); - amici::hdf5::readSolverSettingsFromHDF5(NEW_OPTION_FILE, *solver, "/model_steadystate/nosensi/options"); + amici::hdf5::readModelDataFromHDF5( + NEW_OPTION_FILE, *model, "/model_steadystate/nosensi/options"); + amici::hdf5::readSolverSettingsFromHDF5( + NEW_OPTION_FILE, *solver, "/model_steadystate/nosensi/options"); runAmiciSimulation(*solver, nullptr, *model); runAmiciSimulation(*solver, nullptr, *model); } -TEST(groupSteadystate, testRethrow) { - auto model = getModel(); +TEST(groupSteadystate, testRethrow) +{ + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); - amici::hdf5::readModelDataFromHDF5(NEW_OPTION_FILE, *model, "/model_steadystate/nosensi/options"); - amici::hdf5::readSolverSettingsFromHDF5(NEW_OPTION_FILE, *solver, "/model_steadystate/nosensi/options"); + amici::hdf5::readModelDataFromHDF5( + NEW_OPTION_FILE, *model, "/model_steadystate/nosensi/options"); + amici::hdf5::readSolverSettingsFromHDF5( + NEW_OPTION_FILE, *solver, "/model_steadystate/nosensi/options"); // p = NaN will raise amici::IntegrationFailure auto p = model->getParameters(); @@ -104,78 +109,95 @@ TEST(groupSteadystate, testRethrow) { runAmiciSimulation(*solver, nullptr, *model); // must throw - CHECK_THROWS(amici::IntegrationFailure, runAmiciSimulation(*solver, nullptr, *model, true)); + CHECK_THROWS(amici::IntegrationFailure, + runAmiciSimulation(*solver, nullptr, *model, true)); } -TEST(groupSteadystate, testInitialStatesNonEmpty) { - auto model = getModel(); +TEST(groupSteadystate, testInitialStatesNonEmpty) +{ + auto model = amici::generic_model::getModel(); CHECK_FALSE(model->getInitialStates().empty()); } -TEST(groupSteadystate, testInitialStateSensitivitiesNonEmpty) { - auto model = getModel(); +TEST(groupSteadystate, testInitialStateSensitivitiesNonEmpty) +{ + auto model = amici::generic_model::getModel(); CHECK_FALSE(model->getInitialStateSensitivities().empty()); } -TEST(groupSteadystate, testSimulation) { - amici::simulateVerifyWrite("/model_steadystate/nosensi/", - 100*TEST_ATOL, 100*TEST_RTOL); +TEST(groupSteadystate, testSimulation) +{ + amici::simulateVerifyWrite( + "/model_steadystate/nosensi/", 100 * TEST_ATOL, 100 * TEST_RTOL); } -TEST(groupSteadystate, testSensitivityForward) { +TEST(groupSteadystate, testSensitivityForward) +{ amici::simulateVerifyWrite("/model_steadystate/sensiforward/"); } -TEST(groupSteadystate, testSensitivityForwardPlist) { +TEST(groupSteadystate, testSensitivityForwardPlist) +{ amici::simulateVerifyWrite("/model_steadystate/sensiforwardplist/"); } - -TEST(groupSteadystate, testSensitivityForwardErrorInt) { +TEST(groupSteadystate, testSensitivityForwardErrorInt) +{ amici::simulateVerifyWrite("/model_steadystate/sensiforwarderrorint/"); } -TEST(groupSteadystate, testSensitivityForwardErrorNewt) { +TEST(groupSteadystate, testSensitivityForwardErrorNewt) +{ amici::simulateVerifyWrite("/model_steadystate/sensiforwarderrornewt/"); } - -TEST(groupSteadystate, testSensitivityForwardDense) { +TEST(groupSteadystate, testSensitivityForwardDense) +{ amici::simulateVerifyWrite("/model_steadystate/sensiforwarddense/"); } -TEST(groupSteadystate, testSensitivityForwardSPBCG) { - amici::simulateVerifyWrite("/model_steadystate/nosensiSPBCG/", 10*TEST_ATOL, 10*TEST_RTOL); +TEST(groupSteadystate, testSensitivityForwardSPBCG) +{ + amici::simulateVerifyWrite( + "/model_steadystate/nosensiSPBCG/", 10 * TEST_ATOL, 10 * TEST_RTOL); } -TEST(groupSteadystate, testSensiFwdNewtonPreeq) { +TEST(groupSteadystate, testSensiFwdNewtonPreeq) +{ amici::simulateVerifyWrite("/model_steadystate/sensifwdnewtonpreeq/"); } -TEST(groupSteadystate, testSensiAdjNewtonPreeq) { +TEST(groupSteadystate, testSensiAdjNewtonPreeq) +{ amici::simulateVerifyWrite("/model_steadystate/sensiadjnewtonpreeq/"); } -TEST(groupSteadystate, testSensiFwdSimPreeq) { +TEST(groupSteadystate, testSensiFwdSimPreeq) +{ amici::simulateVerifyWrite("/model_steadystate/sensifwdsimpreeq/"); } -TEST(groupSteadystate, testSensiFwdSimPreeqFSA) { +TEST(groupSteadystate, testSensiFwdSimPreeqFSA) +{ amici::simulateVerifyWrite("/model_steadystate/sensifwdsimpreeqFSA/"); } -TEST(groupSteadystate, testSensiAdjSimPreeq) { +TEST(groupSteadystate, testSensiAdjSimPreeq) +{ amici::simulateVerifyWrite("/model_steadystate/sensiadjsimpreeq/"); } -TEST(groupSteadystate, testSensiAdjSimPreeqFSA) { +TEST(groupSteadystate, testSensiAdjSimPreeqFSA) +{ amici::simulateVerifyWrite("/model_steadystate/sensiadjsimpreeqFSA/"); } -TEST(groupSteadystate, testSensiFwdByhandPreeq) { +TEST(groupSteadystate, testSensiFwdByhandPreeq) +{ amici::simulateVerifyWrite("/model_steadystate/sensifwdbyhandpreeq/"); } -TEST(groupSteadystate, testSensiAdjByhandPreeq) { +TEST(groupSteadystate, testSensiAdjByhandPreeq) +{ amici::simulateVerifyWrite("/model_steadystate/sensiadjbyhandpreeq/"); } diff --git a/deps/AMICI/tests/cpputest/testfunctions.cpp b/deps/AMICI/tests/cpputest/testfunctions.cpp index c2906e757..3a997392e 100644 --- a/deps/AMICI/tests/cpputest/testfunctions.cpp +++ b/deps/AMICI/tests/cpputest/testfunctions.cpp @@ -12,9 +12,13 @@ #include #include +namespace amici { + +namespace generic_model { + extern std::unique_ptr getModel(); -namespace amici { +} // namespace generic_model std::vector getVariableNames(const char* name, int length) { @@ -32,14 +36,14 @@ void simulateVerifyWrite(const std::string& path) simulateVerifyWrite(NEW_OPTION_FILE, HDFFILE, HDFFILEWRITE, path, TEST_ATOL, TEST_RTOL); } -void simulateVerifyWrite(std::string path, double atol, double rtol) +void simulateVerifyWrite(const std::string &path, double atol, double rtol) { simulateVerifyWrite(NEW_OPTION_FILE, HDFFILE, HDFFILEWRITE, std::move(path), atol, rtol); } void simulateWithDefaultOptions() { using namespace amici; - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); std::unique_ptr edata; auto rdata = runAmiciSimulation(*solver, edata.get(), *model); @@ -50,7 +54,7 @@ void simulateVerifyWrite(const std::string& hdffileOptions, const std::string& h using namespace amici; // read options from file std::string optionsPath = path + "/options"; - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); hdf5::readModelDataFromHDF5(hdffileOptions, *model, optionsPath); hdf5::readSolverSettingsFromHDF5(hdffileOptions, *solver, optionsPath); @@ -155,9 +159,9 @@ void checkEqualArrayStrided(const double *expected, const double *actual, int le void verifyReturnData(std::string const& hdffile, std::string const& resultPath, const ReturnData *rdata, const Model *model, double atol, double rtol) { - + CHECK_FALSE(rdata == nullptr); - + if(!hdf5::locationExists(hdffile, resultPath)) { fprintf(stderr, "ERROR: No results available for %s!\n", resultPath.c_str()); @@ -168,7 +172,7 @@ void verifyReturnData(std::string const& hdffile, std::string const& resultPath, H5::H5File file(hdffile, H5F_ACC_RDONLY); hsize_t m, n; - + std::vector expected; auto statusExp = hdf5::getIntScalarAttribute(file, resultPath, "status"); @@ -188,7 +192,7 @@ void verifyReturnData(std::string const& hdffile, std::string const& resultPath, } // CHECK_EQUAL(AMICI_O2MODE_FULL, udata->o2mode); - + if(hdf5::locationExists(file, resultPath + "/diagnosis/J")) { expected = hdf5::getDoubleDataset2D(file, resultPath + "/diagnosis/J", m, n); checkEqualArray(expected, rdata->J, atol, rtol, "J"); diff --git a/deps/AMICI/tests/cpputest/testfunctions.h b/deps/AMICI/tests/cpputest/testfunctions.h index ac07dd2a0..a3d4f3847 100644 --- a/deps/AMICI/tests/cpputest/testfunctions.h +++ b/deps/AMICI/tests/cpputest/testfunctions.h @@ -65,20 +65,20 @@ class Model_Test : public Model { * @param z2event mapping of event outputs to events */ Model_Test(const int nx_rdata, const int nxtrue_rdata, const int nx_solver, - const int nxtrue_solver, const int ny, const int nytrue, - const int nz, const int nztrue, const int ne, const int nJ, - const int nw, const int ndwdx, const int ndwdp, const int ndxdotdw, - const int nnz, const int ubw, const int lbw, + const int nxtrue_solver, const int nx_solver_reinit, const int ny, + const int nytrue, const int nz, const int nztrue, const int ne, + const int nJ, const int nw, const int ndwdx, const int ndwdp, + const int ndxdotdw, const int nnz, const int ubw, const int lbw, const SecondOrderMode o2mode, const std::vector p, const std::vector k, const std::vector plist, const std::vector idlist, const std::vector z2event) - : Model(nx_rdata, nxtrue_rdata, nx_solver, nxtrue_solver, ny, nytrue, nz, + : Model(nx_rdata, nxtrue_rdata, nx_solver, nxtrue_solver, nx_solver_reinit, ny, nytrue, nz, nztrue, ne, nJ, nw, ndwdx, ndwdp, ndxdotdw, {}, nnz, ubw, lbw, o2mode, p, k, plist, idlist, z2event) {} /** default constructor */ Model_Test() - : Model(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, 0, 0, 0, + : Model(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, 0, 0, 0, SecondOrderMode::none, std::vector(), std::vector(), std::vector(), std::vector(), std::vector()) {} @@ -111,6 +111,20 @@ class Model_Test : public Model { const AmiVector &xdot, SUNMatrix J) override { throw AmiException("not implemented"); } + virtual void fJB(const realtype t, realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xB, + const AmiVector &dxB, const AmiVector &xBdot, + SUNMatrix JB) + override { + throw AmiException("not implemented"); + } + virtual void fJSparseB(const realtype t, realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xB, + const AmiVector &dxB, const AmiVector &xBdot, + SUNMatrix JB) + override { + throw AmiException("not implemented"); + } virtual void fJDiag(const realtype t, AmiVector &Jdiag, const realtype cj, const AmiVector &x, const AmiVector &dx) override { @@ -126,6 +140,22 @@ class Model_Test : public Model { throw AmiException("not implemented"); } + virtual void fxBdot_ss(const realtype t, const AmiVector &xB, + const AmiVector &dxB, AmiVector &xBdot) override { + throw AmiException("not implemented"); + } + + virtual void fJSparseB_ss(SUNMatrix JB) override { + throw AmiException("not implemented"); + } + + virtual void writeSteadystateJB(const realtype t, realtype cj, + const AmiVector &x, const AmiVector &dx, + const AmiVector &xB, const AmiVector &dxB, + const AmiVector &xBdot) override { + throw AmiException("not implemented"); + } + virtual std::vector getParameterNames() const override { return getVariableNames("p", np()); @@ -173,7 +203,7 @@ void simulateWithDefaultOptions(); void simulateVerifyWrite(const std::string& path); -void simulateVerifyWrite(std::string path, double atol, double rtol); +void simulateVerifyWrite(std::string const& path, double atol, double rtol); void simulateVerifyWrite(const std::string& hdffileOptions, const std::string& hdffileResults, const std::string& hdffilewrite, const std::string& path, diff --git a/deps/AMICI/tests/cpputest/unittests/tests1.cpp b/deps/AMICI/tests/cpputest/unittests/tests1.cpp index a929af86a..14a303915 100644 --- a/deps/AMICI/tests/cpputest/unittests/tests1.cpp +++ b/deps/AMICI/tests/cpputest/unittests/tests1.cpp @@ -15,12 +15,17 @@ #include "CppUTest/TestHarness.h" #include "CppUTestExt/MockSupport.h" -std::unique_ptr -getModel() +namespace amici { +namespace generic_model { + +std::unique_ptr getModel() { return std::unique_ptr(new amici::Model_Test()); } +} // namespace generic_model +} // namespace amici + using namespace amici; void @@ -36,13 +41,7 @@ testSolverGetterSetters(CVodeSolver solver, double tol, double badtol); -TEST_GROUP(amici){ void setup(){ - -} - - void teardown(){ - - } }; +TEST_GROUP(amici){}; TEST_GROUP(model) { @@ -56,6 +55,7 @@ TEST_GROUP(model) nx, nx, nx, + 0, ny, ny, nz, @@ -283,12 +283,13 @@ TEST_GROUP(edata) int nx = 1, ny = 2, nz = 3, nmaxevent = 4; std::vector timepoints = { 1, 2, 3, 4 }; - std::unique_ptr model = getModel(); + std::unique_ptr model = amici::generic_model::getModel(); Model_Test testModel = Model_Test(nx, nx, nx, nx, + 0, ny, ny, nz, @@ -581,7 +582,7 @@ TEST_GROUP(solver) double tol, badtol; std::vector timepoints = { 1, 2, 3, 4 }; - std::unique_ptr model = getModel(); + std::unique_ptr model = amici::generic_model::getModel(); SensitivityMethod sensi_meth; SensitivityOrder sensi; int steps, badsteps; @@ -594,6 +595,7 @@ TEST_GROUP(solver) nx, nx, nx, + 0, ny, ny, nz, diff --git a/deps/AMICI/tests/cpputest/unittests/testsSerialization.cpp b/deps/AMICI/tests/cpputest/unittests/testsSerialization.cpp index 4e82047f7..14ed09edc 100644 --- a/deps/AMICI/tests/cpputest/unittests/testsSerialization.cpp +++ b/deps/AMICI/tests/cpputest/unittests/testsSerialization.cpp @@ -1,5 +1,5 @@ -#include // needs to be included before cpputest #include +#include // needs to be included before cpputest #include #include "testfunctions.h" @@ -9,12 +9,15 @@ #include "CppUTest/TestHarness.h" #include "CppUTestExt/MockSupport.h" -void checkReturnDataEqual(amici::ReturnData const& r, amici::ReturnData const& s) { +void +checkReturnDataEqual(amici::ReturnData const& r, amici::ReturnData const& s) +{ CHECK_EQUAL(r.np, s.np); CHECK_EQUAL(r.nk, s.nk); CHECK_EQUAL(r.nx, s.nx); CHECK_EQUAL(r.nxtrue, s.nxtrue); CHECK_EQUAL(r.nx_solver, s.nx_solver); + CHECK_EQUAL(r.nx_solver_reinit, s.nx_solver_reinit); CHECK_EQUAL(r.ny, s.ny); CHECK_EQUAL(r.nytrue, s.nytrue); CHECK_EQUAL(r.nz, s.nz); @@ -35,7 +38,7 @@ void checkReturnDataEqual(amici::ReturnData const& r, amici::ReturnData const& s checkEqualArray(r.xdot, s.xdot, 1e-16, 1e-16, "xdot"); checkEqualArray(r.J, s.J, 1e-16, 1e-16, "J"); checkEqualArray(r.z, s.z, 1e-16, 1e-16, "z"); - checkEqualArray(r.sigmaz, s.sigmaz,1e-16, 1e-16, "sigmaz"); + checkEqualArray(r.sigmaz, s.sigmaz, 1e-16, 1e-16, "sigmaz"); checkEqualArray(r.sz, s.sz, 1e-16, 1e-16, "sz"); checkEqualArray(r.ssigmaz, s.ssigmaz, 1e-16, 1e-16, "ssigmaz"); checkEqualArray(r.rz, s.rz, 1e-16, 1e-16, "rz"); @@ -48,7 +51,7 @@ void checkReturnDataEqual(amici::ReturnData const& r, amici::ReturnData const& s checkEqualArray(r.sigmay, s.sigmay, 1e-16, 1e-16, "sigmay"); checkEqualArray(r.sy, s.sy, 1e-16, 1e-16, "sy"); checkEqualArray(r.ssigmay, s.ssigmay, 1e-16, 1e-16, "ssigmay"); - + CHECK_TRUE(r.numsteps == s.numsteps); CHECK_TRUE(r.numstepsB == s.numstepsB); CHECK_TRUE(r.numrhsevals == s.numrhsevals); @@ -60,17 +63,28 @@ void checkReturnDataEqual(amici::ReturnData const& r, amici::ReturnData const& s CHECK_TRUE(r.order == s.order); CHECK_TRUE(r.cpu_time == s.cpu_time); CHECK_TRUE(r.cpu_timeB == s.cpu_timeB); - CHECK_TRUE(r.newton_cpu_time == s.newton_cpu_time); - CHECK_TRUE(r.newton_status == s.newton_status); - CHECK_TRUE(r.newton_numsteps == s.newton_numsteps); - CHECK_TRUE(r.newton_numlinsteps == s.newton_numlinsteps); + CHECK_TRUE(r.preeq_status == s.preeq_status); + CHECK_TRUE(r.preeq_t == s.preeq_t || + (std::isnan(r.preeq_t) && std::isnan(s.preeq_t))); + CHECK_TRUE(r.preeq_wrms == s.preeq_wrms || + (std::isnan(r.preeq_wrms) && std::isnan(s.preeq_wrms))); + CHECK_TRUE(r.preeq_numsteps == s.preeq_numsteps); + CHECK_TRUE(r.preeq_numlinsteps == s.preeq_numlinsteps); + DOUBLES_EQUAL(r.preeq_cpu_time, s.preeq_cpu_time, 1e-16); + + CHECK_TRUE(r.posteq_status == s.posteq_status); + CHECK_TRUE(r.posteq_t == s.posteq_t || + (std::isnan(r.posteq_t) && std::isnan(s.posteq_t))); + CHECK_TRUE(r.posteq_wrms == s.posteq_wrms || + (std::isnan(r.posteq_wrms) && std::isnan(s.posteq_wrms))); + CHECK_TRUE(r.posteq_numsteps == s.posteq_numsteps); + CHECK_TRUE(r.posteq_numlinsteps == s.posteq_numlinsteps); + DOUBLES_EQUAL(r.posteq_cpu_time, s.posteq_cpu_time, 1e-16); - DOUBLES_EQUAL(r.newton_cpu_time, s.newton_cpu_time, 1e-16); checkEqualArray(r.x0, s.x0, 1e-16, 1e-16, "x0"); checkEqualArray(r.sx0, s.sx0, 1e-16, 1e-16, "sx0"); - CHECK_TRUE(r.llh == s.llh || (std::isnan(r.llh) && std::isnan(s.llh))); CHECK_TRUE(r.chi2 == s.chi2 || (std::isnan(r.llh) && std::isnan(s.llh))); CHECK_EQUAL(r.status, s.status); @@ -79,24 +93,23 @@ void checkReturnDataEqual(amici::ReturnData const& r, amici::ReturnData const& s checkEqualArray(r.s2llh, s.s2llh, 1e-5, 1e-5, "s2llh"); } - // clang-format off TEST_GROUP(dataSerialization){ amici::CVodeSolver solver; void setup() { // set non-default values for all members - solver.setAbsoluteTolerance(4); - solver.setRelativeTolerance(4); - solver.setAbsoluteToleranceQuadratures(4); - solver.setRelativeToleranceQuadratures(4); - solver.setAbsoluteToleranceSteadyState(4); - solver.setRelativeToleranceSteadyState(4); + solver.setAbsoluteTolerance(1e-4); + solver.setRelativeTolerance(1e-5); + solver.setAbsoluteToleranceQuadratures(1e-6); + solver.setRelativeToleranceQuadratures(1e-7); + solver.setAbsoluteToleranceSteadyState(1e-8); + solver.setRelativeToleranceSteadyState(1e-9); solver.setSensitivityMethod(amici::SensitivityMethod::adjoint); solver.setSensitivityOrder(amici::SensitivityOrder::second); - solver.setMaxSteps(1e6); - solver.setMaxStepsBackwardProblem(1e6); - solver.setNewtonMaxSteps(1e6); - solver.setNewtonMaxLinearSteps(1e6); + solver.setMaxSteps(1e1); + solver.setMaxStepsBackwardProblem(1e2); + solver.setNewtonMaxSteps(1e3); + solver.setNewtonMaxLinearSteps(1e4); solver.setPreequilibration(true); solver.setStateOrdering(static_cast(amici::SUNLinSolKLU::StateOrdering::COLAMD)); solver.setInterpolationType(amici::InterpolationType::polynomial); @@ -105,6 +118,7 @@ TEST_GROUP(dataSerialization){ solver.setLinearMultistepMethod(amici::LinearMultistepMethod::adams); solver.setNonlinearSolverIteration(amici::NonlinearSolverIteration::newton); solver.setInternalSensitivityMethod(amici::InternalSensitivityMethod::staggered); + solver.setReturnDataReportingMode(amici::RDataReporting::likelihood); } void teardown() { @@ -112,76 +126,114 @@ TEST_GROUP(dataSerialization){ }; // clang-format on - - -TEST(dataSerialization, testFile) { +TEST(dataSerialization, testFile) +{ int np = 1; int nk = 2; int nx = 3; int nz = 4; amici::CVodeSolver solver; - amici::Model_Test m = amici::Model_Test(nx, nx, nx, nx, 4, 4, nz, nz, 8, 9, 10, 11, 12, 13, 14, 15, 16, + amici::Model_Test m = amici::Model_Test(nx, + nx, + nx, + nx, + 0, + 4, + 4, + nz, + nz, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, amici::SecondOrderMode::none, - std::vector(np,0.0), - std::vector(nk,0.0), - std::vector(np,0), - std::vector(nx,0.0), - std::vector(nz,0)); + std::vector(np, 0.0), + std::vector(nk, 0.0), + std::vector(np, 0), + std::vector(nx, 0.0), + std::vector(nz, 0)); { std::ofstream ofs("sstore.dat"); boost::archive::text_oarchive oar(ofs); - //oar & static_cast(solver); - oar & static_cast(m); + // oar & static_cast(solver); + oar& static_cast(m); } { std::ifstream ifs("sstore.dat"); boost::archive::text_iarchive iar(ifs); amici::CVodeSolver v; amici::Model_Test n; - //iar &static_cast(v); - iar &static_cast(n); - //CHECK_TRUE(solver == v); + // iar &static_cast(v); + iar& static_cast(n); + // CHECK_TRUE(solver == v); CHECK_TRUE(m == n); - } } -TEST(dataSerialization, testString) { +TEST(dataSerialization, testString) +{ int np = 1; int nk = 2; int nx = 3; int nz = 4; amici::CVodeSolver solver; - amici::Model_Test m = amici::Model_Test(nx, nx, nx, nx, 4, 4, nz, nz, 8, 9, 10, 11, 12, 13, 14, 15, 16, + amici::Model_Test m = amici::Model_Test(nx, + nx, + nx, + nx, + 0, + 4, + 4, + nz, + nz, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, amici::SecondOrderMode::none, - std::vector(np,0.0), - std::vector(nk,0.0), - std::vector(np,0), - std::vector(nx,0.0), - std::vector(nz,0)); + std::vector(np, 0.0), + std::vector(nk, 0.0), + std::vector(np, 0), + std::vector(nx, 0.0), + std::vector(nz, 0)); amici::ReturnData r(solver, m); std::string serialized = amici::serializeToString(r); - checkReturnDataEqual(r, amici::deserializeFromString(serialized)); + checkReturnDataEqual( + r, amici::deserializeFromString(serialized)); } -TEST(dataSerialization, testChar) { +TEST(dataSerialization, testChar) +{ int length; - char *buf = amici::serializeToChar(solver, &length); + char* buf = amici::serializeToChar(solver, &length); - amici::CVodeSolver v = amici::deserializeFromChar(buf, length); + amici::CVodeSolver v = + amici::deserializeFromChar(buf, length); delete[] buf; CHECK_TRUE(solver == v); } -TEST(dataSerialization, testStdVec) { +TEST(dataSerialization, testStdVec) +{ auto buf = amici::serializeToStdVec(solver); - amici::CVodeSolver v = amici::deserializeFromChar(buf.data(), buf.size()); + amici::CVodeSolver v = + amici::deserializeFromChar(buf.data(), buf.size()); CHECK_TRUE(solver == v); } diff --git a/deps/AMICI/tests/performance/reference.yml b/deps/AMICI/tests/performance/reference.yml index 9152736bf..eae69bc76 100644 --- a/deps/AMICI/tests/performance/reference.yml +++ b/deps/AMICI/tests/performance/reference.yml @@ -1,6 +1,6 @@ # Reference wall times (seconds) with some buffer create_sdist: 25 -install_sdist: 140 +install_sdist: 150 petab_import: 2500 install_model: 470 forward_simulation: 2 @@ -8,3 +8,5 @@ forward_sensitivities: 35 adjoint_sensitivities: 4 forward_simulation_non_optimal_parameters: 2 adjoint_sensitivities_non_optimal_parameters: 5 +forward_steadystate_sensitivities_non_optimal_parameters: 5 +adjoint_steadystate_sensitivities_non_optimal_parameters: 2 diff --git a/deps/AMICI/tests/performance/test.py b/deps/AMICI/tests/performance/test.py index 1a0bc8cad..4e1d07a60 100755 --- a/deps/AMICI/tests/performance/test.py +++ b/deps/AMICI/tests/performance/test.py @@ -18,25 +18,37 @@ def main(): edata.setObservedDataStdDev([1.0]) if arg == 'forward_simulation': - solver.setSensitivityMethod(amici.SensitivityMethod_none) - solver.setSensitivityOrder(amici.SensitivityOrder_none) + solver.setSensitivityMethod(amici.SensitivityMethod.none) + solver.setSensitivityOrder(amici.SensitivityOrder.none) elif arg == 'forward_sensitivities': model.setParameterList(list(range(100))) - solver.setSensitivityMethod(amici.SensitivityMethod_forward) - solver.setSensitivityOrder(amici.SensitivityOrder_first) + solver.setSensitivityMethod(amici.SensitivityMethod.forward) + solver.setSensitivityOrder(amici.SensitivityOrder.first) elif arg == 'adjoint_sensitivities': - solver.setSensitivityMethod(amici.SensitivityMethod_adjoint) - solver.setSensitivityOrder(amici.SensitivityOrder_first) + solver.setSensitivityMethod(amici.SensitivityMethod.adjoint) + solver.setSensitivityOrder(amici.SensitivityOrder.first) elif arg == 'forward_simulation_non_optimal_parameters': tmpPar = model.getParameters() model.setParameters([0.1 for _ in tmpPar]) - solver.setSensitivityMethod(amici.SensitivityMethod_none) - solver.setSensitivityOrder(amici.SensitivityOrder_none) + solver.setSensitivityMethod(amici.SensitivityMethod.none) + solver.setSensitivityOrder(amici.SensitivityOrder.none) elif arg == 'adjoint_sensitivities_non_optimal_parameters': tmpPar = model.getParameters() model.setParameters([0.1 for _ in tmpPar]) - solver.setSensitivityMethod(amici.SensitivityMethod_adjoint) - solver.setSensitivityOrder(amici.SensitivityOrder_first) + solver.setSensitivityMethod(amici.SensitivityMethod.adjoint) + solver.setSensitivityOrder(amici.SensitivityOrder.first) + elif arg == 'forward_steadystate_sensitivities_non_optimal_parameters': + tmpPar = model.getParameters() + model.setParameters([0.1 for _ in tmpPar]) + solver.setSensitivityMethod(amici.SensitivityMethod.forward) + solver.setSensitivityOrder(amici.SensitivityOrder.first) + edata.setTimepoints([float('inf')]) + elif arg == 'adjoint_steadystate_sensitivities_non_optimal_parameters': + tmpPar = model.getParameters() + model.setParameters([0.1 for _ in tmpPar]) + solver.setSensitivityMethod(amici.SensitivityMethod.adjoint) + solver.setSensitivityOrder(amici.SensitivityOrder.first) + edata.setTimepoints([float('inf')]) else: print("Unknown argument:", arg) sys.exit(1) diff --git a/deps/AMICI/tests/testSBMLSuite.py b/deps/AMICI/tests/testSBMLSuite.py index 47b0a7da2..94c3c37fd 100755 --- a/deps/AMICI/tests/testSBMLSuite.py +++ b/deps/AMICI/tests/testSBMLSuite.py @@ -20,6 +20,10 @@ import sympy as sp import pandas as pd +import libsbml + +from typing import List + # directory with sbml semantic test cases TEST_PATH = os.path.join(os.path.dirname(__file__), 'sbml-test-suite', 'cases', @@ -69,15 +73,16 @@ def test_sbml_testsuite_case(test_number, result_path): rdata = amici.runAmiciSimulation(model, solver) # verify - simulated_x = verify_results(settings, rdata, results, wrapper, + simulated_x, x_ids = verify_results(settings, rdata, results, wrapper, model, atol, rtol) print(f'TestCase {test_id} passed.') # record results - write_result_file(simulated_x, model, test_id, result_path) + write_result_file(simulated_x, model, test_id, result_path, x_ids) except amici.sbml_import.SBMLException as err: + #assert False, f"Skipped {test_id}: {err}" print(f'TestCase {test_id} was skipped: {err}') @@ -88,28 +93,133 @@ def verify_results(settings, rdata, results, wrapper, # verify states simulated_x = rdata['x'] - expected_x = results[1:, [ - 1 + wrapper.species_index[variable] - for variable in variables_species - if variable in wrapper.species_index.keys() - ]] - concentrations_to_amounts(amount_species, wrapper, model, simulated_x) + # Add species with assignment rules to the simulated data. + for x_id, x_index in wrapper.species_index.items(): + # Currently assumes that x_id is also an observable. + # Also assumes that observable "species" have the same index in both + # the 'x' and 'y' keys of rdata. + if x_id in [str(s) for s in wrapper.species_assignment_rules]: + simulated_x[:,x_index] = rdata['y'][:,x_index] + + x_ids = [x_id + for x_id in wrapper.species_index + if x_id in variables_species] + x_ids_results_columns = [variables_species.index(x_id) + for x_id in x_ids] + + expected_x = results[1:, [1+c for c in x_ids_results_columns]] + + # SBML test suite case 01308 defines species with initialAmount and + # hasOnlySubstanceUnits="true", but then request results as concentrations. + requested_concentrations = [s + for s in settings['concentration'].replace( + ' ', '').replace('\n', '').split(',') if s] + # The rate rules condition here may be unnecessary/better implemented + # elsewhere. + concentration_species = [species for species in requested_concentrations + if wrapper.species_has_only_substance_units[ + wrapper.species_index[species]] + and species in [str(s) for s in wrapper.species_rate_rules]] + amounts_to_concentrations(concentration_species, wrapper, model, + simulated_x, rdata['y'], requested_concentrations) + + concentrations_to_amounts(amount_species, wrapper, model, + simulated_x, rdata['y'], requested_concentrations) + + # Add observables to the verification. This includes compartments with + # assignment rules, as they are implemented as observables. + # Currently only used for SBML test suite case 01223. + observables = {str(o_id): (o_index, variables_species.index(str(o_id))) + for o_index, o_id in enumerate( + wrapper.symbols['observable']['identifier']) + if str(o_id) in variables_species and ( + str(o_id) not in wrapper.species_index)} + for o_id, indices in observables.items(): + simulated_x = np.hstack((simulated_x, np.array([rdata['y'][:,indices[0]]]).T)) + expected_x = np.hstack((expected_x, np.array([results[1:, 1+indices[1]]]).T)) + x_ids.append(o_id) assert np.isclose(simulated_x, expected_x, atol, rtol).all() # TODO: verify compartment volumes and parameters + # Currently, compartments with assignment and rate rules are verified. + # Compartments with assignment rules are exported as observables, and + # compartments with rate rules are exported as species. - return simulated_x + return simulated_x, x_ids -def concentrations_to_amounts(amount_species, wrapper, model, simulated_x): - """Convert AMICI simulated concentrations to amounts""" +def amounts_to_concentrations( + amount_species, + wrapper, + model, + simulated_x, + simulated_y, + requested_concentrations +): + """ + Convert AMICI simulated amounts to concentrations + Convert from concentration to amount: + C=n/V + n=CV (multiply by V) + Convert from amount to concentration: + n=CV + C=n/V (divide by V) + Dividing by V is equivalent to multiplying the reciprocal by V, then taking + the reciprocal. + This allows for the reuse of the concentrations_to_amounts method... + """ for species in amount_species: if not species == '': + simulated_x[:, wrapper.species_index[species]] = \ + 1 / simulated_x[:, wrapper.species_index[species]] + concentrations_to_amounts([species], wrapper, model, simulated_x, + simulated_y, requested_concentrations) + simulated_x[:, wrapper.species_index[species]] = \ + 1 / simulated_x[:, wrapper.species_index[species]] + + +def concentrations_to_amounts( + amount_species, + wrapper, + model, + simulated_x, + simulated_y, + requested_concentrations +): + """Convert AMICI simulated concentrations to amounts""" + for species in amount_species: + # Skip "species" that are actually compartments + if not species == '' \ + and species not in [ + str(c) for c in wrapper.compartment_symbols] \ + and species not in ( + set([str(s) for s in wrapper.species_rate_rules + if wrapper.species_has_only_substance_units[ + wrapper.species_index[str(s)]] + ]).difference(requested_concentrations) + ): symvolume = wrapper.species_compartment[ wrapper.species_index[species] ] + + # Volumes are already reported for compartments with rate rules + if symvolume in wrapper.compartment_rate_rules: + simulated_x[:, wrapper.species_index[species]] = \ + simulated_x[:, wrapper.species_index[species]] * \ + simulated_x[:, wrapper.species_index[str(symvolume)]] + continue + + # Volumes are reported as observables for compartments with + # assignment rules + if symvolume in wrapper.compartment_assignment_rules: + simulated_x[:, wrapper.species_index[species]] = \ + simulated_x[:, wrapper.species_index[species]] * \ + simulated_y[:, model.getObservableIds().index( + str(symvolume))] + continue + volume = symvolume.subs({ comp: vol for comp, vol in zip( @@ -140,7 +250,7 @@ def concentrations_to_amounts(amount_species, wrapper, model, simulated_x): def write_result_file(simulated_x: np.array, model: amici.Model, - test_id: str, result_path: str): + test_id: str, result_path: str, x_ids: List[str]): """ Create test result file for upload to http://sbml.org/Facilities/Database/Submission/Create @@ -152,7 +262,7 @@ def write_result_file(simulated_x: np.array, filename = os.path.join(result_path, f'{test_id}.csv') df = pd.DataFrame(simulated_x) - df.columns = model.getStateIds() + df.columns = x_ids df.insert(0, 'time', model.getTimepoints()) df.to_csv(filename, index=False) diff --git a/deps/AMICI/version.txt b/deps/AMICI/version.txt index e831019fd..bc859cbd6 100644 --- a/deps/AMICI/version.txt +++ b/deps/AMICI/version.txt @@ -1 +1 @@ -0.10.21 +0.11.2 diff --git a/doc/dataFormatForHDF5generation.md b/doc/dataFormatForHDF5generation.md deleted file mode 100644 index d177f05e9..000000000 --- a/doc/dataFormatForHDF5generation.md +++ /dev/null @@ -1,18 +0,0 @@ -# Description of input format for misc/generateHDF5DataFileFromText.py - -This document describes the input data for -`misc/generateHDF5DataFileFromText.py`, which generates HDF5 files for -parameter estimation. - -For usage of the conversion scripts, run `misc/generateHDF5DataFileFromText.py` -without any arguments. - -Required inputs are: -- the SBML model -- the folder of the corresponding python-AMICI generated model -- a text file with condition specific parameters -- a text file the measurements to be used for model training -- a text file describing optimization parameters - -The SBML model and text files are expected to adhere to the -[PEtab format](https://github.com/ICB-DCM/PEtab/blob/master/doc/documentation_data_format.md) diff --git a/doc/requirements_doc.txt b/doc/requirements_doc.txt index 778538abe..9913deeec 100644 --- a/doc/requirements_doc.txt +++ b/doc/requirements_doc.txt @@ -4,4 +4,4 @@ sphinx_rtd_theme breathe exhale IPython -m2r +m2r @ git+https://github.com/crossnox/m2r@dev#egg=m2r diff --git a/doc/usage.rst b/doc/usage.rst index 201101a3d..49df5562c 100644 --- a/doc/usage.rst +++ b/doc/usage.rst @@ -11,4 +11,3 @@ Usage petab_model_import.md snakemake_workflow.md standaloneSimulator.md - dataFormatForHDF5generation.md diff --git a/examples/parpeamici/CMakeLists.txt b/examples/parpeamici/CMakeLists.txt index 1fb463a87..84d124b19 100644 --- a/examples/parpeamici/CMakeLists.txt +++ b/examples/parpeamici/CMakeLists.txt @@ -1,5 +1,14 @@ find_package(Amici HINTS ${CMAKE_SOURCE_DIR}/deps/AMICI/build) +# create python virtual environment +add_custom_target(rebuild_amici) +add_custom_command( + TARGET rebuild_amici PRE_BUILD + COMMENT "Rebuilding AMICI..." + COMMAND sh -c "${CMAKE_SOURCE_DIR}/misc/rebuild_amici.sh ${CMAKE_BINARY_DIR}" + SOURCES ${CMAKE_SOURCE_DIR}/deps/AMICI/.gitrepo) + + # create python virtual environment add_custom_target(setup_venv) add_custom_command( @@ -8,6 +17,7 @@ add_custom_command( COMMAND sh -c "${CMAKE_SOURCE_DIR}/misc/venv.sh ${CMAKE_BINARY_DIR}" SOURCES ${CMAKE_SOURCE_DIR}/misc/venv.sh) + if(${BUILD_TESTING}) add_test ( NAME "parpe_python_package_tests" diff --git a/examples/parpeamici/steadystate/CMakeLists.txt b/examples/parpeamici/steadystate/CMakeLists.txt index 17a870202..49b633f1e 100644 --- a/examples/parpeamici/steadystate/CMakeLists.txt +++ b/examples/parpeamici/steadystate/CMakeLists.txt @@ -66,28 +66,6 @@ target_link_libraries(${PROJECT_NAME} ) # /example_steadystate executable -# example_steadystate_parallel executable -if(${PARPE_ENABLE_MPI}) - project(example_steadystate_parallel) - - set(SRC_LIST_EXE_PARALLEL - main_parallel.cpp - steadystateProblem.cpp - steadystateProblemParallel.cpp - steadyStateMultiConditionDataprovider.cpp - ) - - add_executable(${PROJECT_NAME} ${SRC_LIST_EXE_PARALLEL}) - add_dependencies(${PROJECT_NAME} ${MODEL_NAME}) - target_link_libraries(${PROJECT_NAME} - ${MODEL_LIBRARIES} - parpeoptimization - parpeloadbalancer - parpeamici - ) -endif() -# /example_steadystate_parallel executable - # example_steadystate_multi executable project(example_steadystate_multi) @@ -113,10 +91,10 @@ install(TARGETS ${PROJECT_NAME} EXPORT ParPETargets ) if("${BUILD_TESTING}" AND ${PARPE_ENABLE_MPI}) - add_test (NAME ${PROJECT_NAME} + add_test (NAME pytest_steadystate_example COMMAND ${CMAKE_SOURCE_DIR}/misc/run_in_venv.sh ${CMAKE_BINARY_DIR}/venv - pytest ${CMAKE_CURRENT_LIST_DIR}/test_steadystate.py + pytest -vv ${CMAKE_CURRENT_LIST_DIR}/test_steadystate.py WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) endif() diff --git a/examples/parpeamici/steadystate/createSteadystateExampleSBML.py b/examples/parpeamici/steadystate/createSteadystateExampleSBML.py index 210b8bc9a..c3f5ad195 100755 --- a/examples/parpeamici/steadystate/createSteadystateExampleSBML.py +++ b/examples/parpeamici/steadystate/createSteadystateExampleSBML.py @@ -119,17 +119,17 @@ def create_model(): c1.setSpatialDimensions(3) c1.setUnits('litre') - s1 = create_species(model, 'x1', 'c1', False, 0.1) - s2 = create_species(model, 'x2', 'c1', False, 0.4) - s3 = create_species(model, 'x3', 'c1', False, 0.7) + create_species(model, 'x1', 'c1', False, 0.1) + create_species(model, 'x2', 'c1', False, 0.4) + create_species(model, 'x3', 'c1', False, 0.7) #TODO: initial amounts should be parameters - p1 = create_parameter(model, 'p1', True, 1.0, 'litre2_per_mole_per_second') - p2 = create_parameter(model, 'p2', True, 0.5, 'litre2_per_mole_per_second') - p3 = create_parameter(model, 'p3', True, 0.4, 'litre_per_second') - p4 = create_parameter(model, 'p4', True, 2.0, 'litre_per_second') - p5 = create_parameter(model, 'p5', True, 0.1, 'mole_per_second') - k0 = create_parameter(model, 'k0', True, 1.0, 'litre_per_second') + create_parameter(model, 'p1', True, 1.0, 'litre2_per_mole_per_second') + create_parameter(model, 'p2', True, 0.5, 'litre2_per_mole_per_second') + create_parameter(model, 'p3', True, 0.4, 'litre_per_second') + create_parameter(model, 'p4', True, 2.0, 'litre_per_second') + create_parameter(model, 'p5', True, 0.1, 'mole_per_second') + create_parameter(model, 'k0', True, 1.0, 'litre_per_second') create_reaction(model, 'r1', [(2, 'x1')], [(1, 'x2')], 'p1 * x1^2') diff --git a/examples/parpeamici/steadystate/create_steadystate_amici_model.py b/examples/parpeamici/steadystate/create_steadystate_amici_model.py index 4855d0a5c..c03e28bb1 100755 --- a/examples/parpeamici/steadystate/create_steadystate_amici_model.py +++ b/examples/parpeamici/steadystate/create_steadystate_amici_model.py @@ -187,7 +187,7 @@ def create_data_tables(model, condition_df): print('Model parameters:', model_parameters) # simulate condition - rdata = getReturnDataForCondition( + rdata = get_return_data_for_condition( model, solver, condition_parameters, model_parameters, sigmay, sigma_parameter_observable_idx, @@ -208,10 +208,10 @@ def create_data_tables(model, condition_df): return measurement_df, true_parameters, expected_llh -def getReturnDataForCondition(model, solver, fixed_parameters, - dynamic_parameters, sigmay, - sigma_parameter_observable_idx, - sigma_parameter_idx): +def get_return_data_for_condition(model, solver, fixed_parameters, + dynamic_parameters, sigmay, + sigma_parameter_observable_idx, + sigma_parameter_idx): model.setParameters(amici.DoubleVector(dynamic_parameters)) @@ -338,9 +338,6 @@ def create_parameter_table(problem: petab.Problem, nominal_parameters): """Create PEtab parameter table""" - # FIXME - #df = problem.create_parameter_df(include_optional=True, lower_bound=1e-3, - # upper_bound=1e5) df = petab.create_parameter_df( problem.sbml_model, problem.condition_df, problem.observable_df, problem.measurement_df, @@ -351,8 +348,6 @@ def create_parameter_table(problem: petab.Problem, df.loc['offset_x2_batch_0', 'hierarchicalOptimization'] = 1 df.loc['offset_x2_batch_1', 'hierarchicalOptimization'] = 1 df.loc['x1withsigma_sigma', 'hierarchicalOptimization'] = 1 - #df.parameterScale = 'lin' - #df.estimate = 0 for pid, val in nominal_parameters.items(): if pid in df.index: @@ -529,10 +524,10 @@ def main(): write_starting_points(args.hdf5_file_name, true_parameters) - # TODO - #hdf5FileMinibatch = 'example_data_minibatch.h5' - #from shutil import copyfile - #copyfile(hdf5_file_name, hdf5FileMinibatch) + hdf5_file_minibatch = os.path.join(os.path.dirname(args.hdf5_file_name), + 'example_data_minibatch.h5') + from shutil import copyfile + copyfile(args.hdf5_file_name, hdf5_file_minibatch) if __name__ == '__main__': diff --git a/examples/parpeamici/steadystate/exampleSteadystateScaledTest.h b/examples/parpeamici/steadystate/exampleSteadystateScaledTest.h index 02b6cfcf2..e98eb37ba 100644 --- a/examples/parpeamici/steadystate/exampleSteadystateScaledTest.h +++ b/examples/parpeamici/steadystate/exampleSteadystateScaledTest.h @@ -20,11 +20,6 @@ class steadystateProblemTests : public ::testing::Test { protected: - void SetUp() override { - } - - void TearDown() override { - } /* const std::vector t { 1.0e8 }; @@ -57,7 +52,7 @@ TEST_F(steadystateProblemTests, testSteadystate) { /* Verify steadystate matches saved results and loglikelihood is correct */ // verify steadystate - auto model = getModel(); + auto model = amici::generic_model::getModel(); model->setTimepoints(t); model->setParameterById("observableParameter1_obs_x1_scaled", 2.0); model->setParameterById("observableParameter1_obs_x2_offsetted", 3.0); @@ -68,7 +63,8 @@ TEST_F(steadystateProblemTests, testSteadystate) { // verify steadystate concentrations parpe::checkEqualArray(xSteadystateExp.data(), rdata->x.data(), - xSteadystateExp.size(), 1e-5, 1e-5); + static_cast(xSteadystateExp.size()), + 1e-5, 1e-5); // verify likelihood for matching measurement / simulation amici::ExpData edata {*model}; @@ -76,7 +72,7 @@ TEST_F(steadystateProblemTests, testSteadystate) { edata.setObservedDataStdDev(std::vector(yExp.size(), 1.0)); rdata = amici::runAmiciSimulation(*solver, &edata, *model); - EXPECT_EQ(rdata->status, AMICI_SUCCESS); + EXPECT_EQ(rdata->status, amici::AMICI_SUCCESS); EXPECT_NEAR(1e-5, rdata->chi2, 1e-5); EXPECT_NEAR(parpe::getLogLikelihoodOffset(edata.nt() * edata.nytrue()), @@ -84,7 +80,7 @@ TEST_F(steadystateProblemTests, testSteadystate) { } TEST_F(steadystateProblemTests, testSteadystateMultiCond) { - auto model = getModel(); + auto model = amici::generic_model::getModel(); auto modelNonOwning = model.get(); // Set output parameters which are not part of amici model model->setParameterById("observableParameter1_obs_x1_scaled", 2.0); @@ -99,23 +95,23 @@ TEST_F(steadystateProblemTests, testSteadystateMultiCond) { parpe::MultiConditionDataProviderDefault dp(std::move(model), modelNonOwning->getSolver()); - dp.edata.push_back(amici::ExpData(*modelNonOwning)); - dp.edata[0].fixedParameters = modelNonOwning->getFixedParameters(); - dp.edata[0].setObservedData(yExp); - dp.edata[0].setObservedDataStdDev(std::vector(yExp.size(), 1.0)); + dp.edata_.push_back(amici::ExpData(*modelNonOwning)); + dp.edata_[0].fixedParameters = modelNonOwning->getFixedParameters(); + dp.edata_[0].setObservedData(yExp); + dp.edata_[0].setObservedDataStdDev(std::vector(yExp.size(), 1.0)); //parpe::AmiciSummedGradientFunction(&dp, nullptr); parpe::MultiConditionProblem problem(&dp); double cost; - problem.costFun->evaluate(p, cost, gsl::span()); + problem.cost_fun_->evaluate(p, cost, gsl::span()); EXPECT_NEAR(-parpe::getLogLikelihoodOffset( - dp.edata[0].getObservedData().size()), cost, 1e-5); + dp.edata_[0].getObservedData().size()), cost, 1e-5); } TEST_F(steadystateProblemTests, testSteadystateHierarchical) { // introduce scaling parameters - auto model = getModel(); + auto model = amici::generic_model::getModel(); //model->setFixedParameters(k); model->setInitialStates(x0); //model->setParameters(p); @@ -130,10 +126,10 @@ TEST_F(steadystateProblemTests, testSteadystateHierarchical) { yScaledExp[offsettedObservableIdx] = offsetExp + yExp[1]; parpe::MultiConditionDataProviderDefault dp(std::move(model), modelNonOwning->getSolver()); // x0? - dp.edata.push_back(amici::ExpData(*modelNonOwning)); - dp.edata[0].fixedParameters = modelNonOwning->getFixedParameters(); - dp.edata[0].setObservedData(yScaledExp); - dp.edata[0].setObservedDataStdDev(std::vector(yExp.size(), 1.0)); + dp.edata_.push_back(amici::ExpData(*modelNonOwning)); + dp.edata_[0].fixedParameters = modelNonOwning->getFixedParameters(); + dp.edata_[0].setObservedData(yScaledExp); + dp.edata_[0].setObservedDataStdDev(std::vector(yExp.size(), 1.0)); //parpe::MultiConditionProblem problem(&dp); @@ -154,7 +150,7 @@ TEST_F(steadystateProblemTests, testSteadystateHierarchical) { auto sigmas = std::make_unique(); auto gradFun = std::make_unique(&dp, nullptr, nullptr); - parpe::HierarchicalOptimizationWrapper hier(std::move(gradFun), + parpe::HierarchicalOptimizationWrapper hier(gradFun.get(), std::move(scalings), std::move(offsets), std::move(sigmas), diff --git a/examples/parpeamici/steadystate/main_multicondition.cpp b/examples/parpeamici/steadystate/main_multicondition.cpp index cd9fc8230..59f3d1486 100644 --- a/examples/parpeamici/steadystate/main_multicondition.cpp +++ b/examples/parpeamici/steadystate/main_multicondition.cpp @@ -49,7 +49,7 @@ class SteadystateApplication : public parpe::OptimizationApplication { logParPEVersion(file_id); dataProvider = std::make_unique( - getModel(), inFileArgument); + amici::generic_model::getModel(), inFileArgument); // read options from file auto optimizationOptions = parpe::OptimizationOptions::fromHDF5(dataProvider->getHdf5FileId()); diff --git a/examples/parpeamici/steadystate/main_parallel.cpp b/examples/parpeamici/steadystate/main_parallel.cpp deleted file mode 100644 index 0da3a9924..000000000 --- a/examples/parpeamici/steadystate/main_parallel.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "steadystateProblemParallel.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -/** @file - * - * This example demonstrates the use of the loadbalancer / queue for parallel - * ODE simulation. - */ - -void initMPI(int *argc, char ***argv); - -int main(int argc, char **argv) { - int status = 0; - - initMPI(&argc, &argv); - - if(argc != 2) { - std::cerr<<"Error: wrong number of arguments. Exactly one argument for data file expected."; - MPI_Finalize(); - return EXIT_FAILURE; - } - std::string dataFileName = argv[1]; - - parpe::initHDF5Mutex(); - - int commSize; - MPI_Comm_size(MPI_COMM_WORLD, &commSize); - - // optimizationOptions.optimizer = parpe::OPTIMIZER_IPOPT; - // optimizationOptions.printToStdout = true; - // optimizationOptions.maxOptimizerIterations = 10; - - if (commSize == 1) { - // run in serial mode - ExampleSteadystateGradientFunctionParallel costFun{nullptr, dataFileName}; - ExampleSteadystateProblem problem {dataFileName}; - status = getLocalOptimum(&problem); - - } else { - // run in parallel - - int mpiRank; - MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); - - if (mpiRank == 0) { - parpe::LoadBalancerMaster lbm; - lbm.run(); - - ExampleSteadystateProblem problem {dataFileName}; - problem.costFun.reset(new ExampleSteadystateGradientFunctionParallel(&lbm, dataFileName)); - - status = parpe::getLocalOptimum(&problem); - - lbm.terminate(); - lbm.sendTerminationSignalToAllWorkers(); - } else { - ExampleSteadystateGradientFunctionParallel costFun{nullptr, dataFileName}; - parpe::LoadBalancerWorker lbw; - lbw.run([&costFun](std::vector &buffer, int jobId) { costFun.messageHandler(buffer, jobId); }); - } - } - - MPI_Finalize(); - - return status; -} - -void initMPI(int *argc, char ***argv) { - int mpiErr = MPI_Init(argc, argv); - if (mpiErr != MPI_SUCCESS) { - parpe::logmessage(parpe::LOGLVL_CRITICAL, "Problem initializing MPI. Exiting."); - exit(1); - } - - int mpiRank; - MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); - if (mpiRank == 0) { - int commSize; - MPI_Comm_size(MPI_COMM_WORLD, &commSize); - - parpe::logmessage(parpe::LOGLVL_INFO, "Running with %d MPI processes.", commSize); - } -} diff --git a/examples/parpeamici/steadystate/main_simulator.cpp b/examples/parpeamici/steadystate/main_simulator.cpp index 1eaa990fa..23ebfa3e9 100644 --- a/examples/parpeamici/steadystate/main_simulator.cpp +++ b/examples/parpeamici/steadystate/main_simulator.cpp @@ -14,88 +14,73 @@ #include #endif +namespace amici::generic_model { std::unique_ptr getModel(); +} + void printUsage() { std::cerr<<"Error: wrong number of arguments.\n"; std::cerr<<"Usage: ... CONDITION_FILE_NAME CONDITION_FILE_PATH " - "[PARAMETER_FILE_NAME PARAMETER_FILE_PATH] " - "OUTFILENAME OUTFILEPATH " - "--at-optimum|--along-trajectory " - "--mpi|--nompi\n"; + "PARAMETER_FILE_NAME PARAMETER_FILE_PATH " + "OUTFILENAME OUTFILEPATH " + "--at-optimum|--along-trajectory|--nominal " + "--mpi|--nompi --compute-inner|--nocompute-inner\n"; // |--parameter-matrix=PATH-UNSUPPORTED } int main(int argc, char **argv) { int status = EXIT_SUCCESS; - if(argc != 7 && argc != 9) { + if(argc != 10) { printUsage(); return EXIT_FAILURE; } + bool computeInner; + if(std::string(argv[argc -1]) == "--compute-inner") { + computeInner = true; + } else if(std::string(argv[argc -1]) == "--nocompute-inner") { + computeInner = false; + } else { + printUsage(); + return EXIT_FAILURE; + } - if(std::string(argv[argc -1]) == "--mpi") { + if(std::string(argv[argc -2]) == "--mpi") { #ifdef PARPE_ENABLE_MPI MPI_Init(&argc, &argv); #else throw std::runtime_error("parPE was built without MPI support."); #endif - } else if(std::string(argv[argc -1]) == "--nompi") { + } else if(std::string(argv[argc -2]) == "--nompi") { ; } else { printUsage(); return EXIT_FAILURE; } - if(argc == 7) { - std::string dataFileName = argv[1]; - std::string dataFilePath = argv[2]; - std::string resultFileName = argv[3]; - std::string resultPath = argv[4]; - std::string simulationMode = argv[5]; - - // TODO: testing-only remove result file - remove(resultFileName.c_str()); - - SteadyStateMultiConditionDataProvider dp(getModel(), dataFileName, dataFilePath + "/inputData"); - - status = parpe::runSimulator(dp, simulationMode, - dataFileName, dataFilePath, - dataFileName, dataFilePath, - resultFileName, resultPath); - } else if(argc == 9) { - // simulate on test set: need optimizer result and test set data as inputs - std::string conditionFileName = argv[1]; - std::string conditionFilePath = argv[2]; - std::string parameterFileName = argv[3]; - std::string parameterFilePath = argv[4]; - std::string resultFileName = argv[5]; - std::string resultPath = argv[6]; - std::string simulationMode = argv[7]; - - // TODO: testing-only remove result file - remove(resultFileName.c_str()); - - auto dpPath = conditionFilePath; - { - // check if this is a result file or a new input file - // TODO: this should be handled cleaner - auto file = parpe::hdf5OpenForReading(conditionFileName); - if(parpe::hdf5GroupExists( - file.getId(), - (conditionFilePath + "/inputData").c_str())) - dpPath = conditionFilePath + "/inputData"; - } - - SteadyStateMultiConditionDataProvider dp( - getModel(), conditionFileName, dpPath); - - status = parpe::runSimulator(dp, simulationMode, - conditionFileName, conditionFilePath, - parameterFileName, parameterFilePath, - resultFileName, resultPath); - } + // simulate on test set: need optimizer result and test set data as inputs + std::string conditionFileName = argv[1]; + std::string conditionFilePath = argv[2]; + std::string parameterFileName = argv[3]; + std::string parameterFilePath = argv[4]; + std::string resultFileName = argv[5]; + std::string resultPath = argv[6]; + std::string simulationMode = argv[7]; + + // TODO: testing-only remove result file + remove(resultFileName.c_str()); + + SteadyStateMultiConditionDataProvider dp( + amici::generic_model::getModel(), + conditionFileName, + conditionFilePath); + + status = parpe::runSimulator(dp, simulationMode, + conditionFileName, conditionFilePath, + parameterFileName, parameterFilePath, + resultFileName, resultPath, computeInner); parpe::finalizeMpiIfNeeded(); diff --git a/examples/parpeamici/steadystate/parpeExampleSteadystateBasic.ipynb b/examples/parpeamici/steadystate/parpeExampleSteadystateBasic.ipynb index 9920da6bd..5b6cf54e1 100644 --- a/examples/parpeamici/steadystate/parpeExampleSteadystateBasic.ipynb +++ b/examples/parpeamici/steadystate/parpeExampleSteadystateBasic.ipynb @@ -13,7 +13,7 @@ "This notebook requires:\n", "\n", "* a successful *parPE* with CMake options `BUILD_EXAMPLES=ON` (default).\n", - "* an installation of the *parPE* Python package (`${PARPE_SOURCE_DIR}/python/`) \n", + "* an installation of the *parPE* Python package (`${PARPE_SOURCE_DIR}/python/`)\n", " in the Python environment in which this notebook is run (ideally the `build/venv/` virtual environment)\n", "\n", "This notebook assumes that this file is used from its default location and that *parPE* was built inside `${PARPE_SOURCE_DIR}/build/`. If this is not the case, adapt `parpe_source_root` and `parpe_build_root` in the following block correspondingly." @@ -21,7 +21,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ @@ -37,51 +37,53 @@ "\n", "# set paths\n", "parpe_source_root = os.path.abspath('../../../')\n", - "parpe_build_root = os.path.join(parpe_source_root, 'build') \n", + "parpe_build_root = os.path.join(parpe_source_root, 'build')\n", "\n", "model_source_dir = f'{parpe_build_root}/examples/parpeamici/steadystate/steadystate_scaled-prefix/src/steadystate_scaled/model_steadystate_scaled'\n", "example_binary_dir = f'{parpe_build_root}/examples/parpeamici/steadystate/'\n", "example_data_dir = f'{parpe_build_root}/examples/parpeamici/steadystate/steadystate_scaled-prefix/src/steadystate_scaled'\n", - "optimizationOptionsPy = f'{parpe_source_root}/misc/optimizationOptions.py'" + "optimization_options_py = f'{parpe_source_root}/misc/optimizationOptions.py'\n", + "\n", + "# MPI launcher and options\n", + "mpiexec = \"mpiexec -n 4 --allow-run-as-root --oversubscribe\"" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[ 9%] Built target parpecommon\n", - "[ 13%] Built target parpeloadbalancer\n", - "[ 23%] Built target parpeoptimization\n", - "[ 35%] Built target parpeamici\n", - "[ 36%] Built target parpe\n", - "-- Found Git: /usr/bin/git (found version \"2.20.1\") \n", - "-- Building version parPE-v0.4.2-12-g8d230-dirty\n", - "[ 36%] Built target get_version\n", - "[ 42%] Built target unittests_common\n", - "[ 47%] Built target unittests_loadbalancer\n", - "[ 54%] Built target unittests_optimization\n", - "\u001b[34m\u001b[1mSetting up virtual environment...\u001b[0m\n", - "[ 54%] Built target setup_venv\n", - "[ 55%] \u001b[34m\u001b[1mCreating test data using hierarchicalOptimizationTest.py\u001b[0m\n", - "...\n", - "----------------------------------------------------------------------\n", - "Ran 3 tests in 0.000s\n", - "\n", - "OK\n", - "[ 55%] Built target prepare_test_hierarchical_optimization\n", - "[ 63%] Built target unittests_amici\n", - "[ 65%] Built target example_loadbalancer\n", - "[ 76%] Built target steadystate_scaled\n", - "[ 79%] Built target example_steadystate_multi_simulator\n", - "[ 85%] Built target example_steadystate_parallel\n", - "[ 89%] Built target example_steadystate_multi\n", - "[ 92%] Built target example_steadystate\n", - "[100%] Built target test_steadystate\n" + "-- Found Git: /usr/bin/git (found version \"2.25.1\") \r\n", + "-- Building version parPE-v0.4.3-37-g5bf1-dirty\r\n", + "[ 0%] Built target get_version\r\n", + "[ 10%] Built target parpecommon\r\n", + "[ 21%] Built target parpeoptimization\r\n", + "[ 25%] Built target parpeloadbalancer\r\n", + "[ 37%] Built target parpeamici\r\n", + "[ 39%] Built target parpe\r\n", + "[ 45%] Built target unittests_common\r\n", + "[ 50%] Built target unittests_loadbalancer\r\n", + "[ 58%] Built target unittests_optimization\r\n", + "\u001B[34m\u001B[1mSetting up virtual environment...\u001B[0m\r\n", + "[ 58%] Built target setup_venv\r\n", + "[ 59%] \u001B[34m\u001B[1mCreating test data using hierarchicalOptimizationTest.py\u001B[0m\r\n", + "...\r\n", + "----------------------------------------------------------------------\r\n", + "Ran 3 tests in 0.000s\r\n", + "\r\n", + "OK\r\n", + "[ 59%] Built target prepare_test_hierarchical_optimization\r\n", + "[ 67%] Built target unittests_amici\r\n", + "[ 69%] Built target example_loadbalancer\r\n", + "[ 81%] Built target steadystate_scaled\r\n", + "[ 84%] Built target example_steadystate\r\n", + "[ 88%] Built target example_steadystate_multi\r\n", + "[ 92%] Built target example_steadystate_multi_simulator\r\n", + "[100%] Built target test_steadystate\r\n" ] } ], @@ -92,33 +94,179 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\u001b[36mRunning tests...\u001b[0m\n", - "Test project /home/dweindl/src/parPE_2/build\n", - " Start 1: unittests_common\n", - "1/7 Test #1: unittests_common ................. Passed 0.32 sec\n", - " Start 2: unittests_loadbalancer\n", - "2/7 Test #2: unittests_loadbalancer ........... Passed 0.01 sec\n", - " Start 3: unittests_optimization\n", - "3/7 Test #3: unittests_optimization ........... Passed 2.16 sec\n", - " Start 4: unittests_amici\n", - "4/7 Test #4: unittests_amici .................. Passed 0.02 sec\n", - " Start 5: example_loadbalancer\n", - "5/7 Test #5: example_loadbalancer ............. Passed 0.39 sec\n", - " Start 6: example_steadystate_multi\n", - "6/7 Test #6: example_steadystate_multi ........ Passed 8.51 sec\n", - " Start 7: test_steadystate\n", - "7/7 Test #7: test_steadystate ................. Passed 0.07 sec\n", - "\n", - "100% tests passed, 0 tests failed out of 7\n", - "\n", - "Total Test time (real) = 11.50 sec\n" + "\u001B[36mRunning tests...\u001B[0m\r\n", + "Test project /home/dweindl/src/parPE_2/build\r\n", + " Start 1: testingMisc.testTenToMinusInf\r\n", + " 1/80 Test #1: testingMisc.testTenToMinusInf .................................................. Passed 0.00 sec\r\n", + " Start 2: testingMisc.testWithinTolerance\r\n", + " 2/80 Test #2: testingMisc.testWithinTolerance ................................................ Passed 0.00 sec\r\n", + " Start 3: testingMisc.testCheckEqualArray\r\n", + " 3/80 Test #3: testingMisc.testCheckEqualArray ................................................ Passed 0.00 sec\r\n", + " Start 4: testingMisc.testRandInt\r\n", + " 4/80 Test #4: testingMisc.testRandInt ........................................................ Passed 0.01 sec\r\n", + " Start 5: commonMisc.testBacktrace\r\n", + " 5/80 Test #5: commonMisc.testBacktrace ....................................................... Passed 0.00 sec\r\n", + " Start 6: commonMisc.testFilexists\r\n", + " 6/80 Test #6: commonMisc.testFilexists ....................................................... Passed 0.00 sec\r\n", + " Start 7: commonMisc.testCreateDirectoryIfNotExists\r\n", + " 7/80 Test #7: commonMisc.testCreateDirectoryIfNotExists ...................................... Passed 0.00 sec\r\n", + " Start 8: commonMisc.testRecursiveMkpath\r\n", + " 8/80 Test #8: commonMisc.testRecursiveMkpath ................................................. Passed 0.00 sec\r\n", + " Start 9: commonMisc.testRandDouble\r\n", + " 9/80 Test #9: commonMisc.testRandDouble ...................................................... Passed 0.01 sec\r\n", + " Start 10: commonMisc.testFillArrayRandomDoubleSameInterval\r\n", + "10/80 Test #10: commonMisc.testFillArrayRandomDoubleSameInterval ............................... Passed 0.00 sec\r\n", + " Start 11: commonMisc.testFillArrayRandomDoubleIndividualInterval\r\n", + "11/80 Test #11: commonMisc.testFillArrayRandomDoubleIndividualInterval ......................... Passed 0.01 sec\r\n", + " Start 12: commonMisc.testMpi\r\n", + "12/80 Test #12: commonMisc.testMpi ............................................................. Passed 0.30 sec\r\n", + " Start 13: commonMisc.runInParallelAndWaitForFinish\r\n", + "13/80 Test #13: commonMisc.runInParallelAndWaitForFinish ....................................... Passed 0.01 sec\r\n", + " Start 14: commonMisc.strFormatCurrentLocaltime\r\n", + "14/80 Test #14: commonMisc.strFormatCurrentLocaltime ........................................... Passed 0.00 sec\r\n", + " Start 15: logging.printDebugInfoAndWait\r\n", + "15/80 Test #15: logging.printDebugInfoAndWait .................................................. Passed 0.01 sec\r\n", + " Start 16: logging.misc\r\n", + "16/80 Test #16: logging.misc ................................................................... Passed 0.00 sec\r\n", + " Start 17: logging.printMPIInfo\r\n", + "17/80 Test #17: logging.printMPIInfo ........................................................... Passed 0.00 sec\r\n", + " Start 18: logging.logProcessStats\r\n", + "18/80 Test #18: logging.logProcessStats ........................................................ Passed 0.01 sec\r\n", + " Start 19: costFunction.mseZero\r\n", + "19/80 Test #19: costFunction.mseZero ........................................................... Passed 0.01 sec\r\n", + " Start 20: costFunction.mseNonzero\r\n", + "20/80 Test #20: costFunction.mseNonzero ........................................................ Passed 0.01 sec\r\n", + " Start 21: costFunction.linearModel\r\n", + "21/80 Test #21: costFunction.linearModel ....................................................... Passed 0.00 sec\r\n", + " Start 22: costFunction.linearModel2\r\n", + "22/80 Test #22: costFunction.linearModel2 ...................................................... Passed 0.01 sec\r\n", + " Start 23: costFunction.linearModel3\r\n", + "23/80 Test #23: costFunction.linearModel3 ...................................................... Passed 0.01 sec\r\n", + " Start 24: hdf5Misc.testOpenExistingFileNoOverwrite\r\n", + "24/80 Test #24: hdf5Misc.testOpenExistingFileNoOverwrite ....................................... Passed 0.01 sec\r\n", + " Start 25: hdf5Misc.testOpenExistingFileOverwrite\r\n", + "25/80 Test #25: hdf5Misc.testOpenExistingFileOverwrite ......................................... Passed 0.01 sec\r\n", + " Start 26: hdf5Misc.testMutexGetLock\r\n", + "26/80 Test #26: hdf5Misc.testMutexGetLock ...................................................... Passed 0.01 sec\r\n", + " Start 27: hdf5Misc.testErrorStackWalker\r\n", + "27/80 Test #27: hdf5Misc.testErrorStackWalker .................................................. Passed 0.01 sec\r\n", + " Start 28: hdf5Misc.testCreateGroup\r\n", + "28/80 Test #28: hdf5Misc.testCreateGroup ....................................................... Passed 0.01 sec\r\n", + " Start 29: hdf5Misc.testCreateExistingGroup\r\n", + "29/80 Test #29: hdf5Misc.testCreateExistingGroup ............................................... Passed 0.01 sec\r\n", + " Start 30: hdf5Misc.testEnsureGroupExists\r\n", + "30/80 Test #30: hdf5Misc.testEnsureGroupExists ................................................. Passed 0.01 sec\r\n", + " Start 31: hdf5Misc.testStringAttribute\r\n", + "31/80 Test #31: hdf5Misc.testStringAttribute ................................................... Passed 0.01 sec\r\n", + " Start 32: hdf5Misc.testDatasetDimensions\r\n", + "32/80 Test #32: hdf5Misc.testDatasetDimensions ................................................. Passed 0.01 sec\r\n", + " Start 33: unittests_loadbalancer\r\n", + "33/80 Test #33: unittests_loadbalancer ......................................................... Passed 0.00 sec\r\n", + " Start 34: multiStartOptimization.testMultiStartOptimization\r\n", + "34/80 Test #34: multiStartOptimization.testMultiStartOptimization .............................. Passed 2.20 sec\r\n", + " Start 35: minibatchOptimization.getBatches\r\n", + "35/80 Test #35: minibatchOptimization.getBatches ............................................... Passed 0.01 sec\r\n", + " Start 36: minibatchOptimization.updateParameters\r\n", + "36/80 Test #36: minibatchOptimization.updateParameters ......................................... Passed 0.01 sec\r\n", + " Start 37: minibatchOptimizationLinearModel.testCostWithTrueParametersIsZeroIndivdually\r\n", + "37/80 Test #37: minibatchOptimizationLinearModel.testCostWithTrueParametersIsZeroIndivdually ... Passed 0.01 sec\r\n", + " Start 38: minibatchOptimizationLinearModel.testCostWithTrueParametersIsZeroFull\r\n", + "38/80 Test #38: minibatchOptimizationLinearModel.testCostWithTrueParametersIsZeroFull .......... Passed 0.01 sec\r\n", + " Start 39: minibatchOptimizationLinearModel.testMinibatchSucceedFromOptimum\r\n", + "39/80 Test #39: minibatchOptimizationLinearModel.testMinibatchSucceedFromOptimum ............... Passed 0.01 sec\r\n", + " Start 40: minibatchOptimizationLinearModel.linearModelCheckCostGradient\r\n", + "40/80 Test #40: minibatchOptimizationLinearModel.linearModelCheckCostGradient .................. Passed 0.01 sec\r\n", + " Start 41: minibatchOptimizationLinearModel.linearModelTestBatchOptimizerSucceeds\r\n", + "41/80 Test #41: minibatchOptimizationLinearModel.linearModelTestBatchOptimizerSucceeds ......... Passed 0.05 sec\r\n", + " Start 42: minibatchOptimizationLinearModel.linearModel\r\n", + "42/80 Test #42: minibatchOptimizationLinearModel.linearModel ................................... Passed 0.02 sec\r\n", + " Start 43: optimizationResultWriter.testResultWriter\r\n", + "43/80 Test #43: optimizationResultWriter.testResultWriter ...................................... Passed 0.02 sec\r\n", + " Start 44: optimizationOptions.setGetOptionStr\r\n", + "44/80 Test #44: optimizationOptions.setGetOptionStr ............................................ Passed 0.01 sec\r\n", + " Start 45: optimizationOptions.setGetOptionInt\r\n", + "45/80 Test #45: optimizationOptions.setGetOptionInt ............................................ Passed 0.01 sec\r\n", + " Start 46: optimizationOptions.setGetOptionDouble\r\n", + "46/80 Test #46: optimizationOptions.setGetOptionDouble ......................................... Passed 0.01 sec\r\n", + " Start 47: optimizationOptions.getNonExistingOption\r\n", + "47/80 Test #47: optimizationOptions.getNonExistingOption ....................................... Passed 0.01 sec\r\n", + " Start 48: optimizationOptions.setIpOptOptions\r\n", + "48/80 Test #48: optimizationOptions.setIpOptOptions ............................................ Passed 0.01 sec\r\n", + " Start 49: optimizationOptions.setCeresOptions\r\n", + "49/80 Test #49: optimizationOptions.setCeresOptions ............................................ Passed 0.01 sec\r\n", + " Start 50: optimizationOptions.fromHDF5\r\n", + "50/80 Test #50: optimizationOptions.fromHDF5 ................................................... Passed 0.02 sec\r\n", + " Start 51: optimizationProblem.quadraticTestFunction\r\n", + "51/80 Test #51: optimizationProblem.quadraticTestFunction ...................................... Passed 0.01 sec\r\n", + " Start 52: optimizationProblem.gradientChecker\r\n", + "52/80 Test #52: optimizationProblem.gradientChecker ............................................ Passed 0.01 sec\r\n", + " Start 53: optimizationProblem.linearModel\r\n", + "53/80 Test #53: optimizationProblem.linearModel ................................................ Passed 0.01 sec\r\n", + " Start 54: optimizationProblem.linearModelToGradientFun\r\n", + "54/80 Test #54: optimizationProblem.linearModelToGradientFun ................................... Passed 0.01 sec\r\n", + " Start 55: optimizationProblem.linearModelToGradientFunOptimization\r\n", + "55/80 Test #55: optimizationProblem.linearModelToGradientFunOptimization ....................... Passed 0.03 sec\r\n", + " Start 56: localOptimizationIpopt.testOptimizationResult\r\n", + "56/80 Test #56: localOptimizationIpopt.testOptimizationResult .................................. Passed 0.04 sec\r\n", + " Start 57: localOptimizationIpopt.testReporterCalled\r\n", + "57/80 Test #57: localOptimizationIpopt.testReporterCalled ...................................... Passed 0.02 sec\r\n", + " Start 58: localOptimizationCeres.testOptimization\r\n", + "58/80 Test #58: localOptimizationCeres.testOptimization ........................................ Passed 0.01 sec\r\n", + " Start 59: localOptimizationCeres.testReporterCalled\r\n", + "59/80 Test #59: localOptimizationCeres.testReporterCalled ...................................... Passed 0.01 sec\r\n", + " Start 60: simulationWorkerAmici.testSerializeResultPackageMessage\r\n", + "60/80 Test #60: simulationWorkerAmici.testSerializeResultPackageMessage ........................ Passed 0.01 sec\r\n", + " Start 61: simulationResultWriter.testResultWriter\r\n", + "61/80 Test #61: simulationResultWriter.testResultWriter ........................................ Passed 0.02 sec\r\n", + " Start 62: simulationResultWriter.testResultWriterNewExistingFile\r\n", + "62/80 Test #62: simulationResultWriter.testResultWriterNewExistingFile ......................... Passed 0.02 sec\r\n", + " Start 63: hierarchicalOptimization1.reader\r\n", + "63/80 Test #63: hierarchicalOptimization1.reader ............................................... Passed 0.01 sec\r\n", + " Start 64: hierarchicalOptimization1.spliceParameters\r\n", + "64/80 Test #64: hierarchicalOptimization1.spliceParameters ..................................... Passed 0.02 sec\r\n", + " Start 65: hierarchicalOptimization1.spliceParametersNothingToDo\r\n", + "65/80 Test #65: hierarchicalOptimization1.spliceParametersNothingToDo .......................... Passed 0.01 sec\r\n", + " Start 66: hierarchicalOptimization1.fillFilteredParams\r\n", + "66/80 Test #66: hierarchicalOptimization1.fillFilteredParams ................................... Passed 0.01 sec\r\n", + " Start 67: hierarchicalOptimization1.likelihoodOfMatchingData\r\n", + "67/80 Test #67: hierarchicalOptimization1.likelihoodOfMatchingData ............................. Passed 0.01 sec\r\n", + " Start 68: hierarchicalOptimization.hierarchicalOptimization\r\n", + "68/80 Test #68: hierarchicalOptimization.hierarchicalOptimization .............................. Passed 0.02 sec\r\n", + " Start 69: hierarchicalOptimization.testNoAnalyticalParameters\r\n", + "69/80 Test #69: hierarchicalOptimization.testNoAnalyticalParameters ............................ Passed 0.01 sec\r\n", + " Start 70: hierarchicalOptimization.testComputeAnalyticalScalings\r\n", + "70/80 Test #70: hierarchicalOptimization.testComputeAnalyticalScalings ......................... Passed 0.02 sec\r\n", + " Start 71: hierarchicalOptimization.testComputeAnalyticalOffsets\r\n", + "71/80 Test #71: hierarchicalOptimization.testComputeAnalyticalOffsets .......................... Passed 0.01 sec\r\n", + " Start 72: hierarchicalOptimization.applyOptimalScaling\r\n", + "72/80 Test #72: hierarchicalOptimization.applyOptimalScaling ................................... Passed 0.01 sec\r\n", + " Start 73: hierarchicalOptimization.applyOptimalOffset\r\n", + "73/80 Test #73: hierarchicalOptimization.applyOptimalOffset .................................... Passed 0.01 sec\r\n", + " Start 74: hierarchicalOptimization.testScaling\r\n", + "74/80 Test #74: hierarchicalOptimization.testScaling ........................................... Passed 0.01 sec\r\n", + " Start 75: hierarchicalOptimization.testWrappedFunIsCalledWithGradient\r\n", + "75/80 Test #75: hierarchicalOptimization.testWrappedFunIsCalledWithGradient .................... Passed 0.01 sec\r\n", + " Start 76: hierarchicalOptimization.problemWrapper\r\n", + "76/80 Test #76: hierarchicalOptimization.problemWrapper ........................................ Passed 0.01 sec\r\n", + " Start 77: example_loadbalancer\r\n", + "77/80 Test #77: example_loadbalancer ........................................................... Passed 0.35 sec\r\n", + " Start 78: parpe_python_package_tests\r\n", + "78/80 Test #78: parpe_python_package_tests ..................................................... Passed 2.78 sec\r\n", + " Start 79: pytest_steadystate_example\r\n", + "79/80 Test #79: pytest_steadystate_example ..................................................... Passed 8.22 sec\r\n", + " Start 80: test_steadystate\r\n", + "80/80 Test #80: test_steadystate ............................................................... Passed 0.02 sec\r\n", + "\r\n", + "\u001B[0;32m100% tests passed\u001B[0;0m, 0 tests failed\u001B[0;0m out of 80\r\n", + "\r\n", + "Total Test time (real) = 14.70 sec\r\n" ] } ], @@ -142,7 +290,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 29, "metadata": {}, "outputs": [ { @@ -176,7 +324,7 @@ " reactants = ' + '.join(['%s %s'%(int(r.getStoichiometry()) if r.getStoichiometry() > 1 else '', r.getSpecies()) for r in reaction.getListOfReactants()])\n", " products = ' + '.join(['%s %s'%(int(r.getStoichiometry()) if r.getStoichiometry() > 1 else '', r.getSpecies()) for r in reaction.getListOfProducts()])\n", " reversible = '<' if reaction.getReversible() else ''\n", - " print('%3s: %10s %1s->%10s\\t\\t[%s]' % (reaction.getId(), \n", + " print('%3s: %10s %1s->%10s\\t\\t[%s]' % (reaction.getId(),\n", " reactants,\n", " reversible,\n", " products,\n", @@ -194,18 +342,17 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 30, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# load model\n", - "sys.path.insert(0, model_source_dir)\n", - "import model_steadystate_scaled as modelModule\n", + "model_module = amici.import_model_module(\"model_steadystate_scaled\", model_source_dir)\n", "\n", - "model = modelModule.getModel()\n", - "model.setTimepoints(amici.DoubleVector(np.logspace(-5, 1, 20))) \n", + "model = model_module.getModel()\n", + "model.setTimepoints(amici.DoubleVector(np.logspace(-5, 1, 20)))\n", "solver = model.getSolver()\n", "rdata = amici.runAmiciSimulation(model, solver)\n", "\n", @@ -217,15 +364,13 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 31, "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEZCAYAAAB4hzlwAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAgAElEQVR4nO3deZicZZno/+9dW1fvSXrJ1tkJWVgMGDZFBhCc4AZHGQWdOcOMP9FRxFmP4IKOR0bUI+rl6HEYXI+M6ABiRhgRFGQnBBIJWYDs6ZCkO+l9qe6qrvv3x/NWdXV39VKdWrq77s91vVdVvfW8bz0Vmr77flZRVYwxxhgAX6ErYIwxZuqwoGCMMSbJgoIxxpgkCwrGGGOSLCgYY4xJsqBgjDEmyYKCMTkmIttF5OIpUI/vicjnCl0PM7VZUDBTiohcKCJPi0i7iLSIyFMico733nUi8mQG91oqIioigUnW5aSuT1DV01T1sZO5h4j8SES+dJL1+Kiq/u+TuYeZ+U7qh92YbBKRKuDXwN8AvwBCwFuAvkLWaywiElDVWKHrMR4R8avqQKHrYaY+yxTMVHIqgKr+TFUHVLVXVX+rqi+JyBrge8AFItIlIm0AIvIOEdkiIh0ickhEvpByv8e9xzbvmgu8a/5aRHaKSKuIPCQiS0apz4jrvWzlKRH5hoicAL4gIitE5PcickJEjovIXSIyK3ETEdkvIpd5z30icpOI7PHK/0JE5qSUTWRKbd73uU5Ergc+CPwvrx7/5ZVdIyKPeWW3i8i7U+7zIxH5vyLyoIh0A5cMzzZE5J0istW7/mkROTPlvU+JyGER6RSRV0TkrRn8dzTTmaraYceUOIAq4ATwY+AKYPaw968Dnhx27mLgDNwfOGcCx4CrvPeWAgoEUspfCewG1uAy5c8CT49Sn3TXXwfEgE9415cCpwCXAyVAHS6YfDPlmv3AZd7zTwLPAg1e+X8Dfua9twToBK4FgkANsM5770fAl1LuGfS+x6dxGdWl3rWrUsq3A2/2/m3CqfcAzgKagPMAP/CXXj1LgFXAIWBByr/DikL/fNiRn8MyBTNlqGoHcCHuF/G/A80islFE5o5xzWOquk1V46r6EvAz4E/G+JiPAl9W1Z3qmn3+BVg3RraQzuuq+m1VjanLZnar6sOq2qeqzcDtY9Tho8BnVLVRVfuALwBXe/0WHwAeUZcpRVX1hKpuHeU+5wMVwG2q2q+qv8c1vV2bUuZXqvqU928TGXb99cC/qepz6rKyH+Oa6c4HBnDBYa2IBFV1v6ruyeDfx0xjFhTMlOL9sr5OVRuA04EFwDdHKy8i54nIoyLSLCLtuF+6tWN8xBLgW16TSRvQAgiwMINqHhpWh7kicrfX3NIB/HSMOiwBfpny+Ttxv4TnAouAif7yXQAcUtV4yrkDw77HIUa3BPiHRD28uizCZQe7gb/FBawm77stmGC9zDRnQcFMWaq6C9fkcXriVJpi/wFsBBapajWu30HGKH8I+Iiqzko5SlX16XRVGK1qw17/i3fuDFWtAv48pQ7pPv+KYZ8fVtXD3nsrJviZrwOLRCT1/+HFwOEJ1D9Rj1uH1aNMVX8GoKr/oaoX4oKHAl8Z415mBrGgYKYMEVktIv8gIg3e60W45pBnvSLHgAYRCaVcVgm0qGpERM7FNcEkNANxYHnKue8BN4vIad5nVIvIn41SpXTXp1MJdAHtIrIQ+Kcxyn4PuDXRXCUidSJypffeXcBlIvI+EQmISI2IrPPeOzasHs8BPbjO56A3D+JdwN3j1DXh34GPepmWiEi512lfKSKrRORSESkBIkCv9+9gioAFBTOVdOI6Pp/zRsw8C7wM/IP3/u+B7cBRETnunfsY8EUR6QRuwQ1lBUBVe4Bbgae8JpLzVfWXuL967/aael7GdWqPkO76Uer9z8DZuI7dB4D7xviO38JlNr/16vys951R1YPA273v2wJsBd7gXfd9XBt/m4jcr6r9uCBwBXAc+C7wP73salyquhn4MPCvQCuu0/o67+0S4DbvvkeBeuDmidzXTH+iapvsGJNLInIQ+HNVfXzcwsYUmGUKxuSQiNThhqnuL3BVjJkQCwrG5Ii45TleA77tNQ0ZM+VZ85ExxpgkyxSMMcYkTfsF8Wpra3Xp0qWFroYxxkwbL7zwwnFVrUv33rQPCkuXLmXz5s2FroYxxkwbInJgtPes+cgYY0ySBQVjjDFJFhSMMcYkTfs+BWOMyaVoNEpjYyORyPDVx6e+cDhMQ0MDwWBwwtdYUDDGmDE0NjZSWVnJ0qVLERlt8dupR1U5ceIEjY2NLFu2bMLXWfORMcaMIRKJUFNTM60CAoCIUFNTk3GGY0HBGGPGMd0CQsJk6m3NR4V2bDvsewIWrIMFZ0GgpNA1MsYUMQsKhTIQhSduh8e/CvGYOxcIw8I3wuILYMkFsOg8KKksbD2NMUXFgkIhHHkJfvUxOLoNzvgz+JOboHkXHHgaDj4NT34Dnvg/ID6YdwYsebMLFIsvgIq0M9ONMSYrLCjkU6wfnvi6+4VfOgfefxesead7r/aUwed9XdC4CQ48Awefgc0/gGe/696rWemyiMVvco+zlsA0be80xkzcJZdcwqc//Wkuv/xyPvvZz9Le3s63v/3trH+OBYV8OfIS3P8xOLYNznw/bLgNyuakL1tSASsudQe4YHJkq5dJPAM7fgUv/sS9V7nACxIXwJI3Qd0a8Nn4AWNy4Z//azs7Xu/I6j3XLqji8+86bfzP/ud/5pZbbqGpqYktW7awcePGrNYjwYJCrsX6XWbwxNehrAau+Rmsfntm9wiEYNG57uBvIR6Hph0uQBx42h0v3+vKhmcN9kksfhPMf4O73hgzrV100UWoKrfffjuPPfYYfr+f7u5uPvaxjxEKhbj44ov54Ac/eNKfY0Ehl4780csOXoYzr4ENXx49O8iEzwfzTnfHuR8GVWjdPxgkDj4Dr/63KxsohYb1LotYfIELLKHyk6+DMUVoIn/R58q2bds4cuQINTU1VFa6ASj33XcfV199Ne9617t4//vfb0Fhyor1w+Nfc9lBeR1cezesuiJ3nycCc5a5Y90H3LmuJi9IPOM6rx//GmgcxO+yhyVvGgwU2QhUxpicOXLkCB/84Af51a9+xY033shvfvMbNmzYQGNjI2eccQYAfr8/K5+Vt6AgIhuAbwF+4E5VvW3Y+98ALvFelgH1qjorX/XLmte3uuygaTu84VqXHZTOzn89Kuph7ZXuAIh0wKFNLkAceAY2/Ts886/uvbrVg30Siy+AWYvyX19jTFo9PT285z3v4etf/zpr1qzhc5/7HJ/61KfYsGEDDQ0NNDY2sm7dOuLxeFY+Ly97NIuIH3gVuBxoBJ4HrlXVHaOU/wRwlqr+9Xj3Xr9+vU6JTXZifV52cLv7hfzOb8KqDYWu1ehifXD4xcEgceg56PM60KoXwdK3wMrLYPkllkmYorZz507WrFlT6Gqk1d3dzQ033EA4HObCCy9M23yUrv4i8oKqrk93z3xlCucCu1V1r1ehu4ErgbRBAbgW+HwuK/TzXT+nrqyOSxdfevI3e32Llx3sgHUfhD+9tTDZQSYCJa4zeskF8BYgPuBmVx98Bg485fok/vgfbq5EwzlwymXumL/ORjcZM0WUl5fzwx/+MKv3zFdQWAgcSnndCJyXrqCILAGWAb8f7WYicj1wPcDixYsnVaGf7vwpq+esPrmgEOuDP3zVTTarqIcP/Cec+rbJ36+QfH6Yf6Y7zvuICxKHX4Ddj8BrD8Oj/wKP3ur6SFa8FVZe7obMWhZhzIwyFTuarwHuUdWB0Qqo6h3AHeCajybzIaWBUrqj3ZOrIUD3CfjxO1Oyg3+B0unXBTIqn39wGOwln4bu47D7d7D7YXjtt/DS3S6LWPhGL4u43K3dZFmEMdNavoLCYSC197LBO5fONcDHc12hilDFyQWFrXe5gDCZeQfTUXktvOH97ogPuA713Q+7LOKx2+CxL7t5GMks4q1QXlPoWhtjMpSvoPA8sFJEluGCwTXAB4YXEpHVwGzgmVxXqDxQztGeo5O/wcv3woKziyMgDOfzQ8Mb3XHxTS5r2vN7FyR2/w62/QIQWHj2YBax8Gx3nTFmSstLUFDVmIjcADyEG5L6A1XdLiJfBDaramK+9jXA3ZqHIVHloXK62romd/GJPW7Zibfdmt1KTVflNXDmn7kjHnf/Nom+iMe/Bn/4ilvracWlg1mELexnzJSUtz4FVX0QeHDYuVuGvf5CvupTHiinJ9YzuYu33QMInP6erNZpRvD5XFaw8Gz4k/8FPS1eFvGIO16+x5Wbv84FiFMudzOuLYswZkqYih3NeVEeKp9cn4Kq+8W25E1QtSD7FZtpyubAGVe7Ix6Hoy95fRGPuBnfj3/NrdeUmkVUzi10rY0pWsUbFALl9A30EY1HCfqCE7/w2Mtw/FU476O5q9xM5fN5O8ytg4v+CXpbYc+jg1nE9vtcuXlnpmQR54C/aH9Mjcm7ov2/rSJUAUB3fzezwhkMJX35Xrd+UGL5CDN5pbNdE9zp73EZ2NFtg1nEk990mUS42s2qTmQRVfMLXWtjZrSiDQrlQbdSaHesm1lMMCiouqCw4hI3RNNkj8jg5Lm3/AP0tsHexwaziB33u3Jzz3DLb5xyuZtD4c8gyzNmGrNNdnKsIugyha7+DEYgNW6GtoNw8adzVCuTVDoLTrvKHapuCY5EFvH0t90s8pIqWH6xG/a68nLr4zG59983uYw2m+adAVfcNm4x22Qnx5KZQiadzS/fA/4SWP2OHNXKpCUyuH/EhX/nVnxNzSJ2ev9z1J82mEUsPt+yCDOjpNtkZ+/evdx66620t7dzzz33ZOVzijYoJDOF6AQzhfgAbP+lW9soXJXDmplxhatg7bvdoQpNOwdnVz/zXXjqWxCqhOV/MphFVDcUutZmJpjAX/S5km6TneXLl/P973+fq6++OmufU7RBoTyUYaaw/0noOganvzeHtTIZE4G5a93x5k9CXyfs/cNgFrHr165c3ZqULOIC26LUTCujbbKTC0UbFBKZQmd/58QuePleCFXAyj/NYa3MSSuphDXvdIcqNL8ymEU892+uPyJYPjSLmDW5lXaNyYexNtnJhaIPChPKFGL9sONXsOrtECrLcc1M1ohA/Wp3vOkT0NcF+59wAWL3w/CKN8G+dpU3L+IyNykxUFLYehuToqysjGeeGVwO7qKLLkq+PnHiBJ/5zGfYsmULX/7yl7n55ptP+vOKNiiUBkoRZGJ9CnsfhUibm5Vrpq+SCrdX9qorXBZx/LXBLGLTHW570mAZLLtoMIuYvbTQtTZmVDU1NXzve9/L6j2LNiiICBXBiokNSd12j1uKYfkl45c104MI1J3qjgs+Dv3drt8okUW8+htXrmZlShbxZgiGC1tvY3KsaIMCuFnN42YK/T2umeH091rn5EwWKodT/9Qdqm4l3EQW8fz34dnvQqAUlr3FdVavvAzmLC90rY3JuqIOCpWhyvE7ml97CPq7rOmomIhA7SnuOP9v3B8GB54azCJe+y38NzBnxWAWsfgC1zxlzDRX1EGhIjiBTOHle6Finms6MMUpVOZ++a+83L0+sWdwv4gXfgTPeW26s5ZA/Rp31HmPtadak5OZVoo6KFSGKmnqaRq9QKQdXv0trP9rW+/fDKpZ4Y7zPgLRXpdFvL7FTaJr2ul2n4tHXVnxuWamutVQv9YbDbXWZRnWHGmmoKIOChWhCva07Rm9wK4HYaDPJqyZ0QVLvS1HLxs8NxB12UTzTmja5fbybt4Fr/w36IAr4wu4Tuz61YNZRf0amL3Mlgo3BVXUP33jNh+9fI+b2NSwPn+VMtOfPzg4P+K0lPOxPjcMtmmnFzB2wutbYfv9gLcDrb/ENTnVrxnMKupWu6Ypn68Q38YUmaIOComOZlVFRIa+2X3CbQDz5htdx6MxJytQMriwX6r+Hjj+ymDzU9NOOPgMbPvFYJlgGdStGgwSiaaoqoX282myquiDwoAO0BvrpSw4bKbyjvtdqn+6jToyORYqgwVnuSNVpMMt05Fofmra4fortt41WKakygsSa4Z2clfUW7Awk5K3oCAiG4BvAX7gTlUdsdygiLwP+AIul/6jqn4gl3VKXSl1RFDY/ku3/MHc09JcaUwehKtg0TnuSNXTMhgkmna5zGLnf8GLPx4sUzo7JatIBIy1bs9sM2lf2fQVdrXsyuo9V89ZzafO/dS45WbUJjsi4ge+A1wONALPi8hGVd2RUmYlcDPwZlVtFZH6XNerMuSWn+3q76K+LOXj4nE4/CKc/Rf215aZesrmuDWalrxp8JwqdDd7/RUpAWPbPdDXPliuvH5kVlG/2m17aqa0mbbJzrnAblXdCyAidwNXAjtSynwY+I6qtgKo6hhjRbMjuVJqdNgEtrYDEO12f1kZMx2IuCajinq3AmyCKnQeGZpVNO+EF/+f+xlPqFroBYmU/oq61W6mt0mayF/0uZJuk53777+fBx54gI6ODj70oQ/xtre97aQ/J19BYSFwKOV1I3DesDKnAojIU7gmpi+o6m/S3UxErgeuB1i8ePLLHqdmCkM0ebHKmo7MdCfitimtWjB02Gw8Du2Hho6EatoJ+55ww7ATZi0ZOr+ibrVNyCuQdJvsXHXVVVx11VW0trbyj//4j9MqKExEAFgJXAw0AI+LyBmq2ja8oKreAdwBsH79ep3sB466p8IxLyjUrZ7srY2Z2nw+mL3EHatS1uWPD0Dr/pTMwuvk3v2ITcgroPE22fnSl77Exz/+8ax8Vr6CwmFgUcrrBu9cqkbgOVWNAvtE5FVckHg+V5WqCI3SfNS03S2ZbGvZmGLj8w/O2F7zrsHziQl5qSOhmna5xSI17l2bMiEvdejsnGW2IsBJGGuTHVXlpptu4oorruDss8/OyuflKyg8D6wUkWW4YHANMHxk0f3AtcAPRaQW15y0N5eVqgq5vZZHNB8d22H9CcakSp2QlyoagROvDZ1j8foWN3oveW2Jt0z5mqGd3NWLbULeBIy1yc63v/1tHnnkEdrb29m9ezcf/ehHT/rz8hIUVDUmIjcAD+H6C36gqttF5IvAZlXd6L33NhHZAQwA/6SqJ3JZr9JAKX7xD20+ivXBid1D/0oyxqQXDMO8M9yRqr/bm2OR0mdx4OlhE/LKvQl5a2xC3iTdeOON3HjjjVm9Z976FFT1QeDBYeduSXmuwN97R16ICFWhKjr6OwZPHn/VTVqbm/tMobd/gHteOMSWQ22cUl/BmnlVrJ5fybyq8MgZ1sZMJ6FyWHi2O1JF2geDRSJg7H7EJuRNIVOpo7kgqkqq6OhLCQqJTub63I08OtHVx4+fOcD/e2Y/rT1R5pSHuO/FwS6WWWVBVs+rZPW8KtbMd4+nzq2kNGTtsmaaC1fDonPdkaqnZdhIqF1pJuTNSQkSicxijU3Iy7KiDwrVoWra+1Mm9zRtB3/IdbRl2f7j3dz55F7+c3MjfbE4l62p5/qLVnDO0tl0RGK8crSTXUc72Hmkk51HOvj584fojbpVNX0CS2vLXTYxr5LV891jw+xSyyrM9Fc2B5a+2R0JyQl5w0ZCvfQLSP1DrmLuyJFQdatsQt4kFX1QqCqpojXSOnji2A63vIU/mLXP2HKwlTse38tvth8l6PPxP85ayIcvWsYp9ZXJMtWlQc5dNodzlw3+1ROPKwdbepKBYtfRDl5+vZ0Hth1JlqksCbDayyYSj6vmVVJRUvT/ac10N2RC3sWD51Wh4/WRcyxe/DFEewbLZXFCXtpFM6cB1yqfmaL/zVFdUs3+9v2DJ5p2ZGWXtXhc+f2uJu54fC+b9rdQFQ7wN3+yguvetJT6qolN/PH5hKW15SytLWfD6fOT57v6BrOKXV6wuH/LYTqfjSXLLKkpG9EEtXhOGT7f9PvBNmYIEahe6I6VwyfkHRw6Eqp5+IQ8ccvhZzAhLxwOc+LECWpqaqZVYFBVTpw4QTic2UTDog8KQzqae1uh4/BJdTL3xQb41ZbXueOJvexu6mLhrFI+9861vP+cRVn7672iJMAbl8zmjUtmJ8+pKofbel1GcaSDXUc72Xm0g4d3HCPu/bFQFvKzaligWDWvkurS7GVFxhSMz+fmF81eCquuGDw/EHMT8lKziqadbr/tuPeHVGJCXupWqvVroOYUGhoaaGxspLm5uQBf6uSEw2EaGhoyuqbog0J1STWd/Z0MxAfwN+10JyfRydzeG+Wu5w7wo6f209TZx5r5VXzz/et4x5nzCfpzPxZbRGiYXUbD7DIuXzs3eb63f4DXmlwfRaIJ6sFtR/jZpoPJMgtnlSaDRKIJaklNWV7qbUzO+QNQe4o7Uoeax/qhZc/QrKJpJ+x6IGVCXpBgzSksGz4SagZPyLOgEKpGUbqiXVQf2+5OZpApHG7r5QdP7uPuTQfp7h/gLStr+fr73sCFp9ROiVSzNOTnzIZZnNkwK3lOVTnW0cdOr/lp55EOdh3t4NFXmhnw0goRqCkvYW5VCXOrwtRXllBfFXavK8PuXFUJNeUhAhY8zHQUCA3+ok8Vjbih6akztw+/ANvvS7k2DLUrRy5PPgMm5FlQKHEjFNr72qlu2gkl1a6DahyR6ACf+eXL/GrrYRR415nz+fBFyzltwdQf8SAizKsOM686zCWrBpcM74sNsLupi51HOjnU0kNTZx9NHRGOdUbYdrid4119DO+38gnUVrjAMbfKBY76ypTXXgCpKQ9Zf4aZHoJhmH+mO1L1dXk75KWMhNr/JLz085RrUybkpTZFVS2YNnMsij4oJJa66OjvcP+h566d0H+8h7Yf5d4XG/mL85fw0YtXsHBWaa6rmnMlAT+nLageNbDFBuIc7+rnWEeEps4+99gR4VhHH8c6Ixxui7D1UBvHu/pHXBvwiRc8RmYcdcnnJcwus+BhpqiSClj4RnekirS7QJHaZ/Haw8Mm5FUPjn5K7eQur5tywaLog0IyU4i0ueGoZ0xs+83n9rVQWRLgC+8+DX+R/BIL+H3JDGMs/bE4x7tc0DjW0UdTZ4SmDu91Zx+HWnrYvL+F1p7oiGuDfqG+0jVNDWYc4RHPZ5UFp0TznDGEq2Hxee5I1X1iaKBo3gU7N6aZkJcIEimZRQEn5BV9UKgqcZlCe/t+t0PV8PbFUWza18L6pbOLJiBkIhTwsWBWKQvGyZ76YgM0d/a5wNERSQYNl4H0se94N8/ubaG9d2TwCAV8I5qp6lOyj0RGUhUOWPAwhVFeA+UXwtILB8+pQldTymqzXsCY0IS81W6L1hwr+qBQHfIyhROvuhMT2FjneFcfu5u6eO/ZmQ31MkOVBPzJEVNjiUQHXKbRGUkGjGMp2ccrRzt54tXjdPbFRlwbDvq8fg2v2Sr53AWQRFNWRYkFD5MHIlA51x0rLhk8r+qGw6f2VzTtSDMhr2FoVnH6e7O+4VHRB4VEptDRfsCdmECmsHl/C8CQ2ccmd8JBP4trylhcM3bw6OmPDWmmSmQfif6Pna938GhHEz39AyOuLQv5Xf9GIvvwHutTRl/NrQpTbjPFTS6IQHWDO4ZPyGs7MHQkVGKHPI3Dme/LelWK/ic86AtSFiijvfN1N+qodPa41zy3r4Vw0McZC6f+SKNiUhYKsLQ2wNLasZcx6OqLJTOOJi/7ONYx2Gy1rbGNhzsiRKLxEddWlARSmqkGR1vVVISoCgepKg1SGQ4kn5eH/JaBmMnz+dyciDnLRk7I62jM6nI8CUUfFMB1Nre3H5/wxjqb9rVw9uLZhALTezxysaooCVBRV8GKutF31lNVOvtig6Orhoy4co8vHGzlWEcf/bGRwSPBJ1AZDlJVGqCyxD1WhYPJc+55gKrSoAskKc8rwwEqwwGbB2JG8gfczO0csKAAVIeq6OjfB4vGbzrqiETZcaSDGy9dmYeamUIREe+XdHDIwoXDqSrtvVFauvvpjMToiETp6I3RGYkOe+499sY42NLjyvZG0/aDDFce8qcNIqkZSfrn7rEk4LNsxUyYBQWgyh+m3ceEIu8L+1tRhfOsP8HggsesshCzyia3Yf1AXOnqcwGiIxJNBovUIOLODz4/3tXP3uPdLqhEYsTiY6+EGfL7XKaSkokMCSIlXnaSzGaCQ8qXhwI2d6SIWFAAqsXPXp8PZi0Zt+ym/S0EfMJZi8fvezBmPH6fUF0anPSihKpKb3RgRHbS4WUnicAxNOBEOdIeST5P13eSyieuyS21WWvk86HZSbLJzCtj62hNHxkHBREpByKqOnIIxzRVFYd2nx9mLRq37KZ9LZzZUG27oJkpQUQoCwUoCwXGnVQ4mv5YfEQT1/DsJDWgdERiHEo0gXnvjacs5B+1iavSa6Ybns1UpZS3JrD8GTcoiIgPuAb4IHAO0AeUiMhx4AHg31R19wTuswH4FuAH7lTV24a9fx3wNSCxL+W/quqdE/8qk1cV66fd70OrGhjrx663f4CXGtv40IXL81EtY/IiFPBRU1FCTUXJpK5PNIGNFkQ6h2UsHRHXB7P/eHcymxmvCSzol/QBpSR9h33yuVe+wprAJmwimcKjwCPAzcDLqm5NWRGZA1wCfEVEfqmqPx3tBiLiB74DXA40As+LyEZV3TGs6M9V9YZJfI+TUt3fS1SEXp8w1kj4LYdaiQ6o9ScYk2JIE9gkWlVVlUg0nsxO2scILIPZTJSjHZFkIEpsWzsaEbdLYeUonfFp+1qGPS+WJrCJBIXLVHXEOgOq2gLcC9wrIuM1iJ4L7FbVvQAicjdwJTA8KBREdcRNL+/o76AsOHpY2LSvBRF441LrTzAmW0SE0pCfUm8C4WREB+IjM5JhzzuGjQ5zm1K5QNTZFxuxAvBwpUF/mg77sQNKdUrzWDg4PZrAxg0K6QLCJMosBA6lvG4EzktT7r0ichHwKvB3qnooTZmsq+5uhTK3fPa88nmjltu0r4W186uoCttOZcZMJUG/jznlIeaUT24UWDyudPXHBjOSUYNLjM4+99jS3c+BEz3JbCY6MH4TWNogMqzDPl02Uxl2o8Ty0QQ2kT6FTiDdtxVAVTVbKzT9F/AzVe0TkY8APwYuHaVO1wPXAyxevPjkPlWVqq5mKP0cQhsAABvQSURBVJs9uC1nGv2xOC8ebOXac0/y84wxU47PNzgvZTLL4KsqfbH4sIxkWDBJM3elqaMrWSbd8iupJDEKLCWI/PRD52V9Eu1EMoXRZ+5M3GEgdWhPA4MdyonPOZHy8k7gq2PU6Q7gDoD169ePk/SNo7uZ6mgEcJnCaLYdbicSjVt/gjFmBBEhHPQTDvqpn+SfydGBOF2jBJF0Q4x7+mME/dnPHPI1T+F5YKWILMMFg2uAD6QWEJH5qnrEe/luYGdeatZ2iOoBN057rExh0z63CN45Sy0oGGOyL+j3Mbs8xOxJNoFly4SDgoisBz4DLPGuSzQfnTnmha5QTERuAB7CDUn9gapuF5EvAptVdSNwo4i8G4gBLcB1mX6ZSWk7QHXcBYWxMoVN+05wSn3FpIftGWPMdJBJpnAX8E/ANmDsKZBpqOqDwIPDzt2S8vxm3LDX/Go/RKkqQV+Q1r7WtEUG4srm/a28a92CPFfOGGPyK5Og0Oz9RT+ztB1EwrOoKa3hRO+JtEV2Humgsy9m/QnGmBkvk6DweRG5E/gdblYzAKp6X9ZrlU9th2DWIupK6zjeezxtEetPMMYUi0yCwl8Bq4Egg81HCkzzoHAQalZQUzqHw12H0xbZtK+FRXPG33PYGGOmu0yCwjmquipnNSkEVWg/BMsvpq60jD82/TFNEWXT/hYuWVWf//oZY0yeZTLr4WkRmdjWZNNFXyf0d0H1QupK62jtayUaHzo5e09zFy3d/Zy7zJa2MMbMfJlkCucDW0VkH65PYcJDUqesTm9aROV8akKuRexE74khS1085/UnnLusJu/VM8aYfJvIMhcXAM8CG3JfnTxLBoV51PlchnC89/iQoLBpXwt1lSUsrRlr/VRjjJkZJpIp/E/cstevAr8BfqOqR3Naq3zpGMwU6rQXYMgIJFXlub0tnLtszrRY3dAYY07WRNY++hsAEVkNXAH8SESqcfss/AZ4atruwpaSKdRGOwFo7m1Ovt3Y2svRjojNTzDGFI0JdzSr6i5V/YaqbsCtXvok8GfAc7mqXM51HoWSagiVUxN2fQbHewYzhcH+BAsKxpjiMKkF8VS1F7dkxYPjlZ3SOl+HStd/EPQHmV0ye0jz0aZ9J6guDXJqfTYWijXGmKkv0/0UhjesZ3M/hfzrPJoMCgC1ZbVDmo827WvhnKVzbG9XY0zRGLf5SFUrVbXKOyqHHdM3IIAXFOYnX9aGa5OZwrGOCPtP9Fh/gjGmqGTUfCQibwDe4r18XFVfyn6V8kR1RKZQV1bHvqP7gMH1jqw/wRhTTCbc0Swin8Qtn13vHXeJyCdyVbGc622FeHRo81GpyxRUlU37WigL+TltwfROhowxJhOZZAofAs5T1W4AEfkK8Azw7VxULOe6jrnHisE1jWpLa4nFY7T3tfPCgVbOXjybgD+7+58aY8xUlslvPAFS5yMMMLLjefpIBoW5yVN1pXWAm6vQ2NrDstryQtTMGGMKJpNM4YfAcyLyS+/1VcD3s1+lPOlqco8pQaG2tBaAw53H6IjEmFcdLkTNjDGmYCYcFFT1dhH5A/Bm79RfqeqW3FQrDxKZQnld8lQiKOxpOQKUMd+CgjGmyGQ0+khVXwBeyFFd8qurCfwhCFcnT9WVuQBxsP0osJx5VRYUjDHFJZPRR+tF5Jci8qKIvCQi20QkoyGpIrJBRF4Rkd0ictMY5d4rIioi6zO5f0a6m6G8HlIWuisPllMaKOVIp5vAZs1Hxphik0mmcBfwT8A2BrfjnDAR8eNWW70caASeF5GNqrpjWLlK4JPkek2lriaoqBtxuq60Ljmr2YKCMabYZDL6qFlVN6rqPlU9kDgyuP5cYLeq7lXVfuBu4Mo05f438BUgksG9M9fdPKQ/IaG2tJa2vhNUhQOUhSa1NJQxxkxbmQSFz4vInSJyrYi8J3FkcP1C4FDK60bvXJKInA0sUtUHxrqRiFwvIptFZHNzc/NYRUfnC0DVwhGna0tr6RpoZX516eTua4wx01gmfwr/FbAaCDLYfKTAfdmoiIj4gNuB68Yrq6p3AHcArF+/Xscpnt71j6Y9XVdWR5+2MdeajowxRSiToHCOqq46ic86DCxKed3gnUuoBE4HHvN2OZsHbBSRd6vq5pP43IzUltaiEqG+cvrOyzPGmMnKpPnoaRFZexKf9TywUkSWiUgIuAbYmHhTVdtVtVZVl6rqUty+0HkNCACzS9xmO5UVvfn8WGOMmRIyyRTOB/4oInuBPtwSF6qqZ07kYlWNicgNwEOAH/iBqm4XkS8Cm1V149h3yI8Abt5CaWlPgWtijDH5l0lQ2JDmXEbt+ao6Yrc2Vb1llLIXZ3LvbIlHKwAIBDsL8fHGGFNQmQSFOuAzwJJh100oU5gu+iMuKEjAgoIxpvjkbfLadNHRHULVR5T2QlfFGGPyLpOg0DxV2v1zqamzHwYq6Iy2FLoqxhiTd5kEhc+LyJ3A73AdzQCoalbmKUwVR9ojBLSa45Hjha6KMcbk3ZSZvDZVHG2PUFoym+O9FhSMMcUnn5PXpoWjHRGqFsyhuWdboatijDF5l8/Ja1NePK4c64gwJ1xDa18rA/GB8S8yxpgZJJOgcD6w1dsPYVL7KUx1LT39RAeUueV1xDVOS8Q6m40xxeVkJ6/NKEfb3WrdDVXzoBmae5uTu7EZY0wxGDcoiIioM+reCYky2a1a/iWCwtJZ8wCss9kYU3Qm0nz0qIh8QkQWp54UkZCIXCoiPwb+MjfVy68jHS4onFq7ALCgYIwpPhNpPtoA/DXwMxFZBrQBYdyidr8FvqmqW3JXxfw52t6L3yesrHFBoblnkhv4GGPMNDVuUFDVCPBd4LsiEgRqgV5Vbct15fLtaHsf9ZUllAZLqApVWaZgjCk6GW1CrKpR4EiO6lJwRzt6meftuFZfVs+R7hn7VY0xJq1MhqTOeEfbI8yrckFh5eyVvNL6SoFrZIwx+WVBwaOqHGmPJDOFNXPWcLT7KG2RGddKZowxo8o4KIhIuYj4c1GZQursi9HTP5DMFFbPWQ3ArtZdhayWMcbk1bhBQUR8IvIBEXlARJqAXcAREdkhIl8TkVNyX83cO+bNUUhkCsmgcMKCgjGmeExongKwArgZmKeqi1S1HrgQeBb4ioj8eQ7rmBdHvKAwv7oUgNnh2cwtm8vOlp2FrJYxxuTVREYfXaaqURFZqqrJHddUtQW4F7jXG6o6rR31Jq4lmo/A9Su80mKdzcaY4jFupuANQ4U0+yaIyPnDyoxJRDZ4C+rtFpGb0rz/UW+hva0i8mQ+V2VNLHFRX1WSPLdqzir2deyjN9abr2oYY0xBTaRP4X0ichtQKSJrRCT1mjsm+kFe5/R3gCuAtcC1aX7p/4eqnqGq64CvArdP9P4n60h7hDnlIcLBwT70NXPWENc4u1t356saxhhTUBPpU3gK2AHMxv2S3i0iL4rIr4FM/oQ+F9itqntVtR+4G7gytYCqdqS8LMft7JYXxzoiQ5qOAFbXuM5m61cwxhSLiSxzcRj4iYjsUdWnAESkBliKG4k0UQuBQymvG4HzhhcSkY8Dfw+EgEvT3UhErgeuB1i8eHG6Ihk70h5hQfXQoLCgfAGVoUp2tdgIJGNMcZhI85EAJAKC9/yEqr6gqt2pZbJBVb+jqiuATwGfHaXMHaq6XlXX19VlZ7+DYx0R5g4LCiLC6jmrrbPZGFM08rl09mFgUcrrBu/caO4GrprAfU9adCBOS3c/dRUlI95bNXsVr7a+altzGmOKwkSCwgZgALd09uvepLV9wGvAtbils380gfs8D6wUkWUiEgKuATamFhCRlSkv3+F9Rs619bjBUzUVoRHvralZQ2Qgwv6O/fmoijHGFFTels5W1ZiI3AA8hNuL4Qequl1EvghsVtWNwA0ichkQBVrJ0+Y9rT39AMwuGxkUkjObW3axYtaKfFTHGGMKJuOls0Xkb4CAiGwFtqrqqxlc/yDw4LBzt6Q8/2Qm9cmWlm4XFOaUjwwKy6qXEfKF2NWyi3csf0e+q2aMMXmVUVAA90tcROYC64D/ISKnqOqHs1+1/GkbI1MI+oKcMvsUG5ZqjCkKE14lVUS+lTIS6ZiqPqSqX5nuAQGgpdv1KcwuT79aR2K5C9W8TZswxpiCyGTp7E5go4iUA4jIn4rIU+NcMy2M1acAbrmLtr42jvUcy2e1jDEm7ybcfKSqnxWRDwCPiUg/0AWMWL9oOmrp7qcs5B+yxEWqNXPWAK6zeV75vHxWzRhj8iqT5qO3Ah8GunEjkG5U1SdyVbF8au3uHzVLADh19qkIYv0KxpgZL5Pmo88An1PVi4GrgZ+LSNplKKab1p7+tCOPEsqCZSypWmIb7hhjZrxMmo8uTXm+TUSuwO2n8KZcVCyfWnqizB4jKICbr7Dt+LY81cgYYwoj4z2aE1T1CPDWLNalYFzz0dj7BK2es5rDXYdp72vPU62MMSb/Jh0UAFR1Ruw+M16fAgzObLbF8YwxM9lJBYWZoD8Wp7MvNmafAgxd7sIYY2aqog8Kbb3eHIVxgkJNaQ31pfUWFIwxM1rRB4VWbzbznHGaj8BNYrNhqcaYmazog0JiMbzxOprBNSHta99H30BfrqtljDEFUfRBIbnExTjNR+CCwoAOsLt1d66rZYwxBVH0QWGsZbOHSyx3YU1IxpiZquiDQmLZ7FkTaD5aWLmQimCFdTYbY2asog8KLd1RKkoClATSL4aXyic+Tp19qgUFY8yMVfRBobWnf0JZQsKamjW82voqA/GBHNbKGGMKo+iDQkv32IvhDbd6zmp6Y70c7DyYw1oZY0xh5C0oiMgGEXlFRHaLyIh9GETk70Vkh4i8JCK/E5El+ahXW8/4S1ykspnNxpiZLC9BQUT8wHeAK4C1wLUisnZYsS3AelU9E7gH+Go+6tYyzrLZw62oXkHAF7CgYIyZkfKVKZwL7FbVvaraD9wNXJlaQFUfVdUe7+WzQEM+KtbaHc0oUwj6g6yctdKCgjFmRspXUFgIHEp53eidG82HgP8e7U0RuV5ENovI5ubm5klXKjoQp6svllFHM7jlLna17EJVJ/3ZxhgzFU25jmYR+XNgPfC10cqo6h2qul5V19fV1U36s9p73bpH1aWZBYXVc1bTEmmhuXfyAckYY6aifAWFw8CilNcN3rkhROQy3Laf71bVnC8wlAgKmWYKiZnN1oRkjJlp8hUUngdWisgyEQkB1wAbUwuIyFnAv+ECQlM+KpUIClUZZgqnzj4VgJ0nbLkLY8zMkpegoKox4AbgIWAn8AtV3S4iXxSRd3vFvgZUAP8pIltFZOMot8ua9p7JNR9VhCpYXLmYV1ptFzZjzMwSyNcHqeqDwIPDzt2S8vyyfNUlYbJ9CuDtrWCZgjFmhplyHc35dDJBYc2cNTR2NdLZ35ntahljTMFYUGByQWFtjZt798iBR7JaJ2OMKaSiDwrlIT9Bf+b/DOfNP4+z6s/iq89/lcbOxhzUzhhj8q+og0JbT3RSWQJAwBfgy2/5MgA3P3EzsXgsm1UzxpiCKOqg0N4bzXg4aqqFFQv57PmfZWvzVv79pX/PYs2MMaYwijoodPROPlNIeMfyd/DO5e/key99j61NW7NUM2OMKYyiDgrtvdGMZzOn85nzPsP88vnc9MRNNhrJGDOtFX1QONlMAdxkttvechtHu49y63O3ZqFmxhhTGBYUshAUANbVr+Mjb/gID+x9gF/v/XVW7mmMMflWtEGhPxanNzqQtaAA8OEzPsxZ9WfxpWe/ZMNUjTHTUtEGhc7I5BbDG0timKogNkzVGDMtFW1QSK6QGs5eUAAbpmqMmd6KNih0RNxf8VWl2V8T0IapGmOmq+INCjnKFBJsmKoxZjoq3qCQgz6FVDZM1RgzHRVvUOj1mo9ylCmADVM1xkw/xRsUIpNfNjsTNkzVGDOdFG9Q6I0S8AnhYG7/CVKHqd70xE02TNUYM6UVb1CIuBVSRSTnn7WwYiGfO/9z/LH5jzZM1RgzpRVtUOiMxKgM522Lat6+/O28a/m7bJiqMWZKy1tQEJENIvKKiOwWkZvSvH+RiLwoIjERuTrX9enojea0kzmdT5/3aRumaoyZ0vISFETED3wHuAJYC1wrImuHFTsIXAf8Rz7qlO9MAWyYqjFm6stXpnAusFtV96pqP3A3cGVqAVXdr6ovAfF8VKgQQQFsmKoxZmrLV1BYCBxKed3onZsUEbleRDaLyObm5uZJ3WPBrDDLaismW4WTYsNUjTFT1bTsaFbVO1R1vaqur6urm9Q9fvhX53LTFauzXLOJsWGqxpipKl9B4TCwKOV1g3euaKUOU/3GC9/gaPdRVLXQ1TLGFLl8Nao/D6wUkWW4YHAN8IE8ffaU9fblb+ep15/iJzt+wk92/ISyQBkrZq1gWfUyVsxawYrqFSyftZyFFQvxybRM6owx04zk669TEXk78E3AD/xAVW8VkS8Cm1V1o4icA/wSmA1EgKOqetp4912/fr1u3rw5l1XPqYH4AFuatrC3fS972vawp30Pe9v20tw72FcS9odZVr1sRLBYVLmIgC//neXGmOlNRF5Q1fVp35vuTRbTPSiMpqO/g71te0cEiyPdR5JlAr4AS6uWsrx6OStmuUCxonoFS6qWEPKHClh7Y8xUNlZQsD8zp6iqUBXr6texrn7dkPM90R72te9jT/se9rS5QLGzZScPH3gYxQV4v/hZVLloRLBYWr2U0kBpIb6OMWaasKAwzZQFyzit9jROqx3ashaJRTjQcWBIVrGnfQ9/aPwDAzoAgCAsrFiYDBKpj+XB8kJ8HWPMFGNBYYYIB8KsmrOKVXNWDTkfHYhysPPgiGDxzOvPEI1Hk+Xmlc9jefXyZHYxt2wu4UCYskAZ4UCYcCBMaaCUsN89t45vY2YmCwozXNAfdJ3Ts1YMOR+Lxzjcddg1QSX6Ldr2cM+xe4gMRMa9byI4lAZKhwSM0kDp0HOBMGF/mLJgWdprUq9LPRf05WcFW2PMUBYUilTAF2BJ1RKWVC3hUi5Nno9rnNe7Xqcl0kJvrJdILEJvrNc9H4iMPOc9jwxEiMQidPR3cKznWPK9xDVxzWz1Ep/4hmQmiWCRGmgSz9NlM6XBUkr9Q4NTqb+U0uDgPW3kljEj2f8VZgif+GiobKChsiFr91RVovFo2kDSG+2ldyDl3BhBKPHY3NM85L1E8MlU0BccGXCGZTPJgJMmm0kNQiX+EgK+AEFf0D36g4PPUx794rcMyExpFhRMzokIIX+IkD9EdUl1Tj4jrvEhmclo2UxvdDDYjAg4A73J8y2RlmTA6Y25wJWt5UjSBYvhj0PO+QMEJUjQHyQgLuCMd/249x/jXumeB3wB60cqEhYUzIzgEx9lwTLKgmU5+4xoPDo0UKRkM/0D/UTjUaLxKLF4jOhAlJh6j/HY4PkMH/vj/fTEeoacH+2eMc3tGlp+8U888KQGnUkGsiFZ10kERcvOMmNBwZgJCvqCBENBKkOVha5KWqo6GDhSA9R4j6kBbIKBbLTnqY/dA91E+8a/Z+oouFwQZNIBbNTsbazM7iSDYur9ChHMLCgYM0OIiPur2p/fHQVPlqoyoAOZZVIpASyqo2dPE3kcHhT7Yn10x7sndG1iDlCuBCQwZiC799334vf5s/uZWb2bMcZkSESSv/zChAtdnYzENe6a7iaSQWWpSTE1kOWin8eCgjHGTJJPfMlBFDOFDScwxhiTZEHBGGNMkgUFY4wxSRYUjDHGJFlQMMYYk2RBwRhjTJIFBWOMMUkWFIwxxiSJqha6DidFRJqBA5O8vBY4nsXqTAf2nYtDsX3nYvu+cHLfeYmq1qV7Y9oHhZMhIptVdX2h65FP9p2LQ7F952L7vpC772zNR8YYY5IsKBhjjEkq9qBwR6ErUAD2nYtDsX3nYvu+kKPvXNR9CsYYY4Yq9kzBGGNMCgsKxhhjkooyKIjIBhF5RUR2i8hNha5PronIIhF5VER2iMh2EflkoeuULyLiF5EtIvLrQtclH0RklojcIyK7RGSniFxQ6Drlmoj8nfdz/bKI/ExEptf2bRMgIj8QkSYReTnl3BwReVhEXvMeZ2fjs4ouKIiIH/gOcAWwFrhWRNYWtlY5FwP+QVXXAucDHy+C75zwSWBnoSuRR98CfqOqq4E3MMO/u4gsBG4E1qvq6YAfuKawtcqJHwEbhp27Cfidqq4Efue9PmlFFxSAc4HdqrpXVfuBu4ErC1ynnFLVI6r6ove8E/eLYmFha5V7ItIAvAO4s9B1yQcRqQYuAr4PoKr9qtpW2FrlRQAoFZEAUAa8XuD6ZJ2qPg60DDt9JfBj7/mPgauy8VnFGBQWAodSXjdSBL8gE0RkKXAW8Fxha5IX3wT+FxAvdEXyZBnQDPzQazK7U0TKC12pXFLVw8D/AQ4CR4B2Vf1tYWuVN3NV9Yj3/CgwNxs3LcagULREpAK4F/hbVe0odH1ySUTeCTSp6guFrkseBYCzgf+rqmcB3WSpSWGq8trRr8QFxAVAuYj8eWFrlX/q5hZkZX5BMQaFw8CilNcN3rkZTUSCuIBwl6reV+j65MGbgXeLyH5cE+GlIvLTwlYp5xqBRlVNZIH34ILETHYZsE9Vm1U1CtwHvKnAdcqXYyIyH8B7bMrGTYsxKDwPrBSRZSISwnVKbSxwnXJKRATXzrxTVW8vdH3yQVVvVtUGVV2K+2/8e1Wd0X9BqupR4JCIrPJOvRXYUcAq5cNB4HwRKfN+zt/KDO9cT7ER+Evv+V8Cv8rGTQPZuMl0oqoxEbkBeAg3UuEHqrq9wNXKtTcDfwFsE5Gt3rlPq+qDBayTyY1PAHd5f/DsBf6qwPXJKVV9TkTuAV7EjbLbwgxc8kJEfgZcDNSKSCPweeA24Bci8iHc9gHvy8pn2TIXxhhjEoqx+cgYY8woLCgYY4xJsqBgjDEmyYKCMcaYJAsKxhhjkiwoGGOMSbKgYIwxJsmCgjGTICINIvL+Ud4rFZE/eMu0p3s/JCKPe6t6GjOlWFAwZnLeyujrCv01cJ+qDqR701uy/XdA2qBiTCFZUDAmQyJyIXA7cLWIbBWR5cOKfBBvHRoRKReRB0Tkj97OYIlAcL9XzpgpxdJXYzKkqk+KyPPAP6rqy6nveWsOLVfV/d6pDcDrqvoO7/1q7/zLwDl5qrIxE2aZgjGTswrYleZ8LZC629k24HIR+YqIvEVV2wG8pqV+EanMfVWNmTgLCsZkSERqcTt8xdK83QskN45X1VdxfQ/bgC+JyC0pZUuASC7rakymrPnImMwtZZR9gFW1VUT8IhJW1YiILABaVPWnItIG/H8AIlIDHPc2hjFmyrBMwZjM7cKta/+yiKTb5eu3wIXe8zOATd4+Fp8HvuSdvwR4IOc1NSZDtp+CMVkmImcDf6eqfzFGmfuAm7zmJWOmDMsUjMkyVX0ReHSsyWvA/RYQzFRkmYIxxpgkyxSMMcYkWVAwxhiTZEHBGGNMkgUFY4wxSRYUjDHGJFlQMMYYk/T/A6aNtMVFnwshAAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -234,10 +379,8 @@ }, { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -277,7 +420,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 32, "metadata": {}, "outputs": [ { @@ -301,7 +444,7 @@ " ipopt/acceptable_tol 1e+20\r\n", " ipopt/hessian_approximation b'limited-memory'\r\n", " ipopt/limited_memory_update_type b'bfgs'\r\n", - " ipopt/max_iter 20\r\n", + " ipopt/max_iter 30\r\n", " ipopt/tol 1e-09\r\n", " ipopt/watchdog_shortened_iter_trigger 0\r\n", " toms611/mxfcal 100000000.0\r\n" @@ -309,26 +452,26 @@ } ], "source": [ - "# enable derivate checker\n", + "# enable derivative checker\n", "input_file = f'{example_data_dir}/example_data.h5'\n", "\n", - "#!{optimizationOptionsPy} {input_file} -s ipopt/derivative_test first-order\n", - "#!{optimizationOptionsPy} {input_file} -s ipopt/derivative_test_print_all yes\n", + "#!{optimization_options_py} {input_file} -s ipopt/derivative_test first-order\n", + "#!{optimization_options_py} {input_file} -s ipopt/derivative_test_print_all yes\n", "\n", "# Use Ipopt\n", - "!{optimizationOptionsPy} {input_file} -s optimizer 0\n", + "!{optimization_options_py} {input_file} -s optimizer 0\n", "\n", "# Perform one optimizer runs from different starting points\n", - "!{optimizationOptionsPy} {input_file} -s numStarts 1\n", + "!{optimization_options_py} {input_file} -s numStarts 1\n", "\n", "# Run for 20 iterations\n", - "!{optimizationOptionsPy} {input_file} -s ipopt/max_iter 20\n", + "!{optimization_options_py} {input_file} -s ipopt/max_iter 30\n", "\n", "# Disable hierarchical optimization (see below)\n", - "!{optimizationOptionsPy} {input_file} -s hierarchicalOptimization 0\n", + "!{optimization_options_py} {input_file} -s hierarchicalOptimization 0\n", "\n", "# Print settings\n", - "!{optimizationOptionsPy} {input_file}" + "!{optimization_options_py} {input_file}" ] }, { @@ -342,45 +485,45 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 0 g: -1.25564e+12 fd_c: -1.25588e+12 Δ/ff: 1.060476e-05 f: 2.2618e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 1 g: -3.95647e+10 fd_c: -3.96655e+10 Δ/ff: 4.456608e-06 f: 2.2618e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 2 g: 3.95672e+10 fd_c: 3.93782e+10 Δ/ff: 8.357255e-06 f: 2.2618e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 3 g: 2.96427e+10 fd_c: 2.9551e+10 Δ/ff: 4.053743e-06 f: 2.2618e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 4 g: 1.59802e+12 fd_c: 1.59777e+12 Δ/ff: 1.114006e-05 f: 2.2618e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 5 g: 1.38876e+10 fd_c: 1.38876e+10 Δ/ff: -1.304981e-11 f: 2.2618e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 6 g: 1.59715e+08 fd_c: 1.59715e+08 Δ/ff: 1.536720e-12 f: 2.2618e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 7 g: -2.87507e+12 fd_c: -2.87507e+12 Δ/ff: 5.650279e-11 f: 2.2618e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 8 g: 3.87833e+08 fd_c: 3.87833e+08 Δ/ff: -5.849452e-12 f: 2.2618e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] Walltime on master: 0.346655s, CPU time of all processes: 2.278692s\u001b[0m\n", + "\u001B[32m[2020-06-24 17:41:30] [INF] [-1:140407870474176/] 0 g: -3.07804e+14 fd_c: -3.07834e+14 Δ/ff: 1.820688e-04 f: 1.61202e+14\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:30] [INF] [-1:140407870474176/] 1 g: -2.22547e+13 fd_c: -2.23559e+13 Δ/ff: 6.276508e-04 f: 1.61205e+14\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:30] [INF] [-1:140407870474176/] 2 g: 2.23191e+13 fd_c: 2.23727e+13 Δ/ff: -3.327962e-04 f: 1.61205e+14\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:30] [INF] [-1:140407870474176/] 3 g: 1.44004e+13 fd_c: 1.43986e+13 Δ/ff: 1.096761e-05 f: 1.61205e+14\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:30] [INF] [-1:140407870474176/] 4 g: 3.92648e+14 fd_c: 3.92711e+14 Δ/ff: -3.915439e-04 f: 1.61209e+14\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:30] [INF] [-1:140407870474176/] 5 g: 7.22972e+14 fd_c: 7.22972e+14 Δ/ff: -1.633158e-09 f: 1.61212e+14\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:30] [INF] [-1:140407870474176/] 6 g: 1.48764e+07 fd_c: 1.48766e+07 Δ/ff: -8.200509e-13 f: 1.61205e+14\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:30] [INF] [-1:140407870474176/] 7 g: -4.32827e+10 fd_c: -4.32827e+10 Δ/ff: -9.508153e-12 f: 1.61205e+14\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:30] [INF] [-1:140407870474176/] 8 g: 1.82786e+08 fd_c: 1.82784e+08 Δ/ff: 7.928618e-12 f: 1.61205e+14\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:30] [INF] [-1:140407870474176/] Walltime on master: 0.357358s, CPU time of all processes: 1.190509s\u001B[0m\r\n", "\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 0 g: 164869 fd_c: 167188 Δ/ff: -1.752857e-10 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 1 g: -7.41219e+06 fd_c: -7.40234e+06 Δ/ff: -7.441389e-10 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 2 g: -1.91554e+07 fd_c: -1.91164e+07 Δ/ff: -2.949228e-09 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 3 g: 99808.7 fd_c: 99804.7 Δ/ff: 3.037380e-13 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 4 g: 8121.31 fd_c: 8203.12 Δ/ff: -6.185202e-12 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 5 g: 0.0242575 fd_c: 97.6562 Δ/ff: -7.381162e-12 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 6 g: 3.05525e+08 fd_c: 3.05525e+08 Δ/ff: 4.660476e-12 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 7 g: 184.207 fd_c: 97.6562 Δ/ff: 6.543384e-12 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] 8 g: 1.11678e+08 fd_c: 1.11678e+08 Δ/ff: 3.823629e-12 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:42] [INF] [-1/] Walltime on master: 0.272558s, CPU time of all processes: 1.777498s\u001b[0m\n", + "\u001B[32m[2020-06-24 17:41:31] [INF] [-1:140118083160000/] 0 g: -6.21971e+09 fd_c: -6.21836e+09 Δ/ff: -7.588395e-08 f: 1.77565e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:31] [INF] [-1:140118083160000/] 1 g: -1.01378e+10 fd_c: -1.01431e+10 Δ/ff: 3.019935e-07 f: 1.77565e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:31] [INF] [-1:140118083160000/] 2 g: 1.01916e+10 fd_c: 1.01875e+10 Δ/ff: 2.299636e-07 f: 1.77565e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:31] [INF] [-1:140118083160000/] 3 g: 1.01496e+10 fd_c: 1.01498e+10 Δ/ff: -1.220489e-08 f: 1.77565e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:31] [INF] [-1:140118083160000/] 4 g: 7.63243e+08 fd_c: 7.61412e+08 Δ/ff: 1.030921e-07 f: 1.77565e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:31] [INF] [-1:140118083160000/] 5 g: 3.5914e+10 fd_c: 3.5914e+10 Δ/ff: -1.675128e-12 f: 1.77565e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:31] [INF] [-1:140118083160000/] 6 g: 8.66367e+07 fd_c: 8.66367e+07 Δ/ff: -1.943272e-12 f: 1.77565e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:31] [INF] [-1:140118083160000/] 7 g: 121.481 fd_c: 195.312 Δ/ff: -4.158002e-12 f: 1.77565e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:31] [INF] [-1:140118083160000/] 8 g: 3.66721e+08 fd_c: 3.66721e+08 Δ/ff: -2.067021e-11 f: 1.77565e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:31] [INF] [-1:140118083160000/] Walltime on master: 0.420946s, CPU time of all processes: 1.274342s\u001B[0m\r\n", "\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] 0 g: 164869 fd_c: 167188 Δ/ff: -1.752857e-10 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] 1 g: -7.41219e+06 fd_c: -7.40225e+06 Δ/ff: -7.515219e-10 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] 2 g: -1.91554e+07 fd_c: -1.91164e+07 Δ/ff: -2.949228e-09 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] 3 g: 99808.7 fd_c: 99902.3 Δ/ff: -7.079258e-12 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] 4 g: 8121.31 fd_c: 8105.47 Δ/ff: 1.197793e-12 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] 5 g: 0.0242575 fd_c: 0 Δ/ff: 1.833909e-15 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] 6 g: 3.05525e+08 fd_c: 3.05525e+08 Δ/ff: 4.660476e-12 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] 7 g: 184.207 fd_c: 195.312 Δ/ff: -8.396113e-13 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] 8 g: 1.11678e+08 fd_c: 1.11678e+08 Δ/ff: 3.823629e-12 f: 1.32272e+13\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] Walltime on master: 0.313284s, CPU time of all processes: 2.024952s\u001b[0m\n", + "\u001B[32m[2020-06-24 17:41:32] [INF] [-1:140466688518080/] 0 g: 3.0421e+07 fd_c: 3.04203e+07 Δ/ff: 4.257906e-11 f: 1.62622e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:32] [INF] [-1:140466688518080/] 1 g: -766.774 fd_c: 195.312 Δ/ff: -5.916097e-11 f: 1.62622e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:32] [INF] [-1:140466688518080/] 2 g: -9.463e+06 fd_c: -9.46338e+06 Δ/ff: 2.347750e-11 f: 1.62622e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:32] [INF] [-1:140466688518080/] 3 g: 4.0764e+07 fd_c: 4.07931e+07 Δ/ff: -1.786592e-09 f: 1.62622e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:32] [INF] [-1:140466688518080/] 4 g: 5.7084e+07 fd_c: 5.7084e+07 Δ/ff: -1.569356e-12 f: 1.62622e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:32] [INF] [-1:140466688518080/] 5 g: -1.73506 fd_c: 0 Δ/ff: -1.066930e-13 f: 1.62622e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:32] [INF] [-1:140466688518080/] 6 g: 3.40035e+08 fd_c: 3.40035e+08 Δ/ff: -7.920917e-12 f: 1.62622e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:32] [INF] [-1:140466688518080/] 7 g: -2.35915e+06 fd_c: -2.35918e+06 Δ/ff: 1.758269e-12 f: 1.62622e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:32] [INF] [-1:140466688518080/] 8 g: 1.20306e+08 fd_c: 1.20307e+08 Δ/ff: -7.991474e-12 f: 1.62622e+13\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:32] [INF] [-1:140466688518080/] Walltime on master: 0.363544s, CPU time of all processes: 1.217862s\u001B[0m\r\n", "\n" ] } @@ -403,7 +546,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 34, "metadata": { "scrolled": true }, @@ -412,126 +555,140 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001b[0m\n", - "\n", - "List of user-set options:\n", - "\n", - " Name Value used\n", - " acceptable_iter = 1 yes\n", - " acceptable_obj_change_tol = 1e-12 yes\n", - " acceptable_tol = 1e+20 yes\n", - " hessian_approximation = limited-memory yes\n", - " limited_memory_update_type = bfgs yes\n", - " max_iter = 20 yes\n", - " print_level = 5 yes\n", - " print_user_options = yes yes\n", - " tol = 1e-09 yes\n", - " watchdog_shortened_iter_trigger = 0 yes\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.11.9, running with linear solver mumps.\n", - "NOTE: Other linear solvers might be more efficient (see Ipopt documentation).\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 0\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 0\n", - "\n", - "Total number of variables............................: 9\n", - " variables with only lower bounds: 0\n", - " variables with lower and upper bounds: 9\n", - " variables with only upper bounds: 0\n", - "Total number of equality constraints.................: 0\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] [o0i0] iter: 0 cost: 626.531 time_iter: wall: 0.126493s cpu: 0.371217s time_optim: wall: 0.126493s cpu: 0.371217s\u001b[0m\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 6.2653094e+02 0.00e+00 1.00e+02 0.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] [o0i1] iter: 1 cost: 1463.44 time_iter: wall: 0.134251s cpu: 0.162105s time_optim: wall: 0.260744s cpu: 0.533322s\u001b[0m\n", - " 1 1.4634444e+03 0.00e+00 4.86e+01 2.0 5.93e+01 - 9.91e-01 2.64e-02f 2\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] [o0i2] iter: 2 cost: 649.013 time_iter: wall: 0.0885094s cpu: 0.123807s time_optim: wall: 0.349254s cpu: 0.657129s\u001b[0m\n", - " 2 6.4901341e+02 0.00e+00 5.14e+01 2.2 6.01e-01 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] [o0i3] iter: 3 cost: 314.319 time_iter: wall: 0.0601696s cpu: 0.115994s time_optim: wall: 0.409423s cpu: 0.773124s\u001b[0m\n", - " 3 3.1431854e+02 0.00e+00 5.53e+01 1.5 7.42e-01 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:27:43] [INF] [-1/] [o0i4] iter: 4 cost: -113.523 time_iter: wall: 0.0422327s cpu: 0.109398s time_optim: wall: 0.451656s cpu: 0.882522s\u001b[0m\n", - " 4 -1.1352340e+02 0.00e+00 1.39e+01 0.3 2.72e-01 - 9.68e-01 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i5] iter: 5 cost: -222.462 time_iter: wall: 0.0326542s cpu: 0.10165s time_optim: wall: 0.484311s cpu: 0.984172s\u001b[0m\n", - " 5 -2.2246159e+02 0.00e+00 9.68e+00 -0.5 4.58e-01 - 9.94e-01 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i6] iter: 6 cost: -288.147 time_iter: wall: 0.0349477s cpu: 0.103492s time_optim: wall: 0.519258s cpu: 1.08766s\u001b[0m\n", - " 6 -2.8814676e+02 0.00e+00 1.04e+01 -1.8 2.99e-01 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i7] iter: 7 cost: -334.082 time_iter: wall: 0.0469568s cpu: 0.120218s time_optim: wall: 0.566215s cpu: 1.20788s\u001b[0m\n", - " 7 -3.3408184e+02 0.00e+00 6.67e+00 -2.8 4.35e-01 - 1.00e+00 5.00e-01f 2\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i8] iter: 8 cost: -356.625 time_iter: wall: 0.0436224s cpu: 0.111017s time_optim: wall: 0.609838s cpu: 1.3189s\u001b[0m\n", - " 8 -3.5662478e+02 0.00e+00 2.60e+00 -2.6 2.50e-01 - 1.00e+00 5.00e-01f 2\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i9] iter: 9 cost: -358.789 time_iter: wall: 0.0385677s cpu: 0.0932949s time_optim: wall: 0.648406s cpu: 1.41219s\u001b[0m\n", - " 9 -3.5878931e+02 0.00e+00 2.85e+00 -4.0 1.20e-01 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i10] iter: 10 cost: -366.213 time_iter: wall: 0.0374389s cpu: 0.0954053s time_optim: wall: 0.685845s cpu: 1.5076s\u001b[0m\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -3.6621295e+02 0.00e+00 5.23e-01 -5.5 7.77e-02 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i11] iter: 11 cost: -366.866 time_iter: wall: 0.0475576s cpu: 0.105388s time_optim: wall: 0.733403s cpu: 1.61299s\u001b[0m\n", - " 11 -3.6686642e+02 0.00e+00 4.37e-01 -7.2 2.93e-02 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i12] iter: 12 cost: -367.081 time_iter: wall: 0.0632619s cpu: 0.146968s time_optim: wall: 0.796665s cpu: 1.75996s\u001b[0m\n", - " 12 -3.6708103e+02 0.00e+00 3.39e-01 -8.5 2.18e-01 - 1.00e+00 1.25e-01f 4\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i13] iter: 13 cost: -367.411 time_iter: wall: 0.043275s cpu: 0.118648s time_optim: wall: 0.83994s cpu: 1.8786s\u001b[0m\n", - " 13 -3.6741091e+02 0.00e+00 9.33e-01 -10.0 5.93e-02 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i14] iter: 14 cost: -367.804 time_iter: wall: 0.0526644s cpu: 0.13573s time_optim: wall: 0.892605s cpu: 2.01433s\u001b[0m\n", - " 14 -3.6780351e+02 0.00e+00 9.75e-01 -11.0 3.24e-01 - 1.00e+00 2.50e-01f 3\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i15] iter: 15 cost: -367.807 time_iter: wall: 0.0618123s cpu: 0.135165s time_optim: wall: 0.954417s cpu: 2.1495s\u001b[0m\n", - " 15 -3.6780707e+02 0.00e+00 7.95e-01 -11.0 9.61e-01 - 1.00e+00 1.25e-01f 4\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i16] iter: 16 cost: -368.218 time_iter: wall: 0.0525751s cpu: 0.119065s time_optim: wall: 1.00699s cpu: 2.26856s\u001b[0m\n", - " 16 -3.6821774e+02 0.00e+00 5.26e-01 -11.0 1.79e-01 - 1.00e+00 5.00e-01f 2\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i17] iter: 17 cost: -368.464 time_iter: wall: 0.0627604s cpu: 0.123603s time_optim: wall: 1.06975s cpu: 2.39217s\u001b[0m\n", - " 17 -3.6846368e+02 0.00e+00 3.89e-01 -11.0 9.68e-02 - 1.00e+00 5.00e-01f 2\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i18] iter: 18 cost: -368.504 time_iter: wall: 0.102443s cpu: 0.152022s time_optim: wall: 1.1722s cpu: 2.54419s\u001b[0m\n", - " 18 -3.6850448e+02 0.00e+00 3.31e-01 -11.0 1.18e-01 - 1.00e+00 2.50e-01f 3\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i19] iter: 19 cost: -368.528 time_iter: wall: 0.130869s cpu: 0.13003s time_optim: wall: 1.30307s cpu: 2.67422s\u001b[0m\n", - " 19 -3.6852794e+02 0.00e+00 2.10e-01 -11.0 1.47e-01 - 1.00e+00 1.25e-01f 4\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i20] iter: 20 cost: -368.587 time_iter: wall: 0.052877s cpu: 0.124684s time_optim: wall: 1.35594s cpu: 2.7989s\u001b[0m\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -3.6858740e+02 0.00e+00 1.88e-01 -11.0 2.33e-02 - 1.00e+00 5.00e-01f 2\n", - "\n", - "Number of Iterations....: 20\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -8.4095251536798425e+00 -3.6858740196040020e+02\n", - "Dual infeasibility......: 1.8768049203585790e-01 8.2259894219920504e+00\n", - "Constraint violation....: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Complementarity.........: 1.0038419038382084e-11 4.3998141696835393e-10\n", - "Overall NLP error.......: 1.8768049203585790e-01 8.2259894219920504e+00\n", - "\n", - "\n", - "Number of objective function evaluations = 84\n", - "Number of objective gradient evaluations = 21\n", - "Number of equality constraint evaluations = 0\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 0\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 0\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.809\n", - "Total CPU secs in NLP function evaluations = 6.780\n", - "\n", - "EXIT: Maximum Number of Iterations Exceeded.\n", - "\u001b[32m[2020-01-31 18:27:44] [INF] [-1/] [o0i21] Optimizer status 1, final llh: -3.685874e+02, time: wall: 1.356467 cpu: 2.798904.\u001b[0m\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[32m[2020-01-31 18:27:46] [INF] [-1/] Walltime on master: 3.009616s, CPU time of all processes: 8.022685s\u001b[0m\r\n" + "\u001B[32m[2020-06-24 17:41:33] [INF] [-1:140425994618816/] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001B[0m\r\n", + "\r\n", + "List of user-set options:\r\n", + "\r\n", + " Name Value used\r\n", + " acceptable_iter = 1 yes\r\n", + " acceptable_obj_change_tol = 1e-12 yes\r\n", + " acceptable_tol = 1e+20 yes\r\n", + " hessian_approximation = limited-memory yes\r\n", + " limited_memory_update_type = bfgs yes\r\n", + " max_iter = 30 yes\r\n", + " print_level = 5 yes\r\n", + " print_user_options = yes yes\r\n", + " tol = 1e-09 yes\r\n", + " watchdog_shortened_iter_trigger = 0 yes\r\n", + "\r\n", + "******************************************************************************\r\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\r\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\r\n", + " For more information visit http://projects.coin-or.org/Ipopt\r\n", + "******************************************************************************\r\n", + "\r\n", + "This is Ipopt version 3.12.12, running with linear solver ma27.\r\n", + "\r\n", + "Number of nonzeros in equality constraint Jacobian...: 0\r\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\r\n", + "Number of nonzeros in Lagrangian Hessian.............: 0\r\n", + "\r\n", + "Total number of variables............................: 9\r\n", + " variables with only lower bounds: 0\r\n", + " variables with lower and upper bounds: 9\r\n", + " variables with only upper bounds: 0\r\n", + "Total number of equality constraints.................: 0\r\n", + "Total number of inequality constraints...............: 0\r\n", + " inequality constraints with only lower bounds: 0\r\n", + " inequality constraints with lower and upper bounds: 0\r\n", + " inequality constraints with only upper bounds: 0\r\n", + "\r\n", + "\u001B[32m[2020-06-24 17:41:33] [INF] [-1:140425699804928/] [o0i0] iter: 0 cost: 532.303 time_iter: wall: 0.137419s cpu: 0.127829s time_optim: wall: 0.137419s cpu: 0.127829s\u001B[0m\r\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\r\n", + " 0 5.3230269e+02 0.00e+00 1.00e+02 0.0 0.00e+00 - 0.00e+00 0.00e+00 0\r\n", + "\u001B[32m[2020-06-24 17:41:33] [INF] [-1:140425699804928/] [o0i1] iter: 1 cost: 820.034 time_iter: wall: 0.090377s cpu: 0.0783326s time_optim: wall: 0.227797s cpu: 0.206162s\u001B[0m\r\n", + " 1 8.2003355e+02 0.00e+00 4.00e+01 2.0 5.98e+01 - 9.91e-01 2.66e-02f 2\r\n", + "\u001B[32m[2020-06-24 17:41:33] [INF] [-1:140425699804928/] [o0i2] iter: 2 cost: 776.643 time_iter: wall: 0.117079s cpu: 0.106627s time_optim: wall: 0.344876s cpu: 0.312788s\u001B[0m\r\n", + " 2 7.7664256e+02 0.00e+00 5.20e+01 2.2 5.80e-01 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:33] [INF] [-1:140425699804928/] [o0i3] iter: 3 cost: -166.319 time_iter: wall: 0.0932628s cpu: 0.0802567s time_optim: wall: 0.438139s cpu: 0.393045s\u001B[0m\r\n", + " 3 -1.6631926e+02 0.00e+00 4.12e+01 1.5 2.34e+00 - 1.00e+00 2.50e-01f 3\r\n", + "\u001B[32m[2020-06-24 17:41:33] [INF] [-1:140425699804928/] [o0i4] iter: 4 cost: -267.208 time_iter: wall: 0.0768777s cpu: 0.0693811s time_optim: wall: 0.515016s cpu: 0.462426s\u001B[0m\r\n", + " 4 -2.6720761e+02 0.00e+00 3.92e+00 0.2 1.85e-01 - 9.91e-01 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:33] [INF] [-1:140425699804928/] [o0i5] iter: 5 cost: -325.047 time_iter: wall: 0.0737827s cpu: 0.0664222s time_optim: wall: 0.588799s cpu: 0.528848s\u001B[0m\r\n", + " 5 -3.2504664e+02 0.00e+00 4.86e+00 -1.2 1.59e-01 - 9.84e-01 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:33] [INF] [-1:140425699804928/] [o0i6] iter: 6 cost: -336.398 time_iter: wall: 0.0699238s cpu: 0.0622717s time_optim: wall: 0.658723s cpu: 0.59112s\u001B[0m\r\n", + " 6 -3.3639830e+02 0.00e+00 1.12e+01 -1.9 8.74e-01 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i7] iter: 7 cost: -389.279 time_iter: wall: 0.0860524s cpu: 0.0719065s time_optim: wall: 0.744776s cpu: 0.663026s\u001B[0m\r\n", + " 7 -3.8927856e+02 0.00e+00 6.91e+00 -1.8 7.08e-01 - 1.00e+00 2.50e-01f 3\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i8] iter: 8 cost: -417.125 time_iter: wall: 0.0824051s cpu: 0.0701718s time_optim: wall: 0.827181s cpu: 0.733198s\u001B[0m\r\n", + " 8 -4.1712507e+02 0.00e+00 2.72e+00 -2.7 5.18e-01 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i9] iter: 9 cost: -425.124 time_iter: wall: 0.0837048s cpu: 0.0707955s time_optim: wall: 0.910886s cpu: 0.803994s\u001B[0m\r\n", + " 9 -4.2512435e+02 0.00e+00 2.77e+00 -4.1 1.14e-01 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i10] iter: 10 cost: -431.91 time_iter: wall: 0.0717744s cpu: 0.0638436s time_optim: wall: 0.982661s cpu: 0.867837s\u001B[0m\r\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\r\n", + " 10 -4.3191005e+02 0.00e+00 9.02e-01 -5.5 4.63e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i11] iter: 11 cost: -432.548 time_iter: wall: 0.0821081s cpu: 0.0695296s time_optim: wall: 1.06477s cpu: 0.937367s\u001B[0m\r\n", + " 11 -4.3254817e+02 0.00e+00 7.07e-01 -7.2 3.94e-02 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i12] iter: 12 cost: -433.253 time_iter: wall: 0.0700837s cpu: 0.0621244s time_optim: wall: 1.13485s cpu: 0.999491s\u001B[0m\r\n", + " 12 -4.3325317e+02 0.00e+00 5.07e-01 -8.8 3.00e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i13] iter: 13 cost: -434.385 time_iter: wall: 0.0719023s cpu: 0.0637952s time_optim: wall: 1.20676s cpu: 1.06329s\u001B[0m\r\n", + " 13 -4.3438479e+02 0.00e+00 6.25e-01 -10.3 4.40e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i14] iter: 14 cost: -438.759 time_iter: wall: 0.0663257s cpu: 0.0583022s time_optim: wall: 1.27308s cpu: 1.12159s\u001B[0m\r\n", + " 14 -4.3875867e+02 0.00e+00 3.98e+00 -11.0 5.21e-01 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i15] iter: 15 cost: -440.48 time_iter: wall: 0.09416s cpu: 0.0771593s time_optim: wall: 1.36724s cpu: 1.19875s\u001B[0m\r\n", + " 15 -4.4047967e+02 0.00e+00 4.39e+00 -11.0 2.61e+00 - 1.00e+00 6.22e-02f 5\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i16] iter: 16 cost: -442.029 time_iter: wall: 0.0896711s cpu: 0.0733529s time_optim: wall: 1.45691s cpu: 1.2721s\u001B[0m\r\n", + " 16 -4.4202943e+02 0.00e+00 2.94e+00 -11.0 4.38e-01 - 1.00e+00 1.25e-01f 4\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i17] iter: 17 cost: -443.967 time_iter: wall: 0.0669892s cpu: 0.0584416s time_optim: wall: 1.5239s cpu: 1.33054s\u001B[0m\r\n", + " 17 -4.4396683e+02 0.00e+00 1.78e+00 -11.0 1.93e-01 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i18] iter: 18 cost: -446.323 time_iter: wall: 0.0676223s cpu: 0.0592318s time_optim: wall: 1.59153s cpu: 1.38977s\u001B[0m\r\n", + " 18 -4.4632309e+02 0.00e+00 1.06e+00 -11.0 9.67e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:34] [INF] [-1:140425699804928/] [o0i19] iter: 19 cost: -446.807 time_iter: wall: 0.0673716s cpu: 0.0595199s time_optim: wall: 1.6589s cpu: 1.44929s\u001B[0m\r\n", + " 19 -4.4680666e+02 0.00e+00 7.12e-01 -11.0 1.64e-01 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:35] [INF] [-1:140425699804928/] [o0i20] iter: 20 cost: -446.911 time_iter: wall: 0.098772s cpu: 0.0806446s time_optim: wall: 1.75767s cpu: 1.52994s\u001B[0m\r\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\r\n", + " 20 -4.4691082e+02 0.00e+00 5.78e-01 -11.0 5.12e-01 - 1.00e+00 3.12e-02f 6\r\n", + "\u001B[32m[2020-06-24 17:41:35] [INF] [-1:140425699804928/] [o0i21] iter: 21 cost: -447.227 time_iter: wall: 0.066089s cpu: 0.0577964s time_optim: wall: 1.82376s cpu: 1.58774s\u001B[0m\r\n", + " 21 -4.4722745e+02 0.00e+00 4.61e-02 -11.0 6.51e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:35] [INF] [-1:140425699804928/] [o0i22] iter: 22 cost: -447.228 time_iter: wall: 0.0922707s cpu: 0.0758644s time_optim: wall: 1.91603s cpu: 1.6636s\u001B[0m\r\n", + " 22 -4.4722816e+02 0.00e+00 4.07e-02 -11.0 3.33e-02 - 1.00e+00 1.25e-01f 4\r\n", + "\u001B[32m[2020-06-24 17:41:35] [INF] [-1:140425699804928/] [o0i23] iter: 23 cost: -447.228 time_iter: wall: 0.0955807s cpu: 0.0783362s time_optim: wall: 2.01161s cpu: 1.74194s\u001B[0m\r\n", + " 23 -4.4722838e+02 0.00e+00 5.88e-02 -11.0 3.66e-02 - 1.00e+00 6.25e-02f 5\r\n", + "\u001B[32m[2020-06-24 17:41:35] [INF] [-1:140425699804928/] [o0i24] iter: 24 cost: -447.23 time_iter: wall: 0.0814274s cpu: 0.0682416s time_optim: wall: 2.09304s cpu: 1.81018s\u001B[0m\r\n", + " 24 -4.4723019e+02 0.00e+00 2.31e-02 -11.0 3.32e-03 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:41:35] [INF] [-1:140425699804928/] [o0i25] iter: 25 cost: -447.231 time_iter: wall: 0.0737931s cpu: 0.0615733s time_optim: wall: 2.16683s cpu: 1.87175s\u001B[0m\r\n", + " 25 -4.4723112e+02 0.00e+00 1.71e-02 -11.0 6.07e-03 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:41:35] [INF] [-1:140425699804928/] [o0i26] iter: 26 cost: -447.231 time_iter: wall: 0.0784649s cpu: 0.0655171s time_optim: wall: 2.2453s cpu: 1.93727s\u001B[0m\r\n", + " 26 -4.4723130e+02 0.00e+00 1.31e-02 -11.0 2.84e-03 - 1.00e+00 2.50e-01f 3\r\n", + "\u001B[32m[2020-06-24 17:41:35] [INF] [-1:140425699804928/] [o0i27] iter: 27 cost: -447.232 time_iter: wall: 0.0659078s cpu: 0.0578224s time_optim: wall: 2.3112s cpu: 1.99509s\u001B[0m\r\n", + " 27 -4.4723151e+02 0.00e+00 1.05e-02 -11.0 1.01e-03 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:35] [INF] [-1:140425699804928/] [o0i28] iter: 28 cost: -447.232 time_iter: wall: 0.0834543s cpu: 0.0689585s time_optim: wall: 2.39466s cpu: 2.06405s\u001B[0m\r\n", + " 28 -4.4723162e+02 0.00e+00 1.13e-02 -11.0 2.20e-03 - 1.00e+00 2.50e-01f 3\r\n", + "\u001B[32m[2020-06-24 17:41:35] [INF] [-1:140425699804928/] [o0i29] iter: 29 cost: -447.232 time_iter: wall: 0.0683976s cpu: 0.0602698s time_optim: wall: 2.46306s cpu: 2.12432s\u001B[0m\r\n", + " 29 -4.4723185e+02 0.00e+00 5.13e-03 -11.0 1.09e-03 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:41:35] [INF] [-1:140425699804928/] [o0i30] iter: 30 cost: -447.232 time_iter: wall: 0.0851599s cpu: 0.0702836s time_optim: wall: 2.54822s cpu: 2.1946s\u001B[0m\r\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\r\n", + " 30 -4.4723198e+02 0.00e+00 1.25e-02 -11.0 1.23e-02 - 1.00e+00 2.50e-01f 3\r\n", + "\r\n", + "Number of Iterations....: 30\r\n", + "\r\n", + " (scaled) (unscaled)\r\n", + "Objective...............: -1.0027481219080936e+01 -4.4723198109367854e+02\r\n", + "Dual infeasibility......: 1.2481077281248806e-02 5.5666391157677142e-01\r\n", + "Constraint violation....: 0.0000000000000000e+00 0.0000000000000000e+00\r\n", + "Complementarity.........: 1.0053736651784596e-11 4.4840298993687491e-10\r\n", + "Overall NLP error.......: 1.2481077281248806e-02 5.5666391157677142e-01\r\n", + "\r\n", + "\r\n", + "Number of objective function evaluations = 130\r\n", + "Number of objective gradient evaluations = 31\r\n", + "Number of equality constraint evaluations = 0\r\n", + "Number of inequality constraint evaluations = 0\r\n", + "Number of equality constraint Jacobian evaluations = 0\r\n", + "Number of inequality constraint Jacobian evaluations = 0\r\n", + "Number of Lagrangian Hessian evaluations = 0\r\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.556\r\n", + "Total CPU secs in NLP function evaluations = 2.283\r\n", + "\r\n", + "EXIT: Maximum Number of Iterations Exceeded.\r\n", + "\u001B[32m[2020-06-24 17:41:35] [INF] [-1:140425699804928/] [o0i31] Optimizer status 1, final llh: -4.472320e+02, time: wall: 2.548704 cpu: 2.194602.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:37] [INF] [-1:140425994618816/] Walltime on master: 4.008655s, CPU time of all processes: 3.462642s\u001B[0m\r\n" ] } ], "source": [ "# !(cd {parpe_build_root} && exec make -j12) # rebuild\n", - "!rm -rf deleteme # delete old result files \n", + "!rm -rf deleteme # delete old result files\n", "\n", "# optimize (using a single process)\n", "!PARPE_NO_DEBUG=1 {example_binary_dir}/example_steadystate_multi -o deleteme/ {example_data_dir}/example_data.h5\n" @@ -543,20 +700,18 @@ "source": [ "### Analyze results\n", "\n", - "A good start for checking the results is a look at optimizer trajectories. This can be easily done using the *parPE* Python package: " + "A good start for checking the results is a look at optimizer trajectories. This can be easily done using the *parPE* Python package:" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 35, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -580,7 +735,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 36, "metadata": {}, "outputs": [ { @@ -588,18 +743,18 @@ "output_type": "stream", "text": [ "# __Exp____ __Act______ __Err______ __RelErr___ __ID_______\n", - "0: 1.00000 2.02746 1.02746 1.02746 p1\n", - "1: 0.50000 0.58197 0.08197 0.16394 p2\n", - "2: 0.40000 0.79902 0.39902 0.99756 p3\n", - "3: 2.00000 2.07928 0.07928 0.03964 p4\n", - "4: 0.10000 0.11157 0.01157 0.11573 p5\n", - "5: 2.00000 0.02880 -1.97120 -0.98560 scaling_x1_common\n", - "6: 3.00000 3.03039 0.03039 0.01013 offset_x2_batch-0\n", - "7: 0.20000 0.18353 -0.01647 -0.08234 x1withsigma_sigma\n", - "8: 4.00000 4.01172 0.01172 0.00293 offset_x2_batch-1\n", + "0: 1.00000 0.30485 -0.69515 -0.69515 p1\n", + "1: 0.50000 0.31305 -0.18695 -0.37391 p2\n", + "2: 0.40000 0.16030 -0.23970 -0.59925 p3\n", + "3: 2.00000 1.81174 -0.18826 -0.09413 p4\n", + "4: 0.10000 0.05128 -0.04872 -0.48718 p5\n", + "5: 2.00000 0.16231 -1.83769 -0.91885 scaling_x1_common\n", + "6: 3.00000 2.99955 -0.00045 -0.00015 offset_x2_batch_0\n", + "7: 0.20000 0.13729 -0.06271 -0.31357 x1withsigma_sigma\n", + "8: 4.00000 4.00132 0.00132 0.00033 offset_x2_batch_1\n", "\n", "Status: 1\n", - "Cost: -368.587402 (expected: -0.000000)\n" + "Cost: -447.231981 (expected: -0.000000)\n" ] } ], @@ -618,16 +773,18 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ + "Running --at-optimum for \r\n", + "\tconditions from deleteme/_rank00000.h5:/inputData and \r\n", + "\tparameters from deleteme/_rank00000.h5:/inputData\r\n", + "\t> sim.h5:/\r\n", "Running for start 0\r\n", - "HierarchicalOptimizationWrapper parameters: 9 total, 5 numerical, 1 proportionality, 2 offset, 1 sigma\r\n", - "Need to compute analytical parameters: //inputData 1 parameters.size() == 5 ; hierarchical.numParameters() == 5\r\n", "Starting simulation. Number of conditions: 4\r\n" ] } @@ -635,43 +792,39 @@ "source": [ "# Simulate with optimal parameters, save results\n", "!rm -f sim.h5 # remove files from previous run\n", - "!{example_binary_dir}/example_steadystate_multi_simulator deleteme/_rank00000.h5 / sim.h5 / --at-optimum --nompi" + "!{example_binary_dir}/example_steadystate_multi_simulator deleteme/_rank00000.h5 /inputData deleteme/_rank00000.h5 /inputData sim.h5 / --at-optimum --nompi --nocompute-inner" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 38, "metadata": {}, "outputs": [], "source": [ "# Load simulated outputs\n", - "(measured, simulated, timepoints, llh) = parpe.readSimulationsFromFile('simh.h5')\n", + "(measured, simulated, timepoints, llh) = parpe.readSimulationsFromFile('sim.h5')\n", "start_idx = '0'" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 39, "metadata": { "scrolled": true }, "outputs": [ { "data": { - "text/plain": [ - "" - ] + "text/plain": "" }, - "execution_count": 14, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -680,23 +833,21 @@ } ], "source": [ - "# Plot correlation of measurements (training data) and model simulation with optimized parameters \n", + "# Plot correlation of measurements (training data) and model simulation with optimized parameters\n", "parpe.plotting.plotCorrelation(measured[start_idx], simulated[start_idx])" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 40, "metadata": { "scrolled": true }, "outputs": [ { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -705,10 +856,8 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAEZCAYAAACU3p4jAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAgAElEQVR4nOzdeXxU1d348c+ZO2sy2RfCvu8imyCCVDQWUdx4flYUUbCtWksfFyi1Klq1FLT6WG3rUutWHnABFx4Ua0UURXBjByXILllIyDbZZrt3zu+PO5lMFkgIIUBy3i/j5Ny5y5mQfM+95557vkJKiaIoitL2WU51BRRFUZTWoQK+oihKO6ECvqIoSjuhAr6iKEo7oQK+oihKO6ECvqIoSjuhAr6iHIMQYqYQ4ouocoUQotcx1v9OCDGhVSqnKMdJBXzljCSEmCaE2BAOwHlCiH8LIc4/2ceVUrqllPvCdXhVCDG/zvuDpZRrWvq4QohrhRDrhRBVQogW37/SPqiAr5xxhBCzgaeABUAHoBvwLHDVqazXSVaM+ZkfPdUVUc5cKuArZxQhRALwCDBLSvmOlLJSShmUUr4npZwbXschhHhKCJEb/npKCOEIvzdBCJEthJgjhCgIXx3cHLX/FCHECiFEmRDiG6B3neNLIUQfIcStwA3A78JXGe+F3z8ghLj4ROtRl5TyYynlUiC3JX+eSvuiAr5ypjkPcALvHmOd+4ExwDBgKDAamBf1fgaQAHQGfgE8I4RICr/3DOADOgI/D3/VI6V8AVgC/DnczXNFC9dDUVqcCvjKmSYFKJRS6sdY5wbgESllgZTyCPAwcGPU+8Hw+0Ep5QdABdBfCKEB/w94MHzlsAP41wnUtVn1OIHjKcoxqYCvnGmKgFQhhPUY63QCDkaVD4aXRfZRp8GoAtxAGmAFDtXZtrmaWw9FOSlUwFfONF8CfuDqY6yTC3SPKnejaX3fRwAd6Fpn26NpbKrZ5tZDUU4KFfCVM4qU0gM8iNnffbUQIkYIYRNCXCqE+HN4tdeBeUKINCFEanj9xU3YtwG8AzwU3u8gYMYxNskHjjomv7n1aIgQQhNCODGvQCxCCKcQwtacfSntlwr4yhlHSvk/wGzMG6BHMLtgfgMsD68yH9gAbAO2A5vCy5riN5jdKoeBV4FXjrHuS8AgIUSpEGJ5A++fSD3quhHwAs8B48Pf/7OZ+1LaKaESoCiKorQP6gxfURSlnTjWSIcWJ4Q4AJQDBqBLKc9pzeMriqK0Z60a8MMulFIWnoLjKoqitGuqS0dRFKWdaNWbtkKI/UAJ5vjlf4QfTz+q1NRU2aNHj9aomqIoSpuwcePGQillWkPvtXaXzvlSyhwhRDqwSgiRJaX8PHqF8KRUtwJ069aNDRs2tHIVFUVRzlxCiKM+Hd6qXTpSypzwawHm5FejG1jnBSnlOVLKc9LSGmykFEVRlGZotYAvhIgVQsRVfw9MBHa01vEVRVHau9bs0ukAvCuEqD7ua1LKD1vx+IqiKO1aqwX8cFq4oa11PEVRznzBYJDs7Gx8Pt+prsppx+l00qVLF2y2pk+pdCrG4SuKojRJdnY2cXFx9OjRg3DvgAJIKSkqKiI7O5uePXs2eTs1Dl9RlNOWz+cjJSVFBfs6hBCkpKQc95WPCviKopzWVLBvWHN+LqpL5wSFjBDBQIigz0APGAT94a+AQdBnIEMSzWZBs1mwWi1odgtWmwXNGl5m08yyzYJFE+qXW1GUk0YF/Ab4KoMUHion4DODd61A7jODuR4uG3qo5Q4sRCT4VzcQVnvtxsF8Da8Tft9sQGq/F/1q0dSFXHP88PVhvvy/vVQU+3EnOzjvqt70OzfjVFdLUZpNBfwwQw+Rf6CMLR//yI/fFWMEQ2g2C0kZMSR1iMHq0LDZNWwODXeSA2v4e1vUcqsjaln4S1gEhh7CCIbQAyEM3UAPhsvh15rvw+/poVrrBHwGRnkQPWhElslQ06fEEBaBZrNQWeqj8FAlQb+BzanRdWASHXokRBoGs5EIX3HYw1ck0Q2NvaaR0ayWNn018sPXh/l0SRZ6wGzQK4r9fLokC0AFfeWM1SYDflPPzKSUeAq8ZGcVk7O7lNLDlRTlViLDJ+1GMERpfhXDL+523H/kJ/vsMGSEIo1DTWNStxGpaUByfyghf385IcNsKII+g/1bi/BX6cQmOgj6DAxDYhHmz8UIhrBoZjeTDEmCAcO8qtAshEKSoE/HEWvD7rIihCDgNffjdNtASipKAyR1cOGKc2Do5s+xQ484YhMd+KsMCg6W0W1QMu5kJ1XlAQ59X8yAMRm4k5wU51Wyd1MBg8d3JibezpFD5ez+Jp/hE7vhirNzeJ+HXV8d5twre+F028jeVULW+jzGT+2LI8bGge2F7FyXR+bMgdidVvZuKuC7tTlcdvvZWO0au77KY8fnOVw9ZwSaZmHHZ9ns+DyX6x4wH/ze/NGPfLl8b71GVQ+E+PL/9oIFjvxYwbj/1weAvL0eqsr89B6eDkClxw8SYhMdLfbvrbQdY8eOZf369afk2G0u4Dd0Zrbqle/J21vKBdMGAGaXTc6uErKzSqgo8WGxWsjolUDuD6WRYF+t+o+8wuMn6DM490ozhenezQUgofcI84+8KKcCzWohsUOMWYfFWejB2meHoZBkwHkdzWUlfiyaICbeDsDh/R4cLitJGbEA7NlYgDvJQUavBAA2r/qR1M5uug5KBuCLZXvo3D+R3sPTkVKy8plt9D0nnf5jOmLoIZYt/JYhE7oweHxnAj6d1f/aWS/ltgxJPEe8/PTng3n1nnVcMK0fA8d2oiS/ijf/+A3nTelNz6GplByu4t/Pb2fEpO507J1AaUEV65btYfBPOpHSyU1pfhW7vjpM7xFpWG0Wygq97NtSSKd+iThjbFR5/BzeX0aHnvG43Da85QHyD5STnVWMM9ZGVVmAgoPl/LijCKfbhq8iSN5eD0U5lbiTHZQd8XJgexEAcSlOCrMr2P1tPimdY3EnOzm8z8OhrGLyD5TjTnLgKaii5HAlvsogmmaJXCWFwgFcaAKrXYv8PBwxNuJTnciQRFgE7mTHUa+gKor9FB6q4OD2wkjA/35tDtm7SiIBf91be8jf7+HG+WMB+GTRTsoKvVw9ewQAGz44QMCnM/a/zO13b8gHoO85HSK/SxZNRH4XQiGJxdJ2r6bam1MV7KENBvwv/29vJNhH2/F5Lh17JxKf5mLLxz9iBEMkZcQyZEIXOvZJxFseYP3bexrcZ0WxH09+Fb4qPbJs2yfZQE3AX7NkF1a7havuGm7WIVi7DnogxGev7YoE/Hef3ERGz3h++vPBAPznhR10GZhM5k0DAfj8jV30GpYWCfgb/32AfudmRAL+gW2FuOJs9B5u3q33VQYJhj+3RRPEp7pwxJgPZGg2S71gH/3Z7E4r51/bl469E9GsFuJTnFx44wA69UkksUMMsYkOJv5yMB16xhOf4iLg00lMjyGtWxyxCQ4CPp3eI9JI7ujG6bYR8OmcU+AlIc2F3WXF7w1SVujDGWteDfgrdbwVATSbBRmSBHwGfq+OAEKGeTXRa3ha5IolMT2GIRc48Xt1qvaXoQcNOvdL5OCOosjnSO8Wx/ZPD0XKCWku1r7xg1kQAneSk8/f+CFybyS9exwb/30Aq11Ds1roflYKu745HO6y0nDF2fCWB+v9vGIT7Jx9YVeGXdwNX2UQiyY49+pejIz6nTvrgs70HlEzD1R6j3jcyc5IubLUj6+qZt87PssBagL+miVZWO0aV901HIC3H9tATIKDyb8+G4BVr3xHfIorcvKx6T8HiUtxRrY/+F0RsQkOUru4AagqC2B3aVhtWsO/BMox7dixg1tvvTUSqDdt2sTcuXNZvXr1MberrKzk2muvJTs7G8MweOCBB5g6dSput5uKigoOHDjApEmTGDNmDOvXr2fUqFHcfPPN/OEPf6CgoIAlS5YwenS96cZOyGmd0/acc86Rxztb5jO/+uSo7zljreYZYKGPoM/AnexgzFW96H9uR/ZvPcIHz21vcDt3soMZC8bVWlZ9w9YZawbVw/s8ICCjZ8Ix6zDr+YsA8wrB5bbTqW8iAHl7SnG6bZGzOs8RL3aXhsttXgHoQQNNsyCaeab3r/vWUVHsb9JnOxNIKWu6s4L1XyP3OwJR3V7B+vdPqu+d1L03UlHioyinkug/DyEwryqSnA3WSVgEFk1EusIsdcta/bKmWQAJAmwOK5rVQnmRF6EJkju6sWiCgzuKcLg0ug1OxaIJNnxwAHeSg6EXdcWiCVb8dQvp3eP5yXX9sGiCJQ9+RfchKVw4fQBCCF6as5Y+56RzwfX9AXjjj9/Qb3QHRlzSHYDVi3bSc0gqvYanIaXku7W5dOgZT1rXOKSUFOdWmt11sU1/orOl7Ny5k4EDzZOg17/5kR+Lq1p0/92SY7h+dLdjrhMKhejUqRM5OTlomsaECRN48sknGTFixDG3e/vtt/nwww/55z/NXPMej4eEhIRaAb9Pnz5s3ryZwYMHM2rUKIYOHcpLL73EihUreOWVV1i+fPkxjxH986kmhNh4tGyCbe4M32IRkUv3unyVOn6vHum2qSj288miLASCvqM6MH5qX758t/YVgtVu4byretfbV/VN2WrVZ+JgBtGjBddq1Zf/1Tr2SaxVTkhz1Sqf6NnZeVf1rtXVBUf/bGcCIUR4SKtGS/aUR+6NBEP88E0+mz46SJUnQEy8ncE/6USXAcmEDIk0JIYRImRI8ysU9b0hCUW/F/29LtH9etS24ddQzbbVrczhPZ5IvcqBwkMVkXJFsY91b+0GIKlDDAFvkNWvfg9AYgcXZYVePnhuOxZNEJfqpLSgitWLdiIsYOgGObtK8FUEERbYv/kIVaV+SguqkFLy1fJ99ByaSo+zUwkZIT577Qf6nZtB7+Fp6EGDTxZlMeSCzvQalkYwEOLb9/fTf0wGnfslEgyE2P3NYboPSSGlsxtDlxRll5PS1U1svAMpQRrmUOUzhcViYfDgwXz33Xfs3r2b7t27M2LECCorK/n1r3+N3W5nwoQJ3HDDDbW2GzJkCHPmzOGee+7h8ssvZ/z48fX23bNnT4YMGQLA4MGDyczMRAjBkCFDOHDgQIt/ljYV8F976MujBvtqdfvoQ4bky//bS79zMzj7wq44Y2wnfLP1dAyu1Z9BDTM8Notmwa5ZwAlDM7syNLNrqx5fSokM1W4A6jYatRoaQyJDIQy94YbGMML7i9o2PsVVa90BYzsSMiRlhV4MPUTvEWlICT/uKEIPhkjr5qayxMfOdbkYRojYePPGeWl+FXrQoDivgp3rcjm4vZCATyd3t4ecXSXEJjoIeHVy93hI6+aOdP/l7vbQsW8iCSlOAj6D3D2ldOmfhDvJQcBnUJhdTkavBGLi7WhpOmWFXqw2C1cPzAj/jAg/sxL+oQmBABCEl4nq/8LLRPVqNeuL6m+bdsU8ZswY1q1bx7PPPsuHH5pzPr7zzjtcc801XHHFFUydOrVewO/Xrx+bNm3igw8+YN68eWRmZvLggw/WWsfhqDldsVgskbLFYkHXdVpamwr4JYe9zdou+my837kZJxwET9fg2hKfTTm5hBAITWDRgNbvQWlQdYNRt6Gpf3VilvWAERkNFvDpdBmYTEy8Hatdo6osgCPGRmpXNw6XjfIi896O023DateoKDVvisenuAjpEndSCF9lELvTGhnirAeMyJDnkCHRgyFsDnOYcHU9rDYNBJHGU9MsZgsgzUY1umu0upGoaQQiCyPfDztrJL+adQu3/PI2kuLSqCoPsH/vQSZOHICvIghS4KsKhhsZswHKzcslOTmZqT+7HndsHK+88jJ60ADMYeCGYZ4QhkKS1rol36YCfnNFd7W0FBVclbZCWARa+FmOljD8p7X7zM+n71HX/f7770nuGGs+92ER6EHz4Ud7jDkAIOg38FUEiU2wIywCf1WQqrIgMQn2yGAGb3kAd6IjUvZV6sSnuECAvyqI36ub92UkBP06Qb95b05iDs0OGQZ9+vTDbrdzx6/vJuDVsWiCDmkdObDvRwb0GUwwYNYj2sZvN/Pgw/djsViw2Wz8z2NPU1FiDtktL/ZRWeLH0EOUFZonqgGfTkWJjyM/llOYXY4RDOGrCJpDnVtIm7ppe6ybpUdjtVu48IYBKjgrymmooZuSx0NKGRnWKoSI3Lh3RD0/EvDpkRvx3vIAviqdpA4xgBmYfZVBHn7sXkaNGsWUy68l4NVJ7RJHZWUlt/3yV9isDjIvmcAN026gotSPEQwRl2o2IL6KIKGQxOU2G5CgzwBkZFhw9Vm+EIKgz8BbEahVfyEEccnOowb99n3TNnzJdsxVNHA4rfgq9dOmq0VRlJNDCIGm1XSYVN/or2Z3WbG7asKgK86OK84eKReU5DB58mTGjRvHjBkzMIKhyMi52NhYXnr5FUJ6KLKNZhWAJTz6qrrrJhzggcoSP6GQJDne7FUoOVwJQFJGrHn2X4eUkopSf4ud5bepgN+lXyLZu0rrLdesAkOXKsArinJcevfuTVZWVqSs2SxEj5dzuGqH0Jj42t3D8am1R9tVn/lXi01wRIoho+F5uY62vDnaVMBvKNgDGLqMjH9XFEU5VbQ6ExlGX11YNEuDwb0lJz88cwbDKoqitGHVN5ajCSFwt+CcTG3qDF9RFOVMVd1PX1HqJ2SYkxe6qyckbCEq4CuKopwmnG5biwb4utpUl05Shuu4liuKorQnbSrgT3vovHrBPSnDxbSHzjtFNVIURTl9tLkuHRXcFUVRGtbmAr6iKO3X8s05PP6fXeSWeumU6GLuJf25enjnU12t00ab6tJRFKX9Wr45h3vf2U5OqRcJ5JR6ufed7SzfnHNC+92xYwdjx46NlDdt2kRmZmaj2x04cIABAwYwc+ZM+vXrxw033MDHH3/MuHHj6Nu3L9988w0AixcvZvTo0QwbNozbbrsNwzCorKxk8uTJDB06lLPOOos333zzhD5DNRXwFUU5Y0z9x5cs22BmNgsaIab+40ve3Wxmn/vzh1l4w7NRVvMGDR55/zsAiisDTP3Hl3z8vZlSsqDc16RjDho0iH379mEY5r5nz57N448/3qRt9+zZw5w5c8jKyiIrK4vXXnuNL774gieeeIIFCxawc+dO3nzzTdatW8eWLVvQNI0lS5bw4Ycf0qlTJ7Zu3cqOHTuYNGlSk47XGNWloyhKm5DnaTiAF1fWT1V5PJqbAAUaT3CyevVqNm7cyKhRowDwer2kp6czbdq0RpOnNIcK+IqinDHevK1mUIZNs9Qqd0p0kVNaPydG50Rz5F5yrL3W+ulxDaeqbEhzEqBA4wlOpJTMmDGDhQsX1tu2seQpzaG6dBRFaRPmXtIfV51UoC6bxtxL+p/wvseMGcO8efOYMmUKnTubN4Gzs7Pp2tXMiKZpzUtBmpmZyVtvvUVBQQEAxcXFHDx4kNzcXGJiYpg+fTpz585l06ZNJ/wZ4BSc4QshNGADkCOlvLy1j68oSttUPRrnZIzSGTBgAA6Hg3vuuSeyrEuXLmRnZzNs2DBCoebNaDlo0CDmz5/PxIkTCYVC2Gw2nnnmGTweD3Pnzo0kT3nuuedO+DPAKUiAIoSYDZwDxDcW8I83AYqiKG3LiSZAaSm/+c1vGDVqFDNmzIgsq6ys5De/+Q1Op5Pzzz+/wS6dk+20ToAihOgCTAb+BMxuzWMriqIcr71799ZKgBItNjaWV1555RTVrHlau0vnKeB3QNzRVhBC3ArcCtCtW7ejraYoinLS1U2AcqZrtZu2QojLgQIp5cZjrSelfEFKeY6U8py0tLRWqp2iKErb15qjdMYBVwohDgBvABcJIRa34vEVRVHatVYL+FLKe6WUXaSUPYDrgE+klNNb6/iKoijtnRqHryiK0k6ckidtpZRrgDWn4tiKoijtlTrDVxRFaSdUwFcURWknVMBXFEVpJ1TAVxRFaUXRyVRamwr4iqIorWj9+vWn7Ngq4CuKohxDc1McHi1NodvtBpqeArElqQQoiqKcGTa+CiUHWnafST1g5MxjrhKd4lDTNGbPns2TTz7Z6K6r0xSuXLkSAI/HU2+dPXv2sGzZMl5++WVGjRoVSYG4YsUKFixYwPLly5vzqY5KneEriqIcQ3SKw7fffjuS4nDfvn384he/4JprrmlwuyFDhrBq1Sruuece1q5dS0JCQr11qlMgVh+jbgrElqbO8BVFOTM0ciZ+MjWU4rBXr1689NJLRw34/fr1azRNYWMpEFuaCviKoiiNGDNmDDNnzmTWrFmRFIeNyc3NJTk5menTp5OYmMiLL754kmvZOBXwFUVRGtFQisPGbN++/aSkKTwRrZ7i8HioFIeK0r6dzikOi4qKuP/++1m1ahW//OUvuffee1u9Xqd1ikNFUZQzybFSHKakpPD888+fopo1jwr4iqIoR6FSHCqKoihnJBXwFUVR2gkV8BVFUdoJFfAVRVHaCRXwFUVR2gkV8BVFUdoJFfAVRVHaCRXwFUVpO7Ythb+cBQ8lmq/blp7qGp1WVMBXFKVt2LYU3rsDPIcAab6+d8cJB/3mJkBpaoKTxYsXM3r0aIYNG8Ztt92GYRhHTZ5yolTAVxTlzPHKZNi8xPzeCJrlreFg+PHDEPTWXj/ohQ9/b35fWWSuv+vfZrk8v0mHjE6AAjB79mwef/zxJm27Z88e5syZQ1ZWFllZWZEEJ0888QQLFixg586dvPnmm6xbt44tW7agaRpLliyJJE/ZunUrO3bsYNKkSU06XmNUwFcUpW0oy2l4eVXRCe22uQlQoPEEJ6tXr2bjxo2MGjWKYcOGsXr1avbt29ek5CnNoebSURTlzHHzyprvNVvtckKXcHdOHQldzdfYlNrrx3Vo8mGbkwAFGk9wIqVkxowZLFy4sN62jSVPaQ51hq8oStuQ+SDYXLWX2Vzm8hM0ZswY5s2bx5QpU5qcAKUpMjMzeeuttygoKACguLiYgwcPkpubS0xMDNOnT2fu3Lls2rSpRY6nzvAVRWkbzr7WfF39CHiyzTP+zAdrlp+A5iRAaYpBgwYxf/58Jk6cSCgUwmaz8cwzz+DxeE5K8hSVAEVRlNOWSoBybCoBiqIoSgtRCVCaSQjhBD4HHOHjviWl/ENrHV9RFOV4tbUEKK15hu8HLpJSVgghbMAXQoh/Sym/asU6KIqitFutFvClebOgIly0hb9O3xsIiqIobUyrDssUQmhCiC1AAbBKSvl1A+vcKoTYIITYcOTIkdasnqIoSpvWqgFfSmlIKYcBXYDRQoizGljnBSnlOVLKc9LS0lqzeoqiKG3aKXnwSkpZCnwKtMwEEYqiKEqjWi3gCyHShBCJ4e9dwE+BtnP7W1EU5TTXmqN0OgL/EkJomA3NUinl+614fEVRlHatNUfpbAOGt9bxFEVRlNrU5GmKoiitKDqZSmtTAV9RFKUVrV+//pQdWwV8RVGUY2huisOjpSl0u91A01MgtiQ1eZqiKGeEt354i+zy7BbdZ5e4LlzT7+gJTKB2ikNN05g9ezZPPvlko/uuTlO4cqWZdMXj8dRbZ8+ePSxbtoyXX36ZUaNGRVIgrlixggULFrB8+fLmfbCjOO4zfCFEbHikjaIoSpt3tBSHy5cv55ZbbmHq1Kl89NFH9bZrSprCxlIgtrRGz/CFEBbgOuAGYBTmJGgOIUQhsBL4h5RyT4vXTFEUJUpjZ+InU0MpDq+++mquvvpqSkpK+O1vf8vEiRNrbdOvX79G0xQ2lgKxpTWlS+dT4GPgXmCHlDIEIIRIBi4EHhNCvCulXNzitVMURTkNjBkzhpkzZzJr1qx6KQ7nz5/PrFmz6m2Tm5tLcnIy06dPJzExkRdffLG1qntUTQn4F0spg3UXSimLgbeBt8PTHSuKorRJDaU4lFLy+9//nksvvZQRI0bU22b79u0nJU3hiWg0xaEQYnadRRIoBL6QUu4/WRUDleJQUdq70znF4V//+lf+9a9/MWrUKIYNG8avfvWrVq/XyUhxGNfAsh7A/UKIh6SUbxx3LRVFUc4Ax0pxeMcdd3DHHXecopo1T6MBX0r5cEPLw334HwMq4CuK0ia1tRSHzX7wKtyHL1qwLoqiKMpJ1OyAL4S4EChpwbooiqIoJ1FTxuFvp37u2WQgF5hRfwtFURTldNSUm7aX1ylLoEhKWXkS6qMoiqKcJE25aXuwoeVCiPOB66WU9Z84UBRFUU47xzV5mhBiODAN+BmwH3jnZFRKURRFaXlN6cPvB1wf/ioE3sR8YOvCk1w3RVEUpQU15Qw/C1gLXF49SZoQ4u6TWitFUZRmWLlvJU9veprDlYfJiM3gzhF3MrnX5FNdrdNGU4Zl/heQB3wqhPinECITNf5eUZTTzMp9K3lo/UPkVeYhkeRV5vHQ+odYuW/lCe23uQlQmprgZPHixYwePZphw4Zx2223YRjGUZOnnKhGA76UcrmU8jpgAObMmXcB6UKI54QQE4+9taIoSsu5+cObWb7HTAoSDAW5+cObeW/vewA8tfEpfIav1vo+w8dj3zwGQImvhJs/vJk1h9YAUOgtbNIxoxOgAMyePZvHH3+8Sdvu2bOHOXPmkJWVRVZWViTByRNPPMGCBQvYuXMnb775JuvWrWPLli1omsaSJUsiyVO2bt3Kjh07mDRpUpOO15gmP3glpayUUr4mpbwC6AJsBu5pZDNFUZRWkV+V3+DyEv+JPR/a3AQo0HiCk9WrV7Nx48bIBGyrV69m3759TUqe0hxNuWkrZJ0pNaWUJcAL4a8G11EURWlpr0x6JfK9zWKrVc6IzSCvMq/eNh1jOwKQ5EyqtX6qK7XJx21OAhRoPMGJlJIZM2awcOHCets2ljylOZpyhv+pEOK/hRDdohcKIexCiIuEEP9CPXGrKMopdueIO3FqzlrLnJqTO0fcecL7HjNmDPPmzWPKlClNToDSFJmZmbz11lsUFBQAUFxczMGDB8nNzSUmJobp06czd+5cNm3adMKfAZo2SmcS8HPgdSFET6AUcAIa8BHwlJRyc4vURlEUpZmqR+OcjFE6zUmA0hSDBg1i/vz5TJw4kVAohM1m45lnnsHj8ZyU5CmNJkCptbKZ2SoV8Fh25KEAACAASURBVEopS1ukBsegEqAoSvumEqAc28lIgBIRTnVYv5NMURSlDWp3CVAURVHaK5UARVEURTkjHXfAF0LECiG0k1EZRVEU5eRpNOALISxCiGlCiJVCiALMuXXyhBDfCyEeF0L0acqBhBBdhRCfhrf7Tghx4mOlFEVRlCZr0jh8oDdwL5AhpewqpUwHzge+Ah4TQkxvwn50YI6UchAwBpglhBjUzHoriqIox6kpN20vllIGhRA9pJSh6oXhJOZvA2+Hh2sek5Qyj/AIHylluRBiJ9AZ+L55VVcURVGOR1MmTwuGv62X7EQIMabOOk0ihOgBDAe+buC9W4UQG4QQG44cOXI8u1UURVGOoSl9+NcKIR4F4oQQA4UQ0du8cLwHFEK4Ma8M7pJSltV9X0r5gpTyHCnlOWlpace7e0VRFOUomtKlsw5zKoVfAk8C/YUQpUAu4D2eg4W7ft4GlkgpVXpERVGUVtSUJOY5wCIhxF4p5ToAIUQK0ANzxE6TCCEE8BKwU0r5ZPOqqyiKcmYbO3Ys69evPyXHbkqXjgCoDvbh74uklBullJXR6zRiHHAjcJEQYkv467Jm1ltRFOWMdKqCPbTi9MhSyi+klEJKebaUclj464PmVlxRFKU1NDfF4dHSFLrdbqDpKRBbUnOnR3ZhNhZqemRFUVpFydKlBA9lt+g+bV27kHTttcdcJzrFoaZpzJ49myefbLxXujpN4cqVZk5dj8dTb509e/awbNkyXn75ZUaNGhVJgbhixQoWLFjA8uXLm/fBjqIpffg+4Fng2daeHllRFOVUi05xuHv37kiKw507d/L0009TWFhIZmYmt99+e63thgwZwpw5c7jnnnu4/PLLGT9+fL19V6dABBpMgdjSjnt6ZCHE7YBVCLEF2CKl/KHFa6UoilJHY2fiJ1NDKQ4HDhzI888/TygU4qabbqoX8Pv169domsLGUiC2tOOeHllK+aAQogMwDJgihOgjpbylxWumKIpymhgzZgwzZ85k1qxZtVIcrlixgueee44bb7yx3ja5ubkkJyczffp0EhMTefHFF1uzyg1qcsAXQqwCfiul3CqlzAf+E/5SFEVp0xpKcQhw5ZVXcuWVVzJ58mSmTZtW673t27eflDSFJ6LJKQ6FECOA/wEOAPeF58Y5qVSKQ0Vp307nFIdr1qzhnXfewe/3c/bZZzc7kfmJOGkpDqWUm4ALhRD/D/hQCPEO8Gcp5XE9basoinKmOFaKwwkTJjBhwoRTU7FmOq4+/PADVruA54D5wC1CiHullP97MiqnKIpyKrXbFIdCiHVADvAXzGmNZwITgNFCiOOeRE1RFEVpXcdzhn8r8L2s3+n/3+G57RVFUZTT2PH04X93jLcnt0BdFEVRlJPouJOYN0RKua8l9qMoiqKcPC0S8BVFUZTTnwr4iqIo7YQK+IqiKO2ECviKorQZnvfeY/dFmewcOIjdF2Xiee+9U12l04oK+IqitAme994j74EH0XNzQUr03FzyHnjwhIN+cxOgNDXByeLFixk9ejTDhg3jtttuwzCMoyZPOVEq4CuKcsY4eONNlL7zLgAyGOTgjTfhWbECgIIn/4L0+WqtL30+8hcsBEAvKeHgjTdR/smnZvnIkSYdMzoBCsDs2bN5/PHHm7Ttnj17mDNnDllZWWRlZUUSnDzxxBMsWLCAnTt38uabb7Ju3Tq2bNmCpmksWbIkkjxl69at7Nixg0mTJjXpeI057umRFUVRTkf64cMNLjdKSk5ov81NgAKNJzhZvXo1GzduZNSoUQB4vV7S09OZNm1ao8lTmkMFfEVRzhjd/3dR5Hths9UqWzt2NLtz6rB26mS+JiXVXj8trcnHbU4CFGg8wYmUkhkzZrBw4cJ62zaWPKU5VJeOoihtQvrddyGczlrLhNNJ+t13nfC+x4wZw7x585gyZUq9BCiTJ0/msssua9Z+MzMzeeuttygoKACguLiYgwcPkpubS0xMDNOnT2fu3Lls2rTphD8DqDP8ejzvvUfBX55Cz8vD2rEj6XffRcIVV5zqaimK0ojqv9OT8ffbnAQoTTFo0CDmz5/PxIkTCYVC2Gw2nnnmGTwez0lJntLkBCinQmsnQKm+yx9940c4nXT84yMq6CvKKaASoBzbSUuA0h4U/OWpBu/yF/zlKRXwFaUdatcJUNo6Pa/hrI16bi4hrxeLy9XKNVIU5VRqtwlQ2gNrx44Nv2GxIOx2AMpWrcLz3vutWCtFUZSWoQJ+lKPd5c/44yMITQOgdOkyihfXZHQs+/e/8W7fXm9f6hFvRVFON6pLJ0rcxRcjJRx56uh3+bv+43mM4mIApJQcnv8n3OPH43p0IVJKylauJJCdTdFzzyP9fsDsEsqb9wB6UREJl1+OcLqwuJyRRkRRFKU1qIAf5fCf/kTw4I/0+XgVwmJe/EgpCfl8GGVlhMrKMMrKCZWXYZSZX4nX/D/04hJy778f/UghlZ9/DpoG4cewq0m/nyN/eYqqr76OLBN2OxaXC+FyYnHFmI2Ay4XF6cIS40I4a5ab67nMV6cTS0wMFqcTYVX/hIqiNI2KFlFiRoxE79qNwIGDeN59F72kmJCnDBkM1l9ZCCxuN1p8PNbUFLT4BFzDhxM7biwFCx9tcP/S78fWpTPOIUMQVivS6yVU5SXk8xHyVpnfFxUjfebyBo9btxo2W7hxcNVuPJxOc3m4kYhuKITNjrDbELY6X1YraBpCiBP9USqKchpqtYAvhHgZuBwokFKe1VrHPR6J/zWFwIEDFDz9NBanC0ffvmjxcVji49Hi47HExaElJKDFxWFxu4/aJVP8r0UNPuKtJSZSsngJvVa+j6N3b6q+/Zay/3xE6qxfY01Kqre+1HWzMaiqQvp8hLxes5Hwegl5zUZC+nzhRqP6PR/BkhKkN7x+IHB8PwQhEHY7wmqt3yDYbdDQcpvNbESq37PXNCAN7QurreEGx6JuKSnKydSaZ/ivAn8HFjWyXqvz7dyJf98+nEOGUPjXv2GJjSV9zpwGg3BTpN99V4MPcKXfdx+x54zEmpEBgH/vPjwrVpD+2zkAlLz+OuWrP6Hrs8+Yo4KkRHO70dzuZn82s9HwI71V4cbDbARkMGh+6cHI90SW6eF19Jr1qpf7/IQqKpHBmn2gV6+nN7uegHl1EXW10XDDUrOcelco9RuohhoerFYsdnvthqeBqxr11LXS2vTSUvT8fGQwiLDZsHbogDUxscX232oBX0r5uRCiR2sd73iULF1K2coPiD3vPCwxMaTffXezgz00/RHvpOumknjtz2rObIUFoWmRIaB5Dz+M//ud9HznbQAC2TlYk5OwxMQ0uS7CakVzW8Ed2+zP01RSyppGI7qRqLssGEQGohoWvabhCAUCUQ1IMNKQyEDAvGIpq7v/6m2Nxit4LFatVmMRyMnF++23kXsxem4uuffeR9nHH+MaNBihWUCzhl81hGYFzYKILIt+T4u8Ck0Di4awNvRqMRutBraP3ketV9X91mbopaUEc3JBhgBz+udgjtlT0FJB/7TrwxdC3ArcCtCtW7fj3n7lvpU8velpDlceJiM2gztH3MnkXpOPuU3Krbei5+djcTpJu+surCkpzap7tIQrrmjS2WB0N0bSdVNJum5qpBw7ejT2Ll0j5dzf3wO6QY83XgegYu0X2Dp3wtGr1wnXtyUIIcBujzRYrUmGQuEGJBi5+iDSoDTQgASjrmD0oNkt5veZ/x7BIOUf/qfejXd0naov1mFLSSV4+DAI0OITkIaOnl8AFgua2400DPQjRxA2G1p8vLlpYSHCbq8pFxQgnM5IOZifj8Xlqinn5WGJja0p5+SYXYrx8UgpCWZnm92LiYkgBMHsbKypqWgpyYAgsG8v1oyO2NLTkaEQ/qwsbN26YcvIIKQH8W3bjqNPH2ydOiH9Pqo2bsQ5aDC2Lp0JVXmp+nI9rpHnYO/aBcNTRsVnnxF7/jjsXbthlBRTtupj4i7OxN6tG3pBAWUffED8lVfi6NaNQE4OnuXLSbrueuzduxHYv5+SZW+R8stfYO/eHd/OnZS89jrpd9+FvWtXqrZspXjRIjLm3Y8tI4PKr76i+NV/0fGPjwBglJejFxVh79IFYbVilJWZ5W7dEJqG4fGY5e7dEZqGXlqKUVSMvWcPhMWCXlyMUVKCvVcvhBDoRUUYJaU4+vSO/NsYpZ5IOVhQQKi8HEfv3pF/m1BFRU05L49QVVVNOfxgZnU5kJ2DDPgjf5eBQ4eQwWCkfN7IkaxZtixS9h84AFKa3a/hYB/1i42en992A76U8gXgBTDn0jmebVfuW8kD6x4gGDJvduZV5vHAugcAGgz6UkqCubkU/u3vWGLdpN11J7YO6Sf6EVpMwpVX1iqn/up2MMxuEykluffei3vcODo9Zt4kLvzHC8ScM5KYkSMb3N+Z1EUhAwFCfj9aXBxg/tEZxcU4w/OGeHd8h16QT9xFFwFQseYzgrm5JE+/AYil5I03CObkkj5nNmAmx9ALCuj0qDkNbc7c32GUlNDtxX8CcPCmGciQQY/FiwHIP8qN91BVFRkPPsC+q67G1rULnRYuAGDvpZfhGNCfLn/5CwB7Lv4prmHD6Pin+WAY7LlkErFjxtDh9/cgDYN9V1yJ+yc/IW3Wr5GhEPuv+RlxmZkkz5gBIYMDN0wn/pKJJF7zMwgZ/PiLXxJ36SQSJk8mFAiQe/ds4i65hLiLLsSo8pL/8MPYunbFNXQooYoKylaswJ2WjrVDB4wyD94tW7DEubF16ECoohLvhg3mTXoBRqmHqm++RQZ19CNHMDylVH71NUZ5OdaUVIzycrxbtmCUlmJNScEoL8e3bRtGSQnWpCQMjwffd99hFJegJSZilJbi27kTo6QULT4evaQE/65dGKWlaG43enEx/j17OOzxYImNRS8qIrBvH7n33W++X1SEf/duDv9xPsZ116G7XEifj2B+PsJiMRtxfwC9wGxkpd9svPWiIoTFQsjnQxqGOQ++EIS8XpASw+NBCIH0B8zPXVYGQiB1HTQLRmUlIEBKhNVmbieEeeVtd5hXn5gDJYTLZW4nBMLhwGKxIEMhczBHjAtpt0V+ZyyxsWDUBPK1q1ZB1BxmkUa9gft+QJMGbzTVaRfwT8Sj3zwaCfbVgqEgj37zaIMB37NiBYcffpiY0eeSMW8etqM9aXuacJ8/rla5x5LF5i8ZZiAqfPZZUm//FTEjRyIDAbJnzyZ52jRix46tNzFcdfo3oElBX+o6oaoqLLGx5llUSQnB7Gyc/fsj7HYCBw/i3baduEsmYrHb8W7bRsXataTccgsWu53yNWso++ADOi1YgLBaKX37HUqXLaP7668hhKDwHy9QsmQJfT//DICC/3mS0mXL6L9pIwBF/3gBz8qV9P/6KwBKly6l/JNPIgG/fNUqKr/6Khzwwf/Dbvy7d0fqb/bf1/y6u84+m1BVVaScdP11yKg/Si0lBaOoqN7Pofpp7E5/fqzWlUyXvz5d66G9ri/8wxwdFZ7/vMf/LkLExESuHnu+/RaWmBisyckA9H7/PSwxMeYZO9Dn44+xxMZE7t/0/WKtub+YGKSUuMeONUddORxIKUm88orwfQs7UkqSb7450hUkpSR9zhwzOIW7gDo98nCj/+bVZChkXi2FQkjdgJCBNIzIspr3dIheJ3pdw3yNfK8bSEMHI2S+NrSdbuCxWdFi3cjY2EiQFE4nmtNplkMhhM2KZnWbV2yY61hiXDX/vlIibHZCHk+t34foxCjCYsEoLKz1ufXwlMXf7drFr++9l8/eeQeAzTt28PsFC/jPa6/VWj946FBNQQhKsrKYNmsWOXl5GIbBfXfdxc+uvJLkfv0o2b2H3d98w+XTpnHuyJF8uWEDIwcO5MarrmL+s89ypLiYlx99lFFDhpj3nVpImwr4pf7SRpfvXPspa99YRHnhEWIsGgPSkxn7u7nYu3RucNvTlRACe/fukbIlJob+335DKGA2ePqRIwT2H8AoKweg4PEnGp4Y7vEnSLjiCqo2bqTgz4/TceECHL16Uf7Jp+Tddx/dX1uCo1cvyj74gNzf3UPv/3yIvXt3Kj75hLz759Fn9cfYOnem8ssvOfzQw/Q5dzSW9HS8W7ZS+Le/kzRtGha7Hf3wYbybNiP9/kjwtcTEgK6DzYajbx/iLs5ESokQAnfmRdii5h1PnHot7gkXRMqps35Nys9vjpQzHn6o1qipjAcfqPVZ0+7471rl5Bun1yrHX3pprXKH39/T8I338Nzqzv79a63v6Nu3drlON5u9R4/a5S5dapVt4SQdkXKdK83obkYhBFpCQq2yiI2tXY5qjIQQ5plqMwmLxeyqa/Yemi9/506saakAfLc2h7JCXyNbHF11Y2C+mN8npDgZNK6jef+p+qy7zuuQ1FT2Z2dDcjKaxcLvHn2UJx57DC3cWBO1rYzadtUnn9Cpc2feW7oUJHjKPOZgAQCrBsLC3gMHeP2f/+Sf/ftz3iWX8OYHH7B60SLe//RTHv/nP1n6t79j7dCh2Z+5rtYclvk6MAFIFUJkA3+QUr7UWscHM9h/9PxT6OEbfFUhg23JMWTkHGRgS/eDb1sKqx8BTzYkdIHMB+Hsa1v2GHUIux0t/Atl69yZ3itr5vw5Wv7O6uXCajUvPcNsHTOIv+zSyA1i51ln0eHe30cCTex559HluWfRwje34ydNImb0uZGb3UnTrifphmmRIJx03XUkXXddZP8JV15Zq8sq7qKLImfrYN6/iB09OlJ29u8PUUHWVuePwNLC9w1O5tzqyqkhqpssEflf+Ea59ZiNmQUYfNZZZO3fz+7du+nRqxejzj8fgMrKSi644AIeeughLr/88lrbDRs7lt899BD3//nPtdMUCoEtPR1bVRU9e/ZkxIUXAnDW8OFcfP75WOx2zurblx/z8rB17nTGjtK5vrWOdTRrFz0fCfbVdCPE2kXPM3D8hS13oG1L4b07IOg1y55DZhlOetA/mqOmfwt3UbiGDqXbyzXtr3PgQDKiUqo5evWqddZq69Sp1lmplpgY6Y4A2sQTwE298a60jsHjT91VeEMpDgEee+wxrr224b/pfv36NZqmsG4KxJjkZJz9+xPjcGBoWosGe2hnk6eVl1Uc1/JmW/1ITbCvFvTCB3Nrynnb4NC3NeVAJRgtd3OmrvS77zIfnIoi7LYWSf+mKG1dQykOV61axaBBg0hPb3igx8lKU3gizvzTsOPgCup4G7gB4go/MFSaf5i8H3aaffxFhcSlpDL+upuafvZftBdSepvdOA3xRd1j+PzPULgbZoXn1nn7l1D6I9y+ziy/dyfofpjyvFle/zewWGFMOFHyDx+BzQU9w5eJpT+CLQZiUxs8dEJ3L4wqoWCzE71KwxpjkD68wlyuKMoxNZTicM2aNVRWVvL999/jcrm47LLLsEQNs96+fftJSVN4ItpVwO+XW8z2rmmEov5RLKEQ/XKL+HHHNpb98T40qw1DN8+0ywuP8NELfwdoOOhX36ARAra8Bstvh1nfmH32nkP110+IulGX+Qfwl9eUh14PgagrDXcHM+BXO/AFaLaagP/JHyG+U03Af20qJPeC65aY5Rcvho5DYfL/mOX37iKhayUJXctq12n1I6esm0lRzhRPP/00CxcuJDbqPtef/vQnAF599VVSU1NrBXuASy65hEsuuaTevioqzL/zHj16sGPHjsjyV199NfJ93fdaSrsK+N0MAw4dYVfHZHw2K86gTv+8YroHykhLT8QRE4M/aqgegB7ws/aNRfUDfvE+WHItTPg9dB8LST1h3J1QcgAG/xd8/RwYUfPYaHYYNAX2rQGrC6wO84y8eH/Nmbo1PNRMCLjwvtrHm/ZmnfJSkFH3IzIfBHvU07S9JkBizSgegpUN/1A82eYx//076H8Z9G7BexmKcoY7VorDajNnzmzdSp2AdhPwpa5j794NX0E+3YrK6FNgdq8Iu5X0X07Bld4Nv7fh7o3ywiNUffAwrpy1CHsMxHeGQLnZRfP187B9Wc3KR3aZr2kDzC4b3WsG8tR+ULTb/GqMZje3sTnNV6sj/FqnbHPVfG+PNRuSvG1mefiN5vs+j1lO6MrOH32sLehBue4gzupnfPoBBnZzmp9jx9uQ3NsM+N5S+OtwuPQx8+xf90PuZuhwFjiaP6+PopxpWjvFobe8jIriIgxdR7NacSen4IqLb7H9t5uA7926Fc1pwd/JTsDrhCOe2kPtApXEuSyUV9WfkyXOKfnfZZvp4/aROVSYXSX2GBg8BWyx5vf2WLC7zbN2e6z5pdnNs3UpzbN93QdBn/mq+8OvdcrBusu8Ne/5PObN3+qy0fSZMHd60vkoz4EuzWGS5bqTj/L6Qic3Aze8AuN/C5rV7JrS/dBxGFQWwsH1UHIQlv8KLn0cBl5uLt/6Goy6xbxnoSjKCfOWl1F2pCAylt/QdcqOmA9/tVTQb1MBXyBqHq6os7zis8+xdBvAfz3ySM2QwVAI8rfDuqch+1vGJ+/iI2/PSFAEsAqDcZ2K0S/6A0kdOsDZI/FVVPDWn+YxftpMuvcf1oSKifCZuAOcCY2v31ShEBhm8JdBH0L3Eaws48B335HWIZnEBCdlhYWsfu8TDucY6LL2Qyu61Pjs+yB7j3zLqAFuOsSHqKqs4lBBgK6pNmL2f0Zo7xowdCydRsKuf8Pe1VB5xDzjz9sKrmTwlsDhbdBvknnvIWSYc4IkdDYbwOork1pXLNXdWq6ost181Wwn9KCQopyuqh8sBDCCQbAINM2MR+VFhTUPbkWtX1FcpAJ+QxoK9gDJZSH8Wd/j33eAgr/8hQ6/utHsS9//OVQVmWfjvS5kwM73oaNer9tjgKMQ8dPLIvurLC1Gs9pwuMyHkopyDrFv07cMuXAizvCj8JEnepsz2if6M0lJcU42dpeLuJRU9GCQL95YRI+zh9Nj6Ai8lUFevvN2xk6dzvBLLidgKWHFK/eT+fPbGTZ8AlpyCeWBz6mqbPgJxcoqnYJAHPrYu2DAIAq2beb9Pz3A1Pv/QEzvXhzcsoF3/vo3pt39Wzp26UDOnj18++k6Lpz4cxLi7JQWFpPz/Vb6uD04knsR1A3koa+wHfoCcfZU8/mW0h/Nq4LkniCaMhJYRDUOTWksjrZenX2o+faVKFJKpJSRm61GMIgErOGRfAGvFwTYnS7APAMXFgvOWPNvvKKkGIumERNvnsR5CvKx2m3EJppP4BbnZGNzOolLMUfOFRzYh9PtJj7VHMZZmP0jrrh44lPTAAjVnawvzNBPcNrxKG0q4EdueALjvjOYtkaSUgaVTiiMX4+tRwabD27n4jfvIikG6DQcRtwEnUeCZiN/5UIGJhxhYELtp1LzSKUj4NcNdEOS0qUb1//x8cj7B7dtZu1rrzL4gkwANrz/Lp+/vggZNdrn38//DTBH+4QMAz0YiPwifffZatxJKXQ/27xaWPrIffQYOoLRV10DwKLf/TcjL7+an0ybiaZpbF/9ITHxCfQYOgJnrJsB519AahdzZlFXfDzTH32axA7mnPuxiUnc9NhfeWHWzZQX1n/aNi41jZ8/9UKk3Ln/QG56/O8kpmeA00lCz8Gcd8004gecB4lJBAuhrGotot9ESEvn0Ccf8dHa97nl7+/iSEtn58cfsmrV19x6x1+JGzeDH776gm1fPMsVyTtx3LaWw3u+J/+jf3CWcw/alGfwlZcQKj6Ay+VA2GNrd3PV7f7yldV0cQW95rK6swsei2ZrYmNR536JZje7uyw2cx8WW52yNWq5DSwqV3Fz6IEAQb8vcjZbVnjEPAsOC/p9GEE9clLlq6zE0IPEJpgPJ1WVeTCCwUiANfvCgySkm38LnoJ8DEMnuaM5jr4kLxcpQ6R0Nmek9RzJByC5kzmarry4EGGxRNav8pRi0ayRgO+vqsRqs0M44MtQKDK3FYDVbkUTNSehse4YNEvN+/HxMVhFzUg8i5CEZP0r2+h9nKi2FfDDxn1ncNsHEme4YYzzgR4IIXrmUVVlR0sbCT+dDTHJtbZbGPgZC20vEiNq+sarpJ1Hg9fyNLB+TxE3v/ot7/x6LCO6JbHlUCmLvzrInIk/5dYx51NlcbI/11Mr2FeTeoCPFr3CwPEX8uqc2+nQqy+T7zAfxPryrdfo1G9gJODHJibhiDFH3AghuPzue0juaP4SCouF37yyNHJZKCwWMn9+e+Q4FotGh571+9XHX3cTH73wd/RAzS+Y1e5g/HU31VrP5nCS1q1HpJzcqQtjfzYtUu4xbCQ9htXMxjng/AvoMugs3MnmXC8ZffoxftpMXKOvAsAwDPyuDKxztoPdxd4dWXz1ZS5Dpg2BDgPZuOZ/+fqdN7n7/AL472/YuPL/2PfZR/zsxstg5EwObNlIaUE+wyaaV1gVxUVIKc0/aikhpDdw78MX1Sj46zcSdZfVujfijTwAd9jjY8+RCvxBA4dNo0+am4yEmgnSjk40vYGwWGu/V6vhsNZpTJqyT2ud9+xmA9SMLjI9EMBbXkZMQiKa1UplaQnFOYfo2HcAVrud4twccrK+Y8C4n2BzOMn9IYu9G75izDXXY7M72LvxG77//BMu/c0crDYbOz5dxeb/vM8NC57EYtH4evkyNqx4m1+/9DpCCNYtXcyWD9/nzsXmJGUb33+XmN4DIvXxlpXhq6yIBHx/ZQV+b1Uk4OuBALrfX+dT1Hxuq8OBZkRNoBcXF+5+NE8UY+PjEUYgUk5IjDdHt4XLSclxCF9ppJyS4DB7CDCn+Uh0haAqBzAbnHi7DlUFgHkGH2sNmL9rmA2QS9NrjZ6Ls/kpCziQUXUWSNy2up+p+dpcwB+9PYm+P8bxySCz3LWwjCG5hVhDYN0eZMaUb6HHjHrBHmBD/E/5fRn8zrqUTqKIXJnCn/Vr2ei+CE9ZBbH4mTU6DX9RPt8W5vHt3ny2bzzIGusR7BhsPVjI17vz+akeCfyeDwAAIABJREFUbHBujmBZMS+9+DrB1O7kBW28sfR9rFaNxPOvRI+N5T8fr8NmsxI38iKq7FY2bdmJzW7DltgRj27Bl1eAzWbHYbdit9tw2G31xv4eTXV3Ukt0M0Wz2R0kZdRMsZDeoxfpPWqmYBg47gIGjquZ9OzcKdcy9OJJWMINRO+R5xJnqUQMNbex2m3YvXmw/S0Ycg1ZX67l4FerGWb5Fi7+A2tf/xfZOzZzy9PPgz2WNUtexVOQz1W/nQfA92s/RQ/4OTtzEgDFudloVhsJ6ccxAVUoxHsb97Fo8dsMObKRGKMKr9XFK0UDmT7lJ1zYN8mcpjoUNBuHkB5+rVvWj/6eETAbqcjyYP19ylCkT1cIgRGSlFVJYhyC/9/emcdHVZ2N/3vunX0me0IggQQCYQmJ7LsoiiCKiFSLvq1VUWur+P7ciqhVwbfWtbUutf5+ra+iotYiFHFhk2JFsCqbEghogAAhGxASkkkyy73n98edTDJJ2EOC4X7zmc+dc+655z5nMvOcc885z/PYrQJ/QFJ0WCMpWsHtUPDWSb4vCpLRWSXGpVDh1dm8O8B53a3ER9soqxKs3VbL2IFxJMa5KDzg59OvDzB5XDpJSdHk763io5Xf8/Ppw0hKjuOH78v4ZOkmbrrlUhI6JVCQu4dlH67llv/zM2KTEijckMfKxZ+SniCxJiRQtnk96z9aypCR2Vhj4qgt2c3Bgny0yhIs7igsKnhiYtGDGopNJSm9O1kXXBxWoL2GjiQ6qcFqNWf8pRSXNyhYd2wsLo/LUNKKSnR8HPitxuemWoiO8UCt3/j8VCsetw2qD0MwDiw23DYJlUUQjAKLDafih6p94MkG1YodH3gLwRMLqgWL9EFNKUR3AmFBkUFjQFA/k1D/xFifdkQbHW09rgSwN5p7j0qBqEYeeWMbYl0AOG0K4KM6YEOTCqrQ8Vj9ofzWQTRdJDibGDp0qFy/fv0Jl//Vby4gc19Ug5MkACnDSh8k/a4rhphucE9zo4bFm/bz8IINpBzZSdfaIiwygFVqRNkVHJbjP6brUhLQJTGHC7DK5vNuAWGh0JNOgsuC0CW6lIa77dPxQ6goYTe4QrGghN4rqvFeUS0IVUW1WFAtFhSLBVVVEYqCqhgRk4RqvFdUBUVRUFQVVVFQVAUhFFTVOGexWAxPjWp9nlFOVVQUi8CiWrFYFISiYFFUVIuKajHeK4qCalGxWYx8RVGxqCoWixI6qg2dl5SGEZo9Cqnr+Bffjb1LHxg1k6IdeXhfn07mmPEw5Xm+/uB9qnNXcvENt0K3YSx6cg6+mprwlNs/HnsQXde57rGnAfjgD49jd3mYdIfhUuKbDxfhio4JT8eV5H8Pdhd3vrCYoYWfRvwfA8LC5q4X89JvZ1Di1clM9lBdUgg2J4onlmiHhYKNXxPbuQuJ3dLRNY2NS5eQ0rsvKb37EfT7+ezNV+k1bCTdBwzGV+Plwz89xYAJl5E5fDTeisO8++gsxky/nn7nj6OypIhX77qNSb+8nf5jRnOocB/zHn6Iy2++iX5DB3Fg3z7efPIPTLnxWnrn9KF0z17mvzSPqT+fQq8+aRTv3c+CNz9i6jUXkZ6WSMn+UlYs28DES7LpnOSmrLScr74pYMywVOKjrRw6WMXWHw4xqE8UUXZJRWUde0u8ZKaoOC2S6ho/5VWSLnEKVovAF5D4AhKPQ6AoAqnrCCQgjPUSXQffkYbpMy0AVcXGYMseY3RuB/MhMRM8nQz3IgVfQPcxhg2J9wB5yVfRr28fY7ot6Ieag+BOMuoM1IG3zFCiVif4a6C61DBwtDohUGOsHUWnGhsCAnXGFmRPsvH0o/mMa1xxxpORFuosrE5jral+uvCE1p1agZpyw2Cz8TSlUAx91cIAFSAvL49+oRgR4UuE2CClHNpS+Q6l8P947WRoSXlKyeXf7WJ9j85YO1Xy2thaSqzWcESsCWmX8frnO3CX7CB33VpqamoptiaB00P/bgn0TonDZrdhs9txOOzY7DacTid2uw2Xy4HT4cDltONyOrDbrPzXA68waO/KZsriq5TxDL54PI9ckYWu68yc/w0/FFfyzs3D8AUCbN9fgcsi8VgFwWAQfyBAwB8kEAgQCAQJBoMEA0Y6GAyiBY08LRAkGAygBTW0YABd09A1DS0YRNeC6Jrhe1wLakg95Htc6khdhh9ppdRBb+fvgsAINqEooaMI+XBXjI4tlBcfKCVoceG1JWIhyNCyhRTGDKIk+jxUoZFTsoSi+KEcjspEVJdjDdZQE5uGzWpBFm5HExaKPOmkJXrQN64kaHfzH2d/LuidhLbunwQ8idQdKMKlN1/olgDdc1jo68k9E3pT+M5zyPTzeK+2B49MzuL7V38PmUNZ5Mtg7pX9+e6lR7Bkn89KevPQpN5seOVxLNlj+crSk7sv6sHGN/+M0mckebY0bh6VypZ/vgM9B1No78LVA5LZsXoZpPWj2pXMBRkx7Nm8HqVzD3RPPP2SXBzcV4AtsTNWp4dou4LPW43d7Ua1nKAP9eoyQ9nVK5T8VYaC7NTX6Hi/+BN0HWYYBgb9sOg26Hs59L4UaivhranGOljWVKg+AK9NhDF3Q78pUFUC7/0cRvwaeo6HI/vho7th8E2QNgKOFMHa5w2DxKQ+hrLO+wjSRxlKufYweclT6derR0MHovkNeQWGYpQyQiF/v7maL1dWUF2h4YlVGTUhlt4DT9B2RAjjS9j4WP++af5Rj0ep50SPdRVGp6gFjOm4qC5HVfZgKnyOpvAv+24XG9OTiamt4+ORR1jb3xixu3AwumIy3m8rSLRDp4xMJl55OVl9epyy3Is37edv895n6IEvidKqqVI9rE8axS9vuoarBjV4/Fu9vYxyr5+rhxjz85e/sIYEj423bhkBwJJvi8hIdJOd2opbOY+BrhudQEDTCAY1NE1D0yXBQJCgpqHputGp6PXndbRQWV3XCGo6uq6hByVB3bhe1zT08HVGealL45yuGx1T6KjreijPWPzSpYau6eF8qeno0ijrDwQRSBRAD/g5VFWD024jijrSKr/mu0A3NE8XEpRqsitW86WWRZ27K9FqgOi6In6oi8bpdGNXBVoggDeg47Kp2DQfOgJPxd4Wn7sk4I1Oxac6sFoUrD4vfqHiEzYcVgU16MMvFXy6gsuuInQdvy6pC0qiHBYEgrqgRp1fI8ZlRSCoDWjU+IMkuG2AwOsPUuvXSPQYnhS9vgB1QZ0Etx2brKPGH6QyaCXBbSdKO0xNQFKqR5EYZSc5sJ+qoMoePZFO0U561G2jQnPwg0ijU7SD/lVfcJA4tql9SIxyMuTwJxRZUtlm7U9ilIOhB/5Joa0HO+znEeexM6LkXfY6+pDvHkS0w8rAskXsdfaj2NMft03Q69C/KHVlUunOwKpAauVGjni643V2QZE6sbV7qHMm47fFoEgdq/ShW5whGxXDQ6QQInwUQiCU0JOmEGRkdCEjo2cjj8aiyfvQlBewa+NB/rNoD1qgUTQpq2D0T9LoOTgu9P+U4aNxneHLXgiMY3inX0O53K153HHPbNYsXwxINm3+jtlznmDl4nfC1xv1Ncy+C6BgbyGTpt/MyKEDWff1RoYNOo8ZP7uaOU+/QNmBQ7z9/55j+OABzP/HYl7825v4AwFGDB7AX559jDp/kOm/mkVhYSGapvHII49w7bUN4U/rOVmF36Hm8I1d+C1PjwhgyB5jFf5nn8GX/SD1gJPuxS5E4D90S5/IVT+9kpysXqcth6HUr+HZ5TkUVdSSEutk1qV9IpQ9wEV9I73sPXV1DsHQKFvTJQ8u/I5rhnQNK/ynl23n4r6dGNb96D3+6aAoCiigWlSwH798a1Lr19CkxGO3oOuS9zcUkpnsYVBaHHUBjVvfWM/VQ1KZNqgrFTV+Bv7PSh65Iotbzu/BoWofQx7/lDmTspgxpgflXj+L393Ery7MYGyKQl1uf3z+bAZl96dr2efw7rX4ZnyKPX0Y7F4Dq59Av/IlgtHp+KvL0YIB3rz/bvy1zUf4Nqedab99JNRJ6ei68XSk6xJN15EBHzLoQ1Nd6FJHrdyH8FVRF9sbTddwlG5AqavkSOoF6LpOzO6lKP4jlGVch5SS5Lw3IFDLrswZWBVBj2//SFDT2ZBxB7EuK5nf/YFa7KztfCMpsQ76bP0TVcLDZ3Hj6J7opm/eyxxS4jjoGktqchRd9+QhNCfC0o3EzlFYygqprXNTJxOJSY6iwjmSvZUWKqWLblFR7LZextaDGtV1kqQ4KxtS/ou8Ui9KRS2eJMGG+Cnkl1ahVh8iPd7JFtswdhdXY1ULSYmxc0R2ZV9+JTa1iiSPjYNSUnakAJsqiHFakFJS4fVhVRXcVsXYZ14XwKoI7BZjpF4b0LAoAquq0C3lamqOVBpjbCFYM7+QbjlRpJ8Xg9Qla9/dT/qAaLrlRLNxaWGEsgfQApKvluwjsacNX43G14uK6TUili6ZHuqqgzg8x1eBSam92Fmwl+KKIKqqctdDjzPn4UcorT7aVI8hQ2mNhfzde/jLy6/w+yd7c9mUKbz69494/x+LWL5yJY/+4f/y29mzeXPhUha9vxCb1cr9Dz3Mn9/6EKfbhSs2kc8W/JM4l43KRtG6TocOpfDPiy3m24oUIkb5oTn8CDQHo7fEYA8olEcF2NKrjDUz721VWa4alNpMwR+P87o2+L5WFcFnsy4iGNrmVe718+a6ApKj7AzrHk9VXYC7/r6ZX12QwYiM0w+63trousQX1HHajCep5VtLiHFaGRmS9a6/b2JA11huPt94khry+Ep+NjyNh6/IQgh45INcbhzdnUFpcdgtCv6gHg4LGu2wMndKVrjd8W4bGx+ZQKzTGk7Pv3VEWBbHiBmEvdrHTYJZu7A7QotpehCQKK54bDYrtvwl8MlvuKRLb1bsTmxmhDehUz4918+Ba0KxA1Y/CTs+gV+vMdIf3GlMi9yXZ6QXvQR718HdW4z0+y/DoW/hZyFX2ZXzjamOiSEneLYvwO9lyKUTjHTXIpCSIUOMXU8MdoFqZ3T6KCN9eBBYHFwUVb8o/VMAGgJ6GjusfhFON0QJOxoBTUfTJQ6r0fb9FbXouqRbvGF3snHvYVQhGNDN+L5+sqUYl01lXB9jAPPqml0kRdmZOtD4/s9dspWMJDc3jOoOwK1vfMOgtDhmXmQMriY8928mZCXzm4m90XSdgY+t4NohXbl3QiZ7CnZRoUYT77aSFGXHaiujRjhQouOJc1iw2MrwCjuKJ47aIy27LfHX6liiYrE7JKrlAH7ViTU6FqtFwxZlpaLGj9tuwaYKdF3i9Wk4rAoWRaBLSV1Ap2+/fuzZX0T+zny6pXVn6KgxCGE4QrtyyhXcP3s2l146KSJWrdXpJi0tnfMGG4Ptvv2yuPCii7C4PPQfMIjC55/ni6++4bvcXCZdeRVSQm1dLdEJnbhi6jTW/f5J7vvN/Vwz7Uoun3Bxi207WTqUwr+kyy4Avq1INcb6smGXzp6EaPbFR9O7+BA/dImhzhZka48jHI4O0MV9dsayTYpqGGbHu218N/dSAiGtV3rEx77yGvyh9NaiSu55bzPPXDOAgd1iCWg6ihCoSkPnt3jTfp5dvuOYTx3HIqDpWFVjVPPVrkMENMn5mcYWtKeWbsdhVbj7kt4ATHrhc3omeXjlemML59NLt9MvJTqs8KvqgtQGGgxNHrysL5nJRsByIQSfzRpHnMsWTv/j16PCZRVFcNOYhik3IQTx7pOIeOVu1EH2vCjSYVz6GLj0Cfot/y10Odzc95DrAJQ3esKK627YcdTTf5ph31HPmLtg2C0N6cnPRS4CXvVypGxNneYNjtw2S8a4yHRcOq2NVVWwNtqjkBrrjBQpLS4ifXlO5O/n1rGR0ePmXtk/Iv3qjcMi0ivvbdjFpSgKm+dOQkqwWYypnYzkKJTQiH/afYOp9gWxqQp2q8q0+4ZQUePHaVXxxNupLm++hdEZa8PpdBAVZ2XqfUPYe6gGu91OdKwVf1CjqFoj1mYn2mWjLqCxt6qKdI+DGJeNWn+QfWXVDB8xii1bvuXPL7/M86//A6vLRbTDyjPPPstFk6/CaneQEB9LVV2AgoNeMpI8xMfH4nA6OBi0kB7vxuVyEhUbRxV2ouOMztLqcHDNddfzpz8+w86y6vDvGeDvn/ybNatXMOfRR1n/5RfNgqecCh1K4dfT2OJWD/22bEENW1BjT1I0uzv72dDnCFIBqVsZE/+Lo9R0dqEqAjVk1NOrkyfih6LpktRYJ4keQ/Etyy3hwUVb+PC/z6dHopv5/yng8Y/zqAsYX6j9FbU8uOg7wHgaySs+QlmVjwt7G3uG563dTeHhWh6+wtjf+ss311NW5eODmUYg9Zf+lU+NPxhW+KVH6sKjeYCbx/QgxtmwcPjGzcOJdjSkX7sp8kf/i9Dor54uMZFKps1IzjJe/3mFfuxrZoRHTDe4bXVDeuB/Ga96eo1vXl9jnK0bwagjUj+oqMfeqPcRQhDV6HukCEG82xgYjZrak9Vvbyfob2z8pHD+tF7ha6yqQs9ODYu4NotKvy4NWycdVpWcRmtmdqtKn85RnD9mNLfcPIPb77iDUTmZOKwqK1euJDs7i4oqb1hmm6qQFOUIpwUCt81CuElSGuvMoeTYCy/ipWt+wgP334dfd1J5+DBebxUWi5WY2Diu+Mm1REXHsGrx30/x04ykQyn8T4sz+PZwStgoCQH746PxWeC8feXsTXCzs7Pkk2E+dAHSH0ugchDLy+KY0zpPTO3GeV1jeX1GQwzYtHgXVw9OpWucoTifXrYjrOzrqQ3oPLt8B1cNSuX1tbv59/cH+OqhSwDYW17LD2UN/von53Shytew6+j307Ijfph/ujbSp9B1w9Mi0vXTAT8axj8aGaYSjO16409/lGVyZug9wjBo+vKDnVSX+/DE2xk1tWc4/0QJ6w+MDsVuUemf1Q+73c6DDzyAO9R5NA2AcuWUK7BbVTrHNO6gIr/7DpuFnp08FNQcBGDE4AE88+QTXHH5ZdT6DQ+ZDz3+LFVHjvCn3z8aDp7y+qsN1vCnQ4fapfPc9MnIliwKpWRbjyqcdSrrUrpR667Fd/BiZDAWd8+nCRwexY572z8azZmkxwMft+hpSAC7n5rM3kM1+IJaeFrFhHYJRG8SSUu7UNqDO++8k2HDhrXoE78+AErTIOYny+EaP/sP16I30smKEKTGOcPTm005p3fpHKvr6lcQxZaUbpRXXIbd9gn2xH8RrM6itvDnJNuy20zG9iIl1sn+iub+/lNC87NpCT+yEXhbcN50U8Gf47RlAJR6pV5aWYdf07GpCskxjqMq+1OhQyn8Y5FQ42PSuGv5er2P2rLLscasx+LZhqIl8MuRFxPUg3gDXmLsbbPnva2ZdWkfHly0JWKh1GlVmXVpn3aUysTk7KatA6DEuWytquCb0qH8xdr8gYhtUYBhTKHpjMgvYuVhD9OHdiU1JopgxUhifJMZ1N3Opuo3uPaja5n171nN/FF3FK4alMqTP8khNdaJwNh58eRPck5666iJicmPlw41wvfbWgicIQRSVVCTO1NZG2DKgC48NrVhCqfKfzXv5L1DkbcIp8VJpa+SWEfH3ElhjdmMu9cLRHlLcLs7Y425CzAVvonJuUKHGuEfi9U9OrHw9tFcNTBSwUXZorjtvNu4Z8g9qIrKE189waayTe0k5Znj410fM3fdXIq9xUgkxd5i5q6by8e7Pm5v0UxMTNqIc0PhC0F1TTVP/Owa5r/9zxZOC8akjmH2sNnsrtzNTUtvIueNHMa9N4752+YT1Fsv4kx7ENSDvLDxBeq0SFcBdVodT3/9NB/u/DCcd8R/hIAeaFqFiYlJB6BDTek0jnjVFAHYtTr2f/QmbwG/uP4nzcqsL13Pzsqd6Bj71Q/VHeLZ9c/y4c4PGdBpACnuFFI8Da84e1zEnt2zBU3XwgZab2x9g9dzX6e8rrzFsod9h3lr21tM6Wk4H5j9+WwO1R7iH1P+AcBLm17Cptj41YBfAbCpbBMeq4fMuMw2aImJiUlr0qEUvpBHi2rbgFUG2b1sAbSg8F/Y+EKz0a0udfZ79zPOPo78inzWlzbYBTgtTrq4uzR0AqEOwWVt2y2OUkokEkUorNq7ike+eIRFUxfR2d2ZzLhMJmdMZkXBCkpqSppd28Xdhb9N/Fs4fU3mNRFPAvuq9uFQG6I8/e4/v6OrpysvXvwiADOWzaBvfF9mD58NwPxt8+ke053zU88H4EDNAWLtsVjVE3TXa2JicsboUApfnmD0J1egqsX8Em9zhQhwxHeE2wcaYQRrAjUUe4vZX72f4upi9nv3s6F0A1/s/yJcPtYeG+4EEp2JqEI1XopxtCgWFKFEvLcIC4piHOvLhY+i4br6JwopJUIItpdvZ+anM3li7BOM6DKC7tHdmdh9YngaanTKaEanjCYrIYu56+ZGKHOH6uCuwXdFbEUdnx7pGuCZC56JSD819qmIgC05iTl0jeoaTv9ty9+YmD4xrPCnfjCVKzKu4KERho+Yu/51FxO7T2RyhuHea9XeVfSJ6xNRh4mJyZmhTRW+EGIS8AKgAq9KKZ9qy/vXU2Nt2Zq0s7szxd7iFvMBfvfl78hOzGZa5jR6xjbEjZVSUuGroKi6yOgIQh3CjvIdaLLlSPQnS72CD+pBNpVtIi06jR4xPZBSYlWtzM+bz/KC5ahCxWFx8O72d1EV1ehIhBGV6sKuF7KuaB1VgSqibdGcn3o+h2oP8da2txCIcGeihJx7KaElnrCf8vo/Icg9aEQMq/8c6tcB7ht6H5qu8cmuTwC4NP1S4hxxLC9YjqZr/FDxA/El8ThUB37Nz/1r7ufKnlcyMX0iPs3Ho+seZVqvaYxJHYMv6GNZwTKGJg8lPSYdTdeo9FUS54gzOj8a5KqXuamcAmHElmia17idQjlqucZTdo3T9XU0LRNxrtG96tONzzct0/i6ls63dL+j1d+SnKE3LdbXUj0mHY82U/hCCBV4GZgAFALfCCGWSCm3tdY9rJpO4DihCAPCQo9JP23x3F2D7zrqKNiv+dlZuZNEl+EsTEpJaU0pnd2dEUIQ54gjzhFH/8QGz4BBPUi1vxpNasZL1wjKILrUm73XpEZQDzaU1TQ0NIJakBc3vUhqVCqX97jcqDNQTVZ8Fr3ieqFJjQFJA8LX61Jvfg9NR5MacY44JvWYhB4KoSaR5FfkI5HhaaH6ttWvY4TLhuwTdKlHlGt8bX2ZphNrB2oPsPXgVgAyYjI4UHuAf+b/EyklQzoNoaymjAXfLyCgB4ixxbDlwBb2Ve2jNljLNyXfUHCkgGRXMt6Al/Wl6+kX349Ork7UBmv54fAPdI/uTrQ9moAWoMJX0WpTSKXeUnYf2Y1P82FX7fSI7kGy+yRi4/7IiQi92agzDGc17qxa6PRa6qwiqzx+B3qF+wr2V+0Py3BMGU+2TY3adjr1nlDZcH8rmHzxZD7+17F3xylCIdGZeMIynChtOcIfDuRLKXcBCCH+DkwFWk3h9y06yJZunVpcuJVAlcVDr8umt7hgC4SnGV7Y+AIl3pJwCMT6/HmT5qHpxoh9Q+kGbllxC6+Mf4XRqaNbrM+iWE54T3/9CB5g7rq5VPgqeP6i5417lW0gPTqdyzMuB+DKXleeUJ3tRWPF36zDaNSRNC4X7jQadRy6NCJcBfUgqqJS6avki/1fMKjTIJJdyeRX5PP8hueZkT2D3vG92VCygd+u/S3PjH2G/on9WV+6nme/eZbfjfkdGbEZFFQU8O/CfzM5YzKxjliqfFV4A14SnAkoQgnfHwlr9q/hy6Iv8et+AHyaj12VuxjXbVz4/91U/nD7G3WIjfOa5oc7RtnomiadadPPtXFeRCfdqK5j3S+iTtlc1paui2hD0zYdo0xLbWose0syNW2jNWDFYWlYQzr+Kl1k/SdU9kTrbPLZnVSdjf4vH676MPy7ONr9z5QBaFsq/FRgX6N0ITCiaSEhxG3AbQBpaWlNTx+TzYm9UGVlM4UvJazuMqFZiMGWmJwxOazgW6J+90tadBq35tzK4OTBAPyn+D9U+iq5JO2ScJkT5X+3/C/LC5aHd8akR6eTEGjw2T5r2KyTqq+9aTxqU1oxAHSiMzFiKi3ZncyY1DHhdHz3ePrE96FbVDdcVhe1wVomZ0xmQNIAklxJ7CjfwZJdS7htwG2kelJZ9MMi5qybw7Krl5HqSWXlnpW8t+M9/njhH1n0w6Kwsq/Hr/v5YOcHzBw0s9XaZHJs8vLySHC2b4Cf3NxcbrvtNtatWwfAxo0bmTVrFqtWrTrmdV6vl+nTpzcLU+jxeKiurqagoIBJkyYxcuRI1q1bx7Bhw5gxYwZz5syhrKyMt99+m+HDhx/zHifLWbdoK6X8K/BXMLxlnsy13ihJtNZcwdQq9hNS9idDJ1cn/nvQf4fTC3YsYHv5diakG5GKPtr5ES9uerHFJ4VlBct4fsPzLLpyES6ri87uzmQlZOHX/NhUGzOyjx+VyKQ5TouTPvENvoH6xPfh4ZEPh9OX9biMS7tfGn4EH5o8lP8Z/T90chqRmjSpUResw2VxHXUBv9hbjC51FKGw4PsFfFn0Jc+New6A9SXrKfYWh7e4VvoqUYWKx3aCQbRNjsl3q5ZRWdry/+VUiUnuzHnjJx2zTFZWFrt27ULTNFRV5d577+W55547bt3Lli0jJSWFjz82pm9aClOYn5/PggULeO211xg2bBjvvPMOX3zxBUuWLOGJJ55g8eLFp9awo9CWhlf7gW6N0l1Dea1GlFbdYr5T+s64z5hnLniGv078K4pQ+DD/Qx764qEIq9YH1zzIq1teBSDJmUR2YjZH/EboxckZk5k7ei429cw5TTIxUIQSfgJJi05jWua08Hz/pO6TmH/5fKyqNbxQ35Qoa1T4qaU2UEulr+FHvGTnEp7f8Hw4/ew3zzKrtkuOAAAPdklEQVRtybRw+sWNL/LAmgfC6RUFKyKM3oqqizhYe7AVWmnSmiiKQv/+/dm6dSsLFy4kPT2dwYMH89lnnzF27Fh+/etf89lnnzW7Licnh5UrVzJ79mzWrFlDTExzx4w9evQgJycnfI/x48cjhCAnJ4eCgoJWb0tbjvC/ATKFED0wFP111AfcbCV0VyxqTUWL+WcaVVFJ9RidygubXmg+/4rk7by3uTXnVoYkD2FI8pCWqjE5SzjaAv5vR/42nL6h/w3c0L8hBOEDwx8Id+IAU3pOYUSXhllLq2rFrjaErXz/+/fxBr3hJ4JH1j5CQA/w5mVvAnD/5/fjsXp4dJQRdOXtvLeJs8eF13J2lO8g2hZNF8/ZGaKztTneSPxMMnLkSNauXctf/vIXli1bBhhTlx6Ph7q6Orp2bb6tuHfv3mzcuJFPPvmEhx9+mPHjxzcLU2i3N3wfFEUJpxVFIRhsfQv/NlP4UsqgEOJOYDnGtszXpJRbW/MeU26+hY9feRGhNRhPSdXKlJtvOcZVrU9ZTVmL+YdqD7WpHCanzvEW8FvCZXVFGN01VvYAtw+4PSL9l0v+Ql2woUP55Xm/DG8KAEhxp+C0NIR6XJy/OGLx/p7P7iE7MTtsK3HdR9cxvPNw7h16LwDPbXiO7IRsJnafCBjrTF09XU2bh1Ng5MiR3HTTTcycOZPUVGNgN3bsWC688EJKS0u59957efvttyOuKSoqIj4+nuuvv57Y2FheffXV9hA9gjadw5dSfgJ8cqbq7zfWCEa95u9vUnXoIFEJiYy97oZwfltxvP38Jj8OjreAf7pYFEvE/P7ILiMjzt895O6I9IIpCyL8Oj02+rGIDmZI8pCIRe0VBStQUJjYfSJSSm7/9HZuyLqBe4bcgy51Rr0zil+e90tuzbkVTdd4cM2DXNHzCi7oegFBPcinez8lOyGbrlFdkVISlEGsyrlpMd23b1/sdjuzZ88O5ykhQ8+4uDh8vubB07ds2cKsWbPCYQpfeeUsiKonpTxrX0OGDJE/Rj7a+ZEc+tZQmT0vO/wa+tZQ+dHOj9pbNJNzFF3X5eayzXJv5V4ppZT+oF/+8Zs/yrWFa6WUUh7xHZGXL7xcLtixQEop5YGaAzJ7XrZ8N+9dKaWUJdUlMntetlz4/cLw+Ts+vUN+Xfy1lFLKiroKufD7hbKoqsioX/PLiroKqenaacm9bdu207q+tZg5c6acN29eRN7ChQvlbbfdJqdPny5Xr17dLnK19PkA6+VRdGq7K/VjvX6sCl9KQ+lPWDBB5szLkRMWTDCVvcmPCr/ml9+Xfy8P1hyUUkp5uPawfGXzKzLvUJ6UUso9lXvkT5f8VK7db3QYWw5skdnzsuVnez+TUkq5qXSTzJ6XLT/f97mUUsqtB7fKm5beJLcf2i6llHLfkX3yra1vyQM1B6SUUlb7q2VRVZEMaIEIOdpb4efn58s+ffrIm2++uV3lOBqmwjcxMWlz/Jpf7q/aL71+r5RSyuLqYvnm1jdlcXWxlFLK78q+kzcuvVHmH86XUkq5omCFzJ6XHe4Alu5eKrPnZcsfyn+QUkr5rz3/kj9d8lO5JXeLlFLKGn+NLPOWyaAWDN+vNlArdV1v03aebZyswj/r9uGbmJj8+LAqVlI8KeF0Z3dnfpH1i3A6JymHeZPmhdPj08az5to1uG1uAPon9GfuqLnhHUd2i50kV1J4C21NsIaymjLiHHGAYeNQ6i2lb3xfVKFyqPYQ5XXl9IztiSIUqvyGFXWyKxkhBD7Nh6Zrbe7J9mzDVPgmJiZtjiKUCLcj3aK60S2qwUyn3strXl4eAAnOBOIccWGjuShbFFbFGraJsCpWnBZng41EsJYKX0V4o0R5bTkVvgr6JfQDDAM6r99Lr7hexvm6cgJaIOwrqSZQg0TithodkpSyQziVMxW+iYnJj4LGbjrsqj3CpiHaHk20PTqc7uTqRJIzKZyOd8YTbWs477K4wt5gAXxBX4TNxcHag/h1P71ijQ5hX9U+gjJIRkwG0LD1upPLsNKu8lehCCXcQWi6FmHkd6JU+Coo85YR0ANYFSud3J2ItbeeHZGp8E1MTDokjZVt0w4ixh4TEQeiqfFaZ3fnCAdn0bbosOM/gIAWGSiprKYMi2IJK/zdR3ZjU2ykRRv+wAqrCrGrxjQVwOG6w9hUW7h8QAtQHag2rPOlYbQZ0AMUVRcBtJrSNxW+iYmJSROaujlp6vU2NSrSVUtaVFqEdX2CIwFVNDhRlE28gpbWlBJtiw4r/PyKfKOcbO4htcxbZip8ExMTk7OFpvEX6heX62m8PgGQGZsZ0QF0dncOj+ab0jTs6unQls7TTExMTEwwfG9ZlIbxdpwj7qhWzK1p3WyO8E1MTDoMeWtWt7trlVOlk7sTRdVFEdM6Qgg6uTu12j3MEb6JiUmHIG/Nalb89c9UHTwAUlJ18AAr/vpn8tasPq16c3NzGT26Iardxo0bGT9+/HGvKygooG/fvtx000307t2bn//853z66aeMGTOGzMxMvv76awDmz5/P8OHDGTdiHM/MfgZFKtR4a5j5s5lMv2g65w85n/fee++02lCPqfBNTEx+NLz32APkfvYpAFowyHuPPcC2kEJf8+4bBP2RTsyCfh+r3/gbADVHKnnvsQfYueErALwVh0/ono0DoADce++9PPvssyd0bX5+Pvfddx/bt29n+/bt4QAnf/jDH3jiiSfIy8vjvffeY+3atWzevBmXzcU3S79h7/q9ZKZnkvtdLrm5uUya1DquoU2Fb2Ji0iGoOtSy+/HaqiMt5p8opxoABY4f4GTVqlVs2LCBYcOGMXDgQFatWsWuXbtOKHjKqWDO4ZuYmPxouHbOU+H3qsUSkY5KTDSmc5oQlWjsfXdFx0SUd8fGNSt7NE4lAAocP8CJlJIbb7yRJ598stm1xwueciqYI3wTE5MOwdjrbsBis0fkWWx2xl53w1GuOHFGjhzJww8/zLRp0yICoCxdupSnn36aOXPmnFK948eP5/3336eszLDcLS8vZ8+ePRQVFeFyubj++uuZNWsWGzduPO02gDnCNzEx6SCcyQBIpxIA5UTIysri8ccfZ+LEiei6jtVq5eWXX6aysvKMBE8RTS27ziaGDh0q169f395imJiYtBN5eXn069evvcXgzjvvZNiwYdx4443hvEWLFrF8+XIqKiq4/fbbGTduXJvL1dLnI4TYIKUc2lL5s1rhCyEOAHtO8fJE4GArivNjwGxzx+ecau/KlStzkpKSUFW19SN6nwB79+4Vd9xxh2PgwIHa448/7m+r+2qaZjmRNpeUlFgmTJiwpUl2upQyqaXyZ/WUztGEPhGEEOuP1st1VMw2d3zOtfZ+++23BaqqJmVnZ+e1x/2zs7MpKCho8/vm5ub2O5E2a5qWeDLfB3PR1sTExOQcwVT4JiYmJucIHVnh/7W9BWgHzDZ3fM619uoJCQnNN9d3cBITE4/bZl3XBTRy0n8CdFiFL6U8134YZpvPAc619gK5iqIEQ8rtnKFz587HXJjXdV0cOHAgBsg9mXrP6kVbExOTc5tgMHhrSUnJqyUlJdl04AHqKaADucFg8NaTueis3pZpYmJiYtJ6dLgeUwgxSQixQwiRL4R4oL3lOdMIIboJIVYLIbYJIbYKIe5qb5naCiGEKoTYJIT4qL1laQuEELFCiPeFENuFEHlCiFHtLdOZRghxT+h7nSuEeFcI4WhvmVobIcRrQogyIURuo7x4IcRKIcQPoeOJO/45Bh1K4QshVOBl4DIgC/gvIURW+0p1xgkC90kps4CRwMxzoM313AW0y/7sduIFYJmUsi8wgA7ediFEKvB/gKFSymxABa5rX6nOCPOApv6PHwBWSSkzgVWh9GnToRQ+MBzIl1LuklL6gb8DU9tZpjOKlLJYSrkx9L4KQwmkHvuqHz9CiK7AZODV9palLRBCxAAXAP8LIKX0Sykr2leqNsECOIUQFsAFtBz49UeMlPJzoLxJ9lTgjdD7N4CrWuNeHU3hpwL7GqULOQeUXz1CiO7AIOCr9pWkTXgeuJ+T3Jb2I6YHcAB4PTSN9aoQwt3eQp1JpJT7gT8Ae4FioFJKuaJ9pWozkqWUxaH3JUBya1Ta0RT+OYsQwgMsBO6WUp5exIezHCHEFUCZlHJDe8vShliAwcArUspBgJdWesw/WwnNW0/F6OxSALcQ4vr2lartkcbOmlbZXdPRFP5+oFujdNdQXodGCGHFUPZvSykXtbc8bcAY4EohRAHGtN3FQoj57SvSGacQKJRS1j+9vY/RAXRkLgF2SykPSCkDwCJg9HGu6SiUCiG6AISOZa1RaUdT+N8AmUKIHkIIG8YCz5J2lumMIoQQGPO6eVLK59pbnrZASvmglLKrlLI7xv/4X1LKDj3yk1KWAPuEEH1CWeOBbe0oUluwFxgphHCFvufj6eAL1Y1YAtT7Yr4R+KA1Ku1QhldSyqAQ4k5gOcaK/mtSyq3tLNaZZgzwC2CLEGJzKO8hKeUn7SiTyZnhv4G3Q4OZXcCMdpbnjCKl/EoI8T6wEWM32iY6oGsJIcS7wDggUQhRCMwBngL+IYS4BcNF/PRWuZdpeGViYmJybtDRpnRMTExMTI6CqfBNTExMzhFMhW9iYmJyjmAqfBMTE5NzBFPhm5iYmJwjmArfxMTE5BzBVPgmJiYm5wimwjcxaYIQoqsQ4tqjnHMKIf4dcsXd0nmbEOLzkHdHE5OzClPhm5g0ZzxH91NzM7BISqm1dDLklnsV0GKHYWLSnpgK38SkEUKI84HngGuEEJuFEBlNivyckF8TIYRbCPGxEOLbUESmeiW/OFTOxOSswnzsNDFphJTyCyHEN8BvpJS5jc+FfNhkSCkLQlmTgCIp5eTQ+ZhQfi4wrI1ENjE5YcwRvolJc/oA21vITwQaR5naAkwQQjwthBgrpawECE33+IUQUWdeVBOTE8dU+CYmjRBCJGJEVgq2cLoWCAfRllJ+jzHXvwV4XAjxaKOydqDuTMpqYnKymFM6JiaRdOcocVOllIeFEKoQwiGlrBNCpADlUsr5QogK4FYAIUQCcDAUtMPE5KzBHOGbmESyHcMvea4QoqXoSiuA80Pvc4CvQ3EI5gCPh/IvAj4+45KamJwkpj98E5OTQAgxGLhHSvmLY5RZBDwQmvIxMTlrMEf4JiYngZRyI7D6WIZXwGJT2ZucjZgjfBMTE5NzBHOEb2JiYnKOYCp8ExMTk3MEU+GbmJiYnCOYCt/ExMTkHMFU+CYmJibnCKbCNzExMTlH+P+rUG6SWUgVtQAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -717,10 +866,8 @@ }, { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -729,10 +876,8 @@ }, { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -751,66 +896,99 @@ "source": [ "## Changing optimizers - Ceres\n", "\n", - "Once parPE has been built with support for different optimizers, selecting a different optimizer is quite easy. \n", + "Once parPE has been built with support for different optimizers, selecting a different optimizer is quite easy.\n", "\n", "(This part of the example requires a parPE build with `PARPE_ENABLE_CERES=ON`)" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32m[2020-01-31 18:27:49] [INF] [0/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:49] [INF] [0/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:49] [INF] [0/dweindl-ThinkPad-L480] [o0i0] iter: 0 cost: 626.531 time_iter: wall: 0.0878097s cpu: 0.215641s time_optim: wall: 0.08781s cpu: 0.215641s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:49] [INF] [0/dweindl-ThinkPad-L480] [o0i1] iter: 1 cost: -282.389 time_iter: wall: 0.0382636s cpu: 0.0854241s time_optim: wall: 0.126074s cpu: 0.301066s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:49] [INF] [0/dweindl-ThinkPad-L480] [o0i2] iter: 2 cost: -312.328 time_iter: wall: 0.0944906s cpu: 0.175008s time_optim: wall: 0.220565s cpu: 0.476073s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:49] [INF] [0/dweindl-ThinkPad-L480] [o0i3] iter: 3 cost: -327.5 time_iter: wall: 0.0798723s cpu: 0.155348s time_optim: wall: 0.300437s cpu: 0.631422s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:49] [INF] [0/dweindl-ThinkPad-L480] [o0i4] iter: 4 cost: -329.721 time_iter: wall: 0.0788383s cpu: 0.146776s time_optim: wall: 0.379276s cpu: 0.778198s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:49] [INF] [0/dweindl-ThinkPad-L480] [o0i5] iter: 5 cost: -329.884 time_iter: wall: 0.0801541s cpu: 0.148324s time_optim: wall: 0.45943s cpu: 0.926522s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i6] iter: 6 cost: -330.163 time_iter: wall: 0.039495s cpu: 0.0720279s time_optim: wall: 0.498925s cpu: 0.99855s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i7] iter: 7 cost: -333.956 time_iter: wall: 0.0792281s cpu: 0.148999s time_optim: wall: 0.578154s cpu: 1.14755s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i8] iter: 8 cost: -336.285 time_iter: wall: 0.0762727s cpu: 0.144594s time_optim: wall: 0.654426s cpu: 1.29214s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i9] iter: 9 cost: -357.97 time_iter: wall: 0.0792642s cpu: 0.147496s time_optim: wall: 0.733691s cpu: 1.43964s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i10] iter: 10 cost: -363.227 time_iter: wall: 0.107617s cpu: 0.200491s time_optim: wall: 0.841308s cpu: 1.64013s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i11] iter: 11 cost: -366.406 time_iter: wall: 0.041734s cpu: 0.0756804s time_optim: wall: 0.883043s cpu: 1.71581s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i12] iter: 12 cost: -367.512 time_iter: wall: 0.0420634s cpu: 0.0801413s time_optim: wall: 0.925107s cpu: 1.79595s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i13] iter: 13 cost: -367.632 time_iter: wall: 0.0417877s cpu: 0.0787956s time_optim: wall: 0.966895s cpu: 1.87475s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i14] iter: 14 cost: -367.686 time_iter: wall: 0.0419693s cpu: 0.081354s time_optim: wall: 1.00886s cpu: 1.9561s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i15] iter: 15 cost: -367.726 time_iter: wall: 0.0432925s cpu: 0.0821559s time_optim: wall: 1.05216s cpu: 2.03826s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i16] iter: 16 cost: -367.784 time_iter: wall: 0.0464071s cpu: 0.0865333s time_optim: wall: 1.09856s cpu: 2.12479s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i17] iter: 17 cost: -367.845 time_iter: wall: 0.0494481s cpu: 0.0878591s time_optim: wall: 1.14801s cpu: 2.21265s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i18] iter: 18 cost: -367.919 time_iter: wall: 0.0458842s cpu: 0.0830575s time_optim: wall: 1.1939s cpu: 2.29571s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i19] iter: 19 cost: -368.005 time_iter: wall: 0.0448905s cpu: 0.0806423s time_optim: wall: 1.23879s cpu: 2.37635s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i20] iter: 20 cost: -368.107 time_iter: wall: 0.0437259s cpu: 0.0809238s time_optim: wall: 1.28251s cpu: 2.45727s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i21] iter: 21 cost: -368.221 time_iter: wall: 0.0451277s cpu: 0.083776s time_optim: wall: 1.32764s cpu: 2.54105s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i22] iter: 22 cost: -368.408 time_iter: wall: 0.0439751s cpu: 0.0847565s time_optim: wall: 1.37162s cpu: 2.62581s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:50] [INF] [0/dweindl-ThinkPad-L480] [o0i23] iter: 23 cost: -368.48 time_iter: wall: 0.086185s cpu: 0.170123s time_optim: wall: 1.4578s cpu: 2.79593s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i24] iter: 24 cost: -368.489 time_iter: wall: 0.088812s cpu: 0.163595s time_optim: wall: 1.54661s cpu: 2.95952s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i25] iter: 25 cost: -368.489 time_iter: wall: 0.088335s cpu: 0.164049s time_optim: wall: 1.63495s cpu: 3.12357s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i26] iter: 26 cost: -368.49 time_iter: wall: 0.0439723s cpu: 0.0811672s time_optim: wall: 1.67892s cpu: 3.20474s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i27] iter: 27 cost: -368.503 time_iter: wall: 0.0922686s cpu: 0.17686s time_optim: wall: 1.77119s cpu: 3.3816s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i28] iter: 28 cost: -368.509 time_iter: wall: 0.0865418s cpu: 0.161949s time_optim: wall: 1.85773s cpu: 3.54355s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i29] iter: 29 cost: -368.52 time_iter: wall: 0.045575s cpu: 0.0824998s time_optim: wall: 1.90331s cpu: 3.62605s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i30] iter: 30 cost: -368.539 time_iter: wall: 0.0436019s cpu: 0.0827147s time_optim: wall: 1.94691s cpu: 3.70876s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i31] iter: 31 cost: -368.547 time_iter: wall: 0.0879193s cpu: 0.17031s time_optim: wall: 2.03483s cpu: 3.87907s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i32] iter: 32 cost: -368.563 time_iter: wall: 0.0425295s cpu: 0.08082s time_optim: wall: 2.07736s cpu: 3.95989s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i33] iter: 33 cost: -368.591 time_iter: wall: 0.0462949s cpu: 0.0899349s time_optim: wall: 2.12365s cpu: 4.04983s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i34] iter: 34 cost: -368.631 time_iter: wall: 0.0434895s cpu: 0.0798537s time_optim: wall: 2.16714s cpu: 4.12968s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i35] iter: 35 cost: -368.646 time_iter: wall: 0.0513606s cpu: 0.0877316s time_optim: wall: 2.21851s cpu: 4.21741s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i36] iter: 36 cost: -368.648 time_iter: wall: 0.0460125s cpu: 0.0840323s time_optim: wall: 2.26452s cpu: 4.30145s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i37] iter: 37 cost: -368.648 time_iter: wall: 0.0473998s cpu: 0.0865129s time_optim: wall: 2.31192s cpu: 4.38796s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:51] [INF] [0/dweindl-ThinkPad-L480] [o0i38] iter: 38 cost: -368.648 time_iter: wall: 0.04657s cpu: 0.0864134s time_optim: wall: 2.35849s cpu: 4.47437s\u001b[0m\n", - "WARNING: Logging before InitGoogleLogging() is written to STDERR\n", - "W0131 18:27:52.205655 1957 line_search.cc:767] Line search failed: Wolfe zoom bracket width: 0.00000e+00 too small with descent_direction_max_norm: 1.36015e-04.\n", - "\u001b[32m[2020-01-31 18:27:52] [INF] [0/dweindl-ThinkPad-L480] [o0i39] Optimizer status 0, final llh: -3.686481e+02, time: wall: 2.665717 cpu: 5.048125.\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:53] [INF] [0/dweindl-ThinkPad-L480] Walltime on master: 4.349326s, CPU time of all processes: 17.333460s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:27:53] [INF] [0/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001b[0m\n" + "\u001B[32m[2020-06-24 17:41:41] [INF] [0:139880673687488/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:41] [INF] [0:139880673687488/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001B[0m\r\n", + "callbacks.cc:105 0: f: 5.323027e+02 d: 0.00e+00 g: 4.46e+03 h: 0.00e+00 s: 0.00e+00 e: 0 it: 4.13e-02 tt: 4.13e-02\r\n", + "\u001B[32m[2020-06-24 17:41:41] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i0] iter: 0 cost: 532.303 time_iter: wall: 0.0415566s cpu: 0.0809107s time_optim: wall: 0.0415569s cpu: 0.0809107s\u001B[0m\r\n", + "callbacks.cc:105 1: f:-3.344605e+02 d: 8.67e+02 g: 1.67e+02 h: 1.13e+00 s: 2.24e-04 e: 1 it: 3.72e-02 tt: 7.95e-02\r\n", + "\u001B[32m[2020-06-24 17:41:41] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i1] iter: 1 cost: -334.461 time_iter: wall: 0.0382083s cpu: 0.0764133s time_optim: wall: 0.0797655s cpu: 0.157324s\u001B[0m\r\n", + "callbacks.cc:105 2: f:-3.788412e+02 d: 4.44e+01 g: 3.85e+02 h: 3.29e-01 s: 1.28e-03 e: 5 it: 1.56e-01 tt: 2.36e-01\r\n", + "\u001B[32m[2020-06-24 17:41:41] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i2] iter: 2 cost: -378.841 time_iter: wall: 0.156987s cpu: 0.293226s time_optim: wall: 0.236753s cpu: 0.45055s\u001B[0m\r\n", + "callbacks.cc:105 3: f:-4.183630e+02 d: 3.95e+01 g: 2.30e+02 h: 3.95e-01 s: 4.06e-04 e: 1 it: 3.77e-02 tt: 2.75e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i3] iter: 3 cost: -418.363 time_iter: wall: 0.0381825s cpu: 0.0691572s time_optim: wall: 0.274936s cpu: 0.519708s\u001B[0m\r\n", + "callbacks.cc:105 4: f:-4.189047e+02 d: 5.42e-01 g: 2.85e+02 h: 4.76e-02 s: 5.58e-04 e: 2 it: 8.96e-02 tt: 3.65e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i4] iter: 4 cost: -418.905 time_iter: wall: 0.0901106s cpu: 0.161033s time_optim: wall: 0.365047s cpu: 0.68074s\u001B[0m\r\n", + "callbacks.cc:105 5: f:-4.197841e+02 d: 8.79e-01 g: 2.78e+02 h: 2.46e-02 s: 3.88e-04 e: 1 it: 3.98e-02 tt: 4.05e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i5] iter: 5 cost: -419.784 time_iter: wall: 0.0402574s cpu: 0.0745627s time_optim: wall: 0.405304s cpu: 0.755303s\u001B[0m\r\n", + "callbacks.cc:105 6: f:-4.207404e+02 d: 9.56e-01 g: 2.96e+02 h: 6.32e-02 s: 1.52e-03 e: 1 it: 3.93e-02 tt: 4.45e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i6] iter: 6 cost: -420.74 time_iter: wall: 0.0398202s cpu: 0.0781893s time_optim: wall: 0.445125s cpu: 0.833492s\u001B[0m\r\n", + "callbacks.cc:105 7: f:-4.223504e+02 d: 1.61e+00 g: 2.93e+02 h: 8.02e-02 s: 1.09e-03 e: 1 it: 3.71e-02 tt: 4.82e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i7] iter: 7 cost: -422.35 time_iter: wall: 0.0375706s cpu: 0.0742174s time_optim: wall: 0.482696s cpu: 0.907709s\u001B[0m\r\n", + "callbacks.cc:105 8: f:-4.252214e+02 d: 2.87e+00 g: 2.84e+02 h: 1.55e-01 s: 2.42e-03 e: 1 it: 3.77e-02 tt: 5.21e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i8] iter: 8 cost: -425.221 time_iter: wall: 0.0381947s cpu: 0.0754364s time_optim: wall: 0.520891s cpu: 0.983146s\u001B[0m\r\n", + "callbacks.cc:105 9: f:-4.291242e+02 d: 3.90e+00 g: 2.72e+02 h: 4.47e-01 s: 5.38e-02 e: 1 it: 3.75e-02 tt: 5.59e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i9] iter: 9 cost: -429.124 time_iter: wall: 0.0379482s cpu: 0.0749299s time_optim: wall: 0.558839s cpu: 1.05808s\u001B[0m\r\n", + "callbacks.cc:105 10: f:-4.358720e+02 d: 6.75e+00 g: 2.09e+02 h: 5.84e-02 s: 1.20e-01 e: 1 it: 3.65e-02 tt: 5.96e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i10] iter: 10 cost: -435.872 time_iter: wall: 0.036973s cpu: 0.0729143s time_optim: wall: 0.595813s cpu: 1.13099s\u001B[0m\r\n", + "callbacks.cc:105 11: f:-4.441651e+02 d: 8.29e+00 g: 3.97e+01 h: 2.26e-01 s: 7.51e-01 e: 1 it: 3.93e-02 tt: 6.35e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i11] iter: 11 cost: -444.165 time_iter: wall: 0.0397685s cpu: 0.0773617s time_optim: wall: 0.635581s cpu: 1.20835s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i12] iter: 12 cost: -445.062 time_iter: wall: 0.0374097s cpu: 0.0724785s time_optim: wall: 0.672991s cpu: 1.28083s\u001B[0m\r\n", + "callbacks.cc:105 12: f:-4.450617e+02 d: 8.97e-01 g: 1.17e+01 h: 6.36e-02 s: 1.00e+00 e: 1 it: 3.65e-02 tt: 6.73e-01\r\n", + "callbacks.cc:105 13: f:-4.451359e+02 d: 7.42e-02 g: 1.17e+01 h: 5.40e-02 s: 1.00e+00 e: 1 it: 4.10e-02 tt: 7.14e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i13] iter: 13 cost: -445.136 time_iter: wall: 0.0415508s cpu: 0.0775626s time_optim: wall: 0.714542s cpu: 1.35839s\u001B[0m\r\n", + "callbacks.cc:105 14: f:-4.452398e+02 d: 1.04e-01 g: 1.16e+01 h: 5.48e-02 s: 1.00e+00 e: 1 it: 3.74e-02 tt: 7.52e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i14] iter: 14 cost: -445.24 time_iter: wall: 0.0379656s cpu: 0.0741554s time_optim: wall: 0.752508s cpu: 1.43255s\u001B[0m\r\n", + "callbacks.cc:105 15: f:-4.454254e+02 d: 1.86e-01 g: 1.15e+01 h: 8.01e-02 s: 6.39e-01 e: 1 it: 4.32e-02 tt: 7.96e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i15] iter: 15 cost: -445.425 time_iter: wall: 0.0437119s cpu: 0.0795556s time_optim: wall: 0.79622s cpu: 1.5121s\u001B[0m\r\n", + "callbacks.cc:105 16: f:-4.457760e+02 d: 3.51e-01 g: 1.08e+01 h: 1.41e-01 s: 2.84e-01 e: 1 it: 3.65e-02 tt: 8.33e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i16] iter: 16 cost: -445.776 time_iter: wall: 0.036956s cpu: 0.0727817s time_optim: wall: 0.833176s cpu: 1.58489s\u001B[0m\r\n", + "callbacks.cc:105 17: f:-4.460990e+02 d: 3.23e-01 g: 1.73e+01 h: 2.69e-01 s: 1.62e-01 e: 1 it: 3.91e-02 tt: 8.72e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i17] iter: 17 cost: -446.099 time_iter: wall: 0.0395317s cpu: 0.0750284s time_optim: wall: 0.872708s cpu: 1.65991s\u001B[0m\r\n", + "callbacks.cc:105 18: f:-4.465246e+02 d: 4.26e-01 g: 9.07e+00 h: 6.18e-02 s: 8.06e-01 e: 1 it: 3.75e-02 tt: 9.10e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i18] iter: 18 cost: -446.525 time_iter: wall: 0.0380117s cpu: 0.0768193s time_optim: wall: 0.91072s cpu: 1.73673s\u001B[0m\r\n", + "callbacks.cc:105 19: f:-4.469159e+02 d: 3.91e-01 g: 8.47e+00 h: 1.57e-01 s: 1.00e+00 e: 1 it: 3.74e-02 tt: 9.48e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i19] iter: 19 cost: -446.916 time_iter: wall: 0.0378456s cpu: 0.0734315s time_optim: wall: 0.948566s cpu: 1.81016s\u001B[0m\r\n", + "callbacks.cc:105 20: f:-4.470190e+02 d: 1.03e-01 g: 7.25e+00 h: 3.44e-02 s: 1.00e+00 e: 1 it: 3.77e-02 tt: 9.86e-01\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i20] iter: 20 cost: -447.019 time_iter: wall: 0.0381489s cpu: 0.0755738s time_optim: wall: 0.986715s cpu: 1.88574s\u001B[0m\r\n", + "callbacks.cc:105 21: f:-4.470725e+02 d: 5.35e-02 g: 3.81e+00 h: 4.45e-02 s: 1.00e+00 e: 1 it: 3.64e-02 tt: 1.02e+00\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i21] iter: 21 cost: -447.072 time_iter: wall: 0.0368396s cpu: 0.0732056s time_optim: wall: 1.02356s cpu: 1.95894s\u001B[0m\r\n", + "callbacks.cc:105 22: f:-4.471107e+02 d: 3.82e-02 g: 5.08e+00 h: 7.65e-02 s: 4.64e-02 e: 1 it: 3.71e-02 tt: 1.06e+00\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i22] iter: 22 cost: -447.111 time_iter: wall: 0.0375187s cpu: 0.0742591s time_optim: wall: 1.06107s cpu: 2.0332s\u001B[0m\r\n", + "callbacks.cc:105 23: f:-4.471110e+02 d: 3.08e-04 g: 4.69e+00 h: 6.83e-04 s: 1.81e-03 e: 2 it: 7.50e-02 tt: 1.14e+00\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i23] iter: 23 cost: -447.111 time_iter: wall: 0.0754316s cpu: 0.152713s time_optim: wall: 1.13651s cpu: 2.18592s\u001B[0m\r\n", + "callbacks.cc:105 24: f:-4.471154e+02 d: 4.41e-03 g: 6.50e+00 h: 5.26e-03 s: 9.69e-03 e: 2 it: 7.74e-02 tt: 1.21e+00\r\n", + "\u001B[32m[2020-06-24 17:41:42] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i24] iter: 24 cost: -447.115 time_iter: wall: 0.0778265s cpu: 0.153936s time_optim: wall: 1.21433s cpu: 2.33985s\u001B[0m\r\n", + "callbacks.cc:105 25: f:-4.471214e+02 d: 5.97e-03 g: 6.20e+00 h: 8.19e-03 s: 5.28e-04 e: 1 it: 3.64e-02 tt: 1.25e+00\r\n", + "\u001B[32m[2020-06-24 17:41:43] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i25] iter: 25 cost: -447.121 time_iter: wall: 0.0368165s cpu: 0.0730412s time_optim: wall: 1.25115s cpu: 2.41289s\u001B[0m\r\n", + "callbacks.cc:105 26: f:-4.471818e+02 d: 6.04e-02 g: 6.25e+00 h: 9.16e-02 s: 4.15e-03 e: 2 it: 7.55e-02 tt: 1.33e+00\r\n", + "\u001B[32m[2020-06-24 17:41:43] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i26] iter: 26 cost: -447.182 time_iter: wall: 0.0760229s cpu: 0.14886s time_optim: wall: 1.32717s cpu: 2.56175s\u001B[0m\r\n", + "callbacks.cc:105 27: f:-4.471928e+02 d: 1.10e-02 g: 6.28e+00 h: 1.63e-02 s: 1.47e-03 e: 2 it: 7.39e-02 tt: 1.40e+00\r\n", + "\u001B[32m[2020-06-24 17:41:43] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i27] iter: 27 cost: -447.193 time_iter: wall: 0.0743093s cpu: 0.149165s time_optim: wall: 1.40148s cpu: 2.71092s\u001B[0m\r\n", + "callbacks.cc:105 28: f:-4.471946e+02 d: 1.84e-03 g: 5.48e+00 h: 7.66e-03 s: 2.21e-02 e: 2 it: 7.66e-02 tt: 1.48e+00\r\n", + "\u001B[32m[2020-06-24 17:41:43] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i28] iter: 28 cost: -447.195 time_iter: wall: 0.076984s cpu: 0.15148s time_optim: wall: 1.47847s cpu: 2.8624s\u001B[0m\r\n", + "callbacks.cc:105 29: f:-4.472208e+02 d: 2.61e-02 g: 2.36e+00 h: 1.22e-02 s: 2.82e-01 e: 2 it: 7.30e-02 tt: 1.55e+00\r\n", + "\u001B[32m[2020-06-24 17:41:43] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i29] iter: 29 cost: -447.221 time_iter: wall: 0.0734252s cpu: 0.146759s time_optim: wall: 1.55189s cpu: 3.00916s\u001B[0m\r\n", + "callbacks.cc:105 30: f:-4.472269e+02 d: 6.11e-03 g: 2.56e+00 h: 3.82e-02 s: 1.00e+00 e: 1 it: 3.69e-02 tt: 1.59e+00\r\n", + "\u001B[32m[2020-06-24 17:41:43] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i30] iter: 30 cost: -447.227 time_iter: wall: 0.037355s cpu: 0.0741047s time_optim: wall: 1.58925s cpu: 3.08326s\u001B[0m\r\n", + "callbacks.cc:105 31: f:-4.472342e+02 d: 7.31e-03 g: 1.12e+00 h: 1.67e-02 s: 7.05e-01 e: 1 it: 3.68e-02 tt: 1.63e+00\r\n", + "\u001B[32m[2020-06-24 17:41:43] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i31] iter: 31 cost: -447.234 time_iter: wall: 0.0372581s cpu: 0.0736081s time_optim: wall: 1.62651s cpu: 3.15687s\u001B[0m\r\n", + "callbacks.cc:105 32: f:-4.472355e+02 d: 1.29e-03 g: 1.60e-01 h: 6.13e-03 s: 1.00e+00 e: 1 it: 3.84e-02 tt: 1.67e+00\r\n", + "\u001B[32m[2020-06-24 17:41:43] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i32] iter: 32 cost: -447.235 time_iter: wall: 0.0388177s cpu: 0.0753357s time_optim: wall: 1.66532s cpu: 3.23221s\u001B[0m\r\n", + "callbacks.cc:105 33: f:-4.472360e+02 d: 4.63e-04 g: 1.61e-01 h: 1.32e-02 s: 1.00e+00 e: 1 it: 3.70e-02 tt: 1.70e+00\r\n", + "\u001B[32m[2020-06-24 17:41:43] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i33] iter: 33 cost: -447.236 time_iter: wall: 0.0374512s cpu: 0.0755949s time_optim: wall: 1.70277s cpu: 3.3078s\u001B[0m\r\n", + "callbacks.cc:105 34: f:-4.472361e+02 d: 1.07e-04 g: 1.54e-02 h: 6.50e-03 s: 1.00e+00 e: 1 it: 3.63e-02 tt: 1.74e+00\r\n", + "\u001B[32m[2020-06-24 17:41:43] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i34] iter: 34 cost: -447.236 time_iter: wall: 0.036703s cpu: 0.0725629s time_optim: wall: 1.73948s cpu: 3.38036s\u001B[0m\r\n", + "callbacks.cc:105 35: f:-4.472361e+02 d: 1.71e-06 g: 4.67e-03 h: 8.97e-04 s: 1.00e+00 e: 1 it: 3.81e-02 tt: 1.78e+00\r\n", + "\u001B[32m[2020-06-24 17:41:43] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i35] iter: 35 cost: -447.236 time_iter: wall: 0.0385312s cpu: 0.076953s time_optim: wall: 1.77801s cpu: 3.45732s\u001B[0m\r\n", + "line_search.cc:758 Line search failed: Wolfe zoom bracket width: 4.68275e-06 too small with descent_direction_max_norm: 8.19905e-05.\r\n", + "line_search_minimizer.cc:413 Terminating: Parameter tolerance reached. Relative step_norm: 0.000000e+00 <= 1.000000e-08.\r\n", + "\u001B[32m[2020-06-24 17:41:43] [INF] [0:139880252290816/dweindl-ThinkPad-L480] [o0i36] Optimizer status 0, final llh: -4.472361e+02, time: wall: 1.970559 cpu: 3.852414.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:44] [INF] [0:139880673687488/dweindl-ThinkPad-L480] Walltime on master: 3.286791s, CPU time of all processes: 13.255544s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:41:44] [INF] [0:139880673687488/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001B[0m\r\n" ] } ], @@ -821,25 +999,23 @@ "\n", "# Change optimizer to CERES\n", "# NOTE: For this moment, optimizers are inconveniently selected based on numeric values, 0 is Ipopt, 1 is Ceres.\n", - "!{optimizationOptionsPy} {example_data_ceres} -s optimizer 1\n", + "!{optimization_options_py} {example_data_ceres} -s optimizer 1\n", "\n", "# Run optimization\n", - "!PARPE_NO_DEBUG=1 mpiexec -n 4 {example_binary_dir}/example_steadystate_multi -o deletemeceres/ {example_data_ceres} --mpi" + "!PARPE_NO_DEBUG=1 {mpiexec} {example_binary_dir}/example_steadystate_multi -o deletemeceres/ {example_data_ceres} --mpi" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 42, "metadata": { "scrolled": true }, "outputs": [ { "data": { - "image/png": "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dBYsWEBHR3QH24ULF3L00UczY8YMrrrqqs7PVFZW8rnPfY6jjjqK0047jfr6eu6//34WL17MhRdeyKxZs9i9e3faYsz7tacyobEzabRmORIRSadv/M9LrHxze1rrPHLCcL72d0clvf+iRYtYuXIlkydP5owzzuCBBx7gXe96F1dddRVLlixh1KhRnH766fzqV7/inHPOYefOncyZM4ebbrqJa6+9lm984xvcfPPN3HzzzXz3u99lzpw5af151NLoh0SyqFf3lIik2QknnMAhhxxCYWEh8+fP55lnnuG5555j7ty51NTUUFRUxIUXXshTTz0FQEFBAeeffz4AH//4x3nmmWcyGp9aGv2Q6JZqammjeU87ZcWFWY5IRNIhlRZBpnSdBpvqtNhMTx9WS6MfGmNjGWptiEg6LVq0iNdff52Ojg7uvfdeTj75ZE444QT+9Kc/0dDQQHt7OwsXLuS9730vAB0dHdx///0A3H333Zx88skAVFVVsWPHjrTHp6TRD/WxsYx6DYaLSBodf/zxXHHFFRxxxBFMnTqVc889l/Hjx3P99dfzvve9j2OOOYbjjjuOefPmAVBRUcGiRYuYMWMGjz/+OF/96lcBuOSSS1iwYIEGwnNBQ1MLBQYdDg1qaYjIADU1NXW+Hj58OL/5zW/222f+/PnMn9/dFQxw44037ld23nnncd5556UvyEAtjX5oaGphSnVFeK0ZVCJy4FDS6IfGplYOP6gK0JiGiKTP3Llzu21l9CbeShkMShr90NDUwvgRwxgxrFgX+InIAUVJI0W7WtvY1drOmMoSaqpKlTRE5ICipJGixjCGUV1ZSnVlibqnROSAoqSRosQU25rKUqor1dIQkQOLkkaKElNs93ZPafaUiAzMW2+9xQUXXMChhx7Kcccdx1lnncWqVauyHVa3lDRS1Lgz3j1VSlNLG7tb27MclYgMVe7Oueeey9y5c1m7di1LlizhW9/6Fps2bUrqs4lVcAeLkkaK9mlpVJZGZeqiEpF+euKJJyguLmbBggWdZccccwzvec97+M53vsPxxx/PzJkz+drXvgbAunXrmD59OhdddBEzZsxg/fr1PPLII5x00knMnj2bj370o53TcK+++mqOPPJIZs6cyRe/+MW0xKsrwlPU0NTC8LIiSosKqamKkkZ9UwsHjy7PcmQiMmC/uxreejG9dR50NJx5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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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zjvvcPrpp/O+972PAw88kOOPP55XXul/Dwfr7qlumLu4kfJMivfVVxW0f+3WNg0lDRHpmLtzyimncM4553DnnXcC8MILL7B06VLe//73d3msu5NK9U0ZQCWNbpizZA177VpLpsDbZ7eVNFQ9JSIde+KJJ8hms1x44YVb102cOJHDDz+ca665hsmTJ7PvvvtyxRXRs9BvvPEGe+65J2effTYTJkxg0aJF7e63bt06TjjhBCZOnMiECRO46667eh2rShoFcnfmLmnkpIkjCj6mWtVTIsny+0vhnZfiPecu+8BxV3e6y5w5czjwwAN3WP/www+zYMECZs6cibtz0kkn8dRTTzFmzBgWLFjAbbfdxpQpUzrcb/ny5YwYMYLf/e53AKxZ0/vet5U0CrTo3Q2s3djMhJGFtWcAZNMpKrNpGjeopCEi3ffwww/z8MMPs//++wPRg3wLFixgzJgxjB07lilTpnS63+GHH85XvvIVLrnkEk488UQOP/zwXsekpFGgbY3ghd05laOuREQSpIsSQbHsvffeW3uqzefuXHbZZVxwwQXbrX/jjTeoqqrqcj+A5557joceeohvfvObHHXUUVs7NOwptWkUaO6SNWRSxvt3runWcbWVWdZuUklDRDp25JFHsmnTJm688cat61588UVqa2u55ZZbtnYVsnjxYpYtW7bD8cccc0y7+y1ZsoRBgwZx1lln8bWvfY3nnnuu17GqpFGgOYsb2WPnGiqy6W4dp5KGiHTFzLj33nv54he/yPe+9z0qKioYN24c1113HXV1dRxyyCFANB74r3/9a9Lp7b+Hjj76aObPn7/DfgsXLuRrX/saqVSKbDbLDTfc0PtYSzSOUZ+YNGmSz5o1q9fncXcmX/UoU/fcie9/emK3jj37lpms2bCF+y86tNdxiEj85s+fz1577VXqMEqmvfdvZrPdvd3BxVU9VYBlazexomkzE7rZngG5koaqp0RkYFDSKMDW7tC7cedUTq2qp0RkAFHSKMDcJY2YwV679qSkkdUttyL93ECupu9MT963kkYB5ixew/jhVVSXd/++gZryDJuaW9nc3FqEyESktyoqKli5cuV7LnG4OytXrqSioqJbx+nuqQLMXdLIAWOH9OjY/K5EhlWXxxmWiMRg1KhRNDQ0sHz58lKH0ucqKioYNWpUt45R0ujCqnWbWbx6A2cfMrZH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\n" }, "metadata": { "needs_background": "light" @@ -860,7 +1036,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 43, "metadata": {}, "outputs": [ { @@ -868,18 +1044,18 @@ "output_type": "stream", "text": [ "# __Exp____ __Act______ __Err______ __RelErr___ __ID_______\n", - "0: 1.00000 1.79204 0.79204 0.79204 p1\n", - "1: 0.50000 0.59116 0.09116 0.18231 p2\n", - "2: 0.40000 0.70481 0.30481 0.76204 p3\n", - "3: 2.00000 2.10835 0.10835 0.05417 p4\n", - "4: 0.10000 0.11230 0.01230 0.12300 p5\n", - "5: 2.00000 0.02749 -1.97251 -0.98626 scaling_x1_common\n", - "6: 3.00000 3.02899 0.02899 0.00966 offset_x2_batch-0\n", - "7: 0.20000 0.18342 -0.01658 -0.08292 x1withsigma_sigma\n", - "8: 4.00000 4.01287 0.01287 0.00322 offset_x2_batch-1\n", + "0: 1.00000 0.30548 -0.69452 -0.69452 p1\n", + "1: 0.50000 0.30052 -0.19948 -0.39895 p2\n", + "2: 0.40000 0.16337 -0.23663 -0.59158 p3\n", + "3: 2.00000 1.81043 -0.18957 -0.09478 p4\n", + "4: 0.10000 0.04597 -0.05403 -0.54034 p5\n", + "5: 2.00000 0.16233 -1.83767 -0.91883 scaling_x1_common\n", + "6: 3.00000 2.99965 -0.00035 -0.00012 offset_x2_batch_0\n", + "7: 0.20000 0.13703 -0.06297 -0.31484 x1withsigma_sigma\n", + "8: 4.00000 4.00120 0.00120 0.00030 offset_x2_batch_1\n", "\n", "Status: 0\n", - "Cost: -368.648089 (expected: -0.000000)\n" + "Cost: -447.236062 (expected: -0.000000)\n" ] } ], @@ -889,7 +1065,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 43, "metadata": {}, "outputs": [], "source": [] @@ -934,4 +1110,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/examples/parpeamici/steadystate/parpeExampleSteadystateHierarchical.ipynb b/examples/parpeamici/steadystate/parpeExampleSteadystateHierarchical.ipynb index f5da386e0..a6cee5a23 100644 --- a/examples/parpeamici/steadystate/parpeExampleSteadystateHierarchical.ipynb +++ b/examples/parpeamici/steadystate/parpeExampleSteadystateHierarchical.ipynb @@ -34,12 +34,15 @@ "\n", "# set paths\n", "parpe_source_root = os.path.abspath('../../../')\n", - "parpe_build_root = os.path.join(parpe_source_root, 'build') \n", + "parpe_build_root = os.path.join(parpe_source_root, 'build')\n", "\n", "model_source_dir = f'{parpe_build_root}/examples/parpeamici/steadystate/steadystate_scaled-prefix/src/steadystate_scaled/model_steadystate_scaled'\n", "example_binary_dir = f'{parpe_build_root}/examples/parpeamici/steadystate/'\n", "example_data_dir = f'{parpe_build_root}/examples/parpeamici/steadystate/steadystate_scaled-prefix/src/steadystate_scaled'\n", - "optimizationOptionsPy = f'{parpe_source_root}/misc/optimizationOptions.py'" + "optimization_options_py = f'{parpe_source_root}/misc/optimizationOptions.py'\n", + "\n", + "# MPI launcher and options\n", + "mpiexec = \"mpiexec -n 4 --allow-run-as-root --oversubscribe\"" ] }, { @@ -51,34 +54,53 @@ "name": "stdout", "output_type": "stream", "text": [ - "[ 9%] Built target parpecommon\n", - "[ 13%] Built target parpeloadbalancer\n", - "[ 23%] Built target parpeoptimization\n", - "[ 35%] Built target parpeamici\n", - "[ 36%] Built target parpe\n", - "-- Found Git: /usr/bin/git (found version \"2.20.1\") \n", - "-- Building version parPE-v0.4.2-12-g8d230-dirty\n", - "[ 36%] Built target get_version\n", - "[ 42%] Built target unittests_common\n", - "[ 47%] Built target unittests_loadbalancer\n", - "[ 54%] Built target unittests_optimization\n", - "\u001b[34m\u001b[1mSetting up virtual environment...\u001b[0m\n", - "[ 54%] Built target setup_venv\n", - "[ 55%] \u001b[34m\u001b[1mCreating test data using hierarchicalOptimizationTest.py\u001b[0m\n", - "...\n", - "----------------------------------------------------------------------\n", - "Ran 3 tests in 0.000s\n", - "\n", - "OK\n", - "[ 55%] Built target prepare_test_hierarchical_optimization\n", - "[ 63%] Built target unittests_amici\n", - "[ 65%] Built target example_loadbalancer\n", - "[ 76%] Built target steadystate_scaled\n", - "[ 79%] Built target example_steadystate_multi_simulator\n", - "[ 85%] Built target example_steadystate_parallel\n", - "[ 89%] Built target example_steadystate_multi\n", - "[ 92%] Built target example_steadystate\n", - "[100%] Built target test_steadystate\n" + "-- Found Git: /usr/bin/git (found version \"2.25.1\") \r\n", + "-- Building version parPE-v0.4.3-41-g696ed\r\n", + "[ 0%] Built target get_version\r\n", + "[ 10%] Built target parpecommon\r\n", + "\u001B[35m\u001B[1mScanning dependencies of target parpeoptimization\u001B[0m\r\n", + "[ 11%] \u001B[32mBuilding CXX object src/parpeoptimization/CMakeFiles/parpeoptimization.dir/optimizationResultWriter.cpp.o\u001B[0m\r\n", + "[ 12%] \u001B[32m\u001B[1mLinking CXX static library libparpeoptimization-dbg.a\u001B[0m\r\n", + "[ 21%] Built target parpeoptimization\r\n", + "[ 25%] Built target parpeloadbalancer\r\n", + "\u001B[35m\u001B[1mScanning dependencies of target parpeamici\u001B[0m\r\n", + "[ 26%] \u001B[32mBuilding CXX object src/parpeamici/CMakeFiles/parpeamici.dir/optimizationApplication.cpp.o\u001B[0m\r\n", + "[ 27%] \u001B[32m\u001B[1mLinking CXX static library libparpeamici-dbg.a\u001B[0m\r\n", + "[ 37%] Built target parpeamici\r\n", + "[ 39%] Built target parpe\r\n", + "[ 45%] Built target unittests_common\r\n", + "[ 50%] Built target unittests_loadbalancer\r\n", + "[ 51%] \u001B[32m\u001B[1mLinking CXX executable unittests_optimization\u001B[0m\r\n", + "[ 58%] Built target unittests_optimization\r\n", + "\u001B[34m\u001B[1mSetting up virtual environment...\u001B[0m\r\n", + "[ 58%] Built target setup_venv\r\n", + "[ 59%] \u001B[34m\u001B[1mCreating test data using hierarchicalOptimizationTest.py\u001B[0m\r\n", + "...\r\n", + "----------------------------------------------------------------------\r\n", + "Ran 3 tests in 0.000s\r\n", + "\r\n", + "OK\r\n", + "[ 59%] Built target prepare_test_hierarchical_optimization\r\n", + "[ 60%] \u001B[32m\u001B[1mLinking CXX executable unittests_amici\u001B[0m\r\n", + "[ 67%] Built target unittests_amici\r\n", + "[ 69%] Built target example_loadbalancer\r\n", + "[ 70%] \u001B[34m\u001B[1mPerforming build step for 'steadystate_scaled'\u001B[0m\r\n", + "[ 90%] Built target model_steadystate_scaled\r\n", + "[ 94%] Built target simulate_model_steadystate_scaled\r\n", + "[ 96%] Built target model_steadystate_scaled_swig_compilation\r\n", + "[100%] Built target _model_steadystate_scaled\r\n", + "[ 72%] \u001B[34m\u001B[1mNo install step for 'steadystate_scaled'\u001B[0m\r\n", + "[ 73%] \u001B[34m\u001B[1mNo test step for 'steadystate_scaled'\u001B[0m\r\n", + "[ 74%] \u001B[34m\u001B[1mCompleted 'steadystate_scaled'\u001B[0m\r\n", + "[ 81%] Built target steadystate_scaled\r\n", + "[ 82%] \u001B[32m\u001B[1mLinking CXX executable example_steadystate\u001B[0m\r\n", + "[ 84%] Built target example_steadystate\r\n", + "[ 86%] \u001B[32m\u001B[1mLinking CXX executable example_steadystate_multi\u001B[0m\r\n", + "[ 88%] Built target example_steadystate_multi\r\n", + "[ 89%] \u001B[32m\u001B[1mLinking CXX executable example_steadystate_multi_simulator\u001B[0m\r\n", + "[ 92%] Built target example_steadystate_multi_simulator\r\n", + "[ 93%] \u001B[32m\u001B[1mLinking CXX executable test_steadystate\u001B[0m\r\n", + "[100%] Built target test_steadystate\r\n" ] } ], @@ -152,18 +174,18 @@ "hdf5_input_file_hierarchical = f'{example_data_dir}/example_data.h5'\n", "hdf5_pe_output_file_hierarchical = 'deletemehierarchical/_rank00000.h5'\n", "\n", - "# Enabling hierarchical optimization in parPE is as easy as this: \n", - "!{optimizationOptionsPy} {hdf5_input_file_hierarchical} -s hierarchicalOptimization 1\n", + "# Enabling hierarchical optimization in parPE is as easy as this:\n", + "!{optimization_options_py} {hdf5_input_file_hierarchical} -s hierarchicalOptimization 1\n", "\n", "# Set some additional options, independently of hierarchical optimization\n", - "!{optimizationOptionsPy} {hdf5_input_file_hierarchical} -s numStarts 1\n", - "!{optimizationOptionsPy} {hdf5_input_file_hierarchical} -s ipopt/max_iter 20\n", - "!{optimizationOptionsPy} {hdf5_input_file_hierarchical} -s ipopt/acceptable_obj_change_tol 1e-5\n", - "!{optimizationOptionsPy} {hdf5_input_file_hierarchical} -s ipopt/acceptable_tol 1e-5\n", - "!{optimizationOptionsPy} {hdf5_input_file_hierarchical} -s retryOptimization 0\n", + "!{optimization_options_py} {hdf5_input_file_hierarchical} -s numStarts 1\n", + "!{optimization_options_py} {hdf5_input_file_hierarchical} -s ipopt/max_iter 20\n", + "!{optimization_options_py} {hdf5_input_file_hierarchical} -s ipopt/acceptable_obj_change_tol 1e-5\n", + "!{optimization_options_py} {hdf5_input_file_hierarchical} -s ipopt/acceptable_tol 1e-5\n", + "!{optimization_options_py} {hdf5_input_file_hierarchical} -s retryOptimization 0\n", "\n", "# Print current settings\n", - "!{optimizationOptionsPy} {hdf5_input_file_hierarchical}\n" + "!{optimization_options_py} {hdf5_input_file_hierarchical}\n" ] }, { @@ -175,35 +197,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "HierarchicalOptimizationWrapper parameters: 9 total, 5 numerical, 1 proportionality, 2 offset, 1 sigma\n", - "scalings [ -1.05079 ]\n", - "sigmas [ -0.533518 ]\n", - "scalings [ -1.05079 ]\n", - "sigmas [ -0.533517 ]\n", - "scalings [ -1.05079 ]\n", - "sigmas [ -0.533518 ]\n", - "\u001b[32m[2020-01-31 18:32:52] [INF] [-1/] 0 g: 76.2148 fd_c: 76.2271 Δ/ff: -1.339275e-05 f: 913.289\u001b[0m\n", - "scalings [ -1.05079 ]\n", - "sigmas [ -0.533517 ]\n", - "scalings [ -1.05079 ]\n", - "sigmas [ -0.533518 ]\n", - "\u001b[32m[2020-01-31 18:32:52] [INF] [-1/] 1 g: 189.565 fd_c: 189.552 Δ/ff: 1.442948e-05 f: 913.291\u001b[0m\n", - "scalings [ -1.05079 ]\n", - "sigmas [ -0.533518 ]\n", - "scalings [ -1.05079 ]\n", - "sigmas [ -0.533517 ]\n", - "\u001b[32m[2020-01-31 18:32:52] [INF] [-1/] 2 g: 32.3656 fd_c: 32.4028 Δ/ff: -4.072976e-05 f: 913.289\u001b[0m\n", - "scalings [ -1.05079 ]\n", - "sigmas [ -0.533518 ]\n", - "scalings [ -1.05079 ]\n", - "sigmas [ -0.533517 ]\n", - "\u001b[32m[2020-01-31 18:32:52] [INF] [-1/] 3 g: -192.293 fd_c: -192.282 Δ/ff: -1.195059e-05 f: 913.287\u001b[0m\n", - "scalings [ -1.05079 ]\n", - "sigmas [ -0.533518 ]\n", - "scalings [ -1.05079 ]\n", - "sigmas [ -0.533517 ]\n", - "\u001b[32m[2020-01-31 18:32:52] [INF] [-1/] 4 g: -21.5 fd_c: -21.5084 Δ/ff: 9.221704e-06 f: 913.288\u001b[0m\n", - "\u001b[32m[2020-01-31 18:32:52] [INF] [-1/] Walltime on master: 0.257105s, CPU time of all processes: 1.635054s\u001b[0m\n" + "\u001B[32m[2020-06-24 17:51:09] [INF] [-1:140661450438592/] 0 g: 3.70264e+06 fd_c: 3.71926e+06 Δ/ff: -1.316027e-05 f: 1.26298e+09\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:51:09] [INF] [-1:140661450438592/] 1 g: -6.39635e+06 fd_c: -6.37737e+06 Δ/ff: -1.502652e-05 f: 1.26298e+09\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:51:09] [INF] [-1:140661450438592/] 2 g: -646595 fd_c: -674557 Δ/ff: 2.213978e-05 f: 1.26298e+09\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:51:09] [INF] [-1:140661450438592/] 3 g: 5.96119e+06 fd_c: 5.96607e+06 Δ/ff: -3.868144e-06 f: 1.26298e+09\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:51:09] [INF] [-1:140661450438592/] 4 g: 5.80955e+09 fd_c: 5.80954e+09 Δ/ff: 1.416672e-05 f: 1.26303e+09\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:51:09] [INF] [-1:140661450438592/] Walltime on master: 0.245290s, CPU time of all processes: 1.148713s\u001B[0m\r\n" ] } ], @@ -221,273 +220,121 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32m[2020-01-31 18:32:52] [INF] [0/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001b[0m\n", - "HierarchicalOptimizationWrapper parameters: 9 total, 5 numerical, 1 proportionality, 2 offset, 1 sigma\n", - "HierarchicalOptimizationWrapper parameters: 9 total, 5 numerical, 1 proportionality, 2 offset, 1 sigma\n", - "HierarchicalOptimizationWrapper parameters: 9 total, 5 numerical, 1 proportionality, 2 offset, 1 sigma\n", - "HierarchicalOptimizationWrapper parameters: 9 total, 5 numerical, 1 proportionality, 2 offset, 1 sigma\n", - "\u001b[32m[2020-01-31 18:32:52] [INF] [0/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001b[0m\n", - "HierarchicalOptimizationWrapper parameters: 9 total, 5 numerical, 1 proportionality, 2 offset, 1 sigma\n", - "\n", - "List of user-set options:\n", - "\n", - " Name Value used\n", - " acceptable_iter = 1 yes\n", - " acceptable_obj_change_tol = 1e-05 yes\n", - " acceptable_tol = 1e-05 yes\n", - " hessian_approximation = limited-memory yes\n", - " limited_memory_update_type = bfgs yes\n", - " max_iter = 20 yes\n", - " print_level = 5 yes\n", - " print_user_options = yes yes\n", - " tol = 1e-09 yes\n", - " watchdog_shortened_iter_trigger = 0 yes\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.11.9, running with linear solver mumps.\n", - "NOTE: Other linear solvers might be more efficient (see Ipopt documentation).\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 0\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 0\n", - "\n", - "scalings [ -1.57319 ]\n", - "sigmas [ -0.719889 ]\n", - "Total number of variables............................: 5\n", - " variables with only lower bounds: 0\n", - " variables with lower and upper bounds: 5\n", - " variables with only upper bounds: 0\n", - "Total number of equality constraints.................: 0\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i0] iter: 0 cost: -345.868 time_iter: wall: 0.116922s cpu: 0.315805s time_optim: wall: 0.116922s cpu: 0.315805s\u001b[0m\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -3.4586844e+02 0.00e+00 1.00e+02 0.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - "scalings [ -1.5883 ]\n", - "sigmas [ -0.480002 ]\n", - "scalings [ -1.5883 ]\n", - "sigmas [ -0.480002 ]\n", - "scalings [ -1.42052 ]\n", - "sigmas [ -0.524592 ]\n", - "scalings [ -1.55546 ]\n", - "sigmas [ -0.632982 ]\n", - "scalings [ -1.54958 ]\n", - "sigmas [ -0.722681 ]\n", - "scalings [ -1.55964 ]\n", - "sigmas [ -0.741617 ]\n", - "scalings [ -1.56589 ]\n", - "sigmas [ -0.735837 ]\n", - "scalings [ -1.56589 ]\n", - "sigmas [ -0.735837 ]\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i1] iter: 1 cost: -367.073 time_iter: wall: 0.108479s cpu: 0.179909s time_optim: wall: 0.225401s cpu: 0.495713s\u001b[0m\n", - " 1 -3.6707266e+02 0.00e+00 4.56e+01 1.8 6.93e+01 - 5.64e-01 1.53e-03f 6\n", - "scalings [ -1.55691 ]\n", - "sigmas [ -0.735263 ]\n", - "scalings [ -1.55691 ]\n", - "sigmas [ -0.735263 ]\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i2] iter: 2 cost: -368.37 time_iter: wall: 0.0554871s cpu: 0.131405s time_optim: wall: 0.280888s cpu: 0.627118s\u001b[0m\n", - " 2 -3.6837034e+02 0.00e+00 4.79e+00 -0.5 2.70e-02 - 9.89e-01 1.00e+00f 1\n", - "scalings [ -1.55508 ]\n", - "sigmas [ -0.735589 ]\n", - "scalings [ -1.55508 ]\n", - "sigmas [ -0.735589 ]\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i3] iter: 3 cost: -368.442 time_iter: wall: 0.0590198s cpu: 0.135856s time_optim: wall: 0.339908s cpu: 0.762975s\u001b[0m\n", - " 3 -3.6844194e+02 0.00e+00 2.62e+00 -2.1 4.00e-03 - 9.99e-01 1.00e+00f 1\n", - "scalings [ -1.55409 ]\n", - "sigmas [ -0.735551 ]\n", - "scalings [ -1.55409 ]\n", - "sigmas [ -0.735551 ]\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i4] iter: 4 cost: -368.514 time_iter: wall: 0.0552678s cpu: 0.125665s time_optim: wall: 0.395176s cpu: 0.88864s\u001b[0m\n", - " 4 -3.6851412e+02 0.00e+00 1.56e+00 -3.9 7.71e-03 - 1.00e+00 1.00e+00f 1\n", - "scalings [ -1.55609 ]\n", - "sigmas [ -0.734996 ]\n", - "scalings [ -1.55609 ]\n", - "sigmas [ -0.734996 ]\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i5] iter: 5 cost: -368.55 time_iter: wall: 0.0557923s cpu: 0.128682s time_optim: wall: 0.450969s cpu: 1.01732s\u001b[0m\n", - " 5 -3.6855018e+02 0.00e+00 9.20e-01 -5.8 8.73e-03 - 1.00e+00 1.00e+00f 1\n", - "scalings [ -1.55638 ]\n", - "sigmas [ -0.734964 ]\n", - "scalings [ -1.55638 ]\n", - "sigmas [ -0.734964 ]\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i6] iter: 6 cost: -368.559 time_iter: wall: 0.0555617s cpu: 0.130171s time_optim: wall: 0.506531s cpu: 1.14749s\u001b[0m\n", - " 6 -3.6855861e+02 0.00e+00 4.56e-01 -7.7 4.77e-03 - 1.00e+00 1.00e+00f 1\n", - "scalings [ -1.55879 ]\n", - "sigmas [ -0.735251 ]\n", - "scalings [ -1.55879 ]\n", - "sigmas [ -0.735251 ]\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i7] iter: 7 cost: -368.6 time_iter: wall: 0.0544242s cpu: 0.126332s time_optim: wall: 0.560955s cpu: 1.27382s\u001b[0m\n", - " 7 -3.6859990e+02 0.00e+00 8.48e-01 -9.2 3.24e-02 - 1.00e+00 1.00e+00f 1\n", - "scalings [ -1.55632 ]\n", - "sigmas [ -0.737346 ]\n", - "scalings [ -1.55632 ]\n", - "sigmas [ -0.737346 ]\n", - "scalings [ -1.5574 ]\n", - "sigmas [ -0.736347 ]\n", - "scalings [ -1.5574 ]\n", - "sigmas [ -0.736347 ]\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i8] iter: 8 cost: -368.611 time_iter: wall: 0.0846797s cpu: 0.165328s time_optim: wall: 0.645635s cpu: 1.43915s\u001b[0m\n", - " 8 -3.6861134e+02 0.00e+00 3.50e+00 -10.8 7.48e-02 - 1.00e+00 5.00e-01f 2\n", - "scalings [ -1.57055 ]\n", - "sigmas [ -0.737185 ]\n", - "scalings [ -1.57055 ]\n", - "sigmas [ -0.737185 ]\n", - "scalings [ -1.56372 ]\n", - "sigmas [ -0.736818 ]\n", - "scalings [ -1.5605 ]\n", - "sigmas [ -0.736595 ]\n", - "scalings [ -1.5605 ]\n", - "sigmas [ -0.736595 ]\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i9] iter: 9 cost: -368.613 time_iter: wall: 0.0820734s cpu: 0.154928s time_optim: wall: 0.727709s cpu: 1.59408s\u001b[0m\n", - " 9 -3.6861276e+02 0.00e+00 3.09e+00 -11.0 9.30e-02 - 1.00e+00 2.50e-01f 3\n", - "scalings [ -1.56896 ]\n", - "sigmas [ -0.737546 ]\n", - "scalings [ -1.56896 ]\n", - "sigmas [ -0.737546 ]\n", - "scalings [ -1.56463 ]\n", - "sigmas [ -0.737127 ]\n", - "scalings [ -1.56254 ]\n", - "sigmas [ -0.736875 ]\n", - "scalings [ -1.56254 ]\n", - "sigmas [ -0.736875 ]\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i10] iter: 10 cost: -368.639 time_iter: wall: 0.0817445s cpu: 0.153025s time_optim: wall: 0.809454s cpu: 1.7471s\u001b[0m\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -3.6863917e+02 0.00e+00 1.08e+00 -11.0 7.11e-02 - 1.00e+00 2.50e-01f 3\n", - "scalings [ -1.56017 ]\n", - "sigmas [ -0.7364 ]\n", - "scalings [ -1.56017 ]\n", - "sigmas [ -0.7364 ]\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i11] iter: 11 cost: -368.645 time_iter: wall: 0.0585112s cpu: 0.134082s time_optim: wall: 0.867965s cpu: 1.88119s\u001b[0m\n", - " 11 -3.6864500e+02 0.00e+00 4.92e-01 -11.0 3.39e-02 - 1.00e+00 1.00e+00f 1\n", - "scalings [ -1.56046 ]\n", - "sigmas [ -0.736691 ]\n", - "scalings [ -1.56046 ]\n", - "sigmas [ -0.736691 ]\n", - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i12] iter: 12 cost: -368.648 time_iter: wall: 0.0598405s cpu: 0.138004s time_optim: wall: 0.927806s cpu: 2.01919s\u001b[0m\n", - " 12 -3.6864775e+02 0.00e+00 2.01e-01 -11.0 1.51e-02 - 1.00e+00 1.00e+00f 1\n", - "scalings [ -1.56231 ]\n", - "sigmas [ -0.736194 ]\n", - "scalings [ -1.56231 ]\n", - "sigmas [ -0.736194 ]\n", - "scalings [ -1.56137 ]\n", - "sigmas [ -0.736445 ]\n", - "scalings [ -1.56091 ]\n", - "sigmas [ -0.736569 ]\n", - "scalings [ -1.56068 ]\n", - "sigmas [ -0.73663 ]\n", - "scalings [ -1.56068 ]\n", - "sigmas [ -0.73663 ]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[32m[2020-01-31 18:32:53] [INF] [0/dweindl-ThinkPad-L480] [o0i13] iter: 13 cost: -368.648 time_iter: wall: 0.0895746s cpu: 0.166721s time_optim: wall: 1.01738s cpu: 2.18591s\u001b[0m\n", - " 13 -3.6864800e+02 0.00e+00 1.41e-01 -11.0 1.97e-02 - 1.00e+00 1.25e-01f 4\n", - "scalings [ -1.56077 ]\n", - "sigmas [ -0.7366 ]\n", - "scalings [ -1.56077 ]\n", - "sigmas [ -0.7366 ]\n", - "\u001b[32m[2020-01-31 18:32:54] [INF] [0/dweindl-ThinkPad-L480] [o0i14] iter: 14 cost: -368.648 time_iter: wall: 0.0591768s cpu: 0.136617s time_optim: wall: 1.07656s cpu: 2.32253s\u001b[0m\n", - " 14 -3.6864806e+02 0.00e+00 5.67e-02 -11.0 9.88e-04 - 1.00e+00 1.00e+00f 1\n", - "scalings [ -1.56067 ]\n", - "sigmas [ -0.736581 ]\n", - "scalings [ -1.56067 ]\n", - "sigmas [ -0.736581 ]\n", - "\u001b[32m[2020-01-31 18:32:54] [INF] [0/dweindl-ThinkPad-L480] [o0i15] iter: 15 cost: -368.648 time_iter: wall: 0.0580674s cpu: 0.133037s time_optim: wall: 1.13463s cpu: 2.45557s\u001b[0m\n", - " 15 -3.6864807e+02 0.00e+00 6.47e-02 -11.0 1.17e-03 - 1.00e+00 1.00e+00f 1\n", - "scalings [ -1.56069 ]\n", - "sigmas [ -0.73657 ]\n", - "scalings [ -1.56068 ]\n", - "sigmas [ -0.736575 ]\n", - "scalings [ -1.56068 ]\n", - "sigmas [ -0.736575 ]\n", - "\u001b[32m[2020-01-31 18:32:54] [INF] [0/dweindl-ThinkPad-L480] [o0i16] iter: 16 cost: -368.648 time_iter: wall: 0.0678461s cpu: 0.139022s time_optim: wall: 1.20247s cpu: 2.59459s\u001b[0m\n", - " 16 -3.6864808e+02 0.00e+00 3.03e-02 -11.0 1.91e-03 - 1.00e+00 5.00e-01f 2\n", - "scalings [ -1.56129 ]\n", - "sigmas [ -0.73668 ]\n", - "scalings [ -1.56129 ]\n", - "sigmas [ -0.73668 ]\n", - "scalings [ -1.56099 ]\n", - "sigmas [ -0.736628 ]\n", - "scalings [ -1.56083 ]\n", - "sigmas [ -0.736602 ]\n", - "scalings [ -1.56076 ]\n", - "sigmas [ -0.736589 ]\n", - "scalings [ -1.56072 ]\n", - "sigmas [ -0.736582 ]\n", - "scalings [ -1.56072 ]\n", - "sigmas [ -0.736582 ]\n", - "\u001b[32m[2020-01-31 18:32:54] [INF] [0/dweindl-ThinkPad-L480] [o0i17] iter: 17 cost: -368.648 time_iter: wall: 0.0966338s cpu: 0.16571s time_optim: wall: 1.29911s cpu: 2.7603s\u001b[0m\n", - " 17 -3.6864808e+02 0.00e+00 1.94e-02 -11.0 8.54e-03 - 1.00e+00 6.25e-02f 5\n", - "scalings [ -1.56073 ]\n", - "sigmas [ -0.73659 ]\n", - "scalings [ -1.56073 ]\n", - "sigmas [ -0.73659 ]\n", - "\u001b[32m[2020-01-31 18:32:54] [INF] [0/dweindl-ThinkPad-L480] [o0i18] iter: 18 cost: -368.648 time_iter: wall: 0.0575679s cpu: 0.131601s time_optim: wall: 1.35667s cpu: 2.8919s\u001b[0m\n", - " 18 -3.6864809e+02 0.00e+00 1.63e-02 -11.0 9.02e-04 - 1.00e+00 1.00e+00f 1\n", - "scalings [ -1.56071 ]\n", - "sigmas [ -0.736589 ]\n", - "scalings [ -1.56071 ]\n", - "sigmas [ -0.736589 ]\n", - "\u001b[32m[2020-01-31 18:32:54] [INF] [0/dweindl-ThinkPad-L480] [o0i19] iter: 19 cost: -368.648 time_iter: wall: 0.0592092s cpu: 0.135657s time_optim: wall: 1.41588s cpu: 3.02755s\u001b[0m\n", - " 19 -3.6864809e+02 0.00e+00 8.06e-03 -11.0 3.45e-04 - 1.00e+00 1.00e+00f 1\n", - "scalings [ -1.56079 ]\n", - "sigmas [ -0.73646 ]\n", - "scalings [ -1.56079 ]\n", - "sigmas [ -0.73646 ]\n", - "scalings [ -1.56075 ]\n", - "sigmas [ -0.736524 ]\n", - "scalings [ -1.56073 ]\n", - "sigmas [ -0.736557 ]\n", - "scalings [ -1.56072 ]\n", - "sigmas [ -0.736573 ]\n", - "scalings [ -1.56071 ]\n", - "sigmas [ -0.736581 ]\n", - "scalings [ -1.56071 ]\n", - "sigmas [ -0.736581 ]\n", - "\u001b[32m[2020-01-31 18:32:54] [INF] [0/dweindl-ThinkPad-L480] [o0i20] iter: 20 cost: -368.648 time_iter: wall: 0.0949889s cpu: 0.166004s time_optim: wall: 1.51087s cpu: 3.19356s\u001b[0m\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -3.6864809e+02 0.00e+00 1.10e-02 -11.0 3.24e-03 - 1.00e+00 6.25e-02f 5\n", - "\n", - "Number of Iterations....: 20\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -1.9645576662469449e+02 -3.6864808727028083e+02\n", - "Dual infeasibility......: 1.0967312862023874e-02 2.0580097894523374e-02\n", - "Constraint violation....: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Complementarity.........: 1.0009336953405942e-11 1.8782461752654997e-11\n", - "Overall NLP error.......: 1.0967312862023874e-02 2.0580097894523374e-02\n", - "\n", - "\n", - "Number of objective function evaluations = 75\n", - "Number of objective gradient evaluations = 21\n", - "Number of equality constraint evaluations = 0\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 0\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 0\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.203\n", - "Total CPU secs in NLP function evaluations = 1.466\n", - "\n", - "EXIT: Maximum Number of Iterations Exceeded.\n", - "\u001b[32m[2020-01-31 18:32:54] [INF] [0/dweindl-ThinkPad-L480] [o0i21] Optimizer status 1, final llh: -3.686481e+02, time: wall: 1.511530 cpu: 3.193558.\u001b[0m\n", - "\u001b[32m[2020-01-31 18:32:55] [INF] [0/dweindl-ThinkPad-L480] Walltime on master: 3.331387s, CPU time of all processes: 13.501588s\u001b[0m\n", - "\u001b[32m[2020-01-31 18:32:55] [INF] [0/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001b[0m\n" + "\u001B[32m[2020-06-24 17:51:10] [INF] [0:139634931677120/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:51:10] [INF] [0:139634931677120/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001B[0m\r\n", + "\r\n", + "List of user-set options:\r\n", + "\r\n", + " Name Value used\r\n", + " acceptable_iter = 1 yes\r\n", + " acceptable_obj_change_tol = 1e-05 yes\r\n", + " acceptable_tol = 1e-05 yes\r\n", + " hessian_approximation = limited-memory yes\r\n", + " limited_memory_update_type = bfgs yes\r\n", + " max_iter = 20 yes\r\n", + " print_level = 5 yes\r\n", + " print_user_options = yes yes\r\n", + " tol = 1e-09 yes\r\n", + " watchdog_shortened_iter_trigger = 0 yes\r\n", + "\r\n", + "******************************************************************************\r\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\r\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\r\n", + " For more information visit http://projects.coin-or.org/Ipopt\r\n", + "******************************************************************************\r\n", + "\r\n", + "This is Ipopt version 3.12.12, running with linear solver ma27.\r\n", + "\r\n", + "Number of nonzeros in equality constraint Jacobian...: 0\r\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\r\n", + "Number of nonzeros in Lagrangian Hessian.............: 0\r\n", + "\r\n", + "Total number of variables............................: 5\r\n", + " variables with only lower bounds: 0\r\n", + " variables with lower and upper bounds: 5\r\n", + " variables with only upper bounds: 0\r\n", + "Total number of equality constraints.................: 0\r\n", + "Total number of inequality constraints...............: 0\r\n", + " inequality constraints with only lower bounds: 0\r\n", + " inequality constraints with lower and upper bounds: 0\r\n", + " inequality constraints with only upper bounds: 0\r\n", + "\r\n", + "\u001B[32m[2020-06-24 17:51:10] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i0] iter: 0 cost: -439.904 time_iter: wall: 0.0541594s cpu: 0.153553s time_optim: wall: 0.0541598s cpu: 0.153553s\u001B[0m\r\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\r\n", + " 0 -4.3990444e+02 0.00e+00 4.56e+01 0.0 0.00e+00 - 0.00e+00 0.00e+00 0\r\n", + "\u001B[32m[2020-06-24 17:51:10] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i1] iter: 1 cost: -440.11 time_iter: wall: 0.131574s cpu: 0.201234s time_optim: wall: 0.185734s cpu: 0.354787s\u001B[0m\r\n", + " 1 -4.4011049e+02 0.00e+00 4.40e+01 1.4 2.88e+01 - 4.36e-01 1.78e-03f 7\r\n", + "\u001B[32m[2020-06-24 17:51:10] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i2] iter: 2 cost: -441.25 time_iter: wall: 0.0601212s cpu: 0.144102s time_optim: wall: 0.245855s cpu: 0.498889s\u001B[0m\r\n", + " 2 -4.4125031e+02 0.00e+00 2.11e+01 -0.6 1.71e-02 - 9.97e-01 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:51:10] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i3] iter: 3 cost: -441.793 time_iter: wall: 0.0587328s cpu: 0.140642s time_optim: wall: 0.304588s cpu: 0.639531s\u001B[0m\r\n", + " 3 -4.4179296e+02 0.00e+00 1.46e+01 -2.2 2.25e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:51:10] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i4] iter: 4 cost: -442.644 time_iter: wall: 0.0593916s cpu: 0.140892s time_optim: wall: 0.36398s cpu: 0.780423s\u001B[0m\r\n", + " 4 -4.4264439e+02 0.00e+00 1.06e+01 -3.9 4.32e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:51:10] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i5] iter: 5 cost: -443.123 time_iter: wall: 0.0812911s cpu: 0.150629s time_optim: wall: 0.445271s cpu: 0.931052s\u001B[0m\r\n", + " 5 -4.4312253e+02 0.00e+00 3.58e+01 -5.4 1.63e-01 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:51:10] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i6] iter: 6 cost: -444.538 time_iter: wall: 0.0535397s cpu: 0.116163s time_optim: wall: 0.498811s cpu: 1.04721s\u001B[0m\r\n", + " 6 -4.4453768e+02 0.00e+00 5.15e+01 -6.6 4.71e-01 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:51:10] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i7] iter: 7 cost: -446.577 time_iter: wall: 0.0549543s cpu: 0.122927s time_optim: wall: 0.553766s cpu: 1.17014s\u001B[0m\r\n", + " 7 -4.4657694e+02 0.00e+00 3.04e+01 -7.2 1.12e-01 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i8] iter: 8 cost: -447.196 time_iter: wall: 0.0552537s cpu: 0.119712s time_optim: wall: 0.60902s cpu: 1.28985s\u001B[0m\r\n", + " 8 -4.4719614e+02 0.00e+00 2.47e+00 -8.8 3.40e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i9] iter: 9 cost: -447.227 time_iter: wall: 0.0555729s cpu: 0.120651s time_optim: wall: 0.664593s cpu: 1.4105s\u001B[0m\r\n", + " 9 -4.4722728e+02 0.00e+00 1.31e+00 -10.5 2.98e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i10] iter: 10 cost: -447.229 time_iter: wall: 0.0754439s cpu: 0.140183s time_optim: wall: 0.740037s cpu: 1.55069s\u001B[0m\r\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\r\n", + " 10 -4.4722879e+02 0.00e+00 1.45e+00 -11.0 2.70e-02 - 1.00e+00 2.50e-01f 3\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i11] iter: 11 cost: -447.232 time_iter: wall: 0.0666346s cpu: 0.12471s time_optim: wall: 0.806672s cpu: 1.6754s\u001B[0m\r\n", + " 11 -4.4723183e+02 0.00e+00 6.10e-01 -11.0 1.32e-02 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i12] iter: 12 cost: -447.232 time_iter: wall: 0.0628816s cpu: 0.122932s time_optim: wall: 0.869554s cpu: 1.79833s\u001B[0m\r\n", + " 12 -4.4723222e+02 0.00e+00 1.03e+00 -11.0 1.69e-02 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i13] iter: 13 cost: -447.235 time_iter: wall: 0.051293s cpu: 0.112279s time_optim: wall: 0.920847s cpu: 1.91061s\u001B[0m\r\n", + " 13 -4.4723457e+02 0.00e+00 5.17e-01 -11.0 1.56e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i14] iter: 14 cost: -447.235 time_iter: wall: 0.0832425s cpu: 0.141398s time_optim: wall: 1.00409s cpu: 2.05201s\u001B[0m\r\n", + " 14 -4.4723480e+02 0.00e+00 1.11e-01 -11.0 2.44e-02 - 1.00e+00 1.25e-01f 4\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i15] iter: 15 cost: -447.236 time_iter: wall: 0.0628442s cpu: 0.121933s time_optim: wall: 1.06693s cpu: 2.17394s\u001B[0m\r\n", + " 15 -4.4723572e+02 0.00e+00 4.75e-01 -11.0 6.24e-02 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i16] iter: 16 cost: -447.236 time_iter: wall: 0.0731104s cpu: 0.142942s time_optim: wall: 1.14004s cpu: 2.31688s\u001B[0m\r\n", + " 16 -4.4723594e+02 0.00e+00 3.20e-01 -11.0 2.53e-03 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i17] iter: 17 cost: -447.236 time_iter: wall: 0.0522144s cpu: 0.118318s time_optim: wall: 1.19226s cpu: 2.4352s\u001B[0m\r\n", + " 17 -4.4723597e+02 0.00e+00 2.59e-01 -11.0 7.42e-03 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i18] iter: 18 cost: -447.236 time_iter: wall: 0.0943844s cpu: 0.150501s time_optim: wall: 1.28664s cpu: 2.5857s\u001B[0m\r\n", + " 18 -4.4723601e+02 0.00e+00 1.58e-01 -11.0 6.68e-02 - 1.00e+00 3.12e-02f 6\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i19] iter: 19 cost: -447.236 time_iter: wall: 0.0741556s cpu: 0.137393s time_optim: wall: 1.3608s cpu: 2.72309s\u001B[0m\r\n", + " 19 -4.4723601e+02 0.00e+00 2.40e-01 -11.0 1.91e-02 - 1.00e+00 2.50e-01f 3\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i20] iter: 20 cost: -447.236 time_iter: wall: 0.0900518s cpu: 0.153743s time_optim: wall: 1.45085s cpu: 2.87684s\u001B[0m\r\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\r\n", + " 20 -4.4723605e+02 0.00e+00 4.28e-02 -11.0 3.79e-02 - 1.00e+00 6.25e-02f 5\r\n", + "\r\n", + "Number of Iterations....: 20\r\n", + "\r\n", + " (scaled) (unscaled)\r\n", + "Objective...............: -4.4723605258672342e+02 -4.4723605258672342e+02\r\n", + "Dual infeasibility......: 4.2768567429715201e-02 4.2768567429715201e-02\r\n", + "Constraint violation....: 0.0000000000000000e+00 0.0000000000000000e+00\r\n", + "Complementarity.........: 1.0056120563555069e-11 1.0056120563555069e-11\r\n", + "Overall NLP error.......: 4.2768567429715201e-02 4.2768567429715201e-02\r\n", + "\r\n", + "\r\n", + "Number of objective function evaluations = 92\r\n", + "Number of objective gradient evaluations = 21\r\n", + "Number of equality constraint evaluations = 0\r\n", + "Number of inequality constraint evaluations = 0\r\n", + "Number of equality constraint Jacobian evaluations = 0\r\n", + "Number of inequality constraint Jacobian evaluations = 0\r\n", + "Number of Lagrangian Hessian evaluations = 0\r\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.213\r\n", + "Total CPU secs in NLP function evaluations = 1.429\r\n", + "\r\n", + "EXIT: Maximum Number of Iterations Exceeded.\r\n", + "\u001B[32m[2020-06-24 17:51:11] [INF] [0:139634512226048/dweindl-ThinkPad-L480] [o0i21] Optimizer status 1, final llh: -4.472361e+02, time: wall: 1.451638 cpu: 2.876838.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:51:13] [INF] [0:139634931677120/dweindl-ThinkPad-L480] Walltime on master: 3.306761s, CPU time of all processes: 13.315272s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:51:13] [INF] [0:139634931677120/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001B[0m\r\n" ] } ], "source": [ "# Run the actual optimization (using MPI with 4 processes, 1 master, 3 workers)\n", - "!PARPE_NO_DEBUG=1 mpiexec -n 4 {example_binary_dir}/example_steadystate_multi -o deletemehierarchical/ {hdf5_input_file_hierarchical} --mpi\n" + "!PARPE_NO_DEBUG=1 {mpiexec} {example_binary_dir}/example_steadystate_multi -o deletemehierarchical/ {hdf5_input_file_hierarchical} --mpi\n" ] }, { @@ -504,29 +351,7 @@ "outputs": [ { "data": { - "text/plain": [ - "array([[-345.86843874],\n", - " [-367.07266293],\n", - " [-368.37034496],\n", - " [-368.44194152],\n", - " [-368.51411736],\n", - " [-368.55018441],\n", - " [-368.55860899],\n", - " [-368.59990271],\n", - " [-368.6113376 ],\n", - " [-368.61276244],\n", - " [-368.63917105],\n", - " [-368.64499917],\n", - " [-368.64774941],\n", - " [-368.64799836],\n", - " [-368.64806435],\n", - " [-368.64807476],\n", - " [-368.64808146],\n", - " [-368.64808151],\n", - " [-368.64808632],\n", - " [-368.64808724],\n", - " [-368.64808727]])" - ] + "text/plain": "array([[-439.90444215],\n [-440.11048578],\n [-441.25031421],\n [-441.7929597 ],\n [-442.64439443],\n [-443.12253462],\n [-444.5376804 ],\n [-446.57693735],\n [-447.1961445 ],\n [-447.22727595],\n [-447.22878988],\n [-447.23182573],\n [-447.23222174],\n [-447.23457001],\n [-447.23480433],\n [-447.23572432],\n [-447.23593991],\n [-447.23597489],\n [-447.23600574],\n [-447.23600689],\n [-447.23605259]])" }, "execution_count": 7, "metadata": {}, @@ -534,10 +359,8 @@ }, { "data": { - "image/png": "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deRYvs5Jw6zRbNq0iUWLFrFhw4Z6h1J3Y8eOZbfddqO9vb3icZw0yih05Hhm5fp6h2FmVbZo0SLGjx/PtGnTyNr8bE4RwbJly1i0aBF77LFHxeO5eqqMQr6d5a6eMms4GzZsYOLEiU2dMCC74GfixInDPuJy0iijkM+xesMmuntGo/VsMxtNzZ4wirZmPThplFHItxMBq9b7CiozsyInjTIKHTkAVvhkuJmNgm9+85usW7du2ONdfvnlLF488MMOly9fzlvf+lb22msv3vrWt7JixYqRhumkUU5XX9LwkYaZ1d7WJI2enp5Bk8Z5553HrFmzeOyxx5g1axbnnXfeiON00iijkM+Shk+Gm1k1rV27lne+850ccMAB7Lffflx99dV8+9vfZvHixRxxxBEcccQRAHzqU59ixowZTJ8+nbPPPrtv/GnTpnH66adz8MEHc+WVVzJv3jxOOOEEDjzwQNav3/KKzxtuuIETTzwRgBNPPJHrr7+ekfIlt2X0VU85aZg1rP/7s4f4w+LVVZ3ma6fsyNnvnl62/Oabb2bKlCn8/Oc/B2DVqlVMmDCBr3/969x2221MmjQJgHPPPZeuri56enqYNWsWCxYsYP/99wdg4sSJ3H///QBcdtllXHDBBcyYMeNl81qyZAm77LILAK94xStYsmTJiJfPRxpldOVdPWVm1fe6172OX/7yl5x++unceeedTJgwYcDhrrnmGg4++GAOOuggHnroIf7whz/0lR133HHDnq+kqlw15iONMsblWhnT1uIT4WYNbLAjglrZe++9uf/++5k7dy5f/OIXmTVrFmedddYWw/z5z3/mggsu4N5776VQKHDSSSdtcT9FR0dHRfPaeeedefbZZ9lll1149tln2WmnnUYcv480BtHV4fanzKy6Fi9eTD6f58Mf/jCnnXZaXzXT+PHjWbNmDQCrV6+mo6ODCRMmsGTJEm666aay0ysdr79jjjmGK664AoArrriC2bNnjzh+H2kMojOf85GGmVXVAw88wGmnnUZLSwvt7e1ccsklAJx88skcddRRTJkyhdtuu42DDjqIfffdl6lTp/LmN7+57PROOukkTjnlFMaNG8fvfvc7xo0b11d2xhlncOyxx/K9732P3XffnWuuuWbE8Tf8M8JnzJgRw30IU9EJl93F+o09XPvp8l+YmW1fHn74YV7zmtfUO4xtxkDrQ9J9EfHyM+u4empQhXyOlT4RbmbWx0ljEIW8m0c3MyvlpDGIQkeOVes30dPb2FV4Zs2m0avlK7U168FJYxBdbrTQrOGMHTuWZcuWNX3iKD5PY+zYscMaz1dPDaJ4V/jytRv72qIys+3bbrvtxqJFi1i6dGm9Q6m74pP7hsNJYxCFvFu6NWs07e3tw3pSnW3J1VOD6HL7U2ZmW3DSGERnPnvYuo80zMwyThqD8DM1zMy25KQxiHHtreTaWlw9ZWaWOGkMQhJd+ZwfxGRmljhpDKHQkXP1lJlZ4qQxhEK+3SfCzcwSJ40hFPxMDTOzPk4aQ+jyMzXMzPo4aQyhkG9npRstNDMDnDSGVOjIudFCM7PESWMIbn/KzGwzJ40hFNz+lJlZn7okDUlflrRA0nxJt0iakvofLmlV6j9f0lkl4xwl6VFJj0s6Y7Ri7cq7KREzs6J6HWmcHxH7R8SBwI3AWSVld0bEgen1JQBJrcBFwNHAa4EPSnrtaATa12ihjzTMzOqTNCJidcnHDmCoS5MOAR6PiCciYiNwFTC7VvGVKjZa6GeFm5nV8ZyGpHMlLQROYMsjjUMl/V7STZKmp367AgtLhlmU+pWb9smS5kmaN9Knc+VzqdFCJw0zs9olDUm3SnpwgNdsgIg4MyKmAnOAU9No9wO7R8QBwHeA67dm3hFxaUTMiIgZkydPHulyZE2JuHrKzKx2j3uNiCMrHHQOMBc4u7TaKiLmSrpY0iTgGWBqyTi7pX6jopDPsXytT4SbmdXr6qm9Sj7OBh5J/V8hSan7ELL4lgH3AntJ2kNSDjge+OloxdvVkWOlq6fMzGp3pDGE8yTtA/QCTwGnpP7vBz4lqRtYDxwfEQF0SzoV+AXQCnw/Ih4arWAL+RwPP7d66AHNzBpcXZJGRLyvTP8LgQvLlM0lq8YadYWOdlb6Pg0zM98RXolCPquecqOFZtbsnDQqUMjn6A1Y7UYLzazJOWlUoHiDn+/VMLNm56RRgb6mRJw0zKzJOWlUoK8pEd+rYWZNzkmjAn6mhplZxkmjAn6mhplZxkmjAh25VnKtLW7p1syanpNGBSTRmW9npc9pmFmTc9KoUFdHzkcaZtb0nDQqVLwr3MysmTlpVKjQ0c5ynwg3sybnpFGhQj7HCjdaaGZNzkmjQsVnavS60UIza2JOGhXqLDZauMFHG2bWvJw0KtTVkbU/5fMaZtbMnDQq1NnXlIiPNMyseTlpVKgr76ZEzMycNCrkZ2qYmTlpVMzP1DAzc9Ko2A5j2mhvlZ+pYWZNzUmjQpLclIiZNT0njWEo5HO+5NbMmpqTxjAUOtp9TsPMmpqTxjB0dbj9KTNrbk4aw9CZz/k+DTNrak4aw9CVz7HCjRaaWRNz0hiGznw7vQFrNnTXOxQzs7pw0hiG4l3hfuyrmTUrJ41hKLgpETNrck4aw1Bwo4Vm1uScNIah2NKtb/Azs2blpDEMhfQgppW+V8PMmpSTxjDsMKaNthb5RLiZNS0njWGQRKHDN/iZWfNy0himQt7tT5lZ83LSGKZCPscKP1PDzJqUk8YwZY0W+kjDzJpTXZKGpC9LWiBpvqRbJE1J/Q+XtCr1ny/prJJxnpT0QOo/rx5xQ2q00EnDzJpUW53me35E/BOApL8DzgJOSWV3RsS7yox3RES8MBoBltPV0c6KdZuICCTVMxQzs1FXlyONiFhd8rED2G6ajS3kc/T0BqvdaKGZNaG6ndOQdK6khcAJZEcaRYdK+r2kmyRNL+kfwC2S7pN08hDTPlnSPEnzli5dWtW43ZSImTWzmiUNSbdKenCA12yAiDgzIqYCc4BT02j3A7tHxAHAd4DrSyY5MyIOBo4G/kbSW8rNOyIujYgZETFj8uTJVV0ut3RrZs2sZuc0IuLICgedA8wFzi6ttoqIuZIuljQpIl6IiGdS/+clXQccAtxR9cCH0JkvNiXipGFmzadeV0/tVfJxNvBI6v8KpbPLkg4hi2+ZpA5J41P/DuBtwIOjG3Wm70jD92qYWROq19VT50naB+gFnmLzlVPvBz4lqRtYDxwfESFpZ+C6lE/agB9FxM11iHvzMzV8TsPMmlBdkkZEvK9M/wuBCwfo/wRwQK3jqsT41Gih79Uws2bkO8KHSZJv8DOzpuWksRW6Otrd/pSZNSUnja3Qmc/5klsza0pOGluhK+9naphZc3LS2AqFjhwr/MhXM2tCThpbofggpojtpsksM7OqcNLYCl0dbrTQzJpTRUlD0n9W0q9ZdKZGC92UiJk1m0qPNEpbm0VSK/D66oezfejqyNqfWu6T4WbWZAZNGpK+IGkNsL+k1em1BngeuGFUItwG9TWP7iMNM2sygyaNiPhqRIwne9Lejuk1PiImRsQXRinGbc7mZ2r4Ciozay6VVk/dmFqXRdKHJX1d0u41jGub1tdooY80zKzJVJo0LgHWSToA+CzwJ+AHNYtqG7fj2DZa3WihmTWhSpNGd2Q3JcwGLoyIi4DxtQtr2yaJQr7dz9Qws6ZTadPoayR9Afhr4DBJLUB77cLa9hXclIiZNaFKjzSOA14CPhYRzwG7AefXLKrtQMHNo5tZE6ooaaREMQeYIOldwIaIaNpzGgCFjnYnDTNrOpXeEX4scA/wAeBY4G5J769lYNu6ro6cz2mYWdOp9JzGmcAbIuJ5AEmTgVuBH9cqsG1dZz7HytRoYXp2uZlZw6v0nEZLMWEky4YxbkPqyufo7g3WvORGC82seVR6pHGzpF8AV6bPxwFzaxPS9qF4g9/KtZvYcWxTX0hmZk1k0KQh6dXAzhFxmqT3AjNT0e/ITow3rUI+NVq4biOvnJivczRmZqNjqCONbwJfAIiIa4FrASS9LpW9u6bRbcP6mhLxvRpm1kSGOi+xc0Q80L9n6jetJhFtJ7rc0q2ZNaGhkkbnIGXjqhnI9qbY0q2fqWFmzWSopDFP0v/u31PSJ4D7ahPS9mG8Gy00syY01DmNzwDXSTqBzUliBpAD/qqWgW3rWlpE57h2VqzzDX5m1jwGTRoRsQR4k6QjgP1S759HxK9qHtl2oNDhRgvNrLlUdJ9GRNwG3FbjWLY7Xfmcz2mYWVNp6ru6R6oz385KV0+ZWRNx0hiBro4cy30i3MyaiJPGCBQ6NjdaaGbWDJw0RqCQb2dTT/CiGy00sybhpDECxRv8Vvi5GmbWJJw0RqDgpkTMrMk4aYxAsdFCnww3s2bhpDECXW7p1syajJPGCBSfqeGmRMysWdQlaUj6sqQFkuZLukXSlJKyw1P/hyT9uqT/UZIelfS4pDPqEXd/O45tp0U+0jCz5lGvI43zI2L/iDgQuBE4C0BSJ3AxcExETAc+kPq3AhcBRwOvBT4o6bV1ibxES4so5HM+EW5mTaMuSSMiVpd87ACKd8d9CLg2Ip5Owz2f+h8CPB4RT0TERuAqYPZoxTuYzny7k4aZNY26ndOQdK6khcAJpCMNYG+gIOl2SfdJ+kjqvyuwsGT0RalfuWmfLGmepHlLly6tRfh9ujrcaKGZNY+aJQ1Jt0p6cIDXbICIODMipgJzgFPTaG3A64F3Am8H/knS3sOdd0RcGhEzImLG5MmTq7REA+vM59xooZk1jYqaRt8aEXFkhYPOAeYCZ5MdQSyLiLXAWkl3AAek/lNLxtkNeKaK4W61rnyO3y9cWe8wzMxGRb2untqr5ONs4JHUfQMwU1KbpDzwRuBh4F5gL0l7SMoBxwM/Hc2Yyyl0ZCfC3WihmTWDmh1pDOE8SfsAvcBTwCkAEfGwpJuBBanssoh4EEDSqcAvgFbg+xHxUF0i76fYaOHajT3sMKZeq9PMbHTUZS8XEe8bpOx84PwB+s8lq8baphRK7gp30jCzRuc7wkeoKzVa6CuozKwZOGmMUKGj2JSIk4aZNT4njRFy8+hm1kycNEZoc0u3vlfDzBqfk8YI9TVa6CMNM2sCThoj1NIiOvNuSsTMmoOTRhV05tvdlIiZNQUnjSro8pGGmTUJJ40qKDYlYmbW6Jw0qqDgZ2qYWZNw0qiCQkeOFWs3udFCM2t4ThpV0JXPsbGnl3Ube+odiplZTTlpVEHB7U+ZWZNw0qiCvpZufV7DzBqck0YVFPLFRgt9r4aZNTYnjSoofaaGmVkjc9KoAj9Tw8yahZNGFew4rh0JVvqchpk1OCeNKmhtEZ3j2lnupGFmDc5Jo0qKN/iZmTUyJ40qKeTd/pSZNT4njSopuKVbM2sCThpVUvAzNcysCThpVElXR47l6za60UIza2hOGlVS6MixsduNFppZY3PSqJLNTYn4vIaZNS4njSoptnTry27NrJE5aVRJV2p/yjf4mVkjc9Koks50pOGmRMyskTlpVEnfkYbv1TCzBuakUSUTUqOFbh7dzBqZk0aVtLaICePa/SAmM2toThpV1JXP+US4mTU0J40q6sy3+0S4mTU0J40q6urIsdz3aZhZA3PSqKJCPucT4WbW0Jw0qqjQkT1Tw40WmlmjqkvSkPRlSQskzZd0i6QpJWWHp/4PSfp1Sf8nJT2QyubVI+6hFPI5XuruZf0mN1poZo2pXkca50fE/hFxIHAjcBaApE7gYuCYiJgOfKDfeEdExIERMWN0w61MV0fWaKFv8DOzRlWXpBERq0s+dgDF+pwPAddGxNNpuOdHO7aR2NyUiE+Gm1ljqts5DUnnSloInEA60gD2BgqSbpd0n6SPlIwSwC2p/8mjHW8l3JSImTW6miUNSbdKenCA12yAiDgzIqYCc4BT02htwOuBdwJvB/5J0t6pbGZEHAwcDfyNpLcMMu+TJc2TNG/p0qW1WsSX8TM1zKzRtdVqwhFxZIWDzgHmAmcDi4BlEbEWWCvpDuAA4I8R8Uya7vOSrgMOAe4oM+9LgUsBZsyYMWqXMm1+poaThpk1pnpdPbVXycfZwCOp+wZgpqQ2SXngjcDDkjokjU/jdgBvAx4czZgrUWy0cLnPaZhZg6rZkcYQzpO0D9ALPAWcAhARD0u6GViQyi6LiAcl7QlcJ6kY848i4ub6hF5eW2sLO451UyJm1rjqkjQi4n2DlJ0PnN+v3xNk1VTbvKwpEScNM2tMviO8ygr5dp8IN7OG5aRRZVn7Uz6nYWaNyUmjyortT5mZNSInjSrzOQ0za2ROGlXWmW/PGi3c6EYLzazxOGlUWVe6wc+PfTWzRuSkUWWdvivczBqYk0aVFRst9MlwM2tEThpV5mdqmFkjc9KoMj9Tw8wamZNGlXWO85GGmTUuJ40qa2ttYcI4NyViZo3JSaMGsvanXD1lZo3HSaMGCh05Hluyxjf4mVnDcdKogeNmTOXRJWt43yW/ZeHydfUOx8ysapw0auD4Q17J9098AwtXrOPdF/6G3zz2Qr1DMjOrCieNGjli35342akz2Wn8GD7y/bu59I4/ETFqjys3M6sJJ40amjapg+s+/WaO2u8VfGXuI/zdVfNZt7G73mGZmW01J40a6xjTxkUfOpjPH7UPNy5YzHsv/i1PL/N5DjPbPjlpjAJJfPrwV/MfJ72BxSvX8+4Lf8Mdf1xa77DMzIbNSWMUHb7PTvzsb2eyy4SxnPQf93DJ7T7PYWbbFyeNUbb7xA6u/fSbOPp1u/C1mx/h1B/9D2tf8nkOM9s+OGnUQT7XxoUfPIgvHL0vNz34LO+9+Lc8tWxtvcMyMxuSk0adSOKT/+tVXPGxQ3hu9Qbe/Z3fcPujz9c7LDOzQTlp1Nlhe03mZ6fOZErnOD56+b1cdNvjPs9hZtustnoHYPDKiXmu/fSbOOMnD3D+Lx7ltkee55UT8+RzrXTk2hiXayWfa2Vcro2Oku58rpVx7a10jEnduVby7a20tfq/gJnVhpPGNiKfa+Nbxx/IAVM7uebehdz9xHLWb+ph3cZuNmzqHda0cm0tL0s42Sv73JG68/2S0bhcK2PaWmhvbaGttYX2VpFrLX4euLu9rYW2luxzS4tqtHbMbFvhpLENkcTHZ+7Bx2fusUX/nt7oSyDrN/aw9qUe1m/qZl2/7nUv9WTvm7r7utdv6s6G2djD82s2bB5mYzZOd291q8IkaJFQ6lZpN6Klfz8JCdpaRHtrC7mUtHIpIY1pbaG9bXOSyrVlZX3DtWVJrEXZtFsklLqL82tp0Rbzb0nzLL4PlOqkl/cdoBetLaKtRbS2tKR30d665ee2FtHW2lIyrGhrFa1pgtnb5lj6r7PifDe/by5PY74sxi1CHWS4reG/BtsHSXR15Ko+XSeN7UBri9hhTBs7jKn+17Wxu7cvgazb2MPG7l66e3vZ1NPLxu7YontTTyrrDjb29NLd08umnqx7U08vvb1BABHQG5u7o2bzjeUAAAelSURBVK87UhkEsUVZd2+wqTvNK81vY08vm7p72bCplzUbutnYXSwrxrR5/hGRTTe9mzW7STuMYd4Xj6z6dJ00mlyurYVcW47OfL0jqa7+SaQ3Jayg5HNv9v6ycctMb6DhenuD7t6gJ7139/Ru8bmnN0tspZ+7e7LuzTFtnn5skVA3l0XJTIvl/WPd3C8G6DfAgFvB+Xj7Mba9tSbTddKwhiSJ1lTtY2bVo0a/vFPSUuCprRx9ErAtPgzDcQ2P4xoexzU8jRjX7hExeaCChk8aIyFpXkTMqHcc/Tmu4XFcw+O4hqfZ4vIF/WZmVjEnDTMzq5iTxuAurXcAZTiu4XFcw+O4hqep4vI5DTMzq5iPNMzMrGJOGmZmVjEnDUDSUZIelfS4pDMGKB8j6epUfrekaaMQ01RJt0n6g6SHJP39AMMcLmmVpPnpdVat40rzfVLSA2me8wYol6Rvp/W1QNLBoxDTPiXrYb6k1ZI+02+YUVlfkr4v6XlJD5b065L0S0mPpfdCmXFPTMM8JunEUYjrfEmPpO/pOkmdZcYd9DuvQVznSHqm5Lt6R5lxB/3t1iCuq0tielLS/DLj1nJ9DbhvGLVtLGsPqHlfQCvwJ2BPIAf8Hnhtv2E+DXw3dR8PXD0Kce0CHJy6xwN/HCCuw4Eb67DOngQmDVL+DuAmstux/wK4uw7f6XNkNyiN+voC3gIcDDxY0u9fgDNS9xnA1wYYrwt4Ir0XUnehxnG9DWhL3V8bKK5KvvMaxHUO8LkKvudBf7vVjqtf+b8CZ9VhfQ24bxitbcxHGnAI8HhEPBERG4GrgNn9hpkNXJG6fwzM0kDNoFZRRDwbEfen7jXAw8CutZxnFc0GfhCZu4BOSbuM4vxnAX+KiK1tCWBEIuIOYHm/3qXb0BXAewYY9e3ALyNieUSsAH4JHFXLuCLilogoPqT+LmC3as1vJHFVqJLfbk3iSr//Y4ErqzW/Sg2ybxiVbcxJI1vZC0s+L+LlO+e+YdIPbBUwcVSiA1J12EHA3QMUHyrp95JukjR9lEIK4BZJ90k6eYDyStZpLR1P+R9zPdYXwM4R8Wzqfg7YeYBh6r3ePkZ2hDiQob7zWjg1VZt9v0xVSz3X12HAkoh4rEz5qKyvfvuGUdnGnDS2cZJ2AH4CfCYiVvcrvp+sCuYA4DvA9aMU1syIOBg4GvgbSW8ZpfkOSVIOOAb4rwGK67W+thBZPcE2da27pDOBbmBOmUFG+zu/BHgVcCDwLFlV0Lbkgwx+lFHz9TXYvqGW25iTBjwDTC35vFvqN+AwktqACcCyWgcmqZ1so5gTEdf2L4+I1RHxYuqeC7RLmlTruCLimfT+PHAdWTVBqUrWaa0cDdwfEUv6F9RrfSVLilV06f35AYapy3qTdBLwLuCEtLN5mQq+86qKiCUR0RMRvcC/l5lfvdZXG/Be4Opyw9R6fZXZN4zKNuakAfcCe0naI/1LPR74ab9hfgoUrzJ4P/Crcj+uakl1pt8DHo6Ir5cZ5hXFcyuSDiH7PmuazCR1SBpf7CY7kfpgv8F+CnxEmb8AVpUcNtda2X+A9VhfJUq3oROBGwYY5hfA2yQVUnXM21K/mpF0FPB54JiIWFdmmEq+82rHVXoO7K/KzK+S324tHAk8EhGLBiqs9foaZN8wOttYLc7ub28vsqt9/kh2JcaZqd+XyH5IAGPJqjseB+4B9hyFmGaSHV4uAOan1zuAU4BT0jCnAg+RXTVyF/CmUYhrzzS/36d5F9dXaVwCLkrr8wFgxih9jx1kSWBCSb9RX19kSetZYBNZnfHHyc6B/T/gMeBWoCsNOwO4rGTcj6Xt7HHgo6MQ1+NkddzFbax4leAUYO5g33mN4/rPtO0sINsZ7tI/rvT5Zb/dWsaV+l9e3KZKhh3N9VVu3zAq25ibETEzs4q5esrMzCrmpGFmZhVz0jAzs4o5aZiZWcWcNMzMrGJOGmYVkvRiep8m6UNVnvY/9vv822pO36xanDTMhm8aMKykke4iHswWSSMi3jTMmMxGhZOG2fCdBxyWnpXwfyS1Knsuxb2pgb1PQt/zO+6U9FPgD6nf9akRu4eKDdlJOg8Yl6Y3J/UrHtUoTfvB9HyG40qmfbukHyt7HsacWre8bAYw1L8fM3u5M8ie9fAugLTzXxURb5A0BvhvSbekYQ8G9ouIP6fPH4uI5ZLGAfdK+klEnCHp1Ig4cIB5vZes0b4DgElpnDtS2UHAdGAx8N/Am4HfVH9xzTbzkYbZyL2NrK2t+WRNVE8E9kpl95QkDIC/k1RsxmRqyXDlzASujKzxviXAr4E3lEx7UWSN+s0nqzYzqykfaZiNnIC/jYgtGn6TdDiwtt/nI4FDI2KdpNvJ2jXbWi+VdPfg37ONAh9pmA3fGrLHbBb9AvhUaq4aSXun1k37mwCsSAljX7JH4RZtKo7fz53Acem8yWSyR5DeU5WlMNsK/mdiNnwLgJ5UzXQ58C2yqqH708nopQz8qM2bgVMkPQw8SlZFVXQpsEDS/RFxQkn/64BDyVpMDeDzEfFcSjpmo86t3JqZWcVcPWVmZhVz0jAzs4o5aZiZWcWcNMzMrGJOGmZmVjEnDTMzq5iThpmZVez/AzmQ3unFML7pAAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -562,18 +385,18 @@ "output_type": "stream", "text": [ "# __Exp____ __Act______ __Err______ __RelErr___ __ID_______\n", - "0: 1.00000 1.79166 0.79166 0.79166 p1\n", - "1: 0.50000 0.59116 0.09116 0.18232 p2\n", - "2: 0.40000 0.70465 0.30465 0.76164 p3\n", - "3: 2.00000 2.10819 0.10819 0.05410 p4\n", - "4: 0.10000 0.11231 0.01231 0.12309 p5\n", - "5: 2.00000 0.02750 -1.97250 -0.98625 scaling_x1_common\n", - "6: 3.00000 3.02900 0.02900 0.00967 offset_x2_batch-0\n", - "7: 0.20000 0.18341 -0.01659 -0.08296 x1withsigma_sigma\n", - "8: 4.00000 4.01287 0.01287 0.00322 offset_x2_batch-1\n", + "0: 1.00000 0.30545 -0.69455 -0.69455 p1\n", + "1: 0.50000 0.30115 -0.19885 -0.39771 p2\n", + "2: 0.40000 0.16319 -0.23681 -0.59202 p3\n", + "3: 2.00000 1.81038 -0.18962 -0.09481 p4\n", + "4: 0.10000 0.04623 -0.05377 -0.53775 p5\n", + "5: 2.00000 0.16235 -1.83765 -0.91882 scaling_x1_common\n", + "6: 3.00000 2.99965 -0.00035 -0.00012 offset_x2_batch_0\n", + "7: 0.20000 0.13704 -0.06296 -0.31482 x1withsigma_sigma\n", + "8: 4.00000 4.00120 0.00120 0.00030 offset_x2_batch_1\n", "\n", "Status: 1\n", - "Cost: -368.648087 (expected: -0.000000)\n" + "Cost: -447.236053 (expected: -0.000000)\n" ] } ], @@ -585,28 +408,31 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ + "Running --at-optimum for \r\n", + "\tconditions from deletemehierarchical/_rank00000.h5:/inputData and \r\n", + "\tparameters from deletemehierarchical/_rank00000.h5:/inputData\r\n", + "\t> simh.h5:/\r\n", "Running for start 0\r\n", - "HierarchicalOptimizationWrapper parameters: 9 total, 5 numerical, 1 proportionality, 2 offset, 1 sigma\r\n", - "Need to compute analytical parameters: //inputData 1 parameters.size() == 5 ; hierarchical.numParameters() == 5\r\n", - "Starting simulation. Number of conditions: 4\r\n" + "Starting simulation. Number of conditions: 4\r\n", + "\u001B[36m[2020-06-24 17:53:21] [DBG] [-1:140138827208640/] [] HierarchicalOptimizationWrapper parameters: 9 total, 5 numerical, 1 proportionality, 2 offset, 1 sigma\u001B[0m\r\n" ] } ], "source": [ "!rm -f simh.h5\n", - "!{example_binary_dir}/example_steadystate_multi_simulator {hdf5_pe_output_file_hierarchical} / simh.h5 / --at-optimum --nompi" + "!{example_binary_dir}/example_steadystate_multi_simulator {hdf5_pe_output_file_hierarchical} /inputData {hdf5_pe_output_file_hierarchical} /inputData simh.h5 / --at-optimum --nompi --compute-inner" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -616,15 +442,13 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 20, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -638,17 +462,15 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 22, "metadata": { "scrolled": false }, "outputs": [ { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -657,10 +479,8 @@ }, { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -669,10 +489,8 @@ }, { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYYAAAEZCAYAAACTsIJzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAgAElEQVR4nOzdeXxU1dnA8d+ZLZONBBLCjiwaFlmiEsSFumARFbe3CipU8LWiVmsr6ItatyqFtlqV1gWpoliwIkgRRFHEBQRBAUECCRAQJCSQBLInk9nO+8edTGaSyUJWIM/38xkz595zzz0TyX3m3nvueZTWGiGEEKKCqbU7IIQQ4uQigUEIIUQQCQxCCCGCSGAQQggRRAKDEEKIIBIYhBBCBJHAIEQjKaUmK6W+CSgXK6X61FJ/p1Lq0hbpnBANIIFBnLaUUrcppTb7DtRZSqlPlFIXN/d+tdZRWuv9vj68rZSaUWX92Vrrr5p6v0qp55VSe5VSRUqpNKXU7U29D9E2SGAQpyWl1FTgJWAm0AnoCbwKXN+a/WpmJcC1QAwwCZitlLqwdbskTkUSGMRpRykVAzwD3Ke1Xqq1LtFau7TWK7TWD/vqhCmlXlJKZfpeLymlwnzrLlVKZSilpimlsn1nG3cEtB+nlFqulCpUSn0H9K2yf62UOlMpNQWYAPyf76xlhW/9AaXUFY3tR1Va66e01mlaa6/WehOwDrigCX+1oo2QwCBORxcAduC/tdT5IzACSAKGAsOBxwPWd8b45t0NuBN4RSnV3rfuFcABdAH+1/eqRms9F1gI/M13eenaJu5HjZRS4UAysLOuukJUJYFBnI7igFyttbuWOhOAZ7TW2VrrHOBPwK8D1rt8611a64+BYqCfUsoM/Ap40ncmkgLMb0RfG9SPerQ7B9gOfNqIvok2ytLaHRCiGRwD4pVSllqCQ1fgYED5oG+Zv40q25YCUUBHjL+bQ1W2baiG9qNGSqnngEHAZVpmyRQNIGcM4nT0LVAO3FBLnUzgjIByT9+yuuQAbqBHlW1rUteBuaH9CEkp9SfgKmC01rqwoe2Itk0CgzjtaK0LgCcxrsffoJSKUEpZlVJXKaX+5qv2H+BxpVRHpVS8r/6CerTtAZYCT/vaHYgxAqgmR4Ean2loaD9CUUo9CtwGXKG1PtaQNoQACQziNKW1/jswFeNGbg7GpZ/7gWW+KjOAzcCPwA5gq29ZfdyPcTnnCPA28FYtdd8EBiql8pVSy0Ksb0w/qpqJccaR7hsFVayUeqyBbYk2TMklSCGEEIHkjEEIIUQQCQxCCCGCSGAQQggRRAKDEEKIIKf8A27x8fG6V69erd0NIYQ4pWzZsiVXa90x1LpTPjD06tWLzZs3t3Y3hBDilKKUqvGJfbmUJIQQIogEBiGEEEEkMAghhAhyyt9jEEK0bS6Xi4yMDBwOR2t35aRkt9vp3r07Vqu13ttIYBBCnNIyMjKIjo6mV69eKKVauzsnFa01x44dIyMjg969e9d7OwkMopo9m47w7Yf7KD5eTlSHMC64vi+J53du7W4JEZLD4ZCgUAOlFHFxceTk5JzQdhIYRJA9m47w5cI03E4vAMXHy/lyYRqABAdx0pKgULOG/G7k5rPwczrcfLtsnz8oVHA7vXy7bB8up6eVeiaEaElyxtBGOR1u9nx3lM592hHfPZpjmcW898x3NdYvzitn7gNfc+0DQ+k5MI7cjGK2rDrA8LG9ad85kpKCco4dLqZznxhsdvlnJZpfYMqAeqUPqKHKCSceOIFUBdVqNibLga5eNJnAZG767/fyF3ya0lpTmOtAmaBdXDhul4cPX9xGvxGdGfSLbgB8/e5uRtzQh/ju0cR0DOf86/qw4+sMSguc1dqLjLUx+NLudOgSCYCjxEXOz0Vo38lF5t58PntjJ7c8OZy4rlHs3XyU9Yv3cuND5xHTMZwjPxVwcMcxkq7oQViElbJiJ84yD9Fxdkymhl0G0FqjNWivxuvRxs+K9zpgmcdYXrE+5DJPwLbe4HUVywLLFev9+/b1w983/38ql/iPJ5oq9WrZToM2/lNLHV1Z1FV2UWvbutqyqv2psuvK/gTuK9TBLrBPFduF2Fn1OsGNVWs7xM66JENBTlmITpz+wiIshEfZmrxdCQwNdLLcoNVejfIdWLd+dpDIdjb6jegCwPszvydxeCcuubUfFqsZe5QVq834dmGzW5g060IiY8IAsFjNDLu6F9FxYXy1YDduV+XlJLPVxJDLe9BrUDyOEjdlRUVYw8yMmjQQR4mLjN15mEyKC3/Vl7wjpRRkl5F/tJTYThFkpB0nK93EodTj7Pn+KDa7GZPFKB/ccYxh1/TCZFJkHywk91Axfc9LAKD4uIPyEhftOoajNXhcXuOgoQk6WDc3ZVIok8JkVihl/DRVLDMpVEBZAfhinAos+BYExT8V4tqvCvpR0QjVqqnqG1SvE7pt462q0s+6twvcZ839CS7U2HYtn0dV/R3VuCNfUYHDmos9sv5DMUO23RC1XLuvs+06Klxy6Ui+/mpdnbtujrMFkMDQIE15g/ZEAkzOz0WUl7ro3r8DAB+9vB2zxcRV9wwGYN+WbNp3iaTfiC4opRg1qT8R7cIoyS/H6XAz7OpeOB1u9v+Qg7PcjbPMg8v30+lw43IYP2M7hZN3tAyPy4vZaqJ9p3Cy9uaTtTe/Hp+oso41zMyBH3P9B9Yzz+1IzqEizGYTZouiW2IsjiInJrMJj9sIcBaLCWVWFOeVk3OoiB4D4zCZFfu35ZDzcxEX33wWyqTI3JtPaaGTARd0QZkUxXkOtIYOXSMxqeADdrWDue/0W5nAZDJVrjcbB6bA+nJT8+SXmpp34oHhJPftxm9bdf8SGBrg2w9D36D9Zsledn93hMsm9ieqvZ1jmcVkpReQOLwTNrsFZ5kbt8tLeJQVZVIhA8wXCyoDzI6vMsjNKOayif3xejUbl++nMLuUq+4ZgtPhJqp9GB6PJnVDJk6Hh15D4nA5vHy1MA2nw4Or3FPz9VClsIWbsYVZsIWbiYwNw2Y3Y7NbsNktWMPMxrdk30HSZA48sNawrMrB2DiwNmxUxLlXnkFZkZN2ceEAtO8SSV5WCWePNC6D5WWVUHTMwVnJnQD4ZM4O8rNLufXJ8wFY/dZOnGUervntEAB2fZOJMikGXGicTRXmlmGzW5rkgHKynD2K1pOSksKUKVPYsGEDAFu3buXhhx9mzZo1tW5XUlLCuHHjyMjIwOPx8MQTTzB+/HiioqIoLi7mwIEDjBkzhhEjRrBhwwaSk5O54447eOLxJzl6NJtXX/oXw85LJio2DHtU0wVHCQxU/8PuNSiOAynHqv2hO0pcbFiaTvHx8pDtlBW5cBS7/Kd3h3fnsW7RXvqe0xHskLohi28W7+XOv4/EHmll7ft7qgUYj8vL2vf2kJ9Txs87j1Gc5+DTN1Jwl3twl3uIbB/Gt/9ND9rmwI/HsNnNWO0WbHYz7eLDsYaZK5eFW/wHfavvp8VmOqm/DVttZqy+oABwxtlxnHF2nL980U1nBdW/4Ma+lJe5/eWOPaKDfre7Nx3BYjX5A8OquSmER9u49ndDAVg9bycxCREMH2s8BLT3+6NEx9np3CcGwH/2VJUM7z25/Oe7n/n5eGmTttmzQwS3Du9Za52BAweyf/9+PB4PZrOZqVOn8sILL9TZ9qpVq+jatSsrV64EoKCgoFqd9PR0Fi9ezLx580hOTubf8xfw4aJVfPLZSma/8nfm/+tdio4bT303VXBok4EhMBCERZpxObx4PcY36+Lj5aSszfTXDfwW33dYApl78wmLsFBe6q7WblSHMG5+NNlfPntkN/okJfi/lXbsGU3SFT04mJJLYa6D8pLqbQCUl7kpL3XRY0AH/4Hc/20+vDIAWH3f9s2Wk/sg3xJiO0UElZOuCP5DvnHauXg8lYFi+LW9gw70SgVf3163eC+9h8T7A8P8x9Zz5rBO/GJ8IgBf/DuVngPjaj177Nw3hnbx4Xg8Xg6n5RHbOYJ2ceF4XF4ydufRoWsk0R3suJ0eMnbnEdctiugOdlzlHg7vziO+RxRR7e04HW4O78knoWc0kbFhlJe5ydyTR0KvdkTGhOEocZG5N5/OfWKIaGejrNhJ1t4CupwZQ3i0jdJCJ1np+XRNjCU8ykZJQTlZ6QV0798ee6SV4rxyjuwvoMeA9oRFWCk67uDI/gLOODsOW7iFwtwyjv5UyBmD47DZLRTklHL0p0J6J3XEajOTd6SE7INF9D23IxarmeNZJeT8XMSZ5yVgtpg4driYnENFJA7vjMmkyM0oIvdQMf1GdEYpRc7PReRmFPuD9tGfCsk7WkJ/372yI/sLKMgu9d87y0zPp+iYg36+wOt2eXEUu/wHReN+FFh899MaW3aVe3CUurBHGO07SlwoBWEV5WInyqQ4++yz2blzJzt3pNK9Ww/OPfdcSkpKuPuue7CF2Rh1xeVMmDCBsiInJouJsHALgwcPZurUaTw07WGuv+E6Ro4cSWlh8BfPXmf0ot9ZAzCZTJx99tmMGHYxAAP6D+RQxs+AcdO+OL/81AsMSik7sBYI8+13idb6qSp1JgPPAYd9i17WWr/RlP3Ys+kIa95J9QeC8pK6x+Z7XF6+/XAfied35ranzid9c3bQt0Qw/hFdcH1ff9lR4qIgp4yC7FLjZ04Z5SUuAPKzy4hqH1ZrgBk5LrGxH1VUYQ64UddrcHzQuivuGBhUvuXx4UEjZJKu6ElctyjAuPmdlV5AbEJErWeP6VuzOXf0GbgcHlb8czsX33wWQ0f1wFHq4qOXt3PJbf0Y9ItulBW7WPnKj1z26/4MvKgrJQXlrHz1R664YyD9zu9M0XEHH7/6I1feNYgzz0ugMKeMj1/bwVX3DKZPUkfyj5byyZwdjP3dUM44O468rBI+eX0H1/8hie79O3DscDGr5qZw40PnEn6mjZyfi/j0Xync9Mgw7JFWsg8U8um/Uhj/eDJhEVaO7Cvgszd3ctvT52MLt5CZns+at1OZ+OwF2OwWDu/O58sFaUyadSFWm5mMtDzWvreHngMvxmI18/POY6xfkk6vIfGYLSYO7Mhl47L9nHleAiaTmZ+25/Ldip+MA7uCfT9ks/XTn/2BIX1rNilfZ/gDw97vj7J70xF/YNiz6Qj7t+dWBoZyj/+geOvwnhTmluEq9/j/fxXklOJ2eYnrapTzs0vxerR/hF3+0VK83spy3tES0NC+s698pARHUWVgKC10YjIrf2AoLXRhtihGjBjB+vXr+efsl/ng/Q8BWLp0KVeNvpZrx17LXfdNZsKECZQUOLGFmwkLt5CYmMjqj77m62++4PHHH2fUqFHcO/nBoH9LFosNZ5kbm92CyWTCZjVGIZmUCben8vjh9QR/QWkMVa/xv02xI+MrbaTWulgpZQW+AX6vtd4YUGcyMExrfX992x02bJg+kUQ9b05bi6OGb+p1uW/O5f73gWcdke3DOPvirsQkhFOQHRwEUIqo2DBiEsKJSYggpmM47eLtWKzmapchwAgwl03oL5chThHzH1sfMjiEt7Mx7tFkotqH4fV4yT5YRHScnciYMDxuLzmHimgXF05EOxsel5fcjGLaxdsJj7bhdnk4nllCu7hw7FFW3E4Px7NKaBcfjj3SisvpIf9IKe3i7YRFWHGVe8jPLiUmPhxbuAWnw01hbhnt4sONe1sON0XHHP5LjP5yx3CsNjPOMjdFeQ5iOoZjsZopL3NTkl9OTHw4ZquJ8jI3pQXltIsPx2wxUV7qoqzIRXS8HbO5stwu3o6polzsol18OCaTwlHiorzUTbs4O8pXdpa5iY6zo5Sv7HD77yc5Sly4yj1Ed7D7y26nh6j2lWWP2+sfUbdr5y769euP2WIE/ooDZMUl3WplrzF2ttYy+IdR17e8cuVHTJ48md/+9rc886dnUCbFrFmzuPLKMZyTlMSEiRN499138Xo1CmPEW2ZmJu1j22MPt7Ny5UreeOMN/rv0v0S3i/bfYxg7diw7duxAKcXkyZP5xQVXMHbMdfx86CAT7xzP2s82+j9ffPeokP9OU1NTGTBgQNAypdQWrfWwUPVb7IxBGxGo2Fe0+l4tE5UCNDQoRHUw/hFW/BEqs+Lsi7uSn20EgewDhWQfLCIqNoz47lHEdAwnpmME7ToaQSCUioO/3Lg8dV1wfd+Qwf3iX51JVHvj34zJbPJfkgIwW0x07h1Qtpro1Ltd5fZWMwlnBJRtwWWrzUzHntGV5TAzHXtUlm12C/Hdg8sV355DlsMtxIVXlsPCLYSFW2ouR1j935brU7ZHWoNu8jekTNVyAGVS/qAA1YdwViubfONcay1XrV93uX///oSFhfHII4/4h5B3796dzMzDnHvuOXi93mrb79ixg4cffhiTyYTVauW1117zbxv0GQOuc9ojLdUuHSvfF9Cm0mJnDABKKTOwBTgTeEVrPb3K+snALCAH2AM8qLU+FKKdKcAUgJ49e5538GCNGeqqeeWeL06432aLos+5HbGFWSjJr/x2GBkb5j8LiE2oPQiI05eMSmpdob4Nt4b777+f5ORkJk2a5F9WUlLC/fffj91u5+KLL2bChAlNsi9HsYvi/HK8Hi8ms6nOUUkn7RkDgNbaAyQppWKB/yqlBmmtUwKqrAD+o7UuV0rdDcwHLg/RzlxgLhiXkpq0kwoSekWTl1mKq9zjH8evUETGhtGtX3tiOxnBQKZ+EGCc+UkgaLv27dvHNddcw0UXXRQUFAAiIyN56623mnyf9ihrkw5PrapVjmxa63yl1JfAGCAlYPmxgGpvAH9r6n3bIy21X07SEN8tml6D4olqbycmIZz2nSKwR1nb/MgfIUR1ffv2JS0trbW70aRaclRSR8DlCwrhwC+Bv1ap00VrneUrXgekNnU/Ro5LZPVbu2pcH9U+jMsm9m/q3QohxCmjJafd7gJ8qZT6EfgeWK21/kgp9YxS6jpfnQeUUjuVUtuBB4DJTd2JxPM7Y7WH/thKwQU39A25Tggh2oqWHJX0I3BOiOVPBrx/FHi0Ofvx9btpuByhx/vaIsxyrVgI0ea1uUQ9O7/JrHFdfR52E0KI012bCwy6locDwyJlqKkQQrS5wFAb1fgZ2oUQ4pQngSFAQ5+KFkKI04k8oRWgYtoLIcTpa9kPh3nu091k5pfRNTach6/sxw3ndGvtbp1U5IwhQODsqEKI08+yHw7z6NIdHM4vQwOH88t4dOkOlv1wuM5ta5OSksKFF17oL2/dupVRo0bVud2BAwfo378/kydPJjExkQkTJvD5559z0UUXcdZZZ/Hdd98BsGDBAoYPH05SUhJ33303Ho+HkpISrrnmGoYOHcqgQYNYtGhRoz5DoDYXGGo6KwiLlKGqQpwOxr/+LYs3G1OsuTxexr/+Lf/9IQOAv61Ko8wVPPqwzOXhmY92AnC8xMn417/l811HAcguctRrn4GJegCmTp3Kc889V69t09PTmTZtGmlpaaSlpfHuu+/yzTff8PzzzzNz5kxSU1NZtGgR69evZ9u2bZjNZhYuXOhP8rN9+3ZSUlIYM2ZMvfZXH20uMFxwfV9/Ao4KFpuJX4zr10o9EkK0lKyC0Af64xXT5DdQRRKdnTt38sEHH3DGGWf4E/VMmjSJu+66i4ULF4bctnfv3gwePNjfxqhRo1BKMXjwYA4cOMCaNWvYsmULycnJJCUlsWbNGvbv38/gwYNZvXo106dPZ926dcTExIRsvyHa3D0GmepaiNPborsv8L+3mk1B5a6x4RzOL6u2TbdYIxdEh0hbUP2EaHu991uRqOfVV19l1apVgJGo56abbuLaa69l/PjxIWdXDQurvIphMpn8ZZPJhNvtRmvNpEmTmDVrVrVtt27dyscff+xP8vPkk09Wq9MQbS4wgMyGKURb9fCV/Xh06Y6gy0nhVjMPX9n4KwYjRoxg8uTJ3HfffXTrZtzMzsjIYPDgwQCYzQ17TmrUqFFcf/31PPjggyQkJHD8+HGKioqwWq106NCBiRMnEhsbyxtvNF2yyzYZGIQQbVPF6KPmGJVUkahn+vTKNDPdu3cnIyODpKQkf6KeEzVw4EBmzJjB6NGj8Xq9WK1WXnnlFQoKCqol+WkqLZqopzmcaGpPIcTppS0m6jlRJ3WiHiGEON20RqKe5iaBQQghGuF0TNTT5oarCiGEqJ0EBiGEEEEkMAghhAgigUEIIUSQFgsMSim7Uuo7pdR2X17nP4WoE6aUWqSUSldKbVJK9Wqp/gkhhDC05BlDOXC51nookASMUUqNqFLnTiBPa30m8CLw1xbsnxBCCFowMGhDsa9o9b2qPl13PTDf934JMEopJWnVhBCiBbXoPQallFkptQ3IBlZrrTdVqdINOASgtXYDBUBciHamKKU2K6U25+TkNHe3hRCiTWnRwKC19mitk4DuwHCl1KAGtjNXaz1Maz2sY8eOTdtJIYRoZYFJf1pDq4xK0lrnA18CVTNLHAZ6ACilLEAMcKxleyeEEK1rw4YNrbr/lhyV1FEpFet7Hw78Eqj6HPlyoGKykZuAL/SpPsufEOK019DUnjWl54yKigLqn/qzqbXkXEldgPlKKTNGQHpfa/2RUuoZYLPWejnwJvBvpVQ6cBy4pQX7J4Q41W15G/IONG2b7XvBeZNrrRKY2tNsNjN16lReeOGFOpuuSM+5cuVKAAoKCqrVSU9PZ/HixcybN4/k5GR/6s/ly5czc+ZMli1b1pBPVasWCwxa6x+Bc0IsfzLgvQO4uaX6JIQQTSEwtefevXv9qT3379/Pn//8ZwoKCliyZEm17QYPHsy0adOYPn06Y8eOZeTIkdXqVKT+BEKm/mwOMruqEOL0Ucc3++YUKrVnnz59ePPNN7nppptCbpOYmFhnes66Un82BwkMQgjRBEKl9qxLZmZms6XnbAwJDEII0QRCpfasy44dO5otPWdjSGpPIcQp7WRO7Xns2DH++Mc/snr1an7zm9/w6KOPtkrfJLWnEEK0oNpSe8bFxTFnzpxW6lnDSWAQQohGkNSeQgghTnsSGIQQQgSRwCCEECKIBAYhhBBBJDAIIYQIIoFBCCFEEAkMQgghgkhgEEK0LT++Dy8OgqdjjZ8/vt/aPTrpSGAQQrQdP74PKx6AgkOANn6ueKDRwaGhiXrqm4hnwYIFDB8+nKSkJO6++248Hk+NSX6aggQGIcTp5a1r4IeFxnuPyyhv9x00P/8TuMqC67vKYNUjxvuSY0b93Z8Y5aKj9dplYKIegKlTp/Lcc8/Va9v09HSmTZtGWloaaWlp/kQ8zz//PDNnziQ1NZVFixaxfv16tm3bhtlsZuHChf4kP9u3byclJYUxY6pmSm44CQxCiLaj8HDo5aWNSy0fmKjngw8+CErUc+edd9aYjwEqE/FUtFE1Ec+aNWvYsmULycnJJCUlsWbNGvbv38/gwYNZvXo106dPZ926dcTExDTqMwRqsbmSlFI9gHeAToAG5mqtZ1epcynwIfCTb9FSrfUzLdVHIcRp4I6Vle/N1uByTHffZaQqYnoYPyPjgutHd6r3bhuSqAfqTsSjtWbSpEnMmjWr2rZ1JflpqJY8Y3AD07TWA4ERwH1KqYEh6q3TWif5XhIUhBBNZ9STYA0PXmYNN5Y30ogRI3j88ce58cYb652opz5GjRrFkiVLyM7OBuD48eMcPHiQzMxMIiIimDhxIg8//DBbt25tsn22ZM7nLCDL975IKZUKdAN2tVQfhBBt3JBxxs81z0BBhnEGMerJyuWN0JBEPfUxcOBAZsyYwejRo/F6vVitVl555RUKCgqaLclPqyTqUUr1AtYCg7TWhQHLLwU+ADKATOAhrfXO2tqSRD1CtG2SqKduJ32iHqVUFMbB/w+BQcFnK3CG1rpYKXU1sAw4K0QbU4ApAD179mzmHgshRM0kUU8jKaWsGEFhodZ6adX1gYFCa/2xUupVpVS81jq3Sr25wFwwzhiaudtCCFEjSdTTCEopBbwJpGqtX6ihTmdfPZRSw339a9w4MiGEECekJc8YLgJ+DexQSm3zLXsM6AmgtZ4D3ATcq5RyA2XALbo1boIIIUQb1pKjkr4BVB11XgZebpkeCSGECEWefBZCCBFEAoMQQoggEhiEEEIEkcAghBAiiAQGIYQQQSQwCCHESSYw6U9rkMAghBAnmQ0bNrTq/iUwCCFEIzU0tWdN6TmjoqKA+qf+bGotPomeEEI0lyV7lpBRlNGkbXaP7s5NiTUn2oHg1J5ms5mpU6fywgshZ/4JUpGec+VKIzlQQUFBtTrp6eksXryYefPmkZyc7E/9uXz5cmbOnMmyZcsa9sFqccJnDEqpSKWUucl7IoQQp6iaUnsuW7aMu+66i/Hjx/PZZ59V264+6TnrSv3ZHOo8Y1BKmYBbgAlAMlAOhCmlcoGVwOta6/Rm6Z0QQpyAur7ZN6dQqT1vuOEGbrjhBvLy8njooYcYPXp00DaJiYl1puesK/Vnc6jPpaQvgc+BR4EUrbUXQCnVAbgM+KtS6r9a6wXN0kMhhDgFjBgxgsmTJ3PfffdVS+05Y8YM7rvvvmrbZGZm0qFDByZOnEhsbCxvvPFGS3W3VvUJDFdorV1VF2qtj2PkVvjAl2dBCCHarFCpPbXWPPLII1x11VWce+651bbZsWNHs6XnbIw6U3sqpaZWWaSBXOAbrfVPzdWx+pLUnkK0bSdzas9//OMfzJ8/n+TkZJKSkrjnnntapW/NkdozOsSyXsAflVJPa63fO+FeCiHEaaK21J4PPPAADzzwQCv1rOHqDAxa6z+FWu67x/A5IIFBCNFmSWrPAL57DLUm3hFCCHHqaXBgUEpdBuQ1YV+EEEKcBOrzHMMOjBvOgToAmcCk6lvU2E4P4B2gk6+9uVrr2VXqKGA2cDVQCkzWWm+t7z6EEEI0Xn1uPo+tUtbAMa11yQnuyw1M01pvVUpFA1uUUqu11rsC6lwFnOV7nQ+85vsphBCihdTn5vPBUMuVUhcDt2qtqz+1EbqdLCDL975IKZUKdAMCA8P1wDvaGEO7USkVq5Tq4ttWCCFECzihewxKqXOUUs8ppQ4AzwINuhWvlOoFnANsqrKqG3AooJzhW1Z1+ylKqc1Kqc05OTKD9GkAACAASURBVDkN6YIQQoga1OceQyJwq++VCyzCeDDusobsUCkVhfHE9B+01oUNaUNrPReYC8YDbg1pQwghRGj1uceQBqwDxlZMlqeUerAhO/NNnfEBsFBrvTRElcNAj4Byd98yIYRoEiv3r2T21tkcKTlC58jO/P7c33NNn2tau1snlfpcSvofjHsDXyql/qWUGkUDnl/wjTh6E0jVWtc0Ufly4HZlGAEUyP0FIURTWbl/JU9veJqskiw0mqySLJ7e8DQr969sVLsNTdRT30Q8CxYsYPjw4SQlJXH33Xfj8XhqTPLTFOoMDFrrZVrrW4D+GDOt/gFIUEq9ppQaXfvWQS4Cfg1crpTa5ntdrZS6RylVMYHIx8B+IB34F/DbE/kwQghxx6o7WJZuJK9xeV3cseoOVuxbAcBLW17C4XEE1Xd4HPz1u78CkOfI445Vd/DVoa8AyC3Lrdc+AxP1AEydOpXnnnuuXtump6czbdo00tLSSEtL8yfief7555k5cyapqaksWrSI9evXs23bNsxmMwsXLvQn+dm+fTspKSmMGTOmXvurj3pncPMNT30XeFcp1R64GZgOVM8+EXr7b6jjTMM3Gqleo5yEEOJEHS09GnJ5XnnjntUNTNSzd+/eoEQ9K1eupLCwkDvvvLNaPgaoTMQDhEzEs2bNGrZs2UJycjIAZWVlJCQkcNtttzFt2jSmT5/O2LFjGTlyZKM+Q6D63HxWusoUrFrrPIybv3NrqiOEEK3hrTFv+d9bTdagcufIzmSVVL863SWyCwDt7e2D6seHx9d7vw1J1AN1J+LRWjNp0iRmzZpVbdu6kvw0VH3uMXyplPqdUqpn4EKllE0pdblSaj4n8AS0EEK0lt+f+3vsZnvQMrvZzu/P/X2j2x4xYgSPP/44N954Y70T9dTHqFGjWLJkCdnZ2QAcP36cgwcPkpmZSUREBBMnTuThhx9m69ammySiPpeSxgD/C/xHKdUbyAfsgBnjMtJLWusfmqxHQgjRTCpGHzXHqKSGJOqpj4EDBzJjxgxGjx6N1+vFarXyyiuvUFBQ0GxJfupM1BNU2RhuGg+Uaa3zm6wXjSCJeoRo2yRRT92aI1GPny/FpwwfFUIInzaZqEcIIUTNJFGPEEKI094JBwalVKRSytwcnRFCCNH66gwMSimTUuo2pdRKpVQ2xtxJWUqpXb6ZVs9s/m4KIYRoKfV6jgHoCzwKdNZa99BaJwAXAxuBvyqlJjZjH4UQQrSg+tx8vkJr7VJK9dJaeysWaq2PY8yU+oFvGKsQQojTQH0m0XP53labJts3A2pgHSGEEKe4+txjGKeU+gsQrZQaoJQK3GZu83VNCCFEa6jPpaT1GFNg/AZ4AeinlMoHMoGyZuybEEKIVlBnYNBaHwbeUUrt01qvB1BKxQG9aGDOZyGEEDW78MIL2bBhQ6vtv97TblcEBQCt9THgWNU6zdRHIYRoU1ozKIBMuy2EEI3W0NSeNaXnjIqKAuqf+rOpNXTa7XCMoCLTbgshThp577+P61BGk7Zp7dGd9uPG1VonMLWn2Wxm6tSpvPBCTantK1Wk51y50sg5XVBQUK1Oeno6ixcvZt68eSQnJ/tTfy5fvpyZM2eybNmyhn2wWtRnuKpDa/2q1voi4AxgFHCO1voMrfVd9Q0KSql5SqlspVRKDesvVUoVBOSDbppUREII0cwCU3t+8MEH/tSeqamp3HPPPdx0000h8yUMHjyY1atXM336dNatW0dMTEy1OhWpPyv2UTX1Z3M44Wm3lVL3Ahal1DZgm9Z6Tz03fxt4GXinljrrtNZjT6RPQghRoa5v9s0pVGrPAQMGMGfOHLxeL7fffjv33ntv0DaJiYl1puesK/VnczjhSfS01k8Cs4EC4Eal1L/qud1a4PiJ7k8IIU4FNaX2XL58Oddccw1XX311tW2aMz1nY9T7jEEptRp4SGu9XWt9FPjU92pKFyiltmM8I/GQ1npnDX2ZAkwB6NmzZ6gqQgjRokKl9gS47rrruO6667jmmmu47bbbgtbt2LGj2dJzNka9U3sqpc4F/g4cAB7TWp9wJjelVC/gI631oBDr2gFerXWxUupqYLbW+qy62pTUnkK0bSdzas+vvvqKpUuXUl5ezpAhQ7jvvvtapW/NltpTa70VuEwp9StglVJqKfA3rXWTPP2stS4MeP+xUupVpVS81jq3KdoXQojmUFtqz0svvZRLL720dTrWCCd081kppYDdwGvADOAupdSjWut/N7YjSqnOwFGttVZKDce4/3Gsjs2EEKJVnY6pPU/kHsN6oDewEyMPw2SMKTF+r5QaqbWeUsf2/wEuBeKVUhnAU4AVQGs9B7gJuFcp5caYg+kWeZpaCCFa3omcMUwBdoU4WP9OKZVa18Za61vrWP8yxnBWIYQQrehE7jGEHCHkc00T9EUIIcRJ4ISfYwhFa72/KdoRQgjR+pokMAghhDh9SGAQQggRRAKDEEKIIBIYhBBtSsGKFey9fBSpAway9/JRFKxY0dpdOulIYBBCtBkFK1aQ9cSTuDMzQWvcmZlkPfFko4NDQxP11DcRz4IFCxg+fDhJSUncfffdeDyeGpP8NAUJDEKI08rBX99O/tL/AqBdLg7++nYKli8HIPuFF9EOR1B97XBwdOYsANx5eRz89e0UffGlUc7Jqdc+AxP1AEydOpXnnnuuXtump6czbdo00tLSSEtL8yfief7555k5cyapqaksWrSI9evXs23bNsxmMwsXLvQn+dm+fTspKSmMGTOmXvurjxOaEkMIIU5l7iNHQi735OU1qt3ARD179+4NStQze/ZscnNzGTVqVLV8DFCZiAcImYhnzZo1bNmyheTkZADKyspISEjgtttuY9q0aUyfPp2xY8cycuTIRn2GQBIYhBCnlTP+XZkLTFmtQWVLly7GZaQqLF27Gj/btw+u37FjvffbkEQ9UHciHq01kyZNYtasWdW2rSvJT0PJpSQhRJuR8OAfUHZ70DJlt5Pw4B8a3XZDEvXUx6hRo1iyZAnZ2dkAHD9+nIMHDzZrkh85YxBCtBkx114LQPaLL+HOysLSpQsJD/7Bv7wxGpKopz4GDhzIjBkzGD16NF6vF6vVyiuvvEJBQUGzJfmpd6Kek5Uk6hGibZNEPXVrtkQ9QgghqmvziXqEEEIEOx0T9cjNZyGEEEEkMAghhAgigUEIIUSQFrvHoJSaB4wFsrXWg0KsV8Bs4GqgFJistW66gbknqdR1X7LuvXcoOpZLdFw8I2+5nQEjL2vtbgkh2rCWPGN4G6htMo+rgLN8rylA0w3KPUmlrvuSz+a+TFFuDmhNUW4On819mdR1X7Z214QQbViLBQat9VrgeC1Vrgfe0YaNQKxSqkvL9K51rHvvHdzO8qBlbmc56957p4YthBCi+Z1Mw1W7AYcCyhm+ZVlVKyqlpmCcVdCzZ88W6VxzKDqWe0LLRdPyer0AuN0evFrj9XrxejUejwetNR6vF601Xk/le4/Xi9frwevVaG9F2VhX8axoTQ+Nau2tfO8NWE71+hV9M9aHpr2Ba2rYZ0CdwP0ENB9cn4D91rDjijYD6wavD24x9PJK3sB9emv4HIHvqzQUE2mlqKikpt9A6J02fZXgWg18bvhE92Oz2YgIt9dSt2FOpsBQb1rrucBcMJ58buXuNFh0XLxxGSnEcoDy0lLCIiKaZF9OpwtHuQuHoxxHuZNyp5NyhxOn00m5y0l5uRNnuROX043L5cLlcqG9Xv8BU/sPfjrgQGgcHLXXi0ajtXFgRXvRGv/2eH1l7dvOd1SqaNN/ENReoz2MdtGV+8H/s7ItgpZXrofK9Vrjq+cro/3bNfSPV5xcrrz1VxTl1XYx4vTljog87QPDYaBHQLm7b9lpa+Qtt7Nqzmy8brd/mclipfPwS/nsk89J+ffLdLloDOE9zsTpdOL2HbDdThdutxO3y43H7cbjcuFxu/G6K396PW60x412u9EeT81f/xpCKd8LlPJdjTSZAIUKXO6rp1AokwmNQpmUr3rAel8bymRCAcpkRpkUSllRxgKUUgHrjW0ryhVtKWUymjSZfP1QmE1mUGAyKcCEyWzy9cfoq8kU0HbVMmAyV7SrMJvNKJTRllKYzSaUMmEyKf/+Kn9FKujXFfrXWHklt4Yqlb+vGq76qqDFqoblgTUC9mkKvdfA/qoa9msyVawP3GeNn6LufQa1XcNnreHzeZyltE9IqGHfNVP1K9S9bYN3rKov8rnkkl/w9ddr69xpTb+rxjqZAsNy4H6l1HvA+UCB1rraZaTTxf4Dh/kxqwRXpzNRWekorxttslAWHsfW77ejPFuw2aLYk7ITnboHk9uB2VWGKzwWZbGiLBaU2YLJYsVktmC2GO+t9nDMVitmiwWL1YrFYsVis2K1WrFYrdhsNmxhNqxWK1abhbAwG2FWGzabjTC7Dbs9jDCbjTCbBbPZjNlswmwyoUwKs8nUbP8QhWio1NRUwu1hdVc8hXz77betuv+WHK76H+BSIF4plQE8BVgBtNZzgI8xhqqmYwxXvaOl+tYSvF4vP+5KZ9uW7Rzek4arIA/lcRLWsRs9rr2YhM6dQh6ow2zGwXrnqmXsWP0R9zz3CrbwCJyOMmz28Nb+WEIIjNSeU6ZMYcOGDYCRJ+Hhhx9mzZo1tW5XUlLCuHHjyMjIwOPx8MQTTzB+/HiioqIoLi7mwIEDjBkzhhEjRrBhwwaSk5O54447eOqpp8jOzmbhwoUMHz68yT9PiwUGrfWtdazXQOtMPdhMHOVOtmzdRcr27WTv24unrBRMiqjOPeh3zrlkrnibIWcmceltN9TZVsLEyQy7aiy2cOOew4fPPYs9Mpprpz7a3B9DiFPGznWHKcx11F3xBLSLt3P2yG611glM7Wk2m5k6dSovvPBCnW1XpOdcuXIlAAUFBdXqpKens3jxYubNm0dycrI/9efy5cuZOXMmy5Yta9gHq8XJdCmpxczYOIPFexbj1V5MysTNiTfz+IjHm6TtgsJiNn2/nbQdO8k7uA/tcqEsFmJ79qHf4EGMGD6U2Jho3C4XexLCiSvbDS8OgoIMiOkOo56EIeNCtl1xU1przZnJF2DxZXrSWrNx6XsMuOhSYjuf1iN8hTgp1ZTaE4yzgksuuYSnn36asWPHBm03ePDgOtNz1pX6szm0ucAwY+MMFu1e5C97tddfbmhwyDp6jE2bfmDfzp0UZR0CrxeT3U6nxIEMHDKI5PMGVbsGarFaGRibC+v+BK4yY2HBIVjxgPG+huAAxo3Nc8ZUJhY5duggGz9YREzHTsR27oLH7QIUZkub+98r2ri6vtk3p1CpPQH++te/Mm5c6L/nxMTEOtNz1pX6szm0uSPH4j2La1x+ooHhy3Xfs2nNFzhyjwJgiY6l5znJnHPeUIYMPAuzxRxyu8LcbA7t3EHi989irQgKFVxlsOaZWgNDVfE9ezHl1bcIi4gEIPWbr/nmvXe4bcbfaRdf/5y1QoiGGzFiBJMnT+a+++7zp/ZcvXo1AwcOxOEIfXkrMzOTDh06MHHiRGJjY3njjTdasss1anOBwVvDUzY1La/J3v2H+HrJIqxRMfQbeRnDkpPo26tb3aN2yovYvejvrF23ix59j2K1hqhTcAjcTrDY6t2fyNj2/vexnbvQ97zh/ktPu7/9hrCICHoNPbfe7QkhTkyo1J5fffUVJSUl7Nq1i/DwcK6++uqgY8SOHTuaLT1nY7S5wKBQIZ80VScwMtnpdLFk/gJMVht3T/sd8R1ia9/AUQhledD+DPC6GZb7Jr3G/452B34ygkBVJguYfRHj+E8Qe0blwPF66N7/bLr3P9tf/u7DxYRHt/MHBrfTicVW/6AjhKjb7NmzmTVrFpGRkf5lf/7znwF4++23iY+Pr/bF8corr+TKK6+s1lZxcTEAvXr1IiUlxb/87bff9r+vuq4ptblB6TUFgBMJDIveX0H5sRwuvu6GmoNC5fwIMPcSWPWIUQ5vj/r9D3S88SnjRrO1ypBTaziMfdF4ysjrgbevgQ9/W+++hXLrs89z5T2/B6C8tITX753Eji8+a1SbQgjDvn376N+/P2VlZdVSe1aYPHlytRvPJ7M2d8bgrWF+l5qWV7U9ZQ/7Nq2nfxcTl2/5X/gixGii9f+A3R/D/64yDvC/fAaiOgPw9YJ5RLWP47xrelTWX/NM6FFJWsPoZ/3b4iiAZb+FS/4Pugyt92e2WK3+y0oel4v+F/2ChN59ASjIPsKB7VsZOPJyrHbj0XqZCvzEyO+rbTsdU3u2ucDQGKVlDj569z0SzAX8j+djKCgxVhQcgmX3gscF50yAiDho39u4kWwNhwHGCCKtNccPH8LjclU2OmRczTeazRYY9KvKcu5eyPjeOJMAKDoK7jJo36venyEiJpZR/3uvv7x30wbWvvs2fc4bjtVuJ+Wrz1nz5mv+WV8rpgIH5GAXQsXU6fL7EqcTuZRUx/JA7y5Yiqswn+s7bMbmLQle6XXD508b78+ZADe+Vu0ykVKKG6c/xWWT7mpI16H7MHhwF3Q9xyhvfAX+OQxKGz6B2Hljb2Ty318juoNxRrFm3mu1TgWevnkTR/bt9a9L27CWrPTd/nLKV5+Tuafy29O2T1f6y1prvl+xlMO7UwHwejxsXLqIw2m7fPtxsn7Rv/1lp6OMrxfM85cdJcV88fbr/u1LCwtYPfdlMvcY5eLjx1j16ov+/RXmZPPR7L/5+5d3JJMPn5/h7/+xjJ9ZOuspjv60D4DsA/tZ/OxjZB/YD0DmnjT+88TD5B46CMChXTtY8OgfOHbYuC90YPtWVr32Uo2/r5L8PHIO/oSnmYYUCtFc2lxgGNcv9LfzmpZX2Pj9DjK2b6b70GF08x4IXamk+kypgVy+IWuqMfMNmS2Vs5wNnwI3zoGIDkZ55UPw9XMn1JxSig5dK8d+u8vLQ9armAp89dx/smPNp/7la954ldR1X/nLX8ybw55N6/3lL+fPZf/W7/zltQvmcfDHHwAjMKxf9G8yUlN8ZTcb//u+/0DudjrZ9ulKcg8d8Jd3rf2C/COZvnI56Zs3UuibodbtdHJo1w5KC42nR90uJ9k/7aPcdyPP43KRf/QIrnLj/4PH7aasqNA/iaH2evG43f5ps00mE5awMP+EeBarjcjY9pjMxjBkW3g4Xo+nxt/X3k0beOf/foejuAiAtPVfs/jZxygvLQUg99BB9m/9vsY2hGgtqqa5408Vw4YN05s3b653/aoPuFXo264vy24M/Wh5QWEx/5jxN0wWCw8+8X9EzBkWejRRTA94MPQogZyDP/HuEw9x/bQ/Bg0bXfbDYZ77dDeZ+WV0jQ3n4Sv7ccM5DXhIR2v44DfQrguMnmEs270K+lxS/QZ3Lebed0foqcDjOzLllbc4npmBLTyCqPZGMCrIPoLVHk5EuxgAio7nYrOH+5+pKC0swGoL89+/cJaV+ib5s/pyHXiMGU1P0cn5Zt91O+7C6mdslnYduGPm82Sl7yHx/AtRJhOp33zFts8+5pan/4IymVj37tts/mgZf1iwFGUysWHxu+zdtJ7bn3sZpRQHfvyBomM5DL5sNABulwuzxRI0c6swJtEbMGBAa3fjpBbqd6SU2qK1Hhaq/qn519gINT3gtq9wHzM2zgi5bsH8RXjKSrhx7IVEuAtqHk006smQ2wNYwsIYcPGl/pu+YASFR5fu4HB+GRo4nF/Go0t3sOyHBsw2rhTc9Cb88lmjnJ0G/xkPW942yvX8AjDylttRVZ6fUBYbI2+5HYAOXbv7gwJATEJnf1AAiO4Q7w8KABHtYvxBAcAWHoHZYvV12Xg6+2QLCoFflsqcHvJLnf5ydpGDA7mVlxHXxQzHW+VA7VWKDe3Pp13HBBJHXOT/fAMuvpRbn/mbv3ze2Bu5bcbz/nL7zl3o1v9s/4F/19ov2PhB5ZeYz+bMZv5DldOJ/fj5Kras/NBfLjqWi6OkuNGfX4iT6y+yBdT2IFuooPHF15vI2b2TM5OHM/Db3xlTVgwZB9f+wzhDQBk/r/1HrU8rt+/cldFTfhd0EH3u092UuYIvI5S5PPz541SyCiqfiD6QWxJ0cMorceLwbWckugk46FccpDr2g0krYMh4o7z3M5h7GeT/XGMfAXZHJbIm/hIKzVFooNAcxZr4S9gdlVjrdjVxe7wUlLlwe4zfe0m5m/05xZS7jf4fL3Hy/YHj/s9zOL+MVSlZlDmNcnp2EQs2HvSXtx/K5x9r9vrrb0jP5akPU/ztfbbzCPe/uxWP73eyZEsGt/1ro78/8775iWv/+Y2//OLqPVzyXGWO7ac+TGHYjM/95aeX72TMS+v85b98nMav523yl7vaDvPLznuJtjgATbTFwS8776WzJQOA38zfzK9e2+Cv/9h/dzB9yY+AETQXH9DMXWvc4xgw8jKKz7uez3YeAWDMvX9g0L1PsPuIcSmq77AR9P3FLykpNy59HfhxK/s2V362j//5PMv+9qy//NU7b7BpWeW/6cw9aeQfOW1nshdNqM0FBlNNGUwICBo/vg8vDqLsiTgKFj5M14hSxt3yP3D9y3DV34w6Q8YZl42ezjd+1hIUcn8+EPIPMjO/LERtyCkq5631B/zlUS98zRvrfgLA49Wc8+xqXv/auEFa7vbS57GPefWrdACKHC4GP/Up/954EHr/gjwdxUV/+YIN6TlgiySH9lw9ex3fffkhHN7C0YIybpn7LWv3GJeP/vJJKjvDz2R+z1/zcu97md/z1+wMP5MZK40bwKlZhVw1ex2bDxiXT7b+nMf5Mz9ny0Gj/M3eXM587GN/+avdOQz902fsyioEYO2eHC7/+9f85PvWvW5vDjfP+ZaMPON3sSE9l3sWbCW32LjX8f2BPB5flkJ+mREYtx3K54XVe/wHx73ZxSzblonTbfy/yykuZ1dmIS5fIPJ4vbg8Xn/wbB9ppUeHyrO9xE7RXNavMsnLyLM68tvzY6HY+H1cl9SVGeeVQKZxX2TiBWfw+tlpxmU64FHb+yTFZjHlrO+ZNuAbppz1PUmxWTxtWwDAmEGdeaDzTv/2seFWEvkJioyD/47DBezJyPGf0b2+dj/vbzYuU5rMZp789CAvfb4HgH4XXMwTe2J5ZOkOo29TH2N+7FU8s8L4fzP8+pvYHJPE2+uNfytFuTms3baPz1KyQGs+/ufzvDdnLimHjoPXw5IZf+TDt94iJ78YPC5Sv/6cjD270C4HuMvB5fC9yoyXsxScJZWv8mIoL6p8OQqNIdUVr7J848HOsjxjgETgq+SY75VrvIpzfK9s41V01PgdVbwKs6Aws/JVcNgY4l2QYQz8cDuNPtfr5Qh+uep6ldXjVWq8nHW9Sur/Ki+u++UOfU+wsdrccNWbE28OeY8BfEHjx/dhxQNoZxnb83pg8jq5JWwFtrTLT2j+okDr/jOf7IM/MeXleSiTibwSJ5+kHKFrbDiHQwSHuEgbN5/X3V9+/uYhnJUQ7S8/fe1AhvaI9fVZ8eAViQzvZVzesZhM3DysB2d1MuqbzYoRfeLQiUPg6omYisvpGhtO/50vwm433ls+w+sF7TUOtEcLy7nO9A3/Z3mfriqXTB3P39zjWFF8MQBhFhPdYsMJ880D1T7CxqWJCcSEG5eHurcPZ8ov+pAQbVw+6tc5mifGDqRzjFEe2iOWl8Yn0aWdcXC+oE8c/75zOF18668Y0ImPHxhJQjtjorDrh3ZhVGIH4sKB8mImDI1hQv9BmEv2gTeWSQNNTEoww94PodMgJpzhZoJOgw2boPeljE/wMP6MD2H5v+HsX3FjhIsbeRveKYdzJnINXq45/BK8piD5Tq7weiDlRdgTCUkTuMjrhh9fhz3tYOD1nOt1Q8o7sK89pK+mM6Hzc8dSCEuncDNAylLI6AVdk/g/gJ1LIasPdBnK6+HaWP/KWdBpEB918mDatxrm9IUOfVjSoZzIw1vgXz2hXVfejS4h9vA+mNcNIjrwki6g494cmJ9Ab1sUE525dPpuDuzvwLWdbcQWZtNt9ZewPYZr+nvZenA/9qXfQccowo87KDq6iaLCJcTHR/LpR6V0iHEycqCNXnERvPpJKZ06uLhwQBhd2tn5Js0JJgcDu9npEGmj1Kk5WlhGx+gwou0WPF7N8RIn0XYLdqsZr9aUu7zYLCbMNWZ3awKJ94W+51eDPduK+XZ1PsX5HqJizVzwy1gSk6Kar3/NKTwWLE2fpKjN3XxeuX8lj6x7JOS68f3G8/i370HBIY6URfFtbk8GxR7lrOhjtd5YrkvRsVzyj2TS4+whAMxdu4+/fJLG9Kv689LqvUGXk8KtZmb9z+CG3YA+EY4C45tXwgDj29bL50HyXTz/xUHud8/HriqftXBoK4vM1zLptonGMxReN2iP8dyG9hplr9u3zmW05ywBsw3wQslxKDsG0V2M7QozofAIJPQ3tju+H4qyjGG4Xjfk7IHiLOiWbNTP2Q0l2dDLNyXxkR+Nb519LjXKWduNz9P7F0Y58wdwFlfWz/oRPOXQPdko5+w2+p3guxmXf8iYciQ+EZTZ+IZqtkJsT2N6krI8448vMt4oez1gDgNrGKyfbey7KnssXO6blLEk15j3yu67jHh0J4R3gJhuxpnCvi+MZ1HizzLa3v4edB4CXYca3wg3/NP4bD1HGN8SVz8JZ99oDCwoy4dPH4WkCUadklz47I9w3mQ44yLjs6x+ApLvQvc4n4KcQ7T77iVMw+7A23kIe/ftpdfPS7ENvYk8cye2pu1nmP6BqAGj+XLjIQ6VObmyVwnteycz5+XluLp157rhHenZ8yzmvLSI7Pju/M8vhzCkRydWrfyGz/Nt/Hr0UIb1iCHtwFH+vu4Qvx3Vn+ReHThwrJRZH6fy28vPYmj3GH7OK+Ot9QeZMOIMzuwYSWaBg09SjnL14C50ibGTU+zkh0MFDO/VgdgIK4UOD5kFZfSKi8RuteD00eGLSgAAIABJREFUeHF7NQcc7RiYeGbof+dV7v/s+T6XL9/7Cber8pKyxWrislt6k5hcx4STIVJyVkhJ2cmU397PhrXGZcmtP2zj4UceY82nn9Ta1oEDBxkz9jpGDB/Oho0bST7vPO6YfDtP/elZsnNyWDj/bYYPT2bBwnf5x8uv4nQ6OX94Mq++/E8cDgfjbp1AxuHDQUl+QjnRm89t7oxh9tbZNa7zeD3GqSnwc0ksNpOHvlHHjJW+5Q0R1SGOrzKcZP10nOG9O3D7Bb24tF8CiZ2i6RRtb5pRSYG0Ng6M/tP8YigvrLIs4FV6HDSw60P+oHdgCQgKAP/f3nnHR1VlD/x737wpmfQOKYQuJQLSRBFBKbIiVkRXUSwsiqLu6ir6W9sqK5Z1ld1Vd11l1wLK6qKiIqBgAbFQpAcEQhKSkN7L1Hd/f7zJJJNGMQkl7/v55DNzy3vvvsnMOe+ee+45NuHmBvkRfFemC/vqQijN0Hdfmyz6tL7oZ+g9Hsx2KN4Ph7fC4OvAbIO8HfrGvFFzQLXpgjhrA3QfrQvgknSoyIFhN+vuuFLTFUz/qbogztmkH3PW9aCYoWCXLqz7TNIFeUUOeF0Qn6r3d9fo57WF62VF1fspJl/ZpJ9HMenJg3+Jl094sr7u1DBKrjkILn7u6GeYI25tvTyy0b6XUbfXv/d69M/JFg62MN1cEdtPV3rhifr/VjFBn0mImD5ElB2C6oOQeiVK18GcEbcbitdCzwuISh7BhG7fw5L/QNI8Jv5+Luz/At6+Csbeym8X34KW9hnq+9fjGLqCsTNuIdFeRtd1v6O4+zLyc0u4YXQqI7c9TGH8Ila9uYwrxo1h0MHXKUpewPrP1jKyawLdC9ZS0/8BMrKycCmF2Mv3w7DbyTpUw0cZnzG2rxtSJrB1bzG/X/c1S3snEdG9L9/uzGPOh1v47J6z6N81jJXbcrn7nZ9YPiMarCGU1bjIK3ewe/E++p+bQOLQGIrKHGx9+2cGnpdI0pAY1i8/FKAUADxujXUfZNFjVDLVFS6+XLSbIRO70f3MaGoqXASHH/mJfMDgoaQfzMCrWPREPQ88pCfqMdtaP1C1sn//Ad57730WDRyoJ+JZ+j7rv92gJ+J59s8sWLCApe8v49sNGzCbzdxxxx0sXvoewcHBJCQm8umKFUDzSX6Ol06nGPKq81psW7ZvGY+FJ+EuzSHPEUq34DL8M+DwpBaPawkpJV+/9To9R53HMytzGZ4SycgeUdjMJvr6TD2Xn5XYuiLwenSB7qrSbbjNCffGda5qaCZQIKALSGsoWEP01/BEXZD0vQisIahLb2j2MEV64YI/QHQvOPCVvrlu6l/1zyVjPex8Hyb8UZ/a5m6FrO9h2ExdSJZmQGmm/gRrUvX78Dj1J3AhYMy9gRcbMSuwPOjqwHLfSS1/Xh3NkcKatDcmFSKS68sWO/SZUF+2R8E5DRIjRiTDpX+rL8cPgFsbxM3qNgoezKwvdz8f7vsZgiJQTCaUHufAjcuxJQ5ieJ9QXamHPEd037O4/R/jIWczbM0jLKEHU+55gCRbCdbt6yhxe1E8Li7tZSJ82yr2/XwZG//5V+7+9TnEf/cs6RFDSXv3Hd64MInIlc9R3GUT0dn7+fq8NCLf+Q3aHwoY3j2Sr4d/R7c35sC8TAZ0DWXJmVtQa3UzkNmkEKtWI7z6epSmScyeaoRXN5PWurzUltc7cTTEUeWmpNpFdmG9V1d+hZPcvCrOCrMghKCw0klFrZtecfr1Sqtd1Li9JEYEoSgK/foP4NuNP1GYk0lKSgr9Uwfra2EeJ2PHjuWRRx5lyiWXoJoC1zmPlIhnzZo1bN68mREj9BlvbW0toZHRjPvVFaxYuYpZd/6WKy+/lIsnXtjKF+XY6FDFIISYDCwETMBrUsqnG7XfBDwH1Plr/l1K2aYByruYwzjsbl6zamjUjHuQgncfwysFyfYyveEIrqjNkVFUzeLPfyLsy8+J6dadd35zLgkRjVxcnVVQelAXnDUljQR9hd7urmn5IiYzWMPA4hPykSk+oV9XF1Jftobqdeag1p+Qw5Na3qOR5Jt1pl6h/9XRY4z+V0fCEP2vjsjugWE7bGEtX/9UpLWwJqc6qgVC4+vLwdG6CauOqJ5w9uz6cuIwSBxGENAvPkWvG3o5XYHrzvTlJp50B91qqrn2iWSikpJg0hwsGblEJ3fDNuxqGDSezN1pfPmfV+n35EPQtTtbv1jF+nff4je/uwERrpC5cxv5abs4u3cC+4SC5vUSpAqCrXDFzZEQp2cyjHA6Sb4xGLro8cZCIlSqypruRA+JshIeZCYysoxhNwZDbAyVDjf9IisRZVUQ2R2TAtGyBCorIbQrTo+G6iiBmiCwR3HmWcNZ/9Ua3nn7TVauWk1hlROPs5b/vPQXpk+fTnG1i/TCKv2hUAiySmrIKq72J945XF6LwyP95bJaN06XGyklM2fO5KFHn0AI8GiSqtJC4ilh+2dv8vHa73jikf9j3TcXseDJP7bNv71NznIUCCFMwEvARCAb2CiEWC6l3N2o61Ip5dz2Gsc9pWU8GEyLwvEDm8BjmUKkeQuRFocuEI/jCXBnbjmL06pY+thL9EsMR5Uu3QRSckB/yio5CFX59Qeo1kChHhLvK4fWC3V/OUwX+u2w6MT4R5s3jRyjYjQwaA2rPZjEM+pt3kkDokgakOor9WFwoofeI0YRFB0LYjSxu3cwaPwkbIOngriU3P+9w6ZPlnHuG+/Dnj1Ul5VSU15GXI9eiLCu1FSU43E6CYvpBlLD49JnCudc1oMvlxxotMYgOOeyXtjMJgiO8sciC7WZwW3TTZtAVLAVXNLvCdQl3KY/xNXWgj2KCePO45abbuTOW24gMTERp9vLV18sYUD3eBxqGHabSi8OQVkwRHYn2GKii5anr6uhW4At3hp9Rg1UO/X1vPHnjeSy6TO4bMZv6BUTRElRAeaqHIrMKlERYdw0bTKR4cG88s6KNvv/dOSMYSSwX0qZDiCEeBe4DGisGNqVKYWH+FCJ4fugpk/OipR8tGkRfcv60vuce1BmXt3CWZruWL5vYh+Kql3Ehdq4fGAEF8cWcf7l1YRlvw3b0wOVQHCM/qTV6wL9NaqnLvBPBk60acTAADCpKmEx9W7EyQPOJHnAmf7yOVf9mrMvn+7fDGgNDsZkNvvLmseD2+XUf+PCRFVpIW6ng77ndAfFzIYP9lFd5iYkyso5l/UiZVAYrtpaLPaogHEQ2iiHemRKYDmmfn/PgP79sdrszHtEf2q3mk18s3kP1TW17N67j6CgIKZNeFV3WgCiQ6xUWoOoW4lOiAhCFdKviJKj7JjwMqBnEvPnz+e2669Eumowqyov/Wke5ZVV3D//RRShYDar/PWpR47rs26ODvNKEkJMAyZLKWf5yjcAZzecHfhMSQuAQuBn4HdSyiZ2DSHEbGA2QLdu3YZlZmY27tIyj+ueIWenJFHTzI7bnvlWhmZEctmdLzBkYGqTdqjfsVzr9hKEgxRRQB+1gAG2Ys4KKWFUrJudWW52ZHq4bFwC9oQ+erTV6F766+lmSjEwOIEcTUgMt9OJ5vVitdsBqCwpRnq9hMXqyqckJxuEvrMfoPRwDopJJTxON6PVVJRjUlX/rn5N05ok3Zk7dy4jRoxoNidDXaKe48rJIKWu4KQErwtZsLvZkJ8SEHUBNhtxqnslfQy8I6V0CiFuA94AmqyoSClfBV4F3V31eC5U24IpKbIkiBqbZNaadyl+65xATyGvG0oz+XbF/7hOy6Snmke8qI+T4/BGMuqs0RDVEzW8Gpv8maDpT/wyrxcDA4NfjNkaaHYNjYoOKIfHxyMbRBAw22wIpT5ne3VZKRabza8YirOzsNiCCI+L58CBA/xq8mTOPfccv1LwuFwoqupXHjfddNPxD75OfggBqhVNmDFJd5NumjDTfJb5Y6cjFUMO0MB9giTqF5kBkFIWNyi+Bjzb5qMQJpBeuni8HDYH3r7VqRBfqVIRGk21spdoWyjdKgQ/ffApqTvdJMh8DuSXMdnhpEwJ5qDWle+0AWTIeDJlF6rcdi45fwoA/VKh35Q2H72BgUE7UBe/q46QyEDFEZPcLUBx2MMiMPkStvfs2ZNvv1iNLVS3BEgpKc7Owh4eQWh0DFJKyvJyCQoNxxYSgpQSV20NqsWKST12EWwKT6C2OJcqtxmvVDAJjRCzm6DohGM+V0t0pGLYCPQRQvRAVwjXAtc17CCE6CqlrIsdcSmQ1uajiO4DRXu4p7SMx2OicDSYDnYpsaIJuDD0O+zeCIqj05laHIzNa2VDRjJXTryYl7Kr+dkcT3qNlcYbXRJ9XkdleYcJi4tDUdpKfxsYGJxIhFAQDX7OwRERDdoEsSk9AoIvhsXFo/oUh9Q0NK+G9K0daF4vpYdzCYuJwx4ejtfjofRwDiFR0diCQ9C8XhzVVViD7JjMehTihhF1a70qFW6b/3peqVDhtoFX5ejjKLdOh8VKklJ6gLnAKnSB/18p5S4hxBNCiEt93e4WQuwSQmwD7gZuavOBFOtxZ6ZU1/B4UQnhHq8/Tk18iY2iEA/PJoTS11PFfhKYHxXH3aYreaz6KkJGzeQf/3cHd08dRVCj2UaQ2cT9F52BpnlZ+vg8Vr3S8kY6AwOD04864S2EICgkFLNV39ymmExEJyUT5JtRKIpCVEIS1mB9vQMpUc0W/4Okx+2morAAt8+Tyu10kn/wAM5a3XW9sqSYxmvDUkqqSoppKzp0jUFKuQJY0aju0QbvHwIeat9B1LupTamuYWFkBOVCYK81EVqrsje5Coei8L9wKzkHr8cS8yWWmLWEekYi5cUIIfwb0prbsax5vYybOZvgyMh2vQ0DA4NTE6EoWILqn+1NZjMRXeq9n8xWKzHduvsTQimKQlBomN/cpbWQEbAtMwWebIvPHU6eLxhcfKkVCRREOf310huKM/9i7DE/0q3nXv6x/R/MHDATu9ne4o5lxWTijHPO68hbMDAwOI0QQvjNUACqxUJYTH0cJ5OqNqsEjme9oiU6XdjtOtLKY3l13whu/CyFaWsT6ZETTKXdg8uszyhsHjsCSIwI5U8XzuHukTeyp3gPz258lpyq5hPp1FSUs+3zz/ypGw0MDAzampCo6CZZ/IQQhDTytPoldLoZgwT2lMey+nAfPNKEAEIcKsEOExRCSp6drf3KmXXNw0yZ1dCtKImkkCRe3/k6f974Z67rfx0juowIOHf6lo188dpLJJzRn9hu3TvwrgwMDDoLdWsVVSXFeD0eTKpKSFS0v74t6HSKIZ9Y1hV0xyMDPYaEz8MoxKFy7o4Yep5nh56Bx/aM6MkDIx5g0c5FvLHrDTIrMrm89+Woiv4xDhw7nvievQ2lYGBg0K4EhYa1qSJoTKdTDAtcV9PNs73VPopXsvrNf9N/zAVN2sKt4dx11l18uP9Dvjr0FVsLtpISlkJyaDJJoUkkxyc3c0YDAwODU4dOpxg2hU2kt7oVl6f1PQbuipIW21RFZVrfafSO6M3m/M0cqjxE5sqvQUrKhkcSagklOTTZ/5cUmkS0rald0KBjkVLilV40qflf6/789ZoXia+fph2xf8P30hfqvM6VUDYOfS7r6xq3SSmb9m+lrblr+N836Nr4eg3dHJsdi6RpXaMxtDSWgDpkU5fKZsbQWltz12vOTbOXuxcltSVNjjtejvf4XxJeqPE1p1w4hU/XfnrE4+yqnRBL22ef63SK4cUB+zDnHeTrvB5NzEkNqbZ5GPTGILoEd+GeofcwpWfTbcxD4oYwJE4PL/3JlueodlUT12cshyoPkV2VTVpJmv/LEqQGkRSqr1PUKYw4exymDt4EVyccpZR4pKdesPmEYIAgPEbB2KKw9V2vofDVpIaGdlTXaHL8MQr1ur9fKjAMmiIabvIUgXUN2/w+/s3UNXfO5vr7y40OSw5NpsbTssNH43O00OmXHX/E07d6gSYsX7Mcr/Qe8drt9Z3udIphxIG/kSY8KFID2cApq8GX1KNobO5bikRyuPowj294HKBZ5VDHJXPvR2oaosFOarfXTW51LocqD+nKojKb9TnrcWt6nBOzYiYxJJGk0CRsqs0v5LyaN0CoeTQPEolH8wT08b9vIBgbCs+WhPuJxCRMKEJBEYr+XtFfBQKTYqqv9/VpWDYJE6qiBpRb6qcoCgq++gbnFUIc3fGN6lq6Rt3YFaG0KvwC6hABbQ1pTSA28URpRmg0PL6l/q0J8+bGdzTC/ESSlpZGUuixJ9JqS3bu3Mns2bPZsGEDAFu2bOH+++9nzZo1rR5XXV3N9OnTyc7ODkjPGRISQlVVFRkZGUyePJlRo0axYcMGRowYwc0338xjjz1GQUEBixcvZuTIkW1+P51OMaRlOViZ2xcNpV5TS4nq8eJRFapskmqLi3N3RXP+9hiqbV42n1HKQtvCFhWD2+HwBd0K9P41m8ykhKWQElYfqterecmvySe7MtuvMDbnb8atuVGEgipUv8BpLIjqBJwqVP1VUbEq1oA6f3/F1OQcqqLqPtIN+jYWxs3VNSc0j0eon4xCxeD0YvualZTnt5yl8XgIj+/CoPGTW+0zYMAA0tPT8Xq9emrPe+/VU3segZUrV5KQkMCnn+pmo+bSc+7fv5/33nuPRYsW6ak/lyxh/fr1eurPp57iww8/PL4ba4VOpxjW5vfWlUJDhEATgkv3/cx9V0UxZkcMiqz3Uhq9I5oNlFDrqSWnModeEb1YcXAFC7cspLKokCu+SSB5+iR+ffk9R7y+STGREJJAQkgCI7u2vaY3MDDoeBRFYeDAgezatYt9+/aRkpLC0KFD+eqrr3jkkUcYOHAg1157LePGjQs47swzz+S+++5j3rx5XHLJJYwZM6bJuY+U+rM96HSKodarNmu10xRBpiWckfvrlUIdqqYwYl80G3I38Nsvf8vsQbN5c9ebOLwO7JjYm1TJioIlhKX3btXcZGBg0L4c6cm+PRk1ahTffvstL7/8MitXrgR8G89CQnA4HCQlNTV39e3bly1btrBixQoefvhhxo8fz6OPBmZLtDYIGa4oir+sKAqeNgyD0ZBOpxhaRAj2do0mqKZ5c0dQjWBw7GAeGfYHXtuziLEbICUvAZeqYvF4iKyqZWFUy+Ymg9OX8o8/puCFF/EcPozatStxv/st4VOnnuhhGXQwo0aN4qabbuLOO+8kMVEPlzNmzBjGjh1Lfn4+9957L4sXLw44Jjc3l6ioKGbMmEFERASvvdamKe6Pm06nGJyKFZvmbLbNYVYJjYmlsqiwSVtoTCx2t5nDz7zHKLODyMpYXGbdJOUym0ksjIW1haRPTKdneM8mxxucnpR//DGHH3kU6XAA4MnN5fAj+hOfoRw6F/369cNqtTJv3jx/XV2insjISJzOpnJnx44d3H///SiKgtls5pVXXumw8bZG54uV1HOIP8x2s81njUC1BGZ7Ui1Wxlx7I1LTGDzpYmLK7WiNFpo1RSElL4pXt7/aLsM2aH+8VdV4Kyr85ap166jdsdNfLnj+L1R89pm/fPCaa8h7cr5fKdQhHQ4KXniB9Msup/TdpXqdx0P2XXdR8fnnAGguF/nPPkfNpk162emk9N13ce7f72+v3rABd0GBfrzbjSs7B622Vi93UEpeg6Nn4cKFLFiwgODgYH/dsmXLuO2227jhhhuYO3duk2Muuugitm/fztatW9m4cSPDh+uZNquqqgDo3r07O3fWfwf/85//MG3atGbb2pJOpxiUA5tbTrUpBOk/bWTS7LmExsSCEITGxDJp9lz6j7mA4IhIxt1wK25T83sPXKrK3b1vxVNayuGqw1z/6fXsLt7djndj0BCtthZPaam/XLNpE9U//ugvFy/6N6XvvOMvZ991N3lPPeUvH7ziCvLmz/eXDz/2GKVLlvjLFatXBSgKS3I3tAaKpCGew3lYuiVjCgsFfII9MwvN53Uia2spXbIER9oeALzl5eQ9/ke/ovAWFpJ1y61Uf/MNAO7cXA5MmEDl6tUAuA4cIG1gKhUrVwHg3L+fA5N/RfX33+vl9HSybruN2p279P6ZmeTN/xMu32KlOyeHkjff8iseT1ERlV99hbeyUr9+VRXO9INovpwA0uNBtpM9+1TnwIED9OvXj9ra2ib5nq+88kr++c9/snTp0iYLzycz4lR/8hg+fLjc5PsxHQ1/vuaS1reMSMmsG25v1Qzw8pWTqTU3tcIFeTWmT76SwhdexPnOizyd9lf+PPxJ4kO7UlxVQBBmbFiQHjd4PEi3W//BuT0BeSKQjXaNSnyzHBnQp27mIxu8r+8iA2dGDc/ZsK+/T+O2I+9ubUJzXZoc1/J5pNuN5nRi8j1xubJz0CorsfXvB1JSs2kT3rJyQieMB6B8+XK85RVE3TADgKJ/vYZ0u4mZczsAxf/UZ2/Rs2fr5ddfRwkKIvI6PXFgxSefoISEEDJ2LAA1W7ZgCg3F2rs3AO78fJSgIL9wb47sp5/CVNl0c5U31E7SvKNPLSI1Da2qCmG1olitSLcbd04OpuhoTKGhaA4Hjl27sXTvjhodhbeykprvf8A26EzM8fG4i4up+vwLgsechzkhAffhw5R/9BFhU6ZgSU7GlZFB6eIlRN4wA0u3bjh//pnSt94m6rbZWJKScOxOo+ydd4ieMwdzQldqd+yk/L//JXruXMzxcdRu3Ub5//5HzG/vQY2OpnbHDipXf070b2ZhCgvDkZZGzfc/EHHNdBS7Hef+/Th27yZ08mQUiwXXoUO4MzOxjxqFUFU8BQV4ioqw9uuHUBS8FRVoNbWYu8T7vwtIibBYjvjZ5fbowRk9O6f5VrHZUOz2I/ZLS0ujf//+AXVCiM1SyuHN9e90iuH56VNanjEANpeb8QcL6PrkE37lID0ePMUluAsL0EpK2PrmIjaWFwSYkxRNYyhWUoLC8JaUYElKQgLOvXvRKivJ7GGnzFXBqK5nB2wYcufn40pPRzqdCKsVS8+emOPjj/2DaEOOd0xS05AeD4rvx6xVV6NVV6PGxQH6U6m3tBRrnz4AuLKy8BQVYR86FITAsWcP3uJigkePBsCRloa3tJTgc8/Vy3v2oFVXY/dNt12ZmUi3238+T2EhSA3VN1atpgaEQAkKTHjYdD9FfVkCmvQCApNQkEiq3FVYTFasJiua1CisLSTEHEKwJYQdO9eSnOvG1OBn5BWQlaAyKHU8Xs1DYW0h4dYIgtQgvJqHclc5IeYQLCYrmvRS66nFarKhKqp/I6IqTAhxjBP6Y9gnIjUNPB5QVYSi6Eq5uholNBRhMqHV1uItLUWNi0OoKt7KSjz5+VhSUhBmM56SEtzZ2dj690eYzbjz83AdzMA+fDjCrOLKysK1bz/BY89HqCrO/Qdw7dtHyEWTEIqCc98+XPsPEDL5IoQQOPfuxXUwg9DJFwHgSNuD+9AhQidNBPTfkSe/gODzdXdO54EDaGXlBA0bSum0afSN74LUNJQgPWuadLtB0xA+Dx7p8eiKpi7dpterf2R1s/86OXiK7LWRLheawwlSQ5jNqPHxqA3SjTbmWBVDp1t8bhUpOeNwCdLhIP9PT+Hctx9PYSGekhJc+/bpQjIlhRRbCJrDyc6aMmpVhSCvxuCE7gwcNxFhVhGqCmYzwqRSs2ULWnk5CWNTwVmAtvg7LD168NV5YZyVDtqG9SgufYounU5qD+wnYvrVhE2apH9Jm4m73qAQ2MffJuqLrfSXbjeaw4HJbtd//DU1lC5dSsXLL6E43QFjirppJuakJCo+/pjY++7DFBxM+cefUPzPf5Ly36WYgoMp/te/KPzLC/Td+hOK1UrRy69Q9Le/0W/puwizmaJXXqFkyRKSXn4JoSiULfuA6u++I/G5ZwGo/v4HXIeyiLz6akA3d0i3G5IT8EovQaou4NPL0zErZnqF6gEL12WvI9wazqDYQQAsSVtCUmgS5yedD8CCHxaQGpPK1F66op+9ejbjksdxXX995jDx/Ylcc8Y1zDpzFl7Ny5C3hnDnkDu5ffDtODwOLl48gnuG3sOsM2dR6apkyjvn8vvhv2fmwJlc/MYgzt0luO4rSXQFFIfBknGCbwfCjpkvklmRyc0fXMJT5z3F1F5TOVB2gOs/upznxj7H5O6TSStOY/on03nxghcZ32082wu3c/2K63l5/MuMSRrDlvwtzFo9i1cmvMLZXc9mS/4W5q2bxwvjXiA1JpUt+Vt4buNzPDn6SXpH9mZrwVZe3/E680bOIyk0iZ1FO3n/5/e5c8idxNpjSStOY+2htczoP4Nwazj7S/ezKX8Tl/a6FLvZTlZFFntLf2ZM0hisJit51XnkVeeRGpOKqqiUO8upcFXQLSQRRSi4vC48mocgNajVDYzS60U6HCi+2aCnuBhPYSG2fv0A3RTmyswkdLw+G6z+4Uece/cSdeMNAJR/8imO3buJf+B+AIr//R8cO3aQ+JfnqUxLQwm2o9U6sCTr3wlXVhbS6awv+x4i6srOjAzwerF0766XDx4EKbH6Zh7OjAw901q3bvrxhw4hVBVzVz3TmvvwYV0gx8To91NYhLCYMYWH6+WyMoTZ7J/9equrEaqK4lNUmsuFMJnqFdMx4Ckrw52T67cy6LPLXIBWlcOx0KGKQQgxGVgImIDXpJRPN2q3Am8Cw4Bi4BopZUZHjU/RJIll+qKPt6yM4ldfRQkLI/Tii5EOB+akJOJ+fx+miAiSheD8ozhn6IV6hNauwEApydtUjDsxloUlb/D3xW5CXIF2W8XlJudvL2CbdhlqZS3lb71N8KSJ2M44A09ePsUvv0zENdcSlDoQV0YG+c88S8yc2wkaNAjH3r0cfvgRujz8B4IGD6bmp5/Iufc+Ev/yPPazzqJq/bdkz5lDyttvETR4MJXr15N951x6LPsftgEDqFm7lqIXXmyy8KS43GQ9/zQpv3+IylWrifjNLFw2E2pkBNY+fShNk3/NAAARG0lEQVSoPEytRyFh9GiUkBB2Fu2gWrgZOf1qwiZfxOeH1lDtreWKOXOImTOHN3a9gcvr4jdX/oaIK6/gqR+eQhEKD456kOBRZ3PHF3cQYgnh2fN1hXHl8itJDklm4YV6Hu171t5D38i+PD/ueQCe+uEpBscN9iuGRTsXcU7COX7FsDl/c0CgMYvJgqlBZvdxSePoEd4D0Dcg3jfsPn8MLKvJyovjXqR3pG5eCjYHs+zSZcTZ9VlQl+AufDvwMN8ODPzMugR3ASAhOIHlly8nJkgXIF2Du7LookV+z7WEkASeO/85BkYP9LfPGzGPXhG9AIi1x3LjgBtJCE7Qv0+WUEZ1HUWYRQ+5rCoqEbYIzCb9SdjhdZBXk4dX6k/E+dX5fJ39Nbem3grA3tK9/GPbP7ii9xWEW8PZUrCFP/3wJyakTMButrMuZx1P//g0665Zh9VkZeXBlTy/+Xl+uO4HVEXlvZ/fY+GWhWyZsQXFpPDajtd4ZdsrbL9Rj1j895/+zrt732X9tesB+Nf2f7E6czXvTX0PERzMG7ve4IfDP/DyhJdRo6NZumcpaSVpPH7u41h79+aj/R+RXZXNnWffSfDZI/k883NKaku45pJrCL9kChtyNlDjqWHCzTcBsK1wG3jxC2ynR/f8qVMAbs2NQGBOSEBKiSY1vRwXH2AeVaOjA8yeppAQaGAREKoKDYS49K291OEpK9XNjnWKIS8fJTTErxjcWYdQwsOwJOj/R9f+A5giI/zjduzejSk62j8zd+zbhxoVhRodjZQSV1YWakQEpvBwPPn5gaZnAKnhyc9vM8XQYaYkIYQJ+BmYCGQDG4FfSyl3N+hzBzBISnm7EOJa4Aop5TWtnbfNTElSMjirwK8YAsZus9HliT8ScemlR32dI1HuLCdn8Khm1zskcM1DKh8Pf5Xaq24h577p/M6yjM+GvUbtnPvZf9tE/iA/YMWwf1H78FPsum4kT7k+4uNh/6D6+b+z5dIzeLH6Y5YPfYWqf7/Nd+Pi+FflZyw76yWqPlzO18MsLCn7gqVD/0rVl1+yuncNn5St599nPce+Cy5sfgMgMHBPGgB/WP8HNuVtYtU0feHzga8fYHfJbj654hMA7v3qXtLL0vnwcn2r/l1r7iKvJo/3pr6n9//mARweB3+98K8APPPjMwgheGDEAwC8tuM1bCYbMwboawcf7f+IEHMI41P0p8nvcr8j1BJKakwqAAfLDxJsDvYLa6fXiVkxoxyrKeY4+DT9Ux7f8DgOb71nks1k4/FzHz9p97TU/eaFEDi9TqpcVURYIzApJsocZeTX5NM7ojcmxURuVS4Z5Rmc3fVsTIqJfaX7SCtJY2rPqQgh+KngJ7YWbOXm1JsB+Cb7Gzblb+LeYfcC8PGBj9mcv5nHz30cgMVpi9mUt4kXLngB0BXJ1oKtvHaR7r8///v57CjawdJLdG+ue7+6lwNlB/jo8o8AuGvtXeRV13+Xbv/idq6Pup4xQ3UTU0Z5BhLpV/QHyw8iEHQP7w5Aelk6JsXkD1NzsPwgZsXsj7WUWZGJ1WT1K/bsymysJiuxdj21Zm5VLjbVRpQtCtAVb5AaRJhVV9RFtUXYTDaChRWEoNxThVW1YnFJhMlEtXDpDyYVNQiLFZdVYFbMyMJiFLsdzW5DEQrenFyUsDBMYWEgJa70g5iiIlGjoqhtxRMpKDW12fqTdo1BCHEO8LiU8iJf+SEAKeWCBn1W+fp8J4RQgTwgVrYyyLZUDBdvT2/xODUhgT5rWw+Idax8M7I/sc04tRSGwYFFD3BlnysJs4Sxp2QPX2V/xYz+Mwi1hLKtcBtfZn3J7EGzsZvtbMzbyNqstdwz9B5sqo0NORv4IusLHhr5EGaTmbVZa1mTtYYnRz+JIhQ+O/gZa7LW8Oexfwbgg30f8E32N7xwwQutjun8H3XF8E32N+RV5zH9jOkA7CjcQaW7knMT9LWAnKocvJqXbmH6NNzpdfoD4J2OfJr+KQu3LCSvOq/VaLwGx05dFGCzos+Iyp3luDW3fwaWVZFF2aEyBg3UZ4s1bt0RwG7WF2QrXbqXVahFdyAodZSiCIVwq/5kX1hTiEkx+QX94erDWBQL0UF6msxDlYewmWx+xXCw/CB21U58sP5k/3Ppz4RZwvyKJK04jUhbpL+8u3g30bZo4oP1Gcru4t3E2mOJs8ehSY204jTi7HHE2mPxal72lOwhPjiemKAYPJqHvSV76RLcheigaNyamwNlB0jM96B6m35WXpMgpP/Apg2c3IphGjBZSjnLV74BOFtKObdBn52+Ptm+8gFfn6JG55oNzAbo1q3bsMzMzKMeR2uK4Vfb01v2WBKC/mlt63r60MOjmf5hCbYG1iSHCv+9PIoF879t02udymMyMGiN5oTeiaIuenHdbNXldfkDWEopqfXUYlbMmE1mpJRUuiqxmqxYVd2xocxZRpAa5HNU8FLsKCbEHILdbMejeSioKcBdVkJsOYiGTocCCsMhJaltZgyn5D4GKeWrUsrhUsrhsbGxx3SsWWteEapeL4nPPYvqswE2affZAtuS8275P/59iZXCMN1UUxgG/77Eynm3/F+bX+tUHpOBwalCXVThOiwmi3+mLITAbrb714OEEIRZw7CqVv+xUbYov5OFSTERZ4/zz35URSUhJAGn3UJhONTlGvOYdKXgtB/Ztfdo6ci5fQ7QMO9lkq+uuT7ZPlNSOPoidJsx+vwJfLXui4CFJTSN88ZO8runNgxxAPoaQ9zvftuWwwB8+R1mw/zhJ48Z4mQck4FBW5K27kvWvfsmlcVFhEbHMObaG5tN43uyEhccR67MpcpW/5ArhCAhOK7NrtGRM4aNQB8hRA8hhAW4FljeqM9yoG7r4DRgbWvrC8fDsLvvZdyYCQR5NZCSIK/GuDETGHa3vlgWPnUqXZ98Qp85CIGakBCwp6GtmdJzCqunrWb7zO2snrb6pBDAJ+OYDAzagrR1X7L61b/r8dCkpLKokNWv/p20dV/+ovPu3LmTc337bUBP1DPe53rbGhkZGfTr14+bbrqJvn37cv311/PFF18wevRo+vTpw4++nftvv/02I0eOZMiQIcy7ex7xQfG4a93M+fUcrhp3FVedfxWrPlz1i+6hIR02Y5BSeoQQc4FV6O6qi6SUu4QQTwCbpJTLgdeBt4QQ+4ESdOXR5gy7+16/ImiO8KlTjQBoBganKEv/+CADx04gddwEvB4P7//pYc688CIGjLmAde+8gccVGMzO43Ly5Rv/ov+YC6ipKOfjFxYw/JIr6DXsbKrLSgmOiDziNY83UQ8cORHPggULWLp0Kd9++y1ms5k77riDT9//lODgYM7ofgbffK6HTWkuyc/x0qFuIlLKFcCKRnWPNnjvAK7uyDEZGBh0HiqLm7dM11Y2H/PqaDneRD1w5EQ8a9asYfPmzYwYMUIfa20tcXFxXHfddUdM8nO8nJ7+gwYGBp2Wax6r3zdrUtWAcmhMTIth9QHsYeEB/Y9mtlDH8STqgSMn4pFSMnPmTBYsWNDk2CMl+TleTkmvJAMDA4PjYcy1N7YYVv+XMmrUKB5++GGuuOKKgEQ9n332Gc888wyPPfbYcZ13/PjxvP/++xT4IuGWlJSQmZlJbm4udrudGTNmcP/997Nly5ZffA91GDMGAwODTkOd91F7eCUdT6Keo2HAgAHMnz+fSZMmoWkaZrOZl156ifLy8nZL8tPpoqsaGBicXpwsG9zmzp3LiBEjAnIyLFu2jFWrVlFWVsacOXNOWE6Gk3bnc3shhCgEjn7rcyAxQNERe51eGPfcOeg09/z555+f2aVLF4/X61VNJlOHZxPKysoSd9xxh23IkCHe+fPnu458RNtxtPecl5enTpw4cUej6hQpZbM7hE95U1JLN3Y0CCE2taQxT1eMe+4cdKZ73rZtW0ZqamrRzp07+6empqZ19PVTU1PJ8GXG62iO9p69Xm/MsXwfjMVnAwMDA4MADMVgYGBgYBBAZ1cMr57oAZwAjHvuHHSme9Y0TRMxMTFNNyic5hzNPWuaJtBjYh41p/zis4GBQedm27Zty7t06TIgNja2XFEUQ6A1QNM0UVhYGJ6Xl7d78ODBR51p7JRffDYwMOjceDyeWXl5ea/l5eWlYlhBGqMBOz0ez6xjOciYMRgYGBgYBNBptasQYrIQYq8QYr8Q4sETPZ72RgiRLIT4UgixWwixSwhxz4keU0cghDAJIX4SQnxyosfSUQghIoQQ7wsh9ggh0nxpdU9bhBC/832ndwoh3hFC2E70mNoDIcQiIUSBL9NlXV2UEOJzIcQ+3+vRB3dqhU6pGIQQJuAl4FfAAODXQogBJ3ZU7Y4HuE9KOQAYBdzZCe4Z4B6gw33bTzALgZVSyn7AYE7j+xdCJAJ3A8OllKnoIf3bJVz/ScB/gMmN6h4E1kgp+wBrfOVfTKdUDMBIYL+UMl1K6QLeBS47wWNqV6SUh6WUW3zvK9GFReKJHVX7IoRIAqYAr53osXQUQohw4Hz03CZIKV1SyrITO6p2RwWCfFkf7UDuCR5PuyCl/AY9T01DLgPe8L1/A7i8La7VWRVDInCoQTmb01xINkQI0R04C/jhxI6k3XkReIBjdNU7xekBFAL/9pnQXhNCBJ/oQbUXUsoc4M9AFnAYKJdSrj6xo+pQ4qWUh33v84D4tjhpZ1UMnRYhRAjwP+C3Uspflp3kJEYIcQlQIKXcfKLH0sGowFDgFSnlWUA1bWReOBnx2dQvQ1eICUCwEGLGiR3VicGXBrlNvIk6q2LIAZIblJN8dac1QggzulJYLKVcdqLH086MBi4VQmSgmwovFEK8fWKH1CFkA9lSyrrZ4PvoiuJ0ZQJwUEpZKKV0A8uAc49wzOlEvhCiK4DvtaAtTtpZFcNGoI8QoocQwoK+WLX8BI+pXRFCCHS7c5qU8uiS0Z7CSCkfklImSSm7o/9/10opT/snSSllHnBICHGGr2o8sPsEDqm9yQJGCSHsvu/4eE7jxfZmWA7UxfmeCXzUFiftlBvcpJQeIcRcYBW6F8MiKeWuEzys9mY0cAOwQwix1Vf3f7483AanF3cBi30PPenAzSd4PO2GlPIHIcT7wBZ0z7ufOE3DgQgh3gHGATFCiGzgMeBp4L9CiFvR0w9Mb5NrGRvcDAwMDAwa0llNSQYGBgYGLWAoBgMDAwODAAzFYGBgYGAQgKEYDAwMDAwCMBSDgYGBgUEAhmIwMDAwMAjAUAwGBgYGBgEYisHA4DgRQiQJIa5poS1ICPG1L8R7c+0WIcQ3voigBgYnFYZiMDA4fsbTchyiW4BlUkpvc42+cO9rgGYVi4HBicRQDAYGx4EQ4jzgL8A0IcRWIUTPRl2uxxe3RggRLIT4VAixzZdlrE4ZfOjrZ2BwUmFMYw0MjgMp5XohxEbg91LKnQ3bfDGKekopM3xVk4FcKeUUX3u4r34nMKKDhmxgcNQYMwYDg+PnDGBPM/UxQMOsaTuAiUKIZ4QQY6SU5QA+M5NLCBHa/kM1MDh6DMVgYHAcCCFi0LOFeZpprgX8CemllD+jr0XsAOYLIR5t0NcKONpzrAYGx4phSjIwOD6600JuYSllqRDCJISwSSkdQogEoERK+bYQogyYBSCEiAaKfAlmDAxOGowZg4HB8bEHPS7+TiFEcxnDVgPn+d6fCfzoy4PxGDDfV38B8Gm7j9TA4Bgx8jEYGLQDQoihwO+klDe00mcZ8KDP1GRgcNJgzBgMDNoBKeUW4MvWNrgBHxpKweBkxJgxGBgYGBgEYMwYDAwMDAwCMBSDgYGBgUEAhmIwMDAwMAjAUAwGBgYGBgEYisHAwMDAIABDMRgYGBgYBPD/iw27i2IWANYAAAAASUVORK5CYII=\n" }, "metadata": { "needs_background": "light" @@ -681,10 +499,8 @@ }, { "data": { - "image/png": "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Q+d4Uvhw+F46x3Lg1VGnLV/zhF+cQdPnX+gzdp3D4kCBajrHLltXLmflm6/iqq0hMS2dsdOv+FkVojclJ7erG+a+dC0bPqrS7/fZMk7cuoV+ny0j+957Y2Rd2escCo4pU8i+/6+YcnJACEw5OfrK8Bhn68rlLHn+GVw11SAlrppqljz/DFtXLj944wOwadMmrSwhwNq1axk/fvxB2xUVFTFgwABmzpxJ//79ueyyy/j0008ZM2YM/fr147vv1CI9r732GiNHjmTYsGFce+21hEIh3G43kydPZujQoRQUFPDWW2/9pHdoocspfB2d9mLfyYOu7Duft/5yO5tWqF5KoWCQt/5yO1vCCn3lf18h6I+tSx30+1j+ygsANDc6eesvt/PjGjX1tLuh7TrP+zJw4EAKCwsJhZ1C/vd//5dHH330IK1Udu3axU033cS2bdvYtm0bb7zxBl9++SWPPfYYDz74IFu3buWtt97iq6++Yv369RiNRl5//XU++eQTcnJy2LBhA5s2beLcc889pOcdDF3h6+jodAlctbVtHve4Gts8fqgYDAYGDRrE5s2beffdd+nRowfDhw9nxYoVjB07lt///vesWLGizba9evVi8ODB2j3Gjx+PEILBgwdTVFTEsmXLWLNmDSNGjGDYsGEsW7aMwsJCBg8ezNKlS7nttttYuXIlDoejzfsfLl3Khq+jo9O1ueTeSIS10WSKkRPT01Vzzj601LO2Jzliro9PTml17f449dRT+eqrr5g7dy6ffKIWuxFCkJCQgNfrJS8vr812Vmuk3KPBYNBkg8FAMBhESsmVV17JQw891Krt2rVr+eijj7jrrrsYP34899xzT6trDhd9hq+jo9MlGDv9CkwWa8wxk8XK2OlX/OR7n3rqqdx1111ceOGF5Obmqs8bO5aPP/6YRx55hHvvvfeI7jt+/HjeeecdqsJxG3V1dRQXF1NWVobdbmfGjBnccsstrN2njseRos/wdXR0ugQt3jhHw0tnwIABWK1WbrvtNu2YIRysl5KSgs/n21/TAzJw4EAeeOABJk6ciKIomM1mnn32WZxOJ7fccotWPOW55577ye8AXcwPX0dHp2txrPjhd5UCKMe0whdCVAPFR9g8Hahpx+78HNDfuetzXL3v0qVLB2dkZGA0GttONHOU2bNnj7juuutsw4YNCz3wwAP+jnpuKBQy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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAEZCAYAAACU3p4jAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAgAElEQVR4nOzdeXhU1fnA8e+ZLZM9hBDCvodFQKQE445iEcUFrFWrKFj3YtVC+aktWrUUq1iXtrhVsVpQEVQEUVwQFQFR2ZcECHtIIITsy+zn98edTPZkCFkgeT/PM8/MueuZSea955575r5Ka40QQojWz9TSFRBCCNE8JOALIUQbIQFfCCHaCAn4QgjRRkjAF0KINkICvhBCtBES8IWog1JqslLq+wrlIqVU7zqW366UGtUslRPiBEnAF6clpdRNSqmf/QE4Uyn1mVLq/Kber9Y6Qmu911+H/yqlZlaZf4bW+pvG3q9S6hml1CGlVIFS6oBS6k+NvQ/R+knAF6cdpdRU4AVgFtAR6A68BFzTkvVqYm8AA7TWUcC5wM1KqWtbuE7iNCMBX5xWlFLRwJPAFK31h1rrYq21W2u9VGs93b9MiFLqBaVUhv/xglIqxD9vlFIqXSk1TSmV5T87uK3C9tsrpZb4W9I/An2q7F8rpfoqpe4Cbgb+z3+WsdQ/f79S6tKTrUdVWuudWuviCpN8QN9G+EhFGyIBX5xuzgHswEd1LPNnIBkYBpwJjARmVJifAEQDXYDbgTlKqXb+eXMAB9AJ+K3/UY3W+jVgPvCMv5vnqkauRzVKqYeVUkVAOhAOvFPbskLURAK+ON20B7K11p46lrkZeFJrnaW1PgY8AdxSYb7bP9+ttf4UKAL6K6XMwK+Ax/xnDtuAt06irg2qR20b01r/HYgEhgP/A/JPom6iDZKAL043x4E4pZSljmU6AwcqlA/4pwW2UeWAUQJEAB0AC3CoyroN1dB61EobNgKlGAcQIYImAV+cbtYCTmB8HctkAD0qlLv7p9XnGOABulVZtzb13Wq2ofUIhoUq1xeEqI8EfHFa0VrnA49h9HePV0qFKaWsSqnLlVLP+Bd7F5ihlOqglIrzLz8viG17gQ+Bx/3bHQRMqmOVo0CtY/IbWo+qlFImpdTdSql2yjASmAKsONFtibZNAr447Wit/wFMxbgAegyjC+Y+YLF/kZnAz8AWYCuwwT8tGPdhdKscAf4LvFnHsm8Ag5RSeUqpxTXMP5l6VDUB2AMUYhw0/uV/CBE0JQlQhBCibZAWvhBCtBES8IUQoo2QgC+EEG2EBHwhhGgj6vrxSouLi4vTPXv2bOlqCCHEaWP9+vXZWusONc07pQN+z549+fnnn1u6GkIIcdpQStX663Dp0hFCiDZCAr4QQrQREvCFEKKNOKX78IUQbZvb7SY9PR2Hw9HSVTnl2O12unbtitVqDXodCfhCiFNWeno6kZGR9OzZE6VUS1fnlKG15vjx46Snp9OrV6+g15OA30R2rTvC2o/3UJTjJCI2hHOu6UPi2QktXS0hTisOh0OCfQ2UUrRv355jx46d0HptLuA3RyDete4IK+en4nH5ACjKcbJyfiqABH0hTpAE+5o15HNpUwG/uQLx2o/3BPZRxuPy8d2CXfQ6qwNWm5mC46UUZDvo1Dcas9mEo9iN2+klIiYEZVJorRv9H13OOoRo29rUKJ3aAvHaj/ec9LZzMov5bsEuSgpcFOU4a1zGWeLB69//nvXH+Pj5jXjdRnn7qsO8/ac1eL1G+adl+3l5ykq0z7h99cYvD/Luk+sC29q+6jDLX90aKO/++ShrF5e/j0M7ctixujy50s+f7uPr/6UE6laU4+TreansWnfkpN+7EOL00KZa+LUF4orT62oFa63x+TRms4ncI8V8M38nyeP70KlPNM4SDylrMun7i3giYkNq3Fd4TAghYcZH3i+pI/E9I7HYzAD0GBxHaKQNs8U4BnfqG81ZY7qjTMq/ro0O3SID23I7vZQWuQPlrP0F7NuczTnjjax3u346QnpqLoPOM1Korl9+AK+ncu4Dr9s42CWencDK+amUFri44t6hgHGA0T7N8MuMDH0Hth/HZFZ0GxBrfGa5Tiw2E/bw4EcInE601mifRmvjdeWZlZ6qJTqsNcdE1fUqr1TxqY51a65LXevWW59qs8sn1LvNWufXvsPAvCDq6/P68Li9dS4fjBNatVFShNS9kfrSkCgF1pDGD89tKuDXFogjYkMAWPbSZg5uz8HnNf4aZa1ggC4D2vHuE+s4Z0IfzrigC/ZwK15P+T9jx15R3Pn8hZhMinOu6VOp6wjAYjNx7oQ+gQAe0S6EiHYhgflxXSOI61qev7rbgNhAcAVITEogMam8+2XYpd0Zdml5utXzruvHedf1C5Qvuql/pf1XPbMpU/Z5RHcIxR5uxef1oTUc2ZuP1+Nj8IVd8Pk065bsxWozE9spHO2DT/69CXu4lVETB6B9mq/fTiEy1s7wsT3RPs3mFQcJjwmh15kd8Pk06Sk52CNstEsIQ/s0xflOLFYzZqsJNPh82giyWqN9oH3GwRVdHnx9/ullB94a55UFaV/5tny6yvSK83watH/9CsvV+40UzaJTktG4aE3GjLuEL5Z9XecyJpNqkoB/Sme8GjFihG7Me+nsWneElfNS8bgrB+KLbx5A4tkJvHr/NzUGxojYEG7927msWrCbvr+Ip3O/mKD21RT95VprvG4fHpcPt8uLx+XF4/IFnt0uLx539WmbVxzC7fBW257FaqLboNh6g5zH7QOtA2ckJQUulILQSBsAOUeKsVhMRMWFApC5J5+QUAuxncMBOJiSQ1iUjbguxkHt4I4cwqNttPeX03fmEtEuhJj4MFCK7EOFhMeEENHOjlKaguMOQiNthEZYQYHb4cVqt2C1mlAmZTyUcSHLKIMyKUxl003KmKfK5ymlMFV4raq8ztyTT9rPWTiK3NgjrCSO7EiXfu0qfzC1XGYJXH6pch1GVXtR07qqxmWqrqtq2oiqunDVdeuuT82XjeqrT5VtVt1GjdWsZZtVylkFh+ifOKCmStX5GTZgsSZYueaN1LrJKjPKzvbrkpKSwsCBAytvRqn1WusRNS3f6lr4dQXasufa5tfVClZKceGNiUHXI/HshEoBXmsdCMRupz9Q+wO3x+nF7fLiddcRxCssH0zr02w1YbGZ/Q8TXfu348C244GzFwCTWdFvZEc6940pD5KqLBAqUEZLQ1UMmiYjSFJ1GVVlOVUh4JoUpYUuTGZFWFQIygR7Nx0jOi6Ujr2iQWlWLdhNtwHt6DuiI9qneffJH+k3oiNnju6G2+Xltfu/5ZwJfRh+WQ+cpR5e/8N3nHddX4Zd2h1HkZt3nviBc6/ty4BzOuEocvPtuzsZfFEXuiS2w1nqYde6I3QbFEtMfBget5eCYw4i29uxhphr/Px2rTtC6prMwP+Eo8jNju8z6NgjSi50N6PjKaZa/0bNZdu2bdx1112sWbMGgA0bNjB9+nRWrKg7h3xxcTHXX3896enpeL1eHn30UW644QYiIiIoKipi//79jB07luTkZNasWUNSUhK33XYbf/nLX8jKymL+/PmMHDmyUd9Lqwr4u9Yd4au3d6D9DdmiHCdfvb0DgN7DO7D0n5v5xeU9mDTrvBrXr6/Lpy4et5eSfBdFeU6K85yB145idyBwNyRQW21mQsItWKxG2WIzY7WZMfvnlU2zWI0vhsVmdJOYTNXbES05Sicy1l6pfMb5XSqVL7mlvJWizIqbn0gOlC0WE5OfPg+L1WjxmC2KMbefQfuyLjAFvYd1ICrO2IfL6eH44SKcJR4AinIcfPfeLi67czAx8WHkZpbw/qyfuPyeIfQe1oGsAwUs/ddmLrvjDLoOiCUno7jamSCUX+DvOjCW7PRCEnpFYwu14HZ6cZV6CI20YjK3qXEQzerdHw9yMKekUbfZPTaM34zsXucygwYNYu/evXi9XsxmM1OnTuW5556rd9vLly+nc+fOLFu2DID8/Pxqy6SlpbFw4ULmzp1LUlIS77zzDt9//z1Llixh1qxZLF68uGFvrBatKuB/9/7OQLAvo73w9fwU4ntF4XJ46vxC1tb3fs41xoVQn9dHSYGb4nwjqAce+U4cFS6gAtjDrYTHhBDXJaKGQF0hqPsDvDWk9kDdWKqedZwulEkRHl1+0LVYzfRL6hgo28OtjLq5/LQ/qn0oNz1efsBo1ymc2545H6vdaClGtrcz5o4ziO8RBYAt1ELf4fGExxj7cDk81YJ9maIcJ5l78lj+6jZumDGSuK4R7N+SzRdvbOc3fzmb2E7h7PrpCKve282vHxlBVFwo+zYfY9NXhxh712BCI20c3pnLno3HSB7fG5vdwrFDhWTtL2DAOZ0wW0wU5jgoznPSsWcUyqRwu7xon8YaYpYx6S3AZDJxxhlnsH37dnbv3k2PHj0YPnw4xcXF/O53v8NmszFq1ChuvvnmSusNGTKEadOm8dBDD3HllVdywQUXVNt2r169GDJkCABnnHEGo0ePRinFkCFD2L9/f6O/l1YV8J3F1fuoAbwuTda+Aq7/U1Kd6yeenYBGs/ajvRTnOQmNsNLzzDjyjpWycl4qJQWuSq10q91CeEwI7btEEB4TYvQ5x4QQFm3DYm3Z01BRzmRShEXZAmV7uJV+I8oPGDHxYVx0U/9AOaF3dJ1ne10S23Ht9F8QHW9cr+jQI5KLbuofOGBEtQ+l34h4bKGVv14msxGsc4+WsOvHIyRf0xuAg9uP88PivfRPNg7GqWsz+XHpPu596WIUsGH5AdZ/tp97X7oYMIbY7lx3NHAWtO3bdA7vzuOyOwYDsGdDFrlHSxhxeU8AMtLycBS56T3MyIlRkF2Kz6uJ6RgGgNfrC3TLncrqa4k3peTkZFavXs1LL73E8uXLAfjwww+57rrruOqqq7jhhhuqBfzExEQ2bNjAp59+yowZMxg9ejSPPfZYpWVCQsobMiaTKVA2mUx4PJ5Gfx+tKuDX5cs3d7D24z2BbgyPy0tRrtFCL8qr3GLv0C2CDt2M7gJXqQenzU10h1A694sxAnu0jfCYEGz2NvPxtTl1ne3Zw6106hMdmB4TH2ZcbPZL6B1NQu/y+b3O7ECvM8sTEA2+sAuDLyzv0hp6STf6n90pcJGu/9kJdOwZFTjb6z4oFnu4NRCQo+PD6NK//OKxy+GtdIaZnprLwR3HAwF/+3eHObKvIBDw13y4h5yMosBZ0OevbaPguIMbZxj9xSv/l4Lb6WWM/wDy4yf7QGtGXmUcoHaszsBiNZE4MsG/vxwsIWYSehnvuSC7FIvNXOkge7pLTk5m8uTJTJkyhS5djL9denp6oHVuNldv4GVkZBAbG8vEiROJiYnh9ddfb9Y616RVRSx7uAVHce1HxaIcJ1+9lcLW79Kxh1UYP64UYZHW8tZ6uxDCo41hkyFhllO+5SMaX30X+BuT1d/dVyYqLjQw2gmgU98YOvUtHxnWb0THSmcowy/rEfi9BFDpbAXg/F/3w1VhhNZZY7rjKin/nvRL6oirtLwc2T4Uj6t8+YLs0krb2/7dYewRtkDA/35RGpGxdsb9zvgNxydzthDbKYyxdxnB8J3HfyChdzSX3Gpcp/nk35tJ6B3FiCuMm359t2AXHXtG0d//2W5ZmU5c13A6+0dEuUo9mCwqcNbs9fgCAwKay4ABAwgJCeGhhx4KTOvatSvp6ekMGzYMn696F+DWrVuZPn06JpMJq9XKyy+/3Gz1rU2rGpb58fMbSN+ZV+9yIWEWRt08wD/sz+iCMcvFNiGCorXG59WBM5K8oyUoE0R3MM5y9m3JJiTUHAjYGz4/QGR7e+Ag9eWb24nvHsWZo7sB8N5ff6TXmXGcfbVxBvHK779hyKiunPervqSkpNA+rAthUTYi2tnRWnPsYCHh0UYXqvZpsg8XER4dQliUDZ9Pk59VQmikzfhdiU9TnOskJNyCzW7B59M4i91Y7WYsVjPap3G7vFisJkxmk/+3IASG+Ja57777SEpKYtKkSYFpxcXF3Hfffdjtds4///xqXToN4ShyU5TnxOf1YTKbiIgJwR5R+48b2/SwzGCCPRi3OOj7i/gmro0QrZNSCrOlPBiWXQso02toXKVyxbMPgF/edkal8o2PVh56+NvZ51cKtu0SwjCZyhtkkbH2wO9BwLgmUzaCq+pIOO3TOErcWEKM+T6vpjDHGJJrsZrxen3kHS0hKi4Ue7gJr9tHTmaxv2wlNWUXV111Jeefdx6TJk0yuoLznEbXbng4/3ntdRxFbkIjjO4rr8cYdm2zmzGZTfi8vsDBseweWWWfYVWOIjeFOY7AMj6vj8IcIw9AXUH/RLSqgB+sYIZZCiFaRtVrYxV/caqUCvzYD4wRXBWH/JrMJtolhAfKZoup0i1JzBZF+y4RgV+8m8wmouPDAgcMZVZEtAvBYjPKffv2Yf0Pmwn1X4/Q2jholN05wefRlBS4CAmzYMaEx+WlILuUdgnhmMzG9ZWC7FLadQrHajPjLPFQkF1KbOdwLFYzzhKjRR8TH0ZRnrPabTC01hTlOSXgN1TFYZZCiLal6tmJyaQIqTCaymw2ERZVeQhwxesp1hDj9iJlbKEW4ntEBQK11W78urysi9gaYqxf1v1ltpoIiw4JXH9QSmGxmlDKaNHXpLbpDdGmAr7cElgI0RTKumhMJoXJVN7dZLaYKt0ioeoFeluoJTB8t6wLqKrG/DFfmwn4U165pKWrIIQQtYqICanUhw/GgSQipvG6oNtMwBdCiFNZWT/9iYzSOVES8IUQ4hRhj7A2aoCvSgafCyFEGyEBXwgh2ohW1aVzMrc3FkKc/hZvPMzsz3eSkVdK55hQpl/Wn/Fndal/xTaiVbXwz7mmT+AHE2Vk3L0QbcPijYd55MOtHM4rRQOH80p55MOtLN54+KS2u23bNs4999xAecOGDYwePbre9fbv38+AAQOYPHkyiYmJ3HzzzXz11Vecd9559OvXjx9//BGAefPmMXLkSIYNG8bdd9+N1+uluLiYcePGceaZZzJ48GAWLFhwUu+hTKsK+IlnJ3DxzQMCLfqI2JBA+kIhxOnvhlfXsvDnQwC4vT5ueHUtH21MB+CZ5amUuivfIr3U7eXJT7YDkFPs4oZX1/LVjqMAZBU6gtpnxQQoAFOnTmX27NlBrZuWlsa0adNITU0lNTU1kODk2WefZdasWaSkpLBgwQJWr17Npk2bMJvNzJ8/P5A8ZfPmzWzbto2xY8cGtb/6tKouHTh9k3wIIU5OZn7NATyn2F3j9GA1NAEK1J/gZMWKFaxfv56kJCNXR2lpKfHx8dx00031Jk9piFYX8IUQrdeCu88JvLaaTZXKnWNCOZxXWm2dLjHGrRFiw22Vlo+PtFdbtjYNSYAC9Sc40VozadIknnrqqWrr1pc8pSFaVZeOEKLtmn5Zf0KrZJoLtZqZfln/WtYIXnJyMjNmzGDChAmVEqB062bc4rmmBCjBGD16NIsWLSIrKwuAnJwcDhw4QEZGBmFhYUycOJHp06ezYcOGk34P0AItfKWUGfgZOKy1vrK59y+EaJ3KRuM0xSidhiRACcagQYOYOXMmY8aMwefzYbVamTNnDvn5+U2SPKXZE6AopaYCI4Co+gL+iSZAEUK0LjUl+GgJzZUA5USd0glQlFJdgXHA34CpzblvIYQ4UXv27GHcuHGc50+AUlF4eDhvvvlmC9WsYZq7S+cF4P+AyNoWUErdBdwF0L17y2WpF0KIPn36kJqa2tLVaDTNdtFWKXUlkKW1Xl/Xclrr17TWI7TWIzp06NBMtRNCiNavOUfpnAdcrZTaD7wHXKKUmteM+xdCiDat2QK+1voRrXVXrXVP4Ebga631xObavxBCtHUyDl8IIdqIFvmlrdb6G+Cblti3EEK0VdLCF0KINkICvhBCtBES8IUQoo2QgC+EEM2oYjKV5iYBXwghmtGaNWtabN8S8IUQog4NTXFYW5rCiIgIIPgUiI1JEqAIIU4P6/8Lufsbd5vtesIvJte5SMUUh2azmalTp/Lcc8/Vu+myNIXLli0DID8/v9oyaWlpLFy4kLlz55KUlBRIgbhkyRJmzZrF4sWLG/KuaiUtfCGEqEPFFIcffPBBIMXh3r17uf3227nuuutqXG/IkCF8+eWXPPTQQ6xatYro6Ohqy5SlQCzbR9UUiI1NWvhCiNNDPS3xplRTisPevXvzxhtv1BrwExMT601TWF8KxMYmAV8IIeqRnJzM5MmTmTJlSiDFYX0yMjKIjY1l4sSJxMTE8PrrrzdxLesnAV8IIepRU4rD+mzdurVJ0hSejGZPcXgiJMWhEG3bqZzi8Pjx4/z5z3/myy+/5I477uCRRx5p9nqd0ikOhRDidFJXisP27dvzyiuvtFDNGkYCvhBC1EJSHAohhDgtScAXQog2QgK+EEK0ERLwhRCijZCAL4QQbYQEfCGEaCMk4AshRBshAV8I0XpseR+eHwyPxxjPW95v6RqdUiTgCyFahy3vw9L7If8QoI3npfefdNBvaAKUYBOczJs3j5EjRzJs2DDuvvtuvF5vrclTTpYEfCHE6ePNcbBxvvHa6zbKm/3B8KsnwF1aeXl3KSx/2HhdfNxYfudnRrnwaFC7rJgABWDq1KnMnj07qHXT0tKYNm0aqamppKamBhKcPPvss8yaNYuUlBQWLFjA6tWr2bRpE2azmfnz5weSp2zevJlt27YxduzYoPZXHwn4QojWoeBwzdNLjp/UZhuaAAXqT3CyYsUK1q9fT1JSEsOGDWPFihXs3bs3qOQpDSH30hFCnD5uW1b+2mytXI7u6u/OqSK6m/Ec3r7y8pEdg95tQxKgQP0JTrTWTJo0iaeeeqrauvUlT2kIaeELIVqH0Y+BNbTyNGuoMf0kJScnM2PGDCZMmBB0ApRgjB49mkWLFpGVlQVATk4OBw4cICMjg7CwMCZOnMj06dPZsGFDo+xPWvhCiNZh6PXG84onIT/daPGPfqx8+kloSAKUYAwaNIiZM2cyZswYfD4fVquVOXPmkJ+f3yTJUyQBihDilCUJUOomCVCEEKKRSAIUIYRoIyQBihBCiNOSBHwhhGgjmi3gK6XsSqkflVKblVLblVJPNNe+hRBCNG8fvhO4RGtdpJSyAt8rpT7TWv/QjHUQQog2q9kCvjbGfxb5i1b/49QdEyqEEK1Ms/bhK6XMSqlNQBbwpdZ6XXPuXwgh2rJmDfhaa6/WehjQFRiplBpcdRml1F1KqZ+VUj8fO3asOasnhBCtWouM0tFa5wErgWr3/NRav6a1HqG1HtGhQ4fmr5wQQrRSzTlKp4NSKsb/OhT4JdB6ftEghBBBqJhMpbk15yidTsBbSikzxoHmfa31J824fyGEaHFr1qxpsX03Wwtfa71Fa32W1nqo1nqw1vrJ5tq3EEI0VENTHNaWpjAiIgIIPgViY5J76QghTguLdi0ivTC9UbfZNbIr1yXWnsAEKqc4NJvNTJ06leeee67ebZelKVy2zEi6kp+fX22ZtLQ0Fi5cyNy5c0lKSgqkQFyyZAmzZs1i8eLFDXtjtTjhFr5SKtzfLSOEEK1ebSkOFy9ezJ133skNN9zAF198UW29YNIU1pcCsbHV28JXSpmAG4GbgSSMX8yGKKWygWXAq1rrtEavmRBCVFBfS7wp1ZTicPz48YwfP57c3Fz++Mc/MmbMmErrJCYm1pumsL4UiI0tmC6dlcBXwCPANq21D0ApFQtcDDytlPpIaz2v0WsnhBCngOTkZCZPnsyUKVOqpTicOXMmU6ZMqbZORkYGsbGxTJw4kZiYGF5//fXmqm6tggn4l2qt3VUnaq1zgA+AD/z3xhFCiFapphSHWmsefvhhLr/8coYPH15tna1btzZJmsKTUW+KQ6XU1CqTNJANfK+13tdUFQNJcShEW3cqpzj85z//yVtvvUVSUhLDhg3jnnvuafZ6NUWKw8gapvUE/qyUelxr/d4J11IIIU4DdaU4vP/++7n//vtbqGYNU2/A11rXeN96fx/+V4AEfCFEqyQpDv38ffiqEesihBCiCTU44CulLgZyG7EuQgghmlAw4/C3Uj1RSSyQAUyqvoYQQohTUTAXba+sUtbAca11cRPURwghRBMJ5qLtgZqmK6XOB36jta7+iwMhhBCnnBO6eZpS6izgJuDXwD7gw6aolBBCiMYXTB9+IvAb/yMbWIDxg62Lm7huQgghGlEwLfxUYBVwZdlN0pRSf2jSWgkhRAMs27uMFze8yJHiIySEJ/DA8AcY13tcS1frlBHMsMxrgUxgpVLqP0qp0cj4eyHEKWbZ3mU8vuZxMosz0WgyizN5fM3jLNu77KS229AEKMEmOJk3bx4jR45k2LBh3H333Xi93lqTp5ysegO+1nqx1vpGYADGnTMfBOKVUi8rpcbUvbYQQjSe25bfxuI0IymI2+fmtuW3sXTPUgBeWP8CDq+j0vIOr4Onf3wagFxHLrctv41vDn0DQHZpdlD7rJgABWDq1KnMnj07qHXT0tKYNm0aqamppKamBhKcPPvss8yaNYuUlBQWLFjA6tWr2bRpE2azmfnz5weSp2zevJlt27YxduzYoPZXn6B/eKW1LtZav6O1vgroCmwEHqpnNSGEaBZHS47WOD3XeXK/D21oAhSoP8HJihUrWL9+feAGbCtWrGDv3r1BJU9piGAu2ipd5ZaaWutc4DX/o8ZlhBCisb059s3Aa6vJWqmcEJ5AZnFmtXU6hXcCoJ29XaXl40Ljgt5vQxKgQP0JTrTWTJo0iaeeeqrauvUlT2mIYFr4K5VSv1dKda84USllU0pdopR6C/nFrRCihT0w/AHsZnulaXaznQeGP3DS205OTmbGjBlMmDAh6AQowRg9ejSLFi0iKysLgJycHA4cOEBGRgZhYWFMnDiR6dOns2HDhpN+DxDcKJ2xwG+Bd5VSvYA8wA6YgS+AF7TWGxulNkII0UBlo3GaYpROQxKgBGPQoEHMnDmTMWPG4PP5sFqtzJkzh/z8/CZJnlJvApRKCxuZreKAUq11XqPUoA6SAEWItk0SoNStKRKgBPhTHVbvJBNCiFaozSVAEUKItkoSoAghhDgtnXDAV0qFK80xLoMAACAASURBVKXMTVEZIYQQTafegK+UMimlblJKLVNKZWHcWydTKbVDKTVbKdW36asphBDiZAU1Dh/oAzwCJGitu2mt44HzgR+Ap5VSE5uwjkIIIRpBMBdtL9Vau5VSPbXWvrKJ/iTmHwAf+IdrCiGEOIUFc/M0t/9ltWQnSqnkKssIIYQ4RQXTh3+9UurvQKRSaqBSquI6rzVd1YQQQjSmYLp0VmPcSuEO4Dmgv1IqD8gASpuwbkIIIRpRMEnMDwNvK6X2aK1XAyil2gM9MUbsCCGECNK5557LmjVrWmTfwXTpKICyYO9/fVxrvV5rXVxxmXq2000ptdI/nHO7Uurkb2EnhBCnmZYK9tC8t0f2ANO01oOAZGCKUmrQiVdZCCGaT0NTHNaWpjAiIgIIPgViY2ro7ZFDMQ4WQd8eWWudif/Ga1rrQqVUCtAF2NHAugsh2pDc99/HfSi9Ubdp7daVdtdfX+cyFVMcms1mpk6dynPPPVfvtsvSFC5bZuTUzc/Pr7ZMWloaCxcuZO7cuSQlJQVSIC5ZsoRZs2axePHihr2xWgTTh+8AXgJeaqzbIyulegJnAetqmHcXcBdA9+7dq84WQohmVTHF4e7duwMpDlNSUnjxxRfJzs5m9OjR3HvvvZXWGzJkCNOmTeOhhx7iyiuv5IILLqi27bIUiECNKRAb2wnfHlkpdS9gUUptAjZprXedyDaUUhEYP9h6UGtdUMM+AqkTR4wYIWkThRAA9bbEm1JNKQ4HDhzIK6+8gs/n49Zbb60W8BMTE+tNU1hfCsTGdsK3R9ZaP6aU6ggMAyYopfpqre8MZl3/GcIHwHytdbUfcgkhxKkoOTmZyZMnM2XKlEopDpcsWcLLL7/MLbfcUm2djIwMYmNjmThxIjExMbz++uvNWeUaBR3wlVJfAn/UWm/WWh8FPvc/gl1fAW8AKVrr+jvAhBDiFFFTikOAq6++mquvvppx48Zx0003VZq3devWJklTeDKCTnGolBoO/APYD/zJfxE2+B0pdT6wCtgKlN2T509a609rW0dSHArRtp3KKQ6/+eYbPvzwQ5xOJ0OHDm1wIvOT0WQpDrXWG4CLlVK/ApYrpT4EntFaB/VrW63190C94/WFEOJUUVeKw1GjRjFq1KiWqVgDnVAfvr9bZifwMjATuFMp9YjW+n9NUTkhhGhJbTbFoVJqNXAYeB5j/PxkYBQwUiklN1ETQohT3Im08O8Cdujqnf6/9/+ISgghxCnsRPrwt9cxe1wj1EUIIUQTOuEk5jXRWu9tjO0IIYRoOo0S8IUQQpz6JOALIUQbIQFfCCHaCAn4QohWI3/pUnZfMpqUgYPYfclo8pcubekqnVIk4AshWoX8pUvJfPQxPBkZoDWejAwyH33spIN+QxOgBJvgZN68eYwcOZJhw4Zx99134/V6a02ecrIk4AshThsHbrmVvA8/AkC73Ry45VbylywBIOu559EOR6XltcPB0VlPAeDJzeXALbdS+PVKo3zsWFD7rJgABWDq1KnMnj07qHXT0tKYNm0aqamppKamBhKcPPvss8yaNYuUlBQWLFjA6tWr2bRpE2azmfnz5weSp2zevJlt27YxduzYoPZXnxO+PbIQQpyKPEeO1Djdm5t7UtttaAIUqD/ByYoVK1i/fj1JSUkAlJaWEh8fz0033VRv8pSGkIAvhDht9Pjf24HXymqtVLZ06mR051Rh6dzZeG7XrvLyHToEvd+GJECB+hOcaK2ZNGkSTz31VLV160ue0hDSpSOEaBXi//Agym6vNE3Z7cT/4cGT3nZycjIzZsxgwoQJ1RKgjBs3jiuuuKJB2x09ejSLFi0iKysLgJycHA4cOEBGRgZhYWFMnDiR6dOns2HDhpN+DyAtfCFEKxF91VUAZD3/Ap7MTCydOhH/hwcD009GQxKgBGPQoEHMnDmTMWPG4PP5sFqtzJkzh/z8/CZJnhJ0ApSWIAlQhGjbJAFK3ZosAYoQQrQ1bToBihBCtCVtNgGKEEKI05sEfCGEaCMk4AshRBshAV8IIdoICfhCCNFGSMAXQog2QgK+EEK0ERLwhRCijZCAL4QQzahiMpXmJgFfCCGa0Zo1a1ps3xLwhRCiDg1NcVhbmsKIiAgg+BSIjUnupSOEOC1sX3WYgmxH/QuegKg4O2dc0KXOZSqmODSbzUydOpXnnnuu3m2XpSlctmwZAPn5+dWWSUtLY+HChcydO5ekpKRACsQlS5Ywa9YsFi9e3LA3Vgtp4QshRB0qpjj84IMPAikOwWjFjxgxgk8++aTaekOGDOHLL7/koYceYtWqVURHR1dbpiwFYtk+qqZAbGzSwhdCnBbqa4k3pZpSHAI8/fTTXH/99TWuk5iYWG+awvpSIDY2CfhCCFGP5ORkJk+ezJQpUwIpDr/88ksGDRqEw1FzN1NGRgaxsbFMnDiRmJgYXn/99easco2aLeArpeYCVwJZWuvBzbVfIYQ4WTWlOPzmm28oLi5mx44dhIaGcsUVV2AylfeSb926tUnSFJ6MZktxqJS6ECgC3g424EuKQyHatlM5xWGZ//73v8TFxXHllVc2e71ONMVhs1201Vp/B+Q01/6EEOJk7dmzhwEDBlBaWlpjsAeYPHlyiwT7hjjl+vCVUncBdwF07969hWsj6uLz+QDw+nxon8anNVprvF6ff75Gax9en/aXvfh8oH1e/3rGfJ/GWN/nQ6PRPo1G4yubpjVag9Yan9fnn+dDA9q/b2Ma+HRZ2Yf2+bdL2TSM/fk0+OuqtQ68D6O+xqPs/VUslwnmrLjaMkGcSGt81adVnxTc/oPZULXtNmxfVVesaZ1g+hFq+pwT+3bheE5eHSsFPbFBYmJiWb16LQDHj+fWv6dG6jFRJhPtY2MaZVsVnXIBX2v9GvAaGF06LVydRuf1eHG63bjdHpwuD263C5fbg8vlxu3y4PZ4cHvceNweXG7j2e324PV68bg9eDxuPB4vXo8Hj8eD1+PF5/Xi9RrTfR4PPq/X/yib70H7jGna60Vrn/8/tTzwGa+NaYEvnhFlA//E5cuVzW/2j0+0Mb26/QpnUWFLV6P5mUzQFgL+6a6ouIQt23axe2caRw8cwFmQi8/rBZ8RbBurBQCAUiizGUwmlMmMMptRJgsmsxllNmEyG6+t1lDMZjMmiwWTyZinUChltCSUAlCgFCaTQmEyiiiU/yKUMimUMh5gDBurWFYVyqpSGVAmFGAyV9i2UuXbQFXaftl6lfZRVjf/tpRJYcJkrGcC5X9tUkZ9zSb/Nk1lZeM9m8wmf/1VoA6B+aayuoDJZMakMPbnf48VmapPquHPY6o6ofp2guhUrWn/1bZdg6p1rGk7wWy3eh3r346phg8ouP1XXmbvnjQSutYzHLOmz6fePdW/79ZIAv5JOp6bz+atO9m3aw/HDh3AkZNltHyVwt4+nrhefbFabZjMZswWMxaLBbPFgsVixmKxYrFaMJvNWK0WLFYLNqsVs8WCzWrBarFitVmw2ayBss1fDrFaMVvMLf32hWhSFQ/K4uQ157DMd4FRQJxSKh34i9b6jebaf2PJOJLN1m072Z+WRvahg7jzjX49ZTYTFt+JPmefT9/+fRgyKJGI8NAWrq0QQpRrtoCvtf5Nc+2rsfh8PvYfzGT7jl0c3LOX3PSDeIqN/kRltRHRsTN9zjyL/gP6MrB/b+whthausRBC1K7Vdenc+fmd/HDkh0A5OSGZ/1z2nxPaxsH0oyxeuJi8wwfxOUoBMNntRHfqRpfe5zJoUCL9+3SXLhUhxGmlVQX8qsEe4IcjP3Dn53cGHfSzc/L435xX8DhKievVl259ejP4jP707N5J+hKFEKe1VhXwqwb7+qZXVVLq4I1/vYanpIirb7+ds4YOaMzqCSGa2K51R1j78R6KcpxExIZwzjV9SDw7oaWrdcpoM03WZXuX1Tnf6/Hy2r/foDT7CBdce50EeyFOM7vWHWHl/FSKcpwAFOU4WTk/lV3rjpzUdhuaACXYBCfz5s1j5MiRDBs2jLvvvhuv11tr8pST1WYC/osbXqx1ns/n4/U33iHvwB569e5J2vuv8I8br+K1KbeRsmplM9ayiW15H54fDI/HGM9b3m/pGp3SUlat5LUpt7XO/4XT1Ef/2EDKmkwAvF4fH/1jAzv9AX3t4j14XJV/Uexx+Vi1cDcApUUuPvrHBvZtyQagON8Z1D4rJkABmDp1KrNnzw5q3bS0NKZNm0ZqaiqpqamBBCfPPvsss2bNIiUlhQULFrB69Wo2bdqE2Wxm/vz5geQpmzdvZtu2bYwdOzao/dWnzQT8I8W1H+UXLvqUzK0b6ZjQgbyfV1CYfQy0pjD7GF+88kLr+KJveR+W3g/5hwBtPC+9X4J+LVJWreSL1/5d+X/htX+3jv+FVqoot+YA7ihyn9R2G5oABepPcLJixQrWr19PUlISw4YNY8WKFezduzeo5CkNei+NspXTQEJ4zf14n3+1mpTvvia27wDMBzbh8Xgrzfd4vKyc+2+2rFhe4/qnpJIcKKxwgPv+BVj+MLhLKy/nLoUVT8J3syFtRfn0gz9A/uHmqWsLK8zJpjiv/B4pW7/+gvSUbax67208rsoBxONy8sVr/2bn2lWAcW+g5S+/wJ71xqm51+Pm6/++ysFtmwFwu5x8/97/yNiVYpQdDtYtXkjW/r0AuEpL2Pj5JxxPPwSAs6SE7d+uID/rSKC8e90aCnOyA+X9WzZSUpAfWD9z904cxUWB7WcfOoDbf392t8tJQXYWHrc7UD9HUZHxy2+M+xD5vN7g7pdzipgwbTgDz+0EgNlsYsK04fT399FHxIbUuE7Z9NAIGxOmDafX0DgAwqNrXr4mZQlQHn/8cWbNmhWYXlcCFKg/wYnWmkmTJrFp0ybj8fNPTLltElFmxRcff0T/vn2ZMWMGTz75ZNB1rUubCfgPDH+g2rR167exdslHhCd05a57J1NYUFTjuqUlDjZ88lGg/M3/3mDF3FcCZUdxUbUvTZN2B2RsgoPrystfzICV5f+EvPFL+Kz8vt1snAclx2veVn46rHoe9n1nlH0+ePNy+Hmuv+yFv3WC1f4uMa8b3rsZdn5mlD0u+OkNOLbTP98DuQeqH1yakM9XfpDOTNvJkT27A+UfP17EtpVfBsoL//pnvp03N1Ce9/CDrHl/fqD83fw3SV2zisLj2TXuy+NyUpxn3MxL+3wc2LopEKC9Hg87vv2a7EMHjGWdTn78eCFH9qQB4Cwp5vt33yJzt/FZlRYW8vXcV8jcnQpAcV4Oy196noxdRrkgO4slz80i01/OO5LBB397NLB89qEDvDNjGkf82zuyZxdv/XEKmWm7ADicsp3/TPktR/2fx/7NG5lz+42BA87un9by/E3XkH1wPwCpa77jhYkTyMkwDvapq7/lpTtuoiA7C4CU1d/y+u9vDxwgU1Z/y9vT78NRVBQov/vo9MABJ3X1t3ww6zG8HuOAs3PtKpY+91Tgu7Lrh+/54tV/Bj7b3T+uqfS32bN+Hc6S4kDZWVJMcX5ehXIJpYUFgXLS5d0wWyuHNLPVxDnX9AHA7XTgcpT/X3pcTtzO8oO6x+0OHBzL/p5ef9ap5ORkZsyYwfjx1wQSoHzxxecMHDiQ+Ph4Gmr06NEsWrSIrKwsSgsLOLB7F/sPHODI0aPYrFbGjb6Y+6dMYcOGDQ3eR0WtapROrbQ2Wq29xwUmpe7ez/J587BGRnPn7+/EHmIj0uKk0GOvtnqkxckNEYtg168gcQyU5qOPpRmt6MgEFs2cQURse8ZPfxSAb/83l43LP8brP1so6xoCGHjBxTXXz1kAdv9p2+4voeAw/GKyUV76ABRkwM0LjfKXj4LbAXf4A1lxNtjCy7d3yaMQFltenrIOXjzT351TRXRXeHAr+CqkU7tlMUT571/i80DSHZAw1Ci7iiF3P5T6v3gl2bBsKlz5AnToD4UZ8OJQuPrfMPwWI/jPuxYue8r47AoyYfULMPxW6HiGsZ30n6DzcAhvT2l+Lq7SEqITjP3v2/gzzpJiBpx3EQCr35+H2+Fg1K13ALDgiYcxW6xc9+e/ArDijVcIi4ri2keeACDtx7W069SZwRf/EoD23boT1aH8C3rJbXcT2b5DoDz5Hy8REhbO3g0/Gt05VUTGdWD45VcBYLZYuful/wbm2eyh3Pdm+cW10Mgopr67JFAObxfL/f/7AJPJ7N9WHPe+Ng9rqPGL7Oj4jtz+4n8I85++xyR04pan/xmob7vOXbjhiadp36UbALGdu3Htw48T37uv8d66dufKBx8irlv3wHsdc8/9xCR0CswfdeudRLY3Wrjtu3TnvOsnEh7Tzr+9rgy//GrsEREARHWIJzH5fKwhxnciPLodnfsPwmy1AhASGkZ0x4QK9ycyY7HZAjfx8bjdOIqLAvfnKSnIJzv9YOCeNXlHj3Box9bA55O1bw+pa77joom/BeDA1k1E9B0UmO8oLsJZUkJ4tHFTMUdRAS6Hg9DIKAA6J1pJujyObd/nU5TjJCzawtBRsYFROkU5Ofi8Htp3NT6fguxstPYFPs+CY0cDn4NRv0yUyURspy4MGDAAq8XC3ZMnB+rz2dKlOBxO9hw4QGhoKCOHnEFIaCjR8cb+cjIO4/OWf6+cxcWVDlBej5vunRKYOXMmY8aMweVwYLFYeOrxv1BQWMhfn34Gk0lhtVr5zxvlB8KT0WwJUBriRBOgDH1rKLqWWzjafZrHe01g3Ki/knEkmzee+ydoH7+dej9dOhlfqC0PJ7NiXyy+Cic+FuVlTK9jDLziJhh6A0R3ge2LYeEkuHcNdDyDre88S8jOj0h8YB66XU+eu/GqGusQGRXOXf9ZwNqXHqW7/RhdfvsKWmuOzL2L6Oy1hD20zVjwo3uNFvfU7UZ57UtGC320cUDh6HYw2yCuX9CfTaAPv2LL2xoKV/0ThtZ+SlovnxeKj4E1DOxR4MjHt/1jTD3Pg/Z9yN35M/lfPE/P8Q9CtyR2fTqPrOUvcv7vn4J+l7LqlVlkrPuUG2Y8CX0uYenMaRzbuZHf/vVJ6Hk+H8+cTu6+FCb//R/QoT8rXnoad9Yexv7xbxDRgS2ffYjJVcjgcb8Bi42s/Xux2GyBL21DpaxayRevvFCpi89iMTPmngdrPmg3lWq3WS4r65rn1zkv2Ok13ie55nknMr22WFNHfVIOHGXggP7+ojG97IDh8/lAa0xm4wDq9d+csOwHkV5/l4nFagVtHIA0GqvV+EW82+VCa43N383i8p+Z2OxG2VFailKKELud++5/kDOHDOaWiTdj9x+gS4qKMJlMvLdwEXFx7bn4ggswmc2EhocBUJSXj9lqJTTMKBfk5mK12QgNNxpn+cdzsNpthIUbB9gjB2tokPkl9Kn5u36iCVBaVQu/tmAP4DApXtz7EZdf+ARvvfwffG4nv77nnkCwB7B1H4Zv3yHCzU6KvUaL/4JOGQz8zeOVg+IZ46HXPggxWhZDzjkbzJshvKylqKnpfn2FBUW4XU7WfLsRU89CumiN21HKO19kcuGF40gCHEVFvPFJLhfd9CyDMVo1K9eXMmT0BLoCLkcpe9Ky6dJ/IFGAz+vF7XRgCw2r+25/Q68nZdteVn32DYUuM5E2LxdcPoqB9QR7l6OUouPZxHRMwKSMVtihHVs565djMClIXbua7d9/x7UP/gHlKmb14o/46fMveOCf56OO72Hzt9+w+ccSHrg+DDK3kHHgEGnuAZwfGgMH1xEVZceVeBa4S2DP15w1pAuOqKzAWcSYpBjMYZmw+yvI3Mzo7kchawFs6AfhHRjq+AE2vwuR6RDajvjD62H3F8ZZiS0MsvdA1nboPQrMVijKMg5QMT2NP5HHaZzFKDPgM7q0tJeBOfsgfh+rsrpT6Akx/hfiDzIw5UnIfNP/Z64v2FHL9LqC4KnbAGsRiVMg7yBQ/RtVtT+66u/eq5arBjtr2Qt/StrAjVH8vTx2YM++A4z7zZ2cd/Zw7rx+LLiOg8uYHwbghcnjLzEm6ALwAP77a0UojHKBUY4yA94SKDDOjqOtgLcU/NdkzCbw1pC2wGxpvDDdqgK+QtUZ9I+YYPPCF3AeP8bZV41nUP9eleYP6NeRzoXriLK5jIuW0V1h9OM1t4Ardpn0usB4YPxT1tU1ZLWF8Id3PjZaJ0phsliZ8NBfaNe5/Baw/c+9iJhOxmmmq6SE9NQd9BlxNgAFx7L49J+zufL+/yMqMozje3fx9uOPcdXtt5I4uB/HDx3ki0WfcNEvz6ZzQhQFx7LYsXUvNrOPVT/sxeMx/uSFLgtffLKa/H0TKXZ4OWdQJGEhsPtgMd9uKeTGi6KIsMP2NAdfb3Fwz2VhhNsV6XvcfLPNxaCchYTaFJ6DbpyHPXg++j1Wi6JrrhdTX4Ve/jBKKYYpHwOSzeivnkApxahoGHUBxoVi4EyAHsCG/wHQFSAOSFkKQChAQl/Y77/GgAkSx0LmFjBZjDOW7ucYB4iCDKNrLKKj0c3lshtdTMf3QI9zQZkgZy8cWA0XTDcOAPtXGY9LHweTFQ6uhaPboDSPgdF5DIw+WvmPmF0MMd2h76X+f6qtUJoLvY0uJ45uB2ehsb+ysrsEuo40ysdSjOsgnc70l1ONg0zHM4zb/B7baTzHJRr/Tdm7wWyB2N7G8jl7jXrGdDOWy90P5hCI6mzMzzsElhCI7GiUCzKNclh7o1ycBRY72P33Wi85bpRDjFYmjgLj7NFmtEpxFRlls82oj8dl1MdkLj9Yld1SOdDgqHZf5oqFKvOqvKjaaCmONBpSJ3Xr4oav22dIR1K3bT7J/QdXjwjfcQoKStEVllNoIiKqx5IG16A1dekMf3s4bl37ECyT1jywKQwHQ7njmZex2QLHeJwlxYSEhRsBxHpyd7lM+dPZfLE3Fo8ub2NYlJcxvXMYOHMteErBVWIEAo/DeHaVGPv2lBrPZdMC5VJwFeNxlpKfV0S41Y3dqih2+EhJ99K3k5mYcBPHCnx8s9XJhWfY6BhjYf9xMx98n0+Y3UyJw1utrqGhVrQPbrj+XOLiY0g/fJzNmw9w0SXDiIiMICe3mKNHcujbvwfWkBBcHh8+nyIkLBRlsuC/ebzxrMxGIFDmeqb7nwOvq0wPzDdXWUad/BevNNcIgh39fcOHfoLDP0PyvUZ5w9uw63N06jJUDY0HDaiIBPS0VOOM6qN7YP9q+IO/L3rRbyFzM/x+vVFeMNE44PzOyJrE/Ouh6Cjc/a1Rfnu8cV2k7HrMm1cY73myf5jf65dCSCTc4h808MoFRnC/yX+tYE6y0bV3g3HA5J/DofNZcJ3/RrTPD4ZeF8L4l4zys4nQ/3K4yn8R/u89jK7KK54xyn/rDCNug8v+ZpSfbA/n3g+X/sUI8E/EwKhHYNTDxtnRzHjjmtGFfzQOdM/0hkufgHN+Z4wWe2EojHkSRvwWCo/Cy+ca2z7zRmPAwBtjjPIZEyBnX/n1nv5jITuNlL0HGTh0hNFd6HZA3n6I6mocoNylxgEuuotxDctVYlz7iu5idDG6SqAw07geZbUbn3PRUaNsCfGXjxmfp8VmlIuzjbLZCs4iKM2ByM7GQc5ZBI48iOxk/E86i8CZDxEJFcqFxsFWmYyyq8hogChllN0lEOHvVXAVG+WynoEjWyl1Q5HbhlebMCsfEVYXoTaT0SCoQZvu0qkr2AOEl1jZ5olgePtNlYJ9zucvMG/+d1x+3x/pN/LcOrZQh7ILrwWZDLx4LDgXsOpI18rdAT27wHvB3DRUGQedig9bOITHYbGG0b53qPEPbQ0l3BrKCP9rrGF0sIby61v9ZYudnkrx4L1uXrj52hr3VOrwMO29pYFyV6DrhPL5sf5HmdPlfqCHckrwaU2P9kZ/6WdbMwkLsXBRYgcIbcfTy1PpHBPKLclJ0C2J37z2A8O6x/DQ2Fth+K0c/ksfuqrqI3WO0oGEaakMeuxzbj23B49c/S/QPi6avZJbkntwx9X/xud185tX13LjyG5MuGYOLpebPy3czJVDOzFq/Es4nE5e/Wo3F/XvwLDxL+FwuVm2Pp3hPdrR65o5OD1eNu/LoXeHcOKumYPbB9n5pbQLs2G/Zo4RjMpc/a/KDZSrXjSCY5krX6h8NnrFs+VnAwBXzIZ2Fc50x86CDhUCyJi/Qedh5eXRfzHOqMA4CI96pPxsxmSFc6aUL2+2GRfnO/h/tW6xwaBrIKaHv2yHPhcbAbSs3OUXENrOv77V2Kb/IreRRcda+aCvTFRuOesKvWLaPxih7JqAzzhIlTVyfV4j4Jalf/S6jQAdKLvA4Q/oYKxbkmMEcMxGY6zomL8MuIuh6IgR0BXGtgoz/QFeGQeDsvlgHDyKjpUHfJ+HUDOEmisMoACo3k5rsFYV8OvT/WgYLrNmfucSJpZNLMnB9uO/GNjjXLr0H8TijYeZ/flOMvJK6RwTyvTL+jP+rAoZd1zFxuicwkzjuSDDX86odEF0YGJHBrbfYSxvj4bEy6HneYFAXRaga3y22BvpFNJgtliJjIuredSJf8RGS3N6vJS6vMSEGYeUHRkFFDjcJPc2uiI+3nSYglI3t5zTE4Cnl6dS6vLy+NVGy+fWuT+igLd+a3SdTHlnA+3CbIHyv75Oo3OM3Qj4wMaDuRQ7y79Y/TpG0DmmPHA+476ev1tfJ0y5AtNKtI2n3L/mRaW456I+nNU9BsxWtNaM6BFLl5hQsIXh8Rj5dn0+wB6NS3lYu2eLsXz/HhRrJ89/9RUxYVaGdetJXr6DaQtXMGvCEHqd3YusnBKuf3Uls68byq9H9OfgsSJGP/U1L944jGuGDWXnkULG/elT/n3TcMYOTiL1SAH3zF7JrGuHcG6fC9h1tJC/vrGO/7tsAEP6XUpaVhFvfLiFOy/oTe9BV3PweAmffJPGtWd1JWHo9WTml/LT5gwu6teB6F9MJqfYxYGDuQzsFIU9+R5KXV6KCp3EtURh6QAAIABJREFUhtswXzC1/I9mthgt/TJWu9E1ViYkwjiAlAltB1c+V14Oj4Nr5pSXozrBr14vL7frAeEl5SPQLHZo36fC/kIhrm952Rbm7worK4cbI8cC9YmE+AoHM3sU2MtHAREaYzzKhMVWPliGtzcegXKHCtftMAJ/RMfyA0pEx/JgD0bLP6Li8gkQXmFIp8kKvhoarebGa2a1qoAfExJDnrPmhMchLhMdc0M4FF/K4RATvR5eVh7Qf7+SX4Z3YPG2HB75cCset5PO5NIxP5eVH35H7z12hkaXGIHdkV9hq8r4B4jsBD39p9qRCcYpYHhcecvkFHDBjbfy2Sv/QnvKA5iy2LjgxlsbZfvHi5xkFToZ2MloXW46lMfOIwXckGQMgft402HWH8jlyWsGA/Dcl7tYuyebhfcYrcOHFm1hw8E8vvs/YwTMnG/SSMks4OtpowD4dGsm6bmlgYDvdPtwVhhB88uB8ZUOkg+NHUCIpfyy3n9vS8JuK/97vHfXOZXqX1avMuujfsnDBfB/lvfprI6TodvzjOd61kcZwzsfuLR81IRSin9cf2agbLOYeP/u8u1HhFhY/fAlgXL7iBD2zLoiMOokLsLGd9MvJjrM6i+HMO/2s+kbb/Srx4WH8PdrhzCsmxGMYsKs3H1Rb3p3MAKh3WLmzG4xRIca67u9PoqcnsD1rONFTr5KyQr8LXZnFfLM8p2c3zeOhGg7mw/lcf+7G/nsgQuIDrPyfVo297+7ka+mXkjf+Eg+25bJ1Pc38+30UfRoH877Px3isSXb+OaPF5MQbWfxxsP/3955h0lRZY37vVWdZnqGyZE0ZBgGJQ1BQBEEUcGwKuKKK7i4a1zFrKvorriurgl/hs+ErvkzoJ+YEUFRBBEQiRKGIUxmcuxQdX9/VE91N8wQh+BMvc8zz/SpcOtWdfW595577jk8s2gr7/51OHFuB1+sK+Ddn3fz9B8HEOmwsfi3Yr7ZVMw952TisCmsyC3jl50V/HlkFxRFsLGgih2ldUzIMnrSu8vrqKz30TfdcE/VAknqbb+XaLUidD5ir9FIaApJRSVsarlduuE6HZpwXijBEVAL0KoU/p2po7k390N8TfSOOxZFgIRdyXU4/BEINE6qWszXL35K9Kk9GdvDScmnP3CfLCbBXhVmv83b0I6Thg8wfMXbpRlfQHSa0YLbfh9Gjt+ierIw8TQGl/xItFZDtRrFz4nDyYjsQR+gsLKBjQVVDO+WgMuu8suuCr7eUMT1Y7rjsqt8vraA15ftYO60bFx2lRe/y+HRr35j/T/OxKYqvLo0l6cXbSXnX2cjhODL9YW8tCSHyYM7IoQgp6SWZTnBxV9pMS66J0eb8gUDO3BKt+Bo45ZxPfFpwe/g2csGoYbkSZ01KaRnBmZD0MiI7uEjl+R2hzbxdduZvbhrnpePvSPNbRF2lYfO7LWfsw4e416M+7GpCp0SIoPXcaiM7BGsf0yknSlDOplySjsXt50ZDO6XkehmzpQBptw3PYYPrx1hykO7JrDi72eY8pjeyWx6YAL2gP/8qB5JfH3zaXSIM0Y4w7rE88r0bHPEc3LHWB44ry8JUYa7Yo+UKP40PIMol82sX4+UKByBBrbep1FS7UEJ/A63Ftfw8Zp8Zk00vrPvNpfwzKKtzBhlmJI++iWPV3/I5bfZZwEw9/tc3vt5F2v/cSZgvJuV9T4y043ORF55PTUeP71SjfenoLKeBp9Ol0SjASyubsDnl7QP3E9prQdNlyRHG+9AZb0XKTFHk40jPbfTuJ8Gn4YQ4Gx079R1Ix/ywSQyPhIi46n1ajjqCrFJP35hwxuRijt0lHGEtKpJW/6VzltVseQUdMTVYKPe5WdVzwq2p9Uz8tcEStt5Wd+1iux6D88UFeHxOnklZzDpyX4mj0jhlbUeCmQ8hTKeIhlPIXEUyTg8ONn+73NYllPKurxKpg7rjMt+4vTewfBRrqz3EeFQcdpUdpfX8dX6IiadnE5StJPBsxewp8a7z3kp7Zwsv/sM3v15F7e//ytLbj+djvGRvLV8J/d8tJYf7xpLSjsX89fk89+lubw8LZuYCDtLt+7h280lzBzXE5ddZXNRNTkltYzLTEFVBJV1PryaTmKU43ebHPqA5j2Lw8Kv6dT7NKJdxoikpNpDWa3XVOBbiqrZXVHP6b2S2bhxIx279MCracS7jQanos6Lx6+TEmjES6o9eP0a7eOMRrOgsh6vXzfnb3aW1uHTdbolGSOmnJIadIk5gtpWYqwUbty/tbgGRUDXgLylqBq7qpARaFC2FtfgtCl0jDeul7unFpddITXGaGB2l9fhsqskBhrIwqoGImwKMYEGprTGg9OuEhVoYKrqfThsCvU+jbzyevQQnawIQfu4COIim+5YtulJ240lkZQUdCYi4B0T2WBn1Lp42pdXYfMLyhLrOKOmhu/ckWRndCRJ07jGvYHV1ecyefIcXtr+DXkVDfuU2z7Q01n8WwlvLt/B9BFGz+TD1bsprvLw19O67XNOSygLXZfoUmJTFaoafCzaVMzATnF0jI8kp6SGf36ygRvH9mBApziW5ZRx6YvLeGvGUE7pnsjO0jr++ckG+qS1IynaSWkTyh6guMpwOh7TO5kPrz2FpGjjJb0kuyOXDuloKutJJ6cz6eTgZN8p3RM5JaQX3TMlmp4pwR57o3ni98z5A9pbCv4oYFMVotWgaSMp2mm+dwA9UqLpEfIuGSOJoKqK3Uv5hZ4LkBYT7mUXOnoCyEhwh7lvd4iLCFv+kBrjCpsGTox2mqMVgHYRtjDzkk0VqCGy16+H7a+o86K77MQEqlFY2UCc22Eq/B1ldSRGOais84UpewBdSooqG5pV+IfK78QodnAsKc4Ic4UEkLpKz93RdEgez588dSxxR+JRFGyaQonNxkPto+iZ+CUIwW1n9iZir557hF3ltsAw/s6zerPk9tNN08KSLXv4bG2BeexTC7fw6g/b+Wh1HnfNW0teRT0SyKuo5655a/lodTAgmU/T+WHrHnaUGrFCKut93PLuGr7bbEys7i6vo+c9n/Nh4JyyGi83vvMLP20vAwyTQGmNl3qvYcfunhzFrImZ5ss9KCOO1feOY2gXYzgYOiEZSuP2xCgnAzrFmSMXVRG/2565hcX+UJRwBe20qThDfvdRTptp3gGIi3SY8yMAydEu4t1BBdwhLjKs0emaFEVqTNCE2Du1Xdjvr1datDk6Aeie5CbB7cTb1KoraHb74dCqevjV/qaj3/mkSv9Rp/HItv+SVhDFoN/icDeo+FTJj1mlPJtWw6CStZw/oB/Afnvmob2Lxyf3D5s4XLWznHi3g+U5ZdT7wn2p6n0aN7/7C7vL67h+TA90KbnspeXcOr4n14/pgdOmsHTbHoZ2NRR0YpSTv5za1Rzmto+L4OubTzVfnM4JbubfELQvJ0U7uXJk0L3OaVNNGyQ02qTXhtUrtDGzsLA4Npw6ciRLly415QiHoYYdqtKkcneoLdcvb1UK31hn23SvdMTwgUQsbccp6xKw6cYDdGiCEWsT+EHC878+T//k/lyceTHnDxjTZBlNEapUX50+BF2XdLv7syaP1SX0Sm1nnvfuX4eTEeiRu+wqP94VzKLjsqvcPiE4MWdXlbBJzkOlsdGybNIWFseXUGUfSkqMq0kbfkpMy620bVUmneaUPRJyBwzgjJWxprJvxKYrDNkSz8RuE1m3Zx2zl83m+7zvDztGuKKIZs0n7WMjGJeZYspDusQfsvfIkXD+gPb8cOcYtv/7HH64c4yl7C0sDoLDTXHYXJrCqEA00r1TIF5/1XS2rF7KtAsmMGnUIDb9unq/E7aHQ6vq4btUPw3avpOFNs2IqudtJgiRq15lQsYEBiYP5J1N7/DOpndYmr+UHrE9SHGnkBqZSnJkMlGOqIOqh2U+sbBoeX5d+AWVRUeWn3ZvYlJSOWns/tMHhqY4VFWVm2++mccff3y/5wBmmsJPPzXyaVdWVu5zzNatW3nvvfeYO3cu2dnZzJ/3Hit/+pGPP/6YV16Yw+SzWzYya6tS+FJvrldubHf5/DQ49m0Q2iUGV7/dMOAGlhcuZ+GOhSzetRhNBpV2pD3SVP4p7hRSIo2/hIgEbErwUVrmk+OPlMZiHV3qSCnR0c3Pjdub2qdLHYkM226uzA9x5WguSF/jyLDZ/WGRMpupe2BH6CjzYMo70Kj0QHUOu3bzlTvo8lqizkIT1PnqAPBoXnxNrUQ9XCR4/F5qvbV7bd63Tr379GbFLyvYtnUb6R3T6ZnVk88XfM4D/3iAPn36cNHkixh12qiwc7r26spXt3zFzFtnMuHsCZwy8hSqvdUAVHurqfHW0DmjMxm9Mqj119KzT09OOe0Uanw1dO3Vldzc3Ja71wCtSuF7ZNOugP5AvOxeBWWs7ZiEHupS5XAyasqfKKkr4cKPLyQ7JZt1pesorC0k1Z3K9L7TOSnpJArrCimuK6aotoj1petZVrDMLEMRCokRiaREppiNwUldUvnqlqG47cHEJFJKNKk1qWR0Qj6H/O1POWlSCztmv2U1odRCr9HUuWHbQ6+DRNeDZQJN1hFA0zV0DKXZ1D0jOaT67f08JMFnGvoc9hc19WApqi1ie9V2PJoHp+qkS7supLhTDnyiRYtxafyl7Kk3YhqlDOvP0Xj6pQ3NZIMLIWtQFgu/XcjrL7/Oax+8RllDGdW+ahwRDqrqqnAnuilrKAs7J6FTAvMXz+ebBd9w36z7GHHaCG6840YkkvKGcio9ldgcNsobjPDJfunHJ3yUN5RT46/B7/c3VZUjolUp/APRviKQii09Ea/DRnRCIqOm/Ik+o05H0zUGpwzmu7zv8GiGb3pBbQGPr3yc+0+5n3NCsmUB1PnqKKorMhqBwP/C2kI2lG4IGxWoQjWV6PHmUBWYQIAABQVFKAghUISCgmJsFwqqMBpTRQSOQYR9Ns8J2SeEQEHBJmwIReyzPfRazZZHM8cIsY9slrm/+oSUKRAsK1jGj/k/4tWN9QsezUNOZQ5jOo1hZHvDO6o5t1URtpx+//vDPjdRnmiqgL2PEU2Xd6BrNFu22P/+A9U59JgDPYsDlVe2o6zZfNQH82wOm72KHjtqLDOunME1117DwJ5GAvPzx5/PHyb8gaKiIm695VZef+P1sHPy8/PpmtyVzD9n0iWlC3Nfnkt6VDoCQXpUOl63F7tiJz3KWN8SYYsgTo8guaCeurwqpNeLv6ICW2wsLUWrUvhyP69AjdPOmk7J9MorZ1XEcF55c1bYflVRWV+63lT2jTRoDcxZNWcfhR9pj6RLTBe6xITH1NelTml9qdEA1BVS461pVpmFKi3zb69tocqrSSXWVLlNlPXNzm949OdHzfvzaB5yq3K5tPelnNX1rH0UXmN5h4Kma3h1Lw7FgaqoeDQPVZ4qYl2x2BU7tb5aiuqK6BDVAYfqoLyhnF3Vu+gV3wun6qSotohtFdsYlDoIp+pkV9Uu1petZ0zHMThUB1vKt7CmZA3ndTsPu2pnbclaVhatZGrmVGyKjRWFK1hWsIzr+l+HIhS+2/0dP+b/yB1DjPy+X2z/gmUFy7j/lPsBmLdlHssLlvPwqQ8D8Nr611hVvIonT3+Su7+/21T2jXh1L6+uf5Vr+l9jllfhqWBK7ykArC5ejVfzMjTNyF2QX5OPIhRTYUkprbUNh0iVUoWjBYOHHS5ZmVk4nU7uuvOuoPk2YChISkjC5/WFmXUBNq7fyG233YaiKNjtdp577jnzGJtiC/sMgM+PXl6ObMyrKyW+vHzjmBZS+q1K4e8Pj03Fq9h4tffZbO43ssljCmubnhAqrC1kZdFK+if1Rz1AQDRFKCRFJpEUmURfmo5hfSzRpY6ma8xdN7fJxuzB5Q/SIboDQ9KGkFuZyx1L7uCWQbcwJG0Iv5X9xs2Lb+b+U+4nOzWbX0t+5fqF1/PY6MfITs1mecFyrv76al4e/zIDUwayNH8p1y68ljfPfpOTkk7i+7zvuWnRTbw36T16x/dmSd4Sbvv2Nj467yO6xXbj+7zvufv7u/nsgs/o2K4jS/OXMmvpLL668CvSotJYmr+U2ctns2jyIhIjEg3lvOJhxnUeR4waw4qiFTyx8gku6X0JNsXGqqJVvLT2Ja4++WoUobCpbBPzc+abCn93zW5WFq0077/CU0FBbXDhXKN5CJp/F+r8debnL3O/ZEf1DlPhv/jri5Q2lPK/Ew1vjPuX3k+tv5Y3zzaSpM/4agaqUHlh/AsA/P37v+O2u7l76N0APLXqKeJd8UzNNGK5ztsyjwRXAqd1NJKrrChcQawzlh5xRuC2otoi3Hb3QTsTWBw+c+bM4aGHHsLtDppo582bx5dffklFRQXXXXed2aBLKZFeL+PHjuXMX39F6jp6dTUikBqxuqICX3ExnVJSWLduHbrXi7+oiBdmzUIGzDid27fn5w8/BKnjLypqMYXfqtwyxX7MJsu7peOx2bA7/M16yzQ3dEyMSGTaF9N4e9PbLVLPo4Vf9/ND3g9sKd8CQHlDOcPfGs77W95vVoF5da+p5OyqncSIRLNHFWmPJCsxiyi7oVDinHGMzxhPgssIEZvuTmda32kkRxohXjNiMpg5aCYpkYaZqHd8b+4ddq+5/+TEk3nk1EdIijQmyYekDuHZsc+SEGGUN6rDKF4/63XiI4zFZ2dmnMmH535IjNOImnhBjwtYcNECoh3GeoSpfaay/I/LcamGa+tfTvoLa/60BrtiN+Xvp3xv3uuMfjOYf0Ew9v+VWVfy2lmvmfIVfa/g/435f0Dz70KaOxi58InTn+Ddie+a8r3D7uXhUQ+b8lUnXcV1J19nyhO6TGB8xnhTjnXGEusM/pA3lG1ga8VWU3557ct8uv1TU77n+3t4df2rpnzpp5fy6M+PmvJZH5zFkyufNOW/Lvgr/7spmFT9wWUPsnjXYlN+Z9M7bCjdABgdg58Lf6a4rhgIxGbyVLbsJOlxJtSsqns86L7gvWlVVej1wfDmvpIStJoatm3bRu/evands4ep559vlKPreLZs5dzRo3n++ed55623GJaUhFYamAvQNDxbtqAFvHKkpuHdtQu9psY8319cjN4QDOOi1zeYyn6fevta7jtoVcHTHpt8zgHjyCtCYcJ1M5tMRP1pzqfcv/R+GrTgF+FSXdw77F4i7BEMThlMnCuOnwp+Yn7OfG4edDNxrriDv6EWQEqJV/fiVI1VxQ8ue5Ce8T25uOfF6FJn6JtDubjXxdyefTtSSh77+TFO73Q6dy25K6w320iaO42vLvrqmN7D74Hm3oWm5nOOFh7Ng6ZrRNqNxXmbyjYRYYugczsjgcgnOZ+QGpnK4FQjTtYTK58gKzGLcZ2NEM5XL7iaMZ3GMLnXZHSpM+bdMUzNnMqMfjPwaT4GvjGQvw34G1eddBV1vjqGvjWUmwfdzPSs6VR6Khn5zkjuyL6DqZlTKa0vZfInk5k5aCYTu06ktL6Uv//wd67IvILh6cMpayjjlXWvMLHrRHrF96LSU8l3u78jOzWbVHcqdb46dlbvpGN0R9x2N5quBUIeB40MoSYvX1ER0udjW3U1ffr0Qas1PGnUQA/bX14OQpg9X19hIcJmw5ZoxHfy7tiBcDqxpxoNd8PmzSiRbhwdDE+5hk2bUKLb4Whv2M8bNm5EjYnBnm7I9Rs2YIuLx54WOH/LFmxxcdgSE5FS4tu1CzUmBjUmBikl/uJilKgoVLcbqetoVVUoEREoTqfR4/d4EDYbwmbbJxl7Iw2//dakchd2O65eTXdS23TwtINBlzpL3nmtSYXf+EOes2qO6aVz48Ab9/mB51blsqJwhemBs7tqF8n2BGwIpKaD34fUNKSmBZJiN5HkutF1LWyXZO+Nm0o30uBvoH+SEW/9pm9uIiUyhbuG3omUkpLf1pAU78NjM77fV/s8SIo7Bc+2bQDcEH8BVEtuTbyEZ3c9g1cL2qUdioNrO06mYfPm/T+0ZvsEh9FZOGCC7yMva7+dmIO8zBgycCTN4J1Nb1Nav4eEiESm9JrCyNrO1K9dd+h1PUwE0NjvNNR8NfUY1x9LBtRCfYkhX+0YB1WY9Xsi9XrwBuXPM58GoH7tWqSULOj7HHa/nfq1a9F0P3M73U1KbTL1a9ei+xu4P3YqmWXtjP2eaiY19CZtZy31tWupLd5B2k87kGyhvjSKPeuXU/bDfymYFEOnNC+7v/2EjT+9TuzltxGTOpicD17jxzWfknXdXfRP6c/W559g0+YfybhrFlmJWeTMnkVxQQ4p/3qALjFd2H7vXZTVFBPz6PPodXV48/PRpYa9fXtsQsW/pwRdCHDYURBodXWgKojISGMeTyggJXqdYYJTo6PBZgvKCQmIENmWloZQVVN2ZGQgICi3NxoK8/hAwxJWfoisOBygaaYMIL1epDf4+9v7VVTj4vCXlIS/10LBltJyvkltrocPgJScvXY7tpQU4q+cjjs7G62iwvirrESrqESrrgK/hvT7kbpmfNY00PxIv4bu9yF0HenXWFn4MzbFxslJwSQYe3ZuRtmZj90PPhvondJJ7NSzyepoUjO9XfJq8qj319M91sjk8+ueX/FpPgalDDL32xSbaTY5FIrqitheGeKlE9PlsMqxODEJ7TlKv9/oVUZEIBQFvb4evabGUHSKYrzn5eXYO3VCKAr+khL8xcU4MzMRQuDLy8OXn09kdjYAnpwcfHl5RI0yfM09W7bgKyw05YbNm9FKSnCPMOLw12/ahFZWimv4MGxCpX7LZrzVlUT0PxmH4qAuN4fa2nKie/fFpbqoydtBaW0JSV37EmmLoKJ4J3nV+aTf9xS9O3bC5/fi0TxEOtwoQsGn+WjQGnDb95ajUITAq/nwaJ7AfoFP9+HTfETYIxAI/Lofv+7HaTMiY2pSQ9M17KrDUPRSNyLVBubsmuuVtzR+bwN4fQgJmiqQiXFEJ6U3e/wJ3cMXQkwA5mCkeXlJSvnvY3n9Rlw+P0iJv7CQ4n8/jLNXL+yBVtRfXoZ3y1b0ujqUqCjcI0bg6tsXoaoImwqqLfBfRag2UBTSqrshVYWYpCx0RfDRBw8xcEc+9oB3psMP3h357BqSSeqYCWyv3M7w9OEgBG9ueIMfC5bx9Fgj1dtXv73NzqqdDBv6VwB61xbgUl2GXVsIEmGvRi00u87em8KTfru+/Y52b76JtseDmhhN3DkTiD7ttIN8avt34TsUmv3R7O/HdKg/tP0ef3BlVS9aRPl//4u/pARbUhJxV1xB9JgjW/nYaLbQvV60khLUhAQUlwutspKG9etx9e2LGhODL7+Amm+/JXrcGdgSE/Fs2ULFB/OInz4Ne0oKdStXUfbSS6TMuhd7WhrV3yyi5LHH6PjyS9hTU6n6/Av2PPUUnV57DVtSIpWffELpM8/S+e23UGNjqfzwI0pfeIH0/zyCGh1N5aefUvnhRyTfPBPF6aR68WJql3xP8m23IlSVupUradiwkfjLjQnlhs2b8RcVmQrfV1yMrK/H0dkYh0i/HxQFcZBZqlKAbnvJvYCt1dXYUlOxAa4QPzxFaii6P6CgBVL3YfM3YLdHIYTA729A89VgdyUghKDBV0ONp4roqFQEghpPBeUN5XSJMUw2lfWllHvK6R5rJJrZU7+HSk8l3WK7mXKVp5KuIXKdr5ZOAfNauaccj99jzv1Ue6vw6X7iXcZ8VJ2vDh3dnA9rHGk3zpfpUqfWV0NxXS0ykH7Jr4IQFaR7IsPmeo6EY6bwhRAq8AwwDtgNrBBCfCyl3NBS17BrOj7bAbxodJ1eBSELJHQdX0EBHZ//H6oXLaL4wX+Zwy69poaaxYtxjxhB3OSL8ZeUUPPdd7hHjcKenIxn2zbK33qbAdOn4+jQnrqff2bHww/SY3tQ2Tfi0MAz/xtKf1zDg2eXMX/CdFixhuyF+TivnIKz/0l4Vv/COdtiSLrxRdToaOrXrSf2t0Li/ngpisuFZ9s2PFu2ED12LMJux1dYiL+4GFdWltFrq65GejxGL24vhVc5fz6l//M/yMBEkVZSQumzz+FISyNm0qQjf/gtQOOklQiEwNA9HhDCGB4DWk0tQlVQAt4OWmUlwmZDabTrlpYinE7UQKwSX1ERSkQEajsjYJ13927UqCjUgN3Xs307amwstrg4Y25k61bUhARs8fFU/N//seepp5Aew7PJX1zMnjlzEKpCwrRpaNXVlL/1NlGjRuLKzMRfUkLRI/8hbsolRA4ahHfHDnbfNJPkW24hauQIGjZsYPslU+gwZw7RY06nbvVqds24io4vvkjEqJHU/vQTRQ/MptOrr+Ds3x9ffj7lr71Gu/HjcHbpgr+oCG/udmxxcTi7dEGrqMDRvRuOTp1xdGiPPKUBvfoqXL16YYuPJ+acs3F06kRE30wUt5v4yy6j3fjxOLt2RdjtJN1wPUl/u8F81knXXUfSdcEJ5oRp00iYNs2UHRkZcCHhMs3LLYXYuBHFuW8UXIVw5eXEiZOgt1Kk00kkMabczumkXVQwH228M4X4dsHRbYIjlTiZjBKYU4i1JeF2x6LYjWtHKXHYXZFmXZxEIe02U9Y1FU0oplzj89IgG0h0GpP8ZZ4ivLrXrENRVSF+3W82KDsrc6nz1yHVcIuLlJLi2uIWU/jH0ktnCLBVSpkjpfQC7wDnteQFDrS60u7X6LerxFyA1YheUYE9OZk9Tz8TZmMDkB4PJU8ang/enTsp+Ps9eLcanhT+PaVUfvIJWiA5uLDZiIyKJS68eJOoWp34jJ7MnfQGEbYI9Lo62lV4+WOfP6IqKt7cXCrnzzcVX92KFRQ/8og5kVO98BvybpppmJaAinnzyJ18iWnzK507ly2nnmYq++LHHuO3bCOJd/ETT5rK3ry3hgYK7v67KRc98h9y/3iZKRc+MJvcy8x07+Tfcw87pl5uynm33saOK6aZ8u4bbmDH9OmmvHPGVey88s+mnDuVaIeEAAAM3klEQVR1KjtnXGXK2/9wIbv+enVQvuAP5M2cGZTPO5+CO+8KyueeS+H9/zDlnImTKPp3cJCYc/Y5lDz+RFA+62z2PPNsmFz68twwufz1NwzB5yNn0rlUvPseACVPPGkq+0ak18ueZ58DQK+vp+SJJ6hfs8bYp+vU//IL/oCnhnC5sKemorgMBWBLSiJh2jQcHTsAhoJMf+RhnD0NF0tXZl+6zPuAiH5GiG730KH0/nUNkYONkbl72DC6f/mlOXkXOWAAHZ9+2pyEdPXpQ/JNN2GLN3qUjs6diZl4jtkY2uLjcfXqhbAbHkzCbjeVvYXhzBE6gexQHWGr5CPtkWEOGjHOmLBFi0mRSXSM7mjK7aPam8ocID0qnc7RnU05OTI5zOMrzhXX7NxTS3pKHctvvD2wK0TeDQzd+yAhxF+AvwB06tRp7937pTGEQnOcVe7FX7GvNrYFZua1PXuaPE8rN5Y+u7Ky6L7wa9Qkw63QPXQIvZYHQyxE9O9P51de4YehWcRXavuUUx6jMuL5l0w5+owziD4jmGs09sILib0w2I2Kv3wqsRdfjOI2vDRiL76IqNGnIQK9iJhzzsGVmYkI3Hf06adjTwm6E0YOHoywG71jf8G+HjoQ7vLlyOgMWtA1zNmzJ0pkSK7VrH7Y04IvaeTgwcZcRwD3iBFhSjL6jPCIgjETJ5kKByB28mTz3gDipk5FjQn2yuKvnG5OjgEkXHO16XUBkHTTjaZXBUDy7bfj6ByS+/Xee3F2yTDltNkP4Oje3ZTT//MfU+Fis9H+icdx9jTmWfxFRTSFXm3EQrElJtJrzS+IwOjDnpJC9wVBbyd7Sgodnws2NrakJJJvuTkox8URc+65pqxGuVEzg3l6LWXcuth7UVaELTyibowzhqLaoiaVe6ObcUtwzCZthRAXAROklDMC8uXAUCnl9c2dc6iTtk9eNBGtGZ0fnZjEJRP+QMG9s8J6usLlIu2BfxIzaRJbxozFn5+/z7m29HR6fLPwoOux+OV/Evvk2zhDvjuPHSpuupTRf57V/IlHkZa6t7aC9bxODJqalGytVHgqyK/JD+vpC2GEYWjOpHOok7bH0qSTB3QMkTsEtrUYCedfCU1lA1NVRk35EzGTJpH2wD+NHr0Q2NLTTWUPkDzzJoQrPD69cLlInnnTIdVj9J9nUXHTpZTFqOhAWYx6XJU9tNy9tRWs5/X7ZOOSRbxw3XQemzKJF66bzsYli453lQ6aWGcs6VHpZo++Mc5OS9nv4dgq/BVADyFEFyGEA5gCfNySF7h86h9IPu9KGhQnEsPPVYlwc/Y1N5l+9zGTJtHjm4X02biBHt8sDJuwPFCDcCiM/vMsRixfR99NGxmxfN1xVfbQsvfWFrCe1++PjUsW8dULT1O9x/Blr95TwlcvPH3ESv9wE6DsneDksssu4+uvv2bEiBH06NGDn376CYA33niDIUOG0L9/f+742x10i+lGRkQGMy+fyWlDTgtLnnKkHFM/fCHE2cCTGG6Zc6WUD+7v+EM16VhYWLQu9jZZ/O8/7qTvaWeQNfoMNL+f9x+8h35jziRz1Om8cO00qkv3nYeLiG7HtS+9RV1VJfOfeIjBEy+g26Ch1FaU44498Ep5XddJT08nLy8PVVUZPXo0jz/+OAMHDtzvebm5uXTv3p3Vq1fTt29fsrOzOfnkk3n55ZeNBCevvMJDDz3E7bffzrx587Db7Vx77bUMGzYMt9vNF198wYsvvggYyVNiQua3mns+cOKYdJBSfial7Cml7HYgZW9hYWFxKFSXNh3Xvj7EseBwUBSFvn37sn79ej744AM6d+7MwIEDWbx4MaNGjeLqq69m8eLFTZ7bpUsX+vXrZ5YxduxYhBD069eP3NxcFi5cyMqVK8nOzqZ///4sXLiQnJwc+vXrx4IFC7jjjjtYsmRJk8r+cLBcASwsLH43XHJf0A1XtdnC5OjERMOcsxfRgYx2ke1iwo4/mN59I8OGDeOHH37g2Wef5YsvvgCMCdWoqCgaGhro0KFDk+c5Q9YQKIpiyoqi4Pf7kVJyxRVX8NBDD+1z7qpVq/jss8+45557GDt2LLNmHblZuFVFy7SwsGi7jJryJ2yO8EVajRntjpRhw4Zxzz33cMEFF9A+EFdn1KhRfP755zz88MPcd999h1Xu2LFjef/99ykuNqKUlpWVsWPHDvLz84mMjGTq1KncdtttrFq16ojvAawevoWFRSuh0TFjyTuvUV26Jyyj3ZHSu3dvnE4nd9xxh7lNCYSNiIuLw7PXIr2DJTMzk9mzZzN+/Hh0Xcdut/PMM89QWVm5T/KUlqBVBU+zsLBoXZwofvjXX3892dnZXHHFFea20AQo11xzDaNHjz7m9TrUSdsTWuELIUqAHYd5eiLQ9NLZ1ot1z62fNnW/CxYs6JeUlISqqi2f0fsg2Llzp7j22mtd/fv312bPnu098Bktg6ZptoO558LCQtu4cePW7rW5s5QyqanjT2iTTnOVPhiEED8318q1Vqx7bv20tftds2ZNrqqqSVlZWRuPx/WzsrLIzc095tddt25dn4O5Z03TEg/lfbAmbS0sLCzaCJbCt7CwsGgjtGaF/8LxrsBxwLrn1k9bu189ISFhX+f6Vk5iYuIB71nXdUHT0cOapdUqfCllW/thWPfcBmhr9wusUxTFH1BubYbU1NT9Tszrui5KSkpigENKsHxCT9paWFi0bfx+/4zCwsKXCgsLs2jFHdTDQAfW+f3+GYdy0gntlmlhYWFh0XK0uhZTCDFBCPGbEGKrEOLO412fo40QoqMQYpEQYoMQYr0Q4sbjXadjhRBCFUKsFkJ8crzrciwQQsQKId4XQmwSQmwUQgw/3nU62gghZgbe63VCiLeFEK4Dn/X7QggxVwhRLIRYF7ItXgixQAixJfD/4AP/7IdWpfBDEqWfBWQClwohMvd/1u8eP3CLlDITGAZc1wbuuZEbgePin32cmAN8IaXsDZxMK793IUR74G/AYCllFkZY9SnHt1ZHhVeBCXttuxNYKKXsASwMyEdMq1L4HINE6ScaUsoCKeWqwOdqDCXQ/vjW6ugjhOgAnAO8dKBjWwNCiBjgVOBlACmlV0pZcXxrdUywARFCCBsQCeybd/J3jpTyO6Bsr83nAf8NfP4vcH5LXKu1KfymEqW3euXXiBAiAxgALD++NTkmPAncziG6pf2O6QKUAK8EzFgvCSHcx7tSRxMpZR7wKLATKAAqpZRf7f+sVkOKlLIg8LkQSGmJQlubwm+zCCGigA+Am6SUR5bx4QRHCDERKJZSrjzedTmG2ICBwHNSygFALS00zD9RCditz8No7NIBtxBi6vGt1bFHGp41LeJd09oU/lFPlH4iIoSwYyj7N6WU8453fY4BI4BzhRC5GGa7MUKIN45vlY46u4HdUsrG0dv7GA1Aa+YMYLuUskRK6QPmAacc4JzWQpEQIg0g8L+4JQptbQr/qCdKP9EQQggMu+5GKeXjx7s+xwIp5V1Syg5SygyM7/gbKWWr7vlJKQuBXUKIXoFNY4ENx7FKx4KdwDAhRGTgPR9LK5+oDuFjoDEW8xXA/7VEoa1q4ZWU0i+EuB74kmCi9PXHuVpHmxHA5cBaIcQvgW13Syk/O451sjg63AC8GejM5ADTj3N9jipSyuVCiPeBVRjeaKtphaElhBBvA6OBRCHEbuA+4N/Au0KIP2OEiJ/cIteyFl5ZWFhYtA1am0nHwsLCwqIZLIVvYWFh0UawFL6FhYVFG8FS+BYWFhZtBEvhW1hYWLQRLIVvYWFh0UawFL6FhYVFG8FS+BYWeyGE6CCEuKSZfRFCiG8Dobib2u8QQnwXiO5oYXFCYSl8C4t9GUvzcWquBOZJKbWmdgbCci8EmmwwLCyOJ5bCt7AIQQgxEngcuEgI8YsQouteh1xGIK6JEMIthPhUCLEmkJGpUcl/FDjOwuKEwhp2WliEIKX8XgixArhVSrkudF8ghk1XKWVuYNMEIF9KeU5gf0xg+zog+xhV2cLioLF6+BYW+9IL2NTE9kQgNMvUWmCcEOJhIcQoKWUlQMDc4xVCRB/9qlpYHDyWwrewCEEIkYiRWcnfxO56wEyiLaXcjGHrXwvMFkLMCjnWCTQczbpaWBwqlknHwiKcDJrJmyqlLBdCqEIIl5SyQQiRDpRJKd8QQlQAMwCEEAnAnkDSDguLEwarh29hEc4mjLjk64QQTWVX+goYGfjcD/gpkIfgPmB2YPvpwKdHvaYWFoeIFQ/fwuIQEEIMBGZKKS/fzzHzgDsDJh8LixMGq4dvYXEISClXAYv2t/AK+MhS9hYnIlYP38LCwqKNYPXwLSwsLNoIlsK3sLCwaCNYCt/CwsKijWApfAsLC4s2gqXwLSwsLNoIlsK3sLCwaCP8f9MpgrW5ikFLAAAAAElFTkSuQmCC\n" }, "metadata": { "needs_background": "light" @@ -714,7 +530,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 23, "metadata": { "scrolled": true }, @@ -752,13 +568,13 @@ "input_file = f'{example_data_dir}/example_data.h5'\n", "\n", "# Perform two optimizer runs from different starting points\n", - "!{optimizationOptionsPy} {input_file} -s numStarts 1\n", + "!{optimization_options_py} {input_file} -s numStarts 1\n", "\n", "# Disable hierarchical optimization\n", - "!{optimizationOptionsPy} {input_file} -s hierarchicalOptimization 0\n", + "!{optimization_options_py} {input_file} -s hierarchicalOptimization 0\n", "\n", "# Print settings\n", - "!{optimizationOptionsPy} {input_file}" + "!{optimization_options_py} {input_file}" ] }, { @@ -770,7 +586,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 24, "metadata": { "scrolled": true }, @@ -779,126 +595,119 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32m[2020-01-31 18:32:59] [INF] [-1/] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001b[0m\n", - "\n", - "List of user-set options:\n", - "\n", - " Name Value used\n", - " acceptable_iter = 1 yes\n", - " acceptable_obj_change_tol = 1e-05 yes\n", - " acceptable_tol = 1e-05 yes\n", - " hessian_approximation = limited-memory yes\n", - " limited_memory_update_type = bfgs yes\n", - " max_iter = 20 yes\n", - " print_level = 5 yes\n", - " print_user_options = yes yes\n", - " tol = 1e-09 yes\n", - " watchdog_shortened_iter_trigger = 0 yes\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.11.9, running with linear solver mumps.\n", - "NOTE: Other linear solvers might be more efficient (see Ipopt documentation).\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 0\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 0\n", - "\n", - "Total number of variables............................: 9\n", - " variables with only lower bounds: 0\n", - " variables with lower and upper bounds: 9\n", - " variables with only upper bounds: 0\n", - "Total number of equality constraints.................: 0\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "\u001b[32m[2020-01-31 18:32:59] [INF] [-1/] [o0i0] iter: 0 cost: 626.531 time_iter: wall: 0.128325s cpu: 0.303161s time_optim: wall: 0.128325s cpu: 0.303161s\u001b[0m\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 6.2653094e+02 0.00e+00 1.00e+02 0.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - "\u001b[32m[2020-01-31 18:32:59] [INF] [-1/] [o0i1] iter: 1 cost: 1463.44 time_iter: wall: 0.0852051s cpu: 0.106241s time_optim: wall: 0.21353s cpu: 0.409402s\u001b[0m\n", - " 1 1.4634444e+03 0.00e+00 4.86e+01 2.0 5.93e+01 - 9.91e-01 2.64e-02f 2\n", - "\u001b[32m[2020-01-31 18:32:59] [INF] [-1/] [o0i2] iter: 2 cost: 649.013 time_iter: wall: 0.0331879s cpu: 0.101892s time_optim: wall: 0.246718s cpu: 0.511294s\u001b[0m\n", - " 2 6.4901342e+02 0.00e+00 5.14e+01 2.2 6.01e-01 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:32:59] [INF] [-1/] [o0i3] iter: 3 cost: 314.319 time_iter: wall: 0.0346526s cpu: 0.10105s time_optim: wall: 0.281371s cpu: 0.612344s\u001b[0m\n", - " 3 3.1431856e+02 0.00e+00 5.53e+01 1.5 7.42e-01 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:32:59] [INF] [-1/] [o0i4] iter: 4 cost: -113.523 time_iter: wall: 0.038709s cpu: 0.10912s time_optim: wall: 0.32008s cpu: 0.721463s\u001b[0m\n", - " 4 -1.1352340e+02 0.00e+00 1.39e+01 0.3 2.72e-01 - 9.68e-01 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:32:59] [INF] [-1/] [o0i5] iter: 5 cost: -222.462 time_iter: wall: 0.0378889s cpu: 0.112344s time_optim: wall: 0.35797s cpu: 0.833807s\u001b[0m\n", - " 5 -2.2246159e+02 0.00e+00 9.68e+00 -0.5 4.58e-01 - 9.94e-01 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:32:59] [INF] [-1/] [o0i6] iter: 6 cost: -288.147 time_iter: wall: 0.0385587s cpu: 0.110554s time_optim: wall: 0.396528s cpu: 0.944361s\u001b[0m\n", - " 6 -2.8814676e+02 0.00e+00 1.04e+01 -1.8 2.99e-01 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:32:59] [INF] [-1/] [o0i7] iter: 7 cost: -334.082 time_iter: wall: 0.0508817s cpu: 0.122703s time_optim: wall: 0.44741s cpu: 1.06706s\u001b[0m\n", - " 7 -3.3408184e+02 0.00e+00 6.67e+00 -2.8 4.35e-01 - 1.00e+00 5.00e-01f 2\n", - "\u001b[32m[2020-01-31 18:32:59] [INF] [-1/] [o0i8] iter: 8 cost: -356.625 time_iter: wall: 0.0492991s cpu: 0.126455s time_optim: wall: 0.49671s cpu: 1.19352s\u001b[0m\n", - " 8 -3.5662478e+02 0.00e+00 2.60e+00 -2.6 2.50e-01 - 1.00e+00 5.00e-01f 2\n", - "\u001b[32m[2020-01-31 18:32:59] [INF] [-1/] [o0i9] iter: 9 cost: -358.789 time_iter: wall: 0.0387502s cpu: 0.110804s time_optim: wall: 0.53546s cpu: 1.30432s\u001b[0m\n", - " 9 -3.5878931e+02 0.00e+00 2.85e+00 -4.0 1.20e-01 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:33:00] [INF] [-1/] [o0i10] iter: 10 cost: -366.213 time_iter: wall: 0.0384761s cpu: 0.111101s time_optim: wall: 0.573936s cpu: 1.41542s\u001b[0m\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -3.6621295e+02 0.00e+00 5.23e-01 -5.5 7.77e-02 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:33:00] [INF] [-1/] [o0i11] iter: 11 cost: -366.866 time_iter: wall: 0.0385245s cpu: 0.111319s time_optim: wall: 0.612461s cpu: 1.52674s\u001b[0m\n", - " 11 -3.6686642e+02 0.00e+00 4.37e-01 -7.2 2.93e-02 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:33:00] [INF] [-1/] [o0i12] iter: 12 cost: -367.081 time_iter: wall: 0.0535711s cpu: 0.135304s time_optim: wall: 0.666033s cpu: 1.66205s\u001b[0m\n", - " 12 -3.6708102e+02 0.00e+00 3.39e-01 -8.5 2.18e-01 - 1.00e+00 1.25e-01f 4\n", - "\u001b[32m[2020-01-31 18:33:00] [INF] [-1/] [o0i13] iter: 13 cost: -367.411 time_iter: wall: 0.0343724s cpu: 0.0933246s time_optim: wall: 0.700405s cpu: 1.75537s\u001b[0m\n", - " 13 -3.6741091e+02 0.00e+00 9.33e-01 -10.0 5.93e-02 - 1.00e+00 1.00e+00f 1\n", - "\u001b[32m[2020-01-31 18:33:00] [INF] [-1/] [o0i14] iter: 14 cost: -367.804 time_iter: wall: 0.0731372s cpu: 0.121933s time_optim: wall: 0.773543s cpu: 1.87731s\u001b[0m\n", - " 14 -3.6780351e+02 0.00e+00 9.75e-01 -11.0 3.24e-01 - 1.00e+00 2.50e-01f 3\n", - "\u001b[32m[2020-01-31 18:33:00] [INF] [-1/] [o0i15] iter: 15 cost: -367.807 time_iter: wall: 0.0499441s cpu: 0.126759s time_optim: wall: 0.823487s cpu: 2.00406s\u001b[0m\n", - " 15 -3.6780707e+02 0.00e+00 7.95e-01 -11.0 9.61e-01 - 1.00e+00 1.25e-01f 4\n", - "\u001b[32m[2020-01-31 18:33:00] [INF] [-1/] [o0i16] iter: 16 cost: -368.218 time_iter: wall: 0.043879s cpu: 0.116849s time_optim: wall: 0.867366s cpu: 2.12091s\u001b[0m\n", - " 16 -3.6821775e+02 0.00e+00 5.26e-01 -11.0 1.79e-01 - 1.00e+00 5.00e-01f 2\n", - "\u001b[32m[2020-01-31 18:33:00] [INF] [-1/] [o0i17] iter: 17 cost: -368.464 time_iter: wall: 0.0509795s cpu: 0.125243s time_optim: wall: 0.918346s cpu: 2.24616s\u001b[0m\n", - " 17 -3.6846370e+02 0.00e+00 3.89e-01 -11.0 9.68e-02 - 1.00e+00 5.00e-01f 2\n", - "\u001b[32m[2020-01-31 18:33:00] [INF] [-1/] [o0i18] iter: 18 cost: -368.505 time_iter: wall: 0.0586174s cpu: 0.134238s time_optim: wall: 0.976964s cpu: 2.3804s\u001b[0m\n", - " 18 -3.6850451e+02 0.00e+00 3.31e-01 -11.0 1.18e-01 - 1.00e+00 2.50e-01f 3\n", - "\u001b[32m[2020-01-31 18:33:00] [INF] [-1/] [o0i19] iter: 19 cost: -368.528 time_iter: wall: 0.0689234s cpu: 0.149573s time_optim: wall: 1.04589s cpu: 2.52997s\u001b[0m\n", - " 19 -3.6852794e+02 0.00e+00 2.10e-01 -11.0 1.47e-01 - 1.00e+00 1.25e-01f 4\n", - "\u001b[32m[2020-01-31 18:33:00] [INF] [-1/] [o0i20] iter: 20 cost: -368.587 time_iter: wall: 0.0617347s cpu: 0.117735s time_optim: wall: 1.10762s cpu: 2.6477s\u001b[0m\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -3.6858740e+02 0.00e+00 1.88e-01 -11.0 2.33e-02 - 1.00e+00 5.00e-01f 2\n", - "\n", - "Number of Iterations....: 20\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -8.4095250170472902e+00 -3.6858739597182932e+02\n", - "Dual infeasibility......: 1.8772006533169214e-01 8.2277239097344612e+00\n", - "Constraint violation....: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Complementarity.........: 1.0038425255336661e-11 4.3998168945593131e-10\n", - "Overall NLP error.......: 1.8772006533169214e-01 8.2277239097344612e+00\n", - "\n", - "\n", - "Number of objective function evaluations = 84\n", - "Number of objective gradient evaluations = 21\n", - "Number of equality constraint evaluations = 0\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 0\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 0\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.819\n", - "Total CPU secs in NLP function evaluations = 5.662\n", - "\n", - "EXIT: Maximum Number of Iterations Exceeded.\n", - "\u001b[32m[2020-01-31 18:33:00] [INF] [-1/] [o0i21] Optimizer status 1, final llh: -3.685874e+02, time: wall: 1.108160 cpu: 2.647703.\u001b[0m\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[32m[2020-01-31 18:33:02] [INF] [-1/] Walltime on master: 3.007232s, CPU time of all processes: 6.903856s\u001b[0m\r\n" + "\u001B[32m[2020-06-24 17:54:17] [INF] [-1:140203247966144/] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001B[0m\r\n", + "\r\n", + "List of user-set options:\r\n", + "\r\n", + " Name Value used\r\n", + " acceptable_iter = 1 yes\r\n", + " acceptable_obj_change_tol = 1e-05 yes\r\n", + " acceptable_tol = 1e-05 yes\r\n", + " hessian_approximation = limited-memory yes\r\n", + " limited_memory_update_type = bfgs yes\r\n", + " max_iter = 20 yes\r\n", + " print_level = 5 yes\r\n", + " print_user_options = yes yes\r\n", + " tol = 1e-09 yes\r\n", + " watchdog_shortened_iter_trigger = 0 yes\r\n", + "\r\n", + "******************************************************************************\r\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\r\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\r\n", + " For more information visit http://projects.coin-or.org/Ipopt\r\n", + "******************************************************************************\r\n", + "\r\n", + "This is Ipopt version 3.12.12, running with linear solver ma27.\r\n", + "\r\n", + "Number of nonzeros in equality constraint Jacobian...: 0\r\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\r\n", + "Number of nonzeros in Lagrangian Hessian.............: 0\r\n", + "\r\n", + "Total number of variables............................: 9\r\n", + " variables with only lower bounds: 0\r\n", + " variables with lower and upper bounds: 9\r\n", + " variables with only upper bounds: 0\r\n", + "Total number of equality constraints.................: 0\r\n", + "Total number of inequality constraints...............: 0\r\n", + " inequality constraints with only lower bounds: 0\r\n", + " inequality constraints with lower and upper bounds: 0\r\n", + " inequality constraints with only upper bounds: 0\r\n", + "\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i0] iter: 0 cost: 532.303 time_iter: wall: 0.150796s cpu: 0.142117s time_optim: wall: 0.150796s cpu: 0.142117s\u001B[0m\r\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\r\n", + " 0 5.3230269e+02 0.00e+00 1.00e+02 0.0 0.00e+00 - 0.00e+00 0.00e+00 0\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i1] iter: 1 cost: 820.034 time_iter: wall: 0.0978683s cpu: 0.0851084s time_optim: wall: 0.248665s cpu: 0.227225s\u001B[0m\r\n", + " 1 8.2003355e+02 0.00e+00 4.00e+01 2.0 5.98e+01 - 9.91e-01 2.66e-02f 2\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i2] iter: 2 cost: 776.643 time_iter: wall: 0.0802227s cpu: 0.0728087s time_optim: wall: 0.328887s cpu: 0.300034s\u001B[0m\r\n", + " 2 7.7664256e+02 0.00e+00 5.20e+01 2.2 5.80e-01 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i3] iter: 3 cost: -166.319 time_iter: wall: 0.089962s cpu: 0.0772412s time_optim: wall: 0.41885s cpu: 0.377275s\u001B[0m\r\n", + " 3 -1.6631926e+02 0.00e+00 4.12e+01 1.5 2.34e+00 - 1.00e+00 2.50e-01f 3\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i4] iter: 4 cost: -267.208 time_iter: wall: 0.0847308s cpu: 0.0763528s time_optim: wall: 0.503581s cpu: 0.453628s\u001B[0m\r\n", + " 4 -2.6720761e+02 0.00e+00 3.92e+00 0.2 1.85e-01 - 9.91e-01 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i5] iter: 5 cost: -325.047 time_iter: wall: 0.0756548s cpu: 0.0673815s time_optim: wall: 0.579236s cpu: 0.521009s\u001B[0m\r\n", + " 5 -3.2504664e+02 0.00e+00 4.86e+00 -1.2 1.59e-01 - 9.84e-01 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i6] iter: 6 cost: -336.398 time_iter: wall: 0.0723731s cpu: 0.0639552s time_optim: wall: 0.651609s cpu: 0.584965s\u001B[0m\r\n", + " 6 -3.3639830e+02 0.00e+00 1.12e+01 -1.9 8.74e-01 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i7] iter: 7 cost: -389.279 time_iter: wall: 0.0873986s cpu: 0.0726503s time_optim: wall: 0.739008s cpu: 0.657615s\u001B[0m\r\n", + " 7 -3.8927856e+02 0.00e+00 6.91e+00 -1.8 7.08e-01 - 1.00e+00 2.50e-01f 3\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i8] iter: 8 cost: -417.125 time_iter: wall: 0.0832864s cpu: 0.0703492s time_optim: wall: 0.822294s cpu: 0.727964s\u001B[0m\r\n", + " 8 -4.1712507e+02 0.00e+00 2.72e+00 -2.7 5.18e-01 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i9] iter: 9 cost: -425.124 time_iter: wall: 0.0853009s cpu: 0.072256s time_optim: wall: 0.907595s cpu: 0.80022s\u001B[0m\r\n", + " 9 -4.2512435e+02 0.00e+00 2.77e+00 -4.1 1.14e-01 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i10] iter: 10 cost: -431.91 time_iter: wall: 0.0697795s cpu: 0.0616751s time_optim: wall: 0.977375s cpu: 0.861895s\u001B[0m\r\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\r\n", + " 10 -4.3191005e+02 0.00e+00 9.02e-01 -5.5 4.63e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i11] iter: 11 cost: -432.548 time_iter: wall: 0.0834681s cpu: 0.0699167s time_optim: wall: 1.06084s cpu: 0.931812s\u001B[0m\r\n", + " 11 -4.3254817e+02 0.00e+00 7.07e-01 -7.2 3.94e-02 - 1.00e+00 5.00e-01f 2\r\n", + "\u001B[32m[2020-06-24 17:54:18] [INF] [-1:140202953152256/] [o0i12] iter: 12 cost: -433.253 time_iter: wall: 0.0688184s cpu: 0.0608798s time_optim: wall: 1.12966s cpu: 0.992692s\u001B[0m\r\n", + " 12 -4.3325317e+02 0.00e+00 5.07e-01 -8.8 3.00e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:54:19] [INF] [-1:140202953152256/] [o0i13] iter: 13 cost: -434.385 time_iter: wall: 0.0718203s cpu: 0.0626103s time_optim: wall: 1.20148s cpu: 1.0553s\u001B[0m\r\n", + " 13 -4.3438479e+02 0.00e+00 6.25e-01 -10.3 4.40e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:54:19] [INF] [-1:140202953152256/] [o0i14] iter: 14 cost: -438.759 time_iter: wall: 0.0686035s cpu: 0.0598197s time_optim: wall: 1.27009s cpu: 1.11512s\u001B[0m\r\n", + " 14 -4.3875867e+02 0.00e+00 3.98e+00 -11.0 5.21e-01 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:54:19] [INF] [-1:140202953152256/] [o0i15] iter: 15 cost: -440.48 time_iter: wall: 0.0965021s cpu: 0.0791499s time_optim: wall: 1.36659s cpu: 1.19427s\u001B[0m\r\n", + " 15 -4.4047967e+02 0.00e+00 4.39e+00 -11.0 2.61e+00 - 1.00e+00 6.22e-02f 5\r\n", + "\u001B[32m[2020-06-24 17:54:19] [INF] [-1:140202953152256/] [o0i16] iter: 16 cost: -442.029 time_iter: wall: 0.0895043s cpu: 0.0736639s time_optim: wall: 1.45609s cpu: 1.26794s\u001B[0m\r\n", + " 16 -4.4202943e+02 0.00e+00 2.94e+00 -11.0 4.38e-01 - 1.00e+00 1.25e-01f 4\r\n", + "\u001B[32m[2020-06-24 17:54:19] [INF] [-1:140202953152256/] [o0i17] iter: 17 cost: -443.967 time_iter: wall: 0.0692997s cpu: 0.0606437s time_optim: wall: 1.52539s cpu: 1.32858s\u001B[0m\r\n", + " 17 -4.4396683e+02 0.00e+00 1.78e+00 -11.0 1.93e-01 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:54:19] [INF] [-1:140202953152256/] [o0i18] iter: 18 cost: -446.323 time_iter: wall: 0.0702509s cpu: 0.0613218s time_optim: wall: 1.59564s cpu: 1.3899s\u001B[0m\r\n", + " 18 -4.4632309e+02 0.00e+00 1.06e+00 -11.0 9.67e-02 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:54:19] [INF] [-1:140202953152256/] [o0i19] iter: 19 cost: -446.807 time_iter: wall: 0.0695901s cpu: 0.0606455s time_optim: wall: 1.66523s cpu: 1.45055s\u001B[0m\r\n", + " 19 -4.4680666e+02 0.00e+00 7.12e-01 -11.0 1.64e-01 - 1.00e+00 1.00e+00f 1\r\n", + "\u001B[32m[2020-06-24 17:54:19] [INF] [-1:140202953152256/] [o0i20] iter: 20 cost: -446.911 time_iter: wall: 0.0982874s cpu: 0.0793654s time_optim: wall: 1.76352s cpu: 1.52991s\u001B[0m\r\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\r\n", + " 20 -4.4691082e+02 0.00e+00 5.78e-01 -11.0 5.12e-01 - 1.00e+00 3.12e-02f 6\r\n", + "\r\n", + "Number of Iterations....: 20\r\n", + "\r\n", + " (scaled) (unscaled)\r\n", + "Objective...............: -1.0020280299723407e+01 -4.4691081555274133e+02\r\n", + "Dual infeasibility......: 5.7791560739777803e-01 2.5775400258007569e+01\r\n", + "Constraint violation....: 0.0000000000000000e+00 0.0000000000000000e+00\r\n", + "Complementarity.........: 1.0893437113616458e-11 4.8585415966389838e-10\r\n", + "Overall NLP error.......: 5.7791560739777803e-01 2.5775400258007569e+01\r\n", + "\r\n", + "\r\n", + "Number of objective function evaluations = 77\r\n", + "Number of objective gradient evaluations = 21\r\n", + "Number of equality constraint evaluations = 0\r\n", + "Number of inequality constraint evaluations = 0\r\n", + "Number of equality constraint Jacobian evaluations = 0\r\n", + "Number of inequality constraint Jacobian evaluations = 0\r\n", + "Number of Lagrangian Hessian evaluations = 0\r\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.578\r\n", + "Total CPU secs in NLP function evaluations = 1.536\r\n", + "\r\n", + "EXIT: Maximum Number of Iterations Exceeded.\r\n", + "\u001B[32m[2020-06-24 17:54:19] [INF] [-1:140202953152256/] [o0i21] Optimizer status 1, final llh: -4.469108e+02, time: wall: 1.764039 cpu: 1.529912.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 17:54:20] [INF] [-1:140203247966144/] Walltime on master: 3.006277s, CPU time of all processes: 2.549641s\u001B[0m\r\n" ] } ], "source": [ "# !(cd {parpe_build_root} && exec make -j12) # rebuild\n", - "!rm -rf deleteme # delete old result files \n", + "!rm -rf deleteme # delete old result files\n", "\n", "# optimize (using a single process)\n", "!PARPE_NO_DEBUG=1 {example_binary_dir}/example_steadystate_multi -o deleteme/ {example_data_dir}/example_data.h5\n" @@ -910,20 +719,18 @@ "source": [ "### Analyze results\n", "\n", - "A good start for checking the results is a look at optimizer trajectories. This can be easily done using the *parPE* Python package: " + "A good start for checking the results is a look at optimizer trajectories. This can be easily done using the *parPE* Python package:" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 25, "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY0AAAEGCAYAAACZ0MnKAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAgAElEQVR4nO3de3zcdZ3v8ddncm0y6T2TphcoNC203NqSsqjgEdtiBaW6q1BEBfVYcUVh3aPC0aPunsPjsKvrhdXFReUBelguXoDuUtSCCLgrQlpKKRRoU25pS5KmtE2aNk0yn/PH/KadprlMkpn5ZZL388E8MvP9/X7z+/SXy5vf7/ud78/cHRERkXREwi5ARETyh0JDRETSptAQEZG0KTRERCRtCg0REUlbYdgFZNvUqVN99uzZYZchIpI31q9fv9vdK3tbNupDY/bs2dTV1eV0n3vbD+MOk8qLc7pfEZFMMLPX+lqmy1NZcN09G/n8Xc+EXYaISMaN+jONMGzesZ/O7jjujpmFXY6ISMboTCPD9rV3srutg30HO9nddjjsckREMkpnGhlWv7vtyPOtTa1UVpSEWI2I9NTZ2UlDQwOHDh0Ku5TQlZaWMnPmTIqKitLeRqGRYfVNbcc8f/ucqSFWIyI9NTQ0UFFRwezZs8f05WN3p6WlhYaGBk466aS0t9PlqQyrbz5AcUGE8uICtqUEiIiMDIcOHWLKlCljOjAAzIwpU6YM+oxLZxoZVt/cxuypZYwrKmBbs0JDZCQa64GRNJTjoDONDKtvbmNOZZQ5sajONERk1FFoZFBnd5zXW9qZUxmlJhalcX8H+w91hl2WiOSB733ve7S3tw96u9tvv52dO3f2umzPnj0sX76cuXPnsnz5ct56663hlqnQyKTXWtrpijtzYuXUVEaBYzvGRUT6MpTQ6O7u7jc0brrpJpYuXcrWrVtZunQpN91007DrVGhkUH3Qh5E80wB0iUpEjnHgwAEuvvhizjrrLE4//XTuuecebr75Znbu3MkFF1zABRdcAMBnP/tZamtrOe200/jGN75xZPvZs2fzla98hcWLF3PXXXdRV1fHFVdcwcKFCzl48OAx+3rggQe48sorAbjyyiu5//77h12/OsIzKBkaJ1dGKS2MUFwQUWe4yAj2d//+PC/s3J/R91wwfTzfeP9pfS7/zW9+w/Tp03nwwQcB2LdvHxMmTOA73/kOjz76KFOnJobp33jjjUyePJnu7m6WLl3Kpk2bOPPMMwGYMmUKGzZsAOAnP/kJ3/72t6mtrT1uX42NjVRXVwMwbdo0Ghsbh/3v05lGBtU3HWDa+FKiJYUUFkQ4aWo52xoVGiJy1BlnnMG6dev4yle+whNPPMGECRN6Xe/ee+9l8eLFLFq0iOeff54XXnjhyLLLLrts0Ps1s4yMGtOZRgbVN7cxJ1Z+5HVNLMrmnftCrEhE+tPfGUG2zJs3jw0bNrB27Vq+9rWvsXTpUr7+9a8fs84rr7zCt7/9bZ5++mkmTZrEVVdddcznKcrLy3u+ba+qqqrYtWsX1dXV7Nq1i1gsNuz6daaRIe5+ZLht0pxYlDf2tHOoszvEykRkJNm5cydlZWV89KMf5Utf+tKRy0wVFRW0trYCsH//fsrLy5kwYQKNjY089NBDfb5f6nY9XXLJJdxxxx0A3HHHHaxcuXLY9etMI0Oa2zpoPdR1TGjUxKLEHV7ZfYD51eNDrE5ERornnnuOL33pS0QiEYqKirjlllsAWL16NStWrGD69Ok8+uijLFq0iFNPPZVZs2bxjne8o8/3u+qqq7j66qsZN24cf/rTnxg3btyRZddffz2XXnopP/3pTznxxBO59957h12/ufuw32Qkq62t9VzchOlP9S1c/uMn+X+f+gvOm5voyHph534uuvkJ/vnyRbz/rOlZr0FEBrZlyxbmz58fdhkjRm/Hw8zWu/vxPevo8lTGHBlum9KncXJlOWYadisio4dCI0Pqm9soKy5g2vjSI22lRQXMmlSmYbciMmooNDKkvvkAcyqjxw1pq4lF9alwkRFmtF+WT9dQjoNCI0Pqm9qYU3n8MLi5sSjbdx+gqzseQlUi0lNpaSktLS1jPjiS99MoLS0deOUUGj2VAQcPd7Nj70FWVc46btmcWJTDXXHeeOsgJ01Nb2y1iGTPzJkzaWhooLm5OexSQpe8c99gZD00zOw24H1Ak7ufHrR9C3g/cBioBz7h7nvNbDawBXgp2PxJd7862OZs4HZgHLAWuNZHyP8qbN+d7ASPHrcsdQ4qhYZI+IqKigZ1pzo5Vi4uT90OrOjRtg443d3PBF4GbkhZVu/uC4PH1SnttwCfBuYGj57vGZr65gMAx3xGI0kTF4rIaJL10HD3x4E9Pdp+5+5dwcsngX7Pj8ysGhjv7k8GZxc/Az6QjXqHor6pjYjBiVPKjls2vrSIWEWJQkNERoWR0BH+SSD1M/InmdkzZvaYmZ0ftM0AGlLWaQjaemVmq82szszqcnHdsr65jVmTyygtKuh1eU0sqmG3IjIqhBoaZvZVoAu4M2jaBZzg7ouALwL/ZmaDnn/D3W9191p3r62srMxcwX1IDrftS3LY7QjpghERGbLQQsPMriLRQX5FskPb3TvcvSV4vp5EJ/k8YAfHXsKaGbSFLh53tjf3Ptw2qSYWpa2ji8b9HTmsTEQk80IJDTNbAXwZuMTd21PaK82sIHh+MokO7+3uvgvYb2bnWuLTcx8HHgih9OPs2HuQjq54/2caleoMF5HRIeuhYWZ3AX8CTjGzBjP7FPADoAJYZ2YbzexHwervBDaZ2Ubgl8DV7p7sRP9r4CfANhJnIH3PFZxDR+ec6ic0qhLLtjb1Pn2xiEi+yPrnNNz98l6af9rHur8CftXHsjrg9AyWlhH9DbdNqoyWML60UGcaIpL3RsLoqbxW39zGpLIiJpcX97mOmSVGUCk0RCTPKTSGKTHnVN9nGUk1seiRS1kiIvlKoTFMAw23TaqJRdnddpi97YdzUJWISHYoNIZhX3snu9s6jrnxUl80nYiIjAYKjWGoT05UmM6ZRmUFoNAQkfym0BiG5M2V0gmNGZPGUVIYUWiISF5TaAxDffMBigsizJw0bsB1CyLGyZWag0pE8ptCYxjqm9uYPbWMwoL0DuPcWJStjQoNEclfCo1hqG9Ob7htUk0syo69B2k/3DXwyiIiI5BCY4g6u+O83tI+6NAA2B58ilxEJN8oNIbotZZ2uuKe1nDbJA27FZF8p9AYoiMTFQ7iTGP2lHIKIqbQEJG8pdAYomRonDyI0CgujHDi5DKFhojkLYXGENU3HWDa+FKiJYObKHiObv0qInlMoTFE9c1tg+rPSKqJRXl19wE6u+NZqEpEJLsUGkPg7oMebps0NxalK+681tI+8MoiIiOMQmMImts6aD3UNaTQODqCSnfxE5H8o9AYgvqmge/W15c5ul+4iOQxhcYQHL0v+OD7NMpLCpk+oVShISJ5SaExBPXNbZQVFzBtfOmQttcIKhHJVzkJDTO7zcyazGxzSttkM1tnZluDr5OCdjOzm81sm5ltMrPFKdtcGay/1cyuzEXtvUnerc/MhrR9TSxKfdMB4nHPcGUiItmVqzON24EVPdquBx5x97nAI8FrgPcCc4PHauAWSIQM8A3gL4BzgG8kgybXEvcFH/ylqaSaWJSDnd3s3Hcwg1WJiGRfTkLD3R8H9vRoXgncETy/A/hASvvPPOFJYKKZVQPvAda5+x53fwtYx/FBlHUHD3ezY+/BIXWCJ9WoM1xE8lSYfRpV7r4reP4mUBU8nwG8kbJeQ9DWV/txzGy1mdWZWV1zc3NGi96evMVrbBihoYkLRSRPjYiOcHd3IGMX+N39VnevdffaysrKTL0tkOjPgKENt02aEi1hcnnxkVFYIiL5IszQaAwuOxF8bQradwCzUtabGbT11Z5T9U1tRAxOnFI2rPepqdRd/EQk/4QZGmuA5AioK4EHUto/HoyiOhfYF1zG+i1woZlNCjrALwzacqq+uY1Zk8soLSoY1vskh90mTrJERPLD4KZoHSIzuwt4FzDVzBpIjIK6CbjXzD4FvAZcGqy+FrgI2Aa0A58AcPc9Zva/gaeD9f7e3Xt2rmddcrjtcNXEouxt76TlwGGmRksyUJmISPblJDTc/fI+Fi3tZV0HPtfH+9wG3JbB0gYlHne2N7dxXs2UYb9Xame4QkNE8sWI6AjPFzv2HqSjK56xMw3QCCoRyS8KjUE4OufU8ENj+oRSyooLFBoiklcUGoOQieG2SWbGnMqoht2KSF5RaAxCfXMbk8qKmFxenJH3q4lFdaYhInlFoTEIiTmnhn+WkVQTi7Jr3yFaD3Vm7D1FRLJJoTEImRpum5TsDE9e9hIRGekUGmna197J7raOId14qS8aQSUi+Uahkab65ESFGTzTOHFyGUUFptAQkbyh0EhTfVPmQ6OwIMLsKeUKDRHJGwqNNNU3H6C4IMLMSeMy+r41MQ27FZH8odBIU31zG7OnllFYkNlDVhOL8lrLATq6ujP6viIi2aDQSFN9c2aH2ybVxKLEHV7d3Z7x9xYRyTSFRho6u+O83tKeldCYo1u/ikgeUWik4bWWdrrintHhtklzKqOYKTREJD8oNNJwZKLCLJxpjCsuYOakcWxtas34e4uIZJpCIw3J0Dg5C6EBiVu/6kxDRPKBQiMN9U0HmDa+lGhJdu5ZVROLsn33AbrjuvWriIxsCo001De3ZaU/I6kmFuVwV5yGtzSCSkRGNoXGANw9a8NtkzQHlYjkC4XGAJrbOmg91JXd0KisABQaIjLyhRYaZnaKmW1Meew3s+vM7JtmtiOl/aKUbW4ws21m9pKZvScXddY3Ze5ufX2ZUFbE1GiJQkNERrzs9Oymwd1fAhYCmFkBsAO4D/gE8F13/3bq+ma2AFgFnAZMBx42s3nuntX5N47eFzx7fRoANbFytmkOKhEZ4UbK5amlQL27v9bPOiuBu929w91fAbYB52S7sPrmNsqKC5g2vjSr+5kbq2BbUxvuGkElIiPXSAmNVcBdKa+vMbNNZnabmU0K2mYAb6Ss0xC0ZVXybn1mltX91MSitB7qoqm1I6v7EREZjtBDw8yKgUuAXwRNtwBzSFy62gX80xDec7WZ1ZlZXXNz87DqS9wXPLuXpkAjqEQkP4QeGsB7gQ3u3gjg7o3u3u3uceDHHL0EtQOYlbLdzKDtOO5+q7vXunttZWXlkAs7eLibHXsPZrUTPEmhISL5YCSExuWkXJoys+qUZR8ENgfP1wCrzKzEzE4C5gJPZbOw7clbvMayHxqxihIqSgoVGiIyooU2egrAzMqB5cBnUpr/0cwWAg68mlzm7s+b2b3AC0AX8Lnsj5zK/nDbJDNjTkxzUInIyBZqaLj7AWBKj7aP9bP+jcCN2a4rqb6pjYjBiVPKcrK/mliUx14eXh+MiEg2jYTLUyNWfXMbsyaXUVpUkJP91cSiNLd2sO9gZ072JyIyWAqNfiSH2+ZKje7iJyIjnEKjD/G4s705N8Ntk+ZWJUKjXqEhIiOUQqMPO/YepKMrntMzjZmTyigujOgufiIyYik0+nB0zqnchUZBxDh5arkuT4nIiKXQ6EMuh9umqolFNXGhiIxYCo0+1De3MamsiMnlxTnd7+kzJvDGnoO83qK7+InIyKPQ6ENizqncnmUArFw4nYjBvXVvDLyyiEiOKTT6kOvhtknVE8bxrlNi/GL9G3R1x3O+fxGR/ig0etHVHWfF6VWcP29qKPu/bMksGvd36NPhIjLipBUaZvbzdNpGi8KCCP/nA2fwvjOnh7L/d58aY2q0hLuf1iUqERlZ0j3TOC31RXB71rMzX44AFBVE+NDZM/n9i0007T8UdjkiIkf0GxpmdoOZtQJnmtn+4NEKNAEP5KTCMeqyJbPojju/WN8QdikiIkf0Gxru/n/dvQL4lruPDx4V7j7F3W/IUY1j0klTyzn35MncW/cG8bjuGy4iI0O6l6f+I7j3BWb2UTP7jpmdmMW6BFi15ARea2nnyVdawi5FRARIPzRuAdrN7Czgb4F64GdZq0oAWHH6NMaXFnKPOsRFZIRINzS63N2BlcAP3P2HQEX2yhKA0qICPrhoBg9tfpO97YfDLkdEJO3QaDWzG4CPAQ+aWQQoyl5ZknTZkhM43BXn/md2hF2KiEjaoXEZ0AF80t3fBGYC38paVXLEgunjOXPmBO5++g0SJ3siIuFJKzSCoLgTmGBm7wMOubv6NHLksiWzePHNVjY17Au7FBEZ49L9RPilwFPAh4FLgT+b2YcyUYCZvWpmz5nZRjOrC9omm9k6M9safJ0UtJuZ3Wxm28xsk5ktzkQNI90lZ01nXFGBPiEuIqFL9/LUV4El7n6lu38cOAf4Xxms4wJ3X+jutcHr64FH3H0u8EjwGuC9wNzgsZrEqK5Rr6K0iIvPrGbNxh0c6OgKuxwRGcPSDY2IuzelvG4ZxLZDsRK4I3h+B/CBlPafecKTwEQzq85iHSPGqiWzOHC4mwef2xV2KSIyhqX7h/83ZvZbM7vKzK4CHgTWZqgGB35nZuvNbHXQVuXuyb+ObwJVwfMZQOo1moagbdQ7+8RJzKks12c2RCRUA809VWNm73D3LwH/CpwZPP4E3JqhGs5z98UkLj19zszembow+HzIoIYNmdlqM6szs7rm5tExvbiZsWrJCax/7S22NraGXY6IjFEDnWl8D9gP4O6/dvcvuvsXgfuCZcPm7juCr03B+54DNCYvOwVfk5fGdgCzUjafGbT1fM9b3b3W3WsrKyszUeaI8MHFMygqMJ1tiEhoBgqNKnd/rmdj0DZ7uDs3s3Izq0g+By4ENgNrgCuD1a7k6Iy6a4CPB6OozgX2pVzGGvWmRktYvqCKXz+zg46u7rDLEZExaKDQmNjPsnEZ2H8V8Ecze5bEkN4H3f03wE3AcjPbCiwLXkOiH2U7sA34MfDXGaghr1y25AT2HDjMwy80DbyyiEiGFQ6wvM7MPu3uP05tNLP/Dqwf7s7dfTtwVi/tLcDSXtod+Nxw95vPzquZyoyJ47j76de5+MwxMXBMREaQgULjOuA+M7uCoyFRCxQDH8xmYdK7gojx4dqZfP+Rrbyxp51Zk8vCLklExpCBbsLU6O5vB/4OeDV4/J27vy2YWkRC8OHaxFgA3dVPRHJtoDMNANz9UeDRLNciaZoxcRzvnFvJL+re4NqlcymIWNglicgYkc1PdUsWrVoyi137DvH41tHxORQRyQ8KjTy1dH4VU8qLuecpfWZDRHJHoZGnigsj/NXZM3l4SyPNrR1hlyMiY4RCI49dWjuLrrjz6w3qEBeR3FBo5LGaWJQlsydxj+7qJyI5otDIc5ctOYHtuw/w1Ct7wi5FRMYAhUaeu+iMaVSUFGoSQxHJCYVGnisrLuSShdN58Lld7DvYGXY5IjLKKTRGgVVLTqCjK86ajcfNEi8iklEKjVHg9BnjWVA9nrt1iUpEskyhMQqYGavOmcXzO/ezece+sMsRkVFMoTFKrDxrBiWFEe5++vWwSxGRUUyhMUpMKCviojOqeeCZnRw8rLv6iUh2KDRGkQ+fPZPWji4ee1l39ROR7FBojCLnnDSZCeOKWKdbwYpIlig0RpHCggjvPjXG719spKs7HnY5IjIKKTRGmWXzq3irvZMNr+8NuxQRGYUUGqPMO+dNpajAeHhLY9iliMgoFFpomNksM3vUzF4ws+fN7Nqg/ZtmtsPMNgaPi1K2ucHMtpnZS2b2nrBqH8kqSos49+QpPPyCQkNEMi/MM40u4G/dfQFwLvA5M1sQLPuuuy8MHmsBgmWrgNOAFcC/mFlBGIWPdBcuqGL77gNsa2oLuxQRGWVCCw133+XuG4LnrcAWYEY/m6wE7nb3Dnd/BdgGnJP9SvPP0vlVALpEJSIZNyL6NMxsNrAI+HPQdI2ZbTKz28xsUtA2A0idXKmBPkLGzFabWZ2Z1TU3N2ep6pFr+sRxnDZ9vC5RiUjGhR4aZhYFfgVc5+77gVuAOcBCYBfwT4N9T3e/1d1r3b22srIyo/Xmi2Xzq1j/+lu0tOn+4SKSOaGGhpkVkQiMO9391wDu3uju3e4eB37M0UtQO4BZKZvPDNqkF8sXVOEOj7yoD/qJSOaEOXrKgJ8CW9z9Oynt1SmrfRDYHDxfA6wysxIzOwmYCzyVq3rzzWnTx1M9oVSXqEQkowpD3Pc7gI8Bz5nZxqDtfwKXm9lCwIFXgc8AuPvzZnYv8AKJkVefc3fNzNcHM2PZ/Cp+ub6BQ53dlBZpoJmIDF9ooeHufwSsl0Vr+9nmRuDGrBU1yixbUMXPn3yN/6rfzbtPrQq7HBEZBULvCJfsOffkyURLClmnS1QikiEKjVGspLCA/zavkoe3NBGPe9jliMgooNAY5ZYtiNHc2sEm3QZWRDJAoTHKXXBKjIKIaRSViGSEQmOUm1hWzJLZk9SvISIZodAYA5bNr+KlxlZeb2kPuxQRyXMKjTFg+QJNYCgimaHQGANOnFLOvKqoQkNEhk2hMUYsm1/Fn1/Zw772zrBLEZE8ptAYI5YtqKI77vzhZU1gKCJDp9AYIxbOnMjUaIlGUYnIsCg0xohIxFg2P8ZjLzVzuCsedjkikqcUGmPIsvlVtHZ08edXWsIuRUTylEJjDHlHzVRKiyL6dLiIDJlCYwwZV1zAeTWJCQzdNYGhiAyeQmOMuXBBFTv2HmTLrtawSxGRPKTQGGMuODWGGRpFJSJDotAYYyorSlg0a6I+HS4iQ6LQGIOWL5jGczv2sWvfwbBLEZE8o9AYg5YviAHwyBZ9OlxEBifvQsPMVpjZS2a2zcyuD7uefDSnMsrsKWXq1xCRQcur0DCzAuCHwHuBBcDlZrYg3Kryj5mxbH4Vf6pvoa2jK+xyRCSP5FVoAOcA29x9u7sfBu4GVoZcU15avqCKw91xnni5OexSRCSP5FtozADeSHndELQdw8xWm1mdmdU1N+uPYm/OPnESE8uKWKdRVCIyCPkWGmlx91vdvdbdaysrK8MuZ0QqLIjw7lNi/P7FJrq6NYGhiKQn30JjBzAr5fXMoE2GYNmCKva2d7L+tbfCLkVE8kS+hcbTwFwzO8nMioFVwJqQa8pb75xXSXFBRB/0E5G05VVouHsXcA3wW2ALcK+7Px9uVfkrWlLI2+ZMYd0LjZrAUETSklehAeDua919nrvPcfcbw64n3y1bUMWrLe3UN7eFXYqI5IG8Cw3JrGXzE58OX/eCPh0uIgNTaIxx1RPGccaMCerXEJG0KDSEZfOr2PD6W+xu6wi7FBEZ4RQawrIFMdzh95rAUEQGoNAQFlSPZ8bEcfp0uIgMSKEhwQSGMZ7Y2syhzu6wyxGREUyhIUBi6O2hzjj3P6MP2ItI3xQaAsC5J09h4ayJ3HDfc/zosXp92E9EeqXQEACKCiLc9elzueiMam566EX+9hfP0tGlS1UicqzCsAuQkWNccQE/uHwRc2NRvvfwVl5vaedHHzubqdGSsEsTkRFCZxpyDDPjumXz+OFHFrN55z5W/uA/2bJrf9hlicgIodCQXl18ZjW/+Mzb6YrH+dAt/6X7iYsIoNCQfpwxcwJrrjmPObEoq39epw5yEVFoSP+qxpdyz+q3qYNcRAB1hEsakh3k82IVfPfhl3mtpZ1/VQe5yJikMw1Ji5lx7bK5/PAji3leHeQiY5ZCQwYltYP8r9RBLjLmKDRk0JId5HPVQS4y5ig0ZEiqxpdyz2fexsXqIBcZU9QRLkNWWlTAP1++iLlBB/kzr+/l8++u4ZKzplNYoP8fERmNQvnNNrNvmdmLZrbJzO4zs4lB+2wzO2hmG4PHj1K2OdvMnjOzbWZ2s5lZGLXLsZId5Ld/YgmlRQV88d5nufC7j3PfMw10x3XJSmS0Cet/B9cBp7v7mcDLwA0py+rdfWHwuDql/Rbg08Dc4LEiZ9XKgN51SowHP38eP/ro2RQXRvibe55l+Xcf4/5ndig8REaRUELD3X/n7l3ByyeBmf2tb2bVwHh3f9ITPa4/Az6Q5TJlkCIRY8Xp01j7hfP50UcXU1wQ4bp7NrL8u4/xwEaFh8hoMBIuPH8SeCjl9Ulm9oyZPWZm5wdtM4CGlHUagrZemdlqM6szs7rm5ubMVyz9SoRHNWu/cD63XLGYokiEa+/eyHu+9zhrnt2p8BDJY1kLDTN72Mw29/JYmbLOV4Eu4M6gaRdwgrsvAr4I/JuZjR/svt39VnevdffaysrKTPxzZAgiEeO9Z1Tz0LXn8y9XLKbAjC/c9Qwrvvc4//7sTuIKD5G8k7XRU+6+rL/lZnYV8D5gaXDJCXfvADqC5+vNrB6YB+zg2EtYM4M2yQORiHHRGdWsOG0aD21+k+8/8jKfv+sZbn5kK9cum8tFp1cTiWhcg0g+CGv01Argy8Al7t6e0l5pZgXB85NJdHhvd/ddwH4zOzcYNfVx4IEQSpdhiESMi8+s5jfXvpMffGQRANf82zOs+H5itFX74a4B3kFEwmZhfJLXzLYBJUBL0PSku19tZn8F/D3QCcSBb7j7vwfb1AK3A+NI9IF83tMovra21uvq6jL/j5Bh6447a5/bxfcf2cq2pjbGFRVw4WlVrFw4nfPnVlKkz3qIhMLM1rt7ba/LRvv0DwqNkS8ed55+dQ9rnt3Jg8/tYm97J5PKirjojGpWLpxB7YmTdPlKJIcUGgqNvHG4K84ftzXzwMad/O75Rg52djN9QinvP2s6lyyczoLq8ehznSLZpdBQaOSl9sNdrHuhkTUbd/LYy810xZ2aWJSVQYCcOKU87BJFRiWFhkIj77114DBrN+/igY07eeqVPQAsnDWRlQunc9EZ1VSNLw25QpHRQ6Gh0BhVdu49yH9s2skDG3fy/M7EjaCmRks4ZVqUeVUVnDqtgnlVFcytqiBaojk5RQZLoaHQGLW2NbXyh5eaebmxlZfebOXlxjYOdh6don3mpHGcUlXBvGkVia9VFcyJlVNSWBBi1SIjW3+hof8Nk7xWE6ugJlZx5HU87jS8dZCXGluPBMlLb7Ye6RMBKIgYs6eUceq08cypLKespJDCiFEYMQoKIomvwevCAV6XFRdSUZp4REsKNcv67pkAAAihSURBVCW8jHoKDRlVIhHjhCllnDCljOULqo60H+6K82rLgeBsJBEkm3fuY+3mXWTyZHtcUQHRIEQqSgqpKC0iWhKESmnidUXwuqQogmGYJaaYN8AMIinPj7YbEQvaMIL/IFiWdLSNlDbrpe3oyskajt3+2Laj2wb1pq5HSl0p61qP909dZziS+++tpuSx6KumY+s7uu5x6/T8twxYVH+Lsjfar7+BhBEzJpcXZ3yfCg0ZE4oLI8wLLk+l6uyO09kdpyvudHc7XXGnKx6nq9vpjided8edzu74Ma+T67Qf7qL1UOLR1tFF66HOxOuOoO1QJ437DwXLEuuI5MLUaAl1X+t3NqchUWjImFZUEMnpJ8/jcactCJrDXXHcHQfcOeZ53D3RRvA1eB5PWY9g3aP8uLbe1uu5/ZFXKV/8yHNPeX7stvSor7d1glnlgv0MX+oxSd1f6r+xr5pS/okp/9aBj5kPUHl/Z6pZ7TEe4BS5pCg7/XYKDZEcikSM8aVFjC8tCrsUkSEZ9aOnzKwZeG2Im08FdmewnExRXYOjugZHdQ3OaKzrRHfv9b4Soz40hsPM6voadhYm1TU4qmtwVNfgjLW6ND5QRETSptAQEZG0KTT6d2vYBfRBdQ2O6hoc1TU4Y6ou9WmIiEjadKYhIiJpU2iIiEjaFBqAma0ws5fMbJuZXd/L8hIzuydY/mczm52DmmaZ2aNm9oKZPW9m1/ayzrvMbJ+ZbQweX892XcF+XzWz54J9HjeFsCXcHByvTWa2OAc1nZJyHDaa2X4zu67HOjk5XmZ2m5k1mdnmlLbJZrbOzLYGXyf1se2VwTpbzezKHNT1LTN7Mfg+3WdmE/vYtt/veRbq+qaZ7Uj5Xl3Ux7b9/u5moa57Ump61cw29rFtNo9Xr38bcvYz5u5j+gEUAPXAyUAx8CywoMc6fw38KHi+CrgnB3VVA4uD5xXAy73U9S7gP0I4Zq8CU/tZfhHwEIlp3M4F/hzC9/RNEh9QyvnxAt4JLAY2p7T9I3B98Px64B962W4ysD34Oil4PinLdV0IFAbP/6G3utL5nmehrm8C/yON73O/v7uZrqvH8n8Cvh7C8er1b0OufsZ0pgHnANvcfbu7HwbuBlb2WGclcEfw/JfAUrP+5pccPnff5e4bguetwBZgRjb3mUErgZ95wpPARDOrzuH+lwL17j7UmQCGxd0fB/b0aE79GboD+EAvm74HWOfue9z9LWAdsCKbdbn779w9OYvik8DMTO1vOHWlKZ3f3azUFfz+Xwrclan9paufvw05+RlTaCQO9hsprxs4/o/zkXWCX7B9wJScVAcEl8MWAX/uZfHbzOxZM3vIzE7LUUkO/M7M1pvZ6l6Wp3NMs2kVff8yh3G8AKrcfVfw/E2gqpd1wj5unyRxhtibgb7n2XBNcNnstj4utYR5vM4HGt19ax/Lc3K8evxtyMnPmEJjhDOzKPAr4Dp3399j8QYSl2DOAv4ZuD9HZZ3n7ouB9wKfM7N35mi/AzKzYuAS4Be9LA7reB3DE9cJRtRYdzP7KtAF3NnHKrn+nt8CzAEWArtIXAoaSS6n/7OMrB+v/v42ZPNnTKEBO4BZKa9nBm29rmNmhcAEoCXbhZlZEYkfijvd/dc9l7v7fndvC56vBYrMbGq263L3HcHXJuA+EpcJUqVzTLPlvcAGd2/suSCs4xVoTF6iC7429bJOKMfNzK4C3gdcEfyxOU4a3/OMcvdGd+929zjw4z72F9bxKgT+Erinr3Wyfbz6+NuQk58xhQY8Dcw1s5OC/0tdBazpsc4aIDnK4EPA7/v65cqU4JrpT4Et7v6dPtaZluxbMbNzSHw/sxpmZlZuZhXJ5yQ6Ujf3WG0N8HFLOBfYl3LanG19/h9gGMcrRerP0JXAA72s81vgQjObFFyOuTBoyxozWwF8GbjE3dv7WCed73mm60rtA/tgH/tL53c3G5YBL7p7Q28Ls328+vnbkJufsWz07ufbg8Ron5dJjMT4atD29yR+kQBKSVzu2AY8BZycg5rOI3F6uQnYGDwuAq4Grg7WuQZ4nsSokSeBt+egrpOD/T0b7Dt5vFLrMuCHwfF8DqjN0fexnEQITEhpy/nxIhFau4BOEteMP0WiD+wRYCvwMDA5WLcW+EnKtp8Mfs62AZ/IQV3bSFzjTv6MJUcJTgfW9vc9z3JdPw9+djaR+GNY3bOu4PVxv7vZrCtovz35M5Wybi6PV19/G3LyM6ZpREREJG26PCUiImlTaIiISNoUGiIikjaFhoiIpE2hISIiaVNoiKTJzNqCr7PN7CMZfu//2eP1f2Xy/UUyRaEhMnizgUGFRvAp4v4cExru/vZB1iSSEwoNkcG7CTg/uFfC35hZgSXuS/F0MMHeZ+DI/TueMLM1wAtB2/3BJHbPJyeyM7ObgHHB+90ZtCXPaix4783B/RkuS3nvP5jZLy1xP4w7sz3zsgjAQP/3IyLHu57EvR7eBxD88d/n7kvMrAT4TzP7XbDuYuB0d38leP1Jd99jZuOAp83sV+5+vZld4+4Le9nXX5KYtO8sYGqwzePBskXAacBO4D+BdwB/zPw/V+QonWmIDN+FJOba2khiiuopwNxg2VMpgQHwBTNLTmMyK2W9vpwH3OWJyfsagceAJSnv3eCJSf02krhsJpJVOtMQGT4DPu/ux0z8ZmbvAg70eL0MeJu7t5vZH0jMazZUHSnPu9Hvs+SAzjREBq+VxG02k34LfDaYrhozmxfMbtrTBOCtIDBOJXEr3KTO5PY9PAFcFvSbVJK4BelTGflXiAyB/s9EZPA2Ad3BZabbge+TuDS0IeiMbqb3W23+BrjazLYAL5G4RJV0K7DJzDa4+xUp7fcBbyMxY6oDX3b3N4PQEck5zXIrIiJp0+UpERFJm0JDRETSptAQEZG0KTRERCRtCg0REUmbQkNERNKm0BARkbT9fyoaoOTYwJ7+AAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -946,7 +753,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -954,18 +761,18 @@ "output_type": "stream", "text": [ "# __Exp____ __Act______ __Err______ __RelErr___ __ID_______\n", - "0: 1.00000 2.02746 1.02746 1.02746 p1\n", - "1: 0.50000 0.58197 0.08197 0.16394 p2\n", - "2: 0.40000 0.79902 0.39902 0.99756 p3\n", - "3: 2.00000 2.07928 0.07928 0.03964 p4\n", - "4: 0.10000 0.11157 0.01157 0.11573 p5\n", - "5: 2.00000 0.02880 -1.97120 -0.98560 scaling_x1_common\n", - "6: 3.00000 3.03039 0.03039 0.01013 offset_x2_batch-0\n", - "7: 0.20000 0.18353 -0.01647 -0.08234 x1withsigma_sigma\n", - "8: 4.00000 4.01172 0.01172 0.00293 offset_x2_batch-1\n", + "0: 1.00000 0.27496 -0.72504 -0.72504 p1\n", + "1: 0.50000 0.30148 -0.19852 -0.39704 p2\n", + "2: 0.40000 0.14082 -0.25918 -0.64794 p3\n", + "3: 2.00000 1.80128 -0.19872 -0.09936 p4\n", + "4: 0.10000 0.04838 -0.05162 -0.51620 p5\n", + "5: 2.00000 0.17859 -1.82141 -0.91070 scaling_x1_common\n", + "6: 3.00000 3.00079 0.00079 0.00026 offset_x2_batch_0\n", + "7: 0.20000 0.13613 -0.06387 -0.31935 x1withsigma_sigma\n", + "8: 4.00000 4.00615 0.00615 0.00154 offset_x2_batch_1\n", "\n", "Status: 1\n", - "Cost: -368.587396 (expected: -0.000000)\n" + "Cost: -446.910816 (expected: -0.000000)\n" ] } ], @@ -975,16 +782,18 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ + "Running --at-optimum for \r\n", + "\tconditions from deleteme/_rank00000.h5:/inputData and \r\n", + "\tparameters from deleteme/_rank00000.h5:/inputData\r\n", + "\t> sim.h5:/\r\n", "Running for start 0\r\n", - "HierarchicalOptimizationWrapper parameters: 9 total, 5 numerical, 1 proportionality, 2 offset, 1 sigma\r\n", - "Need to compute analytical parameters: //inputData 1 parameters.size() == 5 ; hierarchical.numParameters() == 5\r\n", "Starting simulation. Number of conditions: 4\r\n" ] } @@ -992,12 +801,12 @@ "source": [ "# Simulate with optimal parameters, save results\n", "!rm -f sim.h5 # remove files from previous run\n", - "!{example_binary_dir}/example_steadystate_multi_simulator {hdf5_pe_output_file_standard} / sim.h5 / --at-optimum --nompi" + "!{example_binary_dir}/example_steadystate_multi_simulator {hdf5_pe_output_file_standard} /inputData {hdf5_pe_output_file_standard} /inputData sim.h5 / --at-optimum --nompi --nocompute-inner" ] }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 31, "metadata": {}, "outputs": [], "source": [ @@ -1008,17 +817,15 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 32, "metadata": { "scrolled": true }, "outputs": [ { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -1027,23 +834,21 @@ } ], "source": [ - "# Plot correlation of measurements (training data) and model simulation with optimized parameters \n", + "# Plot correlation of measurements (training data) and model simulation with optimized parameters\n", "parpe.plotting.plotCorrelation(measured[start_idx], simulated[start_idx]);" ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 33, "metadata": { "scrolled": false }, "outputs": [ { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -1052,10 +857,8 @@ }, { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -1064,10 +867,8 @@ }, { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -1076,10 +877,8 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAEZCAYAAACU3p4jAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAgAElEQVR4nOzdeXxU5b348c8zZ2Yy2VcSdsJigACKSDCitCgWqVKX1kpVKti6tNKrtyCXeqvV2+vF2+q12t9V2173Qi2ilmJxR20RXCrIagKETUIC2bfJrOc8vz/OZCOBhJAESL7vl+PMc9Znwsz3ec5zzpyv0lojhBCi93Oc6goIIYToGRLwhRCij5CAL4QQfYQEfCGE6CMk4AshRB8hAV8IIfoICfhCHIdSar5S6qNm5Tql1IjjLL9DKTW9RyonxAmSgC/OSEqpG5RSn0cCcLFS6k2l1EXdvV+tdZzWem+kDs8rpR48av44rfWHXb1fpdSvlVIHlVI1SqkDSql/7+p9iN5PAr444yilFgKPAUuBDGAo8CRw1amsVzd7BhijtU4ApgI3KqW+fYrrJM4wEvDFGUUplQj8EligtX5Na+3VWoe01q9rrRdHlolSSj2mlCqKPB5TSkVF5k1XShUqpRYppUoiRwc3N9t+qlJqdaQn/Rkw8qj9a6XUKKXUbcCNwL9FjjJej8zfr5S69GTrcTSt9U6ttbfZJAsY1QV/UtGHSMAXZ5oLAA/wl+Ms83MgF5gInANMAe5tNr8/kAgMAn4IPKGUSo7MewLwAwOAH0QerWit/wAsB34dGeb5VhfXoxWl1M+UUnVAIRAL/OlYywrRFgn44kyTCpRprcPHWeZG4Jda6xKtdSnwH8D3m80PReaHtNZvAHXAaKWUAXwH+EXkyGE78MJJ1LVT9TjWxrTW/w3EA5OAPwLVJ1E30QdJwBdnmnIgTSnlPM4yA4EDzcoHItMat3FUg1EPxAH9ACdw8Kh1O6uz9TgmbfsC8GE3IEJ0mAR8cab5GAgAVx9nmSJgWLPy0Mi09pQCYWDIUeseS3u3mu1sPTrCyVHnF4RojwR8cUbRWlcDv8Ae775aKRWjlHIppb6plPp1ZLGXgHuVUv2UUmmR5Zd1YNsm8BrwQGS72cC846xyBDjmNfmdrcfRlFIOpdTtSqlkZZsCLADWnui2RN8mAV+ccbTW/wMsxD4BWoo9BPMTYFVkkQeBz4GtwDZgU2RaR/wEe1jlMPA88Nxxln0GyFZKVSmlVrUx/2TqcbRrgD1ALXaj8f8iDyE6TEkCFCGE6Bukhy+EEH2EBHwhhOgjJOALIUQfIQFfCCH6iOP9eOWUS0tL05mZmae6GkIIccbYuHFjmda6X1vzTuuAn5mZyeeff36qqyGEEGcMpdQxfx0uQzpCCNFHSMAXQog+QgK+EEL0Eaf1GL4Qom8LhUIUFhbi9/tPdVVOOx6Ph8GDB+NyuTq8jgR8IcRpq7CwkPj4eDIzM1FKnerqnDa01pSXl1NYWMjw4cM7vJ4M6QghTlt+v5/U1FQJ9kdRSpGamnrCRz4S8IUQpzUJ9m3rzN9FhnROgtYaM2wRDliEgiahgEk4aD+CfpNw0EJbGqfbgdNtRB4OnC5H02u3gdPlkA+1EKLb9bqAv+vTw3z81z3UVQSIS4nigqtGknV+/xPaRl1lgNKDtQR94UgAtwgFTEJBk3DDc2QaXXR7acNl4HIf1RC4HThdTWWX28BwO3C5HRiR6a6jGhKHIQdtQoi29aqAv+vTw3ywPJ9w0AKgriLAB8vzAdoN+qGASVFBFVs/OMihnVWYIQvD5SB1YCwpA2PtwBpl4IlzEef24IqKBOgoO+Da5UgQbjZNOVRjoxEOmoRDVsty0D46MENWpCFpWMbC7w21KHekcXE4Wx9BNDQk5Yfq2L+1DL83jCfORfaFAxg2Pg3DZa9jOB043Y5I2cBwKmlAhOhFelXA//ivexqDfYNw0OLjv+5pM+BrS1N6sJbCnZUc2VtDTVk95UX1aMsOrGbIoqLYyzmXDDnho4Tm3B4nbk+nV7fr2jB8dFRDEQ5ahEMtG5DwUdN9tSHKCiso3lONjvx5/HUhvnjnK77aUU5c8rEr5zDsBsBwOXA6HRhu+9npdkQaF3tIqrHRaHw+1nS7YTkThrC64mhRiKNNnTqVDRs2nJJ996qAX1cROOb0XZ8ebvyyeqsCHMyroHBnJQFvCJfHyZDsFP65prox2Ddo3mCUF9URmxCFJ6796167OlgopSLB1YDY1vs3Qxa+uiDRcW4MlwN/XYjyojr6DY3H7XHy/JKPGoN9A62hvjbEZbdOoOKwlyN7axiYlYhSiqoj9ZQf8pI+LB6tobbcR1WJj+SMGCxLU3m4nrqqAHGJUZimxlcXJOgLE5voRilF0B8m5DeJTYoCsMsBk9hEuxwOW1imJik9BsPlIOQLY5qa1EGxGE4Hfm8Iy9T0GxKP4XLgrQlghTUZwxNwugzqKvxYlqb/iEScbgfVpT4s0yIjMxGA8qK6xvUBKoq8aK1JHRQHQOVhLwDJ/WMby8qhSEqPAeCLdw7w6ev7MENNR4vvL+vY0aIQx3Oqgj30soAflxJ1zKD/7nNfsu7lXWSd35/acj9aQ/qweAZPG0R6ZjyG4eDvf9rZ5rp1FQG01qx86HMmTB/Mhd8Zhdaa5fd/wtkXD+HsiwejLc361woYfnYa3spA66GlZfmUHqxlwsWDSUiNxu8NsfOTwwzJTiFlQCze6gCb3jrAmAsG0G9oPFUl9Xy0cjeTL8+k//BESg/W8u4zO5g+dwwDRyVRtLuSvz62mSvvmsigrGQKd1Xyt/+3he/823n0H5FI8Z4q3nhqG9+9ZzLpwxLwVgfbfG/11UGSMmIo3lPFprcPMO5rF5CQGk1NmZ8vPypiyrcuJDYxii3vH2TT21/xw/+ZhifWxRfvfMWuz45w62Nfw+1x8s839vHZ6n1ceddFWKZm01sH2PpBIRffNBYzZLHl/YPs3VTKed/MJBy0yP+kmCN7a8ickIYZMtm7p5qKYi9RMU7MkMWhXVV4qwMMGZMMQOnBOgLeEIMj5ZKv7HMsg0dHygdqCQVNho1Pxel0ULizEjNsMXbqQJxuBzs/OYxlac6bNQyny8HGtw6gHIqLvnsWhsv+t3d7DC69ORvDafDJX/dimS0bfzPU1Pj/6YFPyMhMYMb8bABWPbqJ/iMTyb1qJADvPLODASMTmTB9MAAbXi0gY0QCI89NB2DrBwdJGxLPwFFJAOzbWkZSenRjA1R+qI6YRDfRcW601oSD9hCjw3H6Hxn1Ntu3b+e2225rDNSbNm1i8eLFrF17/BzyXq+X6667jsLCQkzT5L777mPOnDnExcVRV1fH/v37mTVrFrm5uWzYsIGcnBxuvvlm7r//fkpKSli+fDlTpkzp0vfSqwL+BVeN5L0Xv0Sbbc/3e8Nsfb8Qp8tBOGRRVlhLQpqHASPtXqHT7Wg1JAR2QwLwjR9kk5AWDdDY24xNcgMQDJjsWFdEfLKHzWu/aj20FLLY/N5BkjJiGDdtEIH6MB+t3M2MeWNJGRBLyG+y89PDDMxKot/QeNB2MG7YjivKaDyXABCX7GHipUMae9CpA2OZfuNo4lPt4Zn+IxO56l8nNvZY45KjqKts3RjGJdvrj5qcwdBxqURHjl6ypmSQOSGV6Hj7/Y29YADDz07DHW1/ZLIvGsCIc9Ma6zPha4M567wMPLEulFJMvjyTcdMGkTLQDmDxqR4mfzOzsYc9KCsZvzdE2mC7PDp3AH5vqLFHXl3qI+gLkzo4zh5aK/Li94ZIyogmHLSoPOwlUB8mITWacNhiwFlewgH7iCIcsnBHOwkFzci/e4jUQbGYIYvCnZWEgxZRMfb72Pr+QQDcHvt9fPTybvvf12z7fEldRYC1L+bh8jjxVgVYt2IXylAE6sOUHqjls9f34jAUJftrCPjCWKbGYSi+3FBEebGXUMDEYSg+Wml3DgL1YZQD3nhyK6PP70/2tIEA/OWRTUyYPpjxXxuEZVqs+K9/MmnWMM6+eDChoMlrv95IzhXDGXvhAIK+MG/8bhvnXTaM4ef0w1cX5KOXdzNu2iAGnpWEvy7E1g8OMnJSOqmD4vB7Q+zfVsagrGTiUzwE/WHKCutIGRCLJ9aFGbLPH3niXBjO0+cczkuffcVXFfVdus2hKTFcP2XocZfJzs5m7969mKaJYRgsXLiQRx99tN1tv/XWWwwcOJA1a9YAUF1d3WqZgoICVq5cybPPPktOTg5/+tOf+Oijj1i9ejVLly5l1apVnXtjx3BaJzGfPHmyPpHbI+/69DBrX8w75pe1TQou/M4oJl46lO1/P8T6V3YTDjUFa6fbwcU3junwYby2NE/e8cEx5//gkYuIjnNjWZpgfRhXtIHRAydGjz6hDSf+3noLrTWWqTFDFuGQFTk3YtrPIQszaPH209vx1YZarRsV4yTniuFYpsay7MtuLbPZw7IfuuG1aUWem6bpyHSUwuFQaK0J+k0Mpz1sp7WmviaIK8rA7XFiWZracj+eWCdRMS4s06LicD2xiVFEx7kwwxalB+tI7BdNXHIUZlhzaGcl6ZnxJKbHEPSFKfi8hMwJqaQMjMVfF+LL9cWclZNB2uA4vNUBtr5fyPivDSRtSDw1ZT42vf0V580aRtqQeCoPe/n8zf3kXjWStCFxVBZ72bL2IFO+NYKUAbGUF9WRv6GY876ZSWK/aCoPe9m7uZSzLxlCXLKH6pJ6indXkXXBAKJjXdSU+6go8jJ4dDJOt4G/LoSvLkhiv2gchgPTtD+jhuEgLy+PsWPHAqcu4APMmDGD3/zmN+zevZvVq1fzwgsv4PV6ueOOO3C73UyfPp0bb7yxxTq7du1i5syZzJkzh9mzZzNt2jSAFj38b3zjG+zebXcybrrpJi677DJuvPFG9u7dy7e//W02b9583Ho1//s0UEpt1FpPbmv5XtXD//ive04s2ANo+OKdr5h46VDGf30Qbo9xUmPvyqGOObQUlxJFdJzdY3Y4VIfOBXSVhvcgJyHt8yGGU2E4Hbij217momvParOB/NqcrJP+m2l9dKPQvME4qhFpbCCalU2NaUaWi8wbbTZbztIMGZuCtpqWS+4fYzc6GlweJ2MuGIDDUNSU+wkFwgwZk0x9bYjCnZUE/WFSB8VyZH815YfqCAVM4pKiOLC9jKJdlQTqw4SDFnnri3BFGfjqQlQWe9n45n5cUQbe6gBlhV6qS3y4ogxqK/yUH/Kyf1sZzigndZV+yg7WMfwc+4ix6kg9R/bVMHZqf9weF6UHaynaXcW53xhKzPAwVSX1hAImV47OQCn7qrdQwCQm0Y1CNV7lFh1vf58aGnFP5FyXGbbQpraPTpV9dK61xuk2QNnLK2V/dxuuJTj6ooLc3FzWr1/Pk08+yVtvvQXAa6+9xrXXXsu3vvUt5syZ0yrgZ2VlsWnTJt544w3uvfdeZsyYwS9+8YsWy0RFRTW+djgcKG1QVlhHRZGXgC+Ivy7UpXGiVwX8Y43ft6e+pml8O+v8/if9hb7gqpFtBosLIuO7p0pXvLe+ojsbSKUUhqHAOOlNdavmDUrrBspqszGyTI22rBblcNAk6DNxuhxo7CG2+nFBYhPtzk9sopuEVA9xqdEoICHNg9aJjdsHu4PUcAI9HLIbsaAvjNb2uRXL1BCJ0eGQhRW5KADsCy8sy8IdMJuVdeMwXjhooi1wNS/rhmE+u4HJPusc/mXhj7n1B7cT7UiiotjLnt37mXnpTKqO1GOGNN5qO/6YIQsUlJYfISU5hauvuBaPK5YXlj2Hv94+avTVBQn67foHfWG74Qma+GpD9tEfoIHaCvvWCV0V9HtVwHe6FeHgiQ9RNYzRdxXpTfcOfb2BVA6F4VAYpzBK5OXlNZ6HOhatNdj/tSjbBbAsC8sCh6FA2z1+y7R/AY+GUNBEmxqXx0BrCBkOu0GINuztas3orNFERUWxaOHdjdsdNHAQh4oOkTVynL3NsEajCfjCKAVbvtjKff/xc5RSuJxOHn34t/jrQmhtXynor7ODe3WpD+UgMpSsW723uqpAlwX8XjWG/8SP3j/u/KhYg5DfajHs01fHsYU4E7Q1Rn0q/OQnPyEnJ4d58+Y1TvN6vfzkJz/B4/Fw0UUXNQ7pWJYGrRt/tBiOXDxguOwGJuCzT9S73HYD468L4TBUY2++LenDEtqc3qfH8I8nLiWKeUsvlB/TCCE6bM+ePVxxxRVceOGFLYI9QGxsLM8991yrdexLZ5vOATjdzcbuFI3nFhq3E7nSzlsdbBzOabG9Lryoo88E/Ibx/b5+mC6E6LiRI0eSn5/fI/uKS4qitsJP81EXpRRxSV035NxnAn5Xj9MLIURXahinr6sKYJkWDsNBXFLHftnfUX0m4J/qK2SEEKI9njhXt16uffr8jK6byTCOEKKv6zMBXwgh+joJ+EII0Uf0qoA/eHTSCU0XQoi+pFcF/Kt+OqlVcB88OomrfjrpFNVICCFOH73uKh0J7kL0Xau+OMTDb++kqMrHwKRoFl82mqvPHXSqq3Xa6FU9fCFE37Xqi0Pc89o2DlX50MChKh/3vLaNVV8cOqntbt++nalTpzaWN23axIwZM9pdb//+/YwZM4b58+eTlZXFjTfeyHvvvceFF17IWWedxWeffQbAsmXLmDJlChMnTuT222/HNE28Xi9XXHEF55xzDuPHj2fFihUn9R4aSMAXQpwx5vz+Y1Z+bietCZkWc37/MX/5ohCAX7+Vjy/UMvuRL2Tyy7/tAKDCG2TO7z/mvS+PAFBSe+x71zTXPAEKwMKFC3n44Yc7tG5BQQGLFi0iPz+f/Pz8xgQnjzzyCEuXLiUvL48VK1awfv16Nm/ejGEYLF++vDF5ypYtW9i+fTuzZs3q0P7a0+uGdIQQfVNxddsBvMLbOpHNiXA4HIwbN44dO3awe/duhg0bxqRJk9pNgAIwfPhwJkyYAMC4ceOYMWMGSikmTJjA/v37Wbt2LRs3biQnJwcAn89Heno6N9xwA4sWLWLJkiUtkqecLAn4QogzxorbL2h87TIcLcoDk6I5VOVrtc6gJDvLTUqsu8Xy6fGeDu+3MwlQoHWCk4ayw+EgHA6jtWbevHk89NBDrdZtL3lKZ8iQjhCiV1h82WiiXS2zykS7DBZfNvqkt52bm8u9997LNddcw6BB9kngwsJChgwZAoBhdC6bzYwZM3jllVcoKSkBoKKiggMHDlBUVERMTAxz585l8eLFbNq06aTfA5yCHr5SygA+Bw5prWf39P6FEL1Tw9U43XGVzpgxY4iKimLJkiWN0wYPHkxhYSETJ07Eslrf1rgjsrOzefDBB5k5cyaWZeFyuXjiiSeorq5m8eLFOBwOXC4XTz311Em/BzgFCVCUUguByUBCewH/RBOgCCF6lzMxAUpPOq0ToCilBgNXAP8FLOzJfQshxInqTAKU01lPD+k8BvwbEH+sBZRStwG3AQwdOrSHqiWEEK31ZAKUntBjJ22VUrOBEq31xuMtp7X+g9Z6stZ6cr9+/XqodkII0fv15FU6FwJXKqX2A38GLlFKLevB/QshRJ/WYwFfa32P1nqw1joT+B7wvtZ6bk/tXwgh+jq5Dl8IIfqIU/JLW631h8CHp2LfQgjRV0kPXwgh+ggJ+EII0UdIwBdCiD5CAr4QQvSg5slUepoEfCGE6EEbNmw4ZfuWgC+EEMfR2RSHx0pTGBcXB3Q8BWJXkgQoQogzw8bnoXJ/124zORPOm3/cRZqnODQMg4ULF/Loo4+2u+mGNIVr1qwBoLq6utUyBQUFrFy5kmeffZacnJzGFIirV69m6dKlrFq1qjPv6pikhy+EEMfRPMXhq6++2pjicO/evfzwhz/k2muvbXO9CRMm8O6777JkyRLWrVtHYmJiq2UaUiA27OPoFIhdTXr4QogzQzs98e7UVorDESNG8Mwzzxwz4GdlZbWbprC9FIhdTQK+EEK0Izc3l/nz57NgwYLGFIftKSoqIiUlhblz55KUlMTTTz/dzbVsnwR8IYRoR1spDtuzbdu2bklTeDJ6PMXhiZAUh0L0badzisPy8nJ+/vOf8+6773LLLbdwzz339Hi9TusUh0IIcSY5XorD1NRUfve7352imnWOBHwhhDgGSXEohBDijCQBXwgh+ggJ+EII0UdIwBdCiD5CAr4QQvQREvCFEKKPkIAvhBB9hAR8IUTvsfVl+M14eCDJft768qmu0WlFAr4QonfY+jK8fidUHwS0/fz6nScd9DubAKWjCU6WLVvGlClTmDhxIrfffjumaR4zecrJkoAvhDhzPHcFfLHcfm2G7PKWSDB87z8g5Gu5fMgHb/3Mfu0tt5ff+aZdrj3SoV02T4ACsHDhQh5++OEOrVtQUMCiRYvIz88nPz+/McHJI488wtKlS8nLy2PFihWsX7+ezZs3YxgGy5cvb0yesmXLFrZv386sWbM6tL/2SMAXQvQONYfanl5fflKb7WwCFGg/wcnatWvZuHEjOTk5TJw4kbVr17J3794OJU/pDLmXjhDizHHzmqbXhqtlOXFwZDjnKIlD7OfY1JbLx2d0eLedSYAC7Sc40Vozb948HnrooVbrtpc8pTOkhy+E6B1m/AJc0S2nuaLt6ScpNzeXe++9l2uuuabDCVA6YsaMGbzyyiuUlJQAUFFRwYEDBygqKiImJoa5c+eyePFiNm3a1CX7kx6+EKJ3OPs6+3ntL6G60O7xz/hF0/ST0JkEKB2RnZ3Ngw8+yMyZM7EsC5fLxRNPPEF1dXW3JE+RBChCiNOWJEA5PkmAIoQQXUQSoAghRB8hCVA6SSnlUUp9ppTaopTaoZT6j57atxBCiJ7t4QeAS7TWdUopF/CRUupNrfUnPVgHIYTos3os4Gv77HBdpOiKPE7fM8ZCCNHL9Oh1+EopQym1GSgB3tVaf9rGMrcppT5XSn1eWlrak9UTQoherUcDvtba1FpPBAYDU5RS49tY5g9a68la68n9+vXryeoJIUSvdkp+aau1rgI+ALrmjkBCCCHa1ZNX6fRTSiVFXkcD3wB6z/VOQghxmuvJq3QGAC8opQzshuZlrfXfenD/QgjRp/XkVTpbgXN7an9CCHE6mjp1Khs2bDgl+5a7ZQohRA86VcEeJOALIcRxdTbF4bHSFMbFxQEdT4HYleReOkKIM8Iru16hsLawS7c5OH4w12YdO4EJtExxaBgGCxcu5NFHH2132w1pCtessZOuVFdXt1qmoKCAlStX8uyzz5KTk9OYAnH16tUsXbqUVatWde6NHcMJ9/CVUrGRE69CCNHrHSvF4apVq7j11luZM2cO77zzTqv1OpKmsL0UiF2t3R6+UsoBfA+4EcjBvidOlFKqDFgD/F5rXdDlNRNCiGba64l3p7ZSHF599dVcffXVVFZWcvfddzNz5swW62RlZbWbprC9FIhdrSNDOh8A7wH3ANu11haAUioFuBj4lVLqL1rrZV1eOyGEOA3k5uYyf/58FixY0CrF4YMPPsiCBQtarVNUVERKSgpz584lKSmJp59+uqeqe0wdCfiXaq1DR0/UWlcArwKvRu5+KYQQvVJbKQ611vzsZz/jm9/8JpMmTWq1zrZt27olTeHJaDfFoVJq4VGTNFAGfKS13tddFQNJcShEX3c6pzj87W9/ywsvvEBOTg4TJ07kRz/6UY/XqztSHMa3MS0T+LlS6gGt9Z9PuJZCCHEGOF6KwzvvvJM777zzFNWsc9oN+FrrNjNTRcbw3wMk4AsheiVJcRgRGcNXXVgXIYQQ3ajTAV8pdTFQ2YV1EUII0Y06ch3+NlqnIkwBioB5rdcQQghxOurISdvZR5U1UK619nZDfYQQQnSTjpy0PdDWdKXURcD1WuvWvzgQQghx2jmhm6cppc4FbgC+C+wDXuuOSgkhhOh6HRnDzwKujzzKgBXYP9i6uJvrJoQQogt1pIefD6wDZjfcJE0p9dNurZUQQnTCmr1reHzT4xz2HqZ/bH/umnQXV4y44lRX67TRkcsyvw0UAx8opf5PKTUDuf5eCHGaWbN3DQ9seIBibzEaTbG3mAc2PMCavWtOarudTYDS0QQny5YtY8qUKUycOJHbb78d0zSPmTzlZLUb8LXWq7TW3wPGYN8581+BdKXUU0qpmcdfWwghus7Nb93MqgI7KUjICnHzWzfz+p7XAXhs42P4TX+L5f2mn1999isAKv2V3PzWzXx48EMAynxlHdpn8wQoAAsXLuThhx/u0LoFBQUsWrSI/Px88vPzGxOcPPLIIyxdupS8vDxWrFjB+vXr2bx5M4ZhsHz58sbkKVu2bGH79u3MmjWrQ/trT4d/eKW19mqt/6S1/hYwGPgCWNLOakII0SOO1B9pc3pl4OR+H9rZBCjQfoKTtWvXsnHjxsYbsK1du5a9e/d2KHlKZ3TkpK3SR91SU2tdCfwh8mhzGSGE6GrPzXqu8bXL4WpR7h/bn2Jvcat1BsQOACDZk9xi+bTotA7vtzMJUKD9BCdaa+bNm8dDDz3Uat32kqd0Rkd6+B8opf5FKTW0+USllFspdYlS6gXkF7dCiFPsrkl34TE8LaZ5DA93TbrrpLedm5vLvffeyzXXXNPhBCgdMWPGDF555RVKSkoAqKio4MCBAxQVFRETE8PcuXNZvHgxmzZtOun3AB27SmcW8APgJaXUcKAK8AAG8A7wmNb6iy6pjRBCdFLD1TjdcZVOZxKgdER2djYPPvggM2fOxLIsXC4XTzzxBNXV1d2SPKXdBCgtFrYzW6UBPq11VZfU4DgkAYoQfZskQDm+7kiA0iiS6rD1IJkQQvRCfS4BihBC9FWSAEUIIcQZ6YQDvlIqVilldEdlhBBCdJ92A75SyqGUukEptUYpVYJ9b51ipdSXSqmHlVKjur+aQgghTlaHrsMHRgL3AP211kO01unARcAnwK+UUnO7sY5CCCG6QEdO2l6qtQ4ppTK11lbDxEgS81eBVyOXax6XUmoI8CKQgZ016w9a68c7WW8hhBAnqCM3TwtFXrZKdqKUyj1qmeMJA4u01tlALrBAKZV9AnUVQghxEjoyhn+dUuq/gXil1FilVPN1/tDRHWmti7XWmyKva4E8YNDx1yb9po0AACAASURBVBJCCNFVOjKksx77Vgq3AI8Co5VSVUAR4OvMTpVSmcC5wKdtzLsNuA1g6NChR88WQgjRSR1JYn4IeFEptUdrvR5AKZUKZGJfsXNClFJx2GP//6q1rmljf4134Zw8ebLcgVMI0atMnTqVDRs2nJJ9d/j2yA3BHkBrXQ6UH71MB7blwg72y7XWkgBdCNHnnKpgDz14e2SllAKeAfK01o92rrpCCNGzOpvi8FhpCuPi4oCOp0DsSp29PXI0dmNxIrdHvhD4PrBNKbU5Mu3ftdZvnHi1hRB9TeXLLxM6WNil23QNGUzyddcdd5nmKQ4Nw2DhwoU8+mj7fdaGNIVr1tg5daurq1stU1BQwMqVK3n22WfJyclpTIG4evVqli5dyqpVqzr3xo6hI2P4fuBJ4MmTuT2y1vojJPm5EOIM0zzF4e7duxtTHObl5fH4449TVlbGjBkz+PGPf9xivQkTJrBo0SKWLFnC7NmzmTZtWqttN6RABNpMgdjVTvj2yEqpHwPOSC99s9Z6V5fXSgghjtJeT7w7tZXicOzYsfzud7/DsixuuummVgE/Kyur3TSF7aVA7GonfHtkrfUvlFIZwETgGqXUKK31rV1eMyGEOE3k5uYyf/58FixY0CLF4erVq3nqqaf4/ve/32qdoqIiUlJSmDt3LklJSTz99NM9WeU2dTjgK6XeBe7WWm/RWh8B3o48hBCiV2srxSHAlVdeyZVXXskVV1zBDTfc0GLetm3buiVN4cnocIpDpdQk4H+A/dgnW7s985WkOBSibzudUxx++OGHvPbaawQCAc4+++xOJzI/Gd2W4jByW4SLlVLfAd5SSr0G/Fpr3alf2wohxOnueCkOp0+fzvTp009NxTrphMbwI9fS7wSeAh4EblVK3aO1/mN3VE4IIU6lPpviUCm1HjgE/Ab7pmfzgenAFKVUh2+iJoQQ4tQ4kR7+bcCXbdxC4V+UUnldWCchhBDd4ETG8HccZ/YVXVAXIYQQ3eiEk5i3RWu9tyu2I4QQovt0ScAXQghx+pOAL4QQfYQEfCGE6CMk4Asheo3q119n9yUzyBubze5LZlD9+uunukqnFQn4Qoheofr11ym+7xeEi4pAa8JFRRTf94uTDvqdTYDS0QQny5YtY8qUKUycOJHbb78d0zSPmTzlZEnAF0KcMQ58/yaqXvsLADoU4sD3b6J69WoASh79Ddrvb7G89vs5svQhAMKVlRz4/k3Uvv+BXS4t7dA+mydAAVi4cCEPP/xwh9YtKChg0aJF5Ofnk5+f35jg5JFHHmHp0qXk5eWxYsUK1q9fz+bNmzEMg+XLlzcmT9myZQvbt29n1qxZHdpfe0749shCCHE6Ch8+3OZ0s7LypLbb2QQo0H6Ck7Vr17Jx40ZycnIA8Pl8pKenc8MNN7SbPKUzJOALIc4Yw/74YuNr5XK1KDsHDLCHc47iHDjQfk5Obrl8v34d3m9nEqBA+wlOtNbMmzePhx56qNW67SVP6QwZ0hFC9ArpP/1XlMfTYpryeEj/6b+e9LZzc3O59957ueaaa1olQLniiiu4/PLLO7XdGTNm8Morr1BSUgJARUUFBw4coKioiJiYGObOncvixYvZtGnTSb8HkB6+EKKXSPzWtwAo+c1jhIuLcQ4YQPpP/7Vx+snoTAKUjsjOzubBBx9k5syZWJaFy+XiiSeeoLq6uluSp3Q4AcqpIAlQhOjbJAHK8XVbAhQhhOhr+nQCFCGE6Ev6bAIUIYQQZzYJ+EII0UdIwBdCiD5CAr4QQvQREvCFEKKPkIAvhBB9hAR8IYToIyTgCyFEH9FjAV8p9axSqkQptb2n9imEEKeb5slUelpP9vCfB7rmLv5CCHGG2rBhwynbd48FfK31P4CKntqfEEJ0hc6mODxWmsK4uDig4ykQu9Jpdy8dpdRtwG0AQ4cOPcW1EUKcLnasO0RNmb/9BU9AQpqHcdMGHXeZ5ikODcNg4cKFPProo+1uuyFN4Zo1awCorq5utUxBQQErV67k2WefJScnpzEF4urVq1m6dCmrVq3q3Bs7htPupK3W+g9a68la68n9TiAjjRBCdIfmKQ5fffXVxhSHYPfiJ0+ezN/+9rdW602YMIF3332XJUuWsG7dOhITE1st05ACsWEfR6dA7GqnXQ9fCCHa0l5PvDu1leIQ4Fe/+hXXXXddm+tkZWW1m6awvRSIXa3XBfw1e9fw+KbHOew9TP/Y/tw16S6uGHHFqa6WEOIMlpuby/z581mwYEFjisN3332X7Oxs/P62h5mKiopISUlh7ty5JCUl8fTTT/dkldvUYwFfKfUSMB1IU0oVAvdrrZ/pyn2s2buGBzY8gN+0/wGKvcU8sOEBAAn6QohOayvF4YcffojX6+XLL78kOjqayy+/HIejaZR827Zt3ZKm8GT0qhSHM1+ZSbG3uNX0AbEDeOfad7qyakKIHnA6pzhs8Pzzz5OWlsbs2bN7vF4nmuLwtDtpezLaCvbHmy6EEMezZ88exowZg8/nazPYA8yfP/+UBPvO6HVj+EII0VV6W4pDCfhCCHG6qK+A2mIwg2C4IX4AxKR02eYl4AshxOmgvgKqD4K27LIZtMvQZUG/V43hd4mtL8NvxsMDSfbz1pdPdY2EEL1Zw4UzNUVNwb5xnmX3+LuI9PCb2/oyvH4nhHx2ufqgXQY4u40fV2htt8JBL4Tq7fWCdZHnegh5wTLBFR15xNjPzuiW05xRoFTPvU8hRNfTuilgOwz7tb8anB77u26FoboQolPAkwDhAJTmQ+JgiEkFK9T2ds1gl1WxbwR8re0ee+JgmPGLtoM3wNpfNgX7BiEfvLHYDv5BbySYNwvwVtu/hss7GGJdXohanyY+WjFtrIuxQ1zHqKBq1gAcq3GIOWqeJ9JYeFrOcxjH/DOs+uIQD7+9k6IqHwOToll82WiuPvfU/XpRiNNeOAAocLrtcl2p3UHzJNhxpbwAopMhNg3QcHirPe4e39+eX7nfLrui7e0EvRAVb2/L4bQDvdMTKbvaDvqGu8veTt8I+MCa2GiuOF6PPeiF6kLyqvuxriST2nAU8c4A09L3M5ZSqD4E7liISrD/Md2xkUAb0/TaHQOuWPK+2MY7by4nHLQP1Wp9mne2A+dcy9hJ4yONhd9uMBoajobnsK+pUfGWNs0LBzr2Rg13swagoWGIZltJiC+2ljMl7CLgcBGocbH6tc9JKR/D17KH2B86Z1TkudnDIaN+4gynddMRdNALKPu7ClB7xO4kxabZ5bLd9ncncXCkvAs8iZAUuZFj3WHwJNkBX6mWR+bKAQkDwW3fDROHAf3GgOFqKmeMa1reYTTtB+x1m4/hN2wzfkCX/BmgrwR8pbivXyoAI4piWffws9SG/kh8ahrTZk1nbEo1HPyEvNoBvFOcSVjbveTasId3is+i3ErlrOw7yBg6BEI+Nn34DxLS0hk1MReAt556jP4js5g480K7/PxiLNNsUYVwMMi6199g7Kzvsu39dxgwKou0szIB0Fqj2hvSsaxIY+DHCtbjMP2E/V4KDpWQGmXSz2Ph93n5x46vGJPgZGg8eL21vLtxP5MGeti/r5jzdD3RRhBF0wcq9Pc3KNmTRHp8FPXBMF8W1TAyPY7kGDe+oElBeYChGakkxsfitVzsrggzYkAqCXFx1FkuDlabDM1IITYmDh8uKgMO0pIScHtiMQ03yunBEWl07AYl2v4CyBCW6AzLAm02BdFArT1sGp1kl2sP2/MTIkeuZQX2c9oo+7m60A60qZGyv9r+XDYEfFdMU28eIHFIyx52+lhQzY6iG7bTIC6jZdkV3fH31nBiVq7S6bzhh2I4b2cysX6Dzc4h5JsKtAPQ1JaV8s5LKynp72VAQph11eMI65b3xQhrg3+WpFO1+lVmT02Btf/JpsKLGTT2bEbl2AG/prSExH5N/9BHB/sGtWWlhPx+3vn9b7no+nmkDc1k96Fy1iy5lek33cLEmZfzx3W7cW1fy8WzvkF65ghuf/GfXDw8nu9NG4NpRDP+P//BHdNHceeMswiHTGb971ssvmw0Cy4eRTgQ5rYVb3Pf7Gx+eNFwLH+IlQc3En/ecO7c/jn28YbGhUkUQaII4SHIsxeeTXqqk6ryat768EvmjE0nOcVJaUklqwvzuT4lncQkJ2UlFfxj3x7S4z0kUE9teSX5u4roPyKe2Cioqwvw5cEqpmSm4I52UV7rZ2thNecPTyXe46S0NkBBSR0ThyYTHRPLkXrILwuSM2ogMTGxFHk1+WUhpo4ehCc6hmIv7KsymTxqAG5PDKV+RakPsgam4YyKwWs5CeImKSEe5fSA0bUfZxkC6wF1pXaAG3C2XS5YCyVfwtR/scv+GijfA6kj7XLVAfuoNyPbLntL7aPfSMDf9XkZH79dQV3VTuJSorhgVjpZ5yU37S9xiN1rbtAvq2V9Eo/6921oSBo4ujlkxqR0aYA/Wq8K+A4UFk23ihh+KIYLt6XitOx/YE+49fh22IQvDsfzlc9FbW3bN0GyLM20G+aBVQZTbuHmu3+Gw+mCrz7hkDuT8xf8nGGpsQC8veMwXlc8saHaVtvxuuK57pnPmXDVPUy4ZDwA8575hMuHTyFtiH3I+H9vb+bKgjcoHz+ajOEjqS87QtEbvyRfLWLstIv5wTlJJHy2kpKR3yM9cwTP3TiBfrqOUMBPrDuKPUsvx3DYved4j4vlt9iN0sCkaGIObmFq5afEm3XUGnFsSD6f+iHnMHq8favXgQPg3vHTGus7dCz8/OtN9R9iaW693MJlKDAcxPlDnFVejzstFlwOzMpqgnuKYFg8uEzqj5RzJP8QVnYyuCwqD5XypSpk3Jg0op0WFQdLKDh8iMnRyaDC1FSVcuSrYlRSBRAicLic+iPVOGr6geHAW+6lqKSO0aPTwaE4Uuplb1kdl4xJRylFQXmA3RUhZp0zDOX0sL0kyO6KENfkjAJnFJsP+9hfZXJ1pLzlsJ9iL8w6JxOcUeSVh6gJGZx/1kDW5FVy3+pd1IYNQHGoysc9r20FkKB/NMu0g6hSUHUQDm+DrMvsnnTBWvhyFcx+3B4e3PC/8MmT8NMd9vIbHofP/g/uPWJvq+A9+GJZU8BXqmWPOia15XmzxMGA/Xnf9elhPvhLGeGgfQRbVxHgg1cOQVQ8WedHlm8YyjkB27dv57bbbmvMVLVp0yYWL17M2rVrj7ve/v37mTVrFrm5uWzYsIGcnBxuvvlm7r//fkpKSli+fDlTpkxh2bJl/Pa3vyUYDHL++efz5JNP4vf7ue666ygsLMQ0Te677z7mzJlzwnU/Wq8K+N/1W6yIonG44LydyY3B/nhM0+L6x19i6Q/mtRmo641o/vF5HkopXts0kvD6PzPnvP6MWb+QL62hrIi5nhvOHwbAc+v3YUSP4tzQVpw09fTDymBL7FjGRdeT5ollX1EZrrJq7vr6MDKSsvFkJFNdU8eKhbNIir0St2F/yP9wyzTyxlj0P2s0ADedm8bqD3YT9NUDMEJX8Mp/3Uvi/Q8xJHsCh3flsf7PLzLjljtIHTSEmrJSSvbv5baMUko2v48jcglYglnHzPL36X/BsA7/fR0ORbS76csX73ExflDTPb77pyZzeWpTbyozZTiZY5tu6ZE1ArKa2hPGngfN7wIyJvJokB4M46rz4YjWYAWJKq8ksbQKxyAPhINYRWVwpAzHWUkQ8hE4WIoVW47KSIGwD11VQrRREekF+nEfLiG1qga2bwHAVVRDXH0Qau3DefNQNWFfCEalkVhQxm+UiXYpwhiYGIRxYP3FgK+GgcPFZwdrCVoOLsrKAIeTrUV1WMrJxGFpYLgoKPfjNFxkpieAw0WF38LlchEf7bGHJBxO+0Sdw4i8jjwMZ7N5zqb5jes0THM1Te+qITIzBN4yu5fpjLJPOhashfHftk9O7lsHG/4fXPW/EJcOm16E1XfCop0QnwE734A3/w0W77GHScr3wK537KvXPAmQMgJGXWrvx+mGc66HYRc2jbPPuB9mPthUn6h4SMlsLP7liQLGXDCAsVPt7+3qx7aTfdFARp/fn49X7WkM9g3CQYt1K3eTdX5/fHVB3vr9diZ+YyjDz07DWx0gNjGK9nQ2AQq0n+DkoYceYsWKFaxfvx6Xy8Udd9zB8uXLiY2NbTd5Smf0qoB/b/FBKhhB4r4MYv3HvlrlaPHuMA6nk82x48it+gyj2Ri3haLOEcPGN14HID1kooF/lhhst6YStBTDqjeyafVnpJpHGG9kUG5qKlxJJIercGqTsDKodCYxKFSCc9NbVAAr32/afx7w4dGVciiUw0AZhv38j00ow8BhGKh+Y/jTyjdxGO+irDCOkefy2poPcb73KbqukvChYl577S1cCUmEivZSs3kdTrerMdg37kJrKt/5Iy+V7mfQeRfhio7CDARwKkVUQgJOw8DpdGI4HTgdhv1sGDgNA8NpNM03HDidBobD0eJugScrxu0kJiW+sTwgNo0BzZKgjRoMzUdQx02AZqfEmDANJjQrZze80BrCAcaEfAQDPiAEYT/9q2pIqq+DeAfPbF+HOzLk5VImTpoe3+43Gqww9UeKscIh++S2FeZQaSUGJqSEwQqzb0ch0U7I9CeBGSJv9xHinJpzhtjDBJ/tryA+ysnYAQkA7CiqJi7KxbBUuxe6v9xLrNtJv3g7KJXVBfC4DOKi7K9tIGzidDjsIzrlaNkINDQcYI9zR6fYFxeEfHBkB/Q/G+LT7ZOW+a/D+O9C8jD7MsHP/gDT/90e9y7eAusftwN0vyy7XLEHDnwMSYPtczLn3WyfbAx5YfBkuGGlPcxSXwHnfA8mfd+uj9Yw5nL70SBjXMsTmS7PiX1ImqmrbPvCBn/dMS537KDmCVB2797dKgHK17/+dR544IE276fTkOAEaDPBydq1a9m4cSM5OTkA+Hw+0tPTueGGG1i0aBFLlixh9uzZTJs2rdW2O6NXBfy86n4MK+7feNK1I5zKZHRcMb964L8ZHDpMiTuNpHA1HitAnRHLPxMnUTdwHC/dag+N6MgZdOuom4y68v5C3IcrqLzuNdYeiWfH2uV8R31CBhUU61SesWYzNvdqJg1NIhwMEzJDhENhQqEw4XCYcDhEOGRimibhUAgzbGKaDdPCWKY9zwqHMcNhtGlimWEsy0I7olAVJZiWxrKAuAzCuzbiJ4qwCa7EgXiqD9Fw6NtcKBCk6JP3Kdy1A78jFqO+mqj6cnypwzAdLpy+WoxgHf6EgaAUjpAfZYUxoyJXIjS/AgLshko57MN35UA1KzscBiiFcjjsRszhQCm7YXM4Iss2vnbYDZxyoAy7IXE4HBiG017HcGAYRtN0pzPyWmE4DRwOA8OINEKGgWE0PBs4HQYOp8IwDFxOJ8rhwOlw4nT1w4jvzz6nwd6oao7UBdE40Ao0Co1iQKKHu8/5OobhIDdHYRgOrEgdvnlpy7/tuGk+LK0h2Q7g/rwjKKcDRqaAFWbj+zvpH+9k7NkZYIV5/uWNZGfEcPMFQ8AKc8/v1zFtRDJ3TBsK4QCLn/8nM0bFM3dAKcQPYOFfv+Kbo6KZba5DD5rM0k8CzBxqkXNoGdaYb/HK/himpNSTWfAXzLFXs6kERrqrSflqA2ZUAiVVdSTpGqIBXZqPWVWIEapFZUyArz6Gok328MmI6bBnLez9wH5jqaNgy59avtl/PNyxL5wyWh7RtDhqaXb00jA96RL7RKxSgOKaHw2xP8feMgyluObHmfY8XxVxyW7qKltfsx6X7IZQPdFRimvuzLaXDweJjVN2Q4Zq3H7jZ/moI6bOJECB9hOcaK2ZN28eDz30UKt120ue0hm9KuCvK8lsN9ibWLgME8t04nGESXLXUxxMprwuwMCpl/LHfQZes6mXGu0yeGj2BAb2Tzv+zgfeDpNmEZc8jPn6ZSzPMzi0PdaYQDEPOV7EGDQazrvVDpL5a+zD24xsMMPw8f/C0Fz7EfLBG3fD2Ksgayb4quBPc+D82+1D69rD8NRUuPw/4dwb7cPux8+Bq5+CiTfYl5b972T49tNY479DsHALL96zmNpw695TrDPI12++hYy1d1E8/RGOmP2o37mBnMNPc2DqUvZ+VUPtzs/5Rvwb7D/3Hgq27cJ7IJ9LBu1m31nzKNq2g1DJQSaN0BwcOIvqosM46o4wKDHA4aRJBHxBnMEa4nQ1ldHDCGNgBOtwhrzUOxOwLA2WiWmF0GH7iiVtmWjLanpoCyLP2or8uKVxevfc3vuCsElcoISRqogoggRws0cPpK4mnUeWHONW24rGS/VUQ/CIjG2ryDylHPxdB0AZmI4oypWidOVX+JwJJLlSObwXXnnnEyo9gzk7eji1+Yf5cN1/cjDhXIa5x1BYcISPPl7BgaQpxHEWW/eGiK88zIE9ZRT5B/HmXjgSuIAjeel8UBLNtsoMxkbdQXVhf94sqCd74EhGZEzDX6V4e0cJ5wxJYlTG5fhqLV7fdpic4amclRFPfSDM+1tLyMlMYkhyFIFQmM1fVTJuQBxpcS5CoRBfVXgZmuQhwePAskzq6gMkRjuJMjQOpXFoE4eyMNA4sOwyGoe2UKaJYZqokNU0T1s4MFE6hAMvDm1hxpkEA4FIV0VjN72R15EjVhX53/kz4vn7XysIh5o+E06XIvfSeHRNcdOyHdHQAKBAQe74EcxfcDcLbpnHoDgN1Yd494N/kJ05AH8gAPWV9tFSQ2WUso9wLBPqy+1pDT/S9FfbR13aYsa0XK669np+uuA20tMzqKispLa2DpfbTUr6gC5PntKrAn5tuO3xOB05keuPthjW/xBjvWEO1ieigPSYejYNnI1j1DUsufYcxmwu6vyVGcmR8fC1v2wM9g0MKwBr/wOm3Gp/GFbOgwvvgoxf2EHhvfth+j12wFcO2PMBDDw3srLbHu9suELAHQfZV0PKcLsckwaz/hsG2oeZJAyCG1+F/uNxOBx4Bo5j2tAq3tnXr0WD6FQmXx9Ww9gLL4MRK0jpP4FxMSlw4TjYNYSMMZcxJb4/lOTBxhfIvGAGU2Zdg2/nP0jNf44Jl19MfuZwqnb8g9z6l+GaX/Hmn16jsrySywOr4Pp/59WnnsZXvIfrU16Hn+zk7eUvY3j3cGloGfx0Hzu37CBq/3tk7nwMfnaQIC5cm19EffokLPjMHkfe/BJsfxVuXGn/7fLfgK82wMwHsSwLc996rNICQhPmEA6bmCU7sbzlBDPOJWyaWHXlmOEwIXcS4XAY07KwwiYh08SyTHsd08QyLUzTwjRN4g+tI+PLN3BYITu2oDhXFXNw5I1Upk3G0hrLskBr3N4itIb6qH6gIb1kHQEjjoqk8ViWZvS+ZdR4BlLY72uA5tz831CWMI59/S4BrTm7YBUlMePYnzoWbVkk+f0EPQZ1sXFYlsWRxHOo9/QnzuVGaydbUi8nYMSTohRaG3yc/G201gyOCqPDmi2OCVCnGRvtR/t87K13o3UZ58VqVHUdh6s12tJMdJoYR8o4eERjWZqzzTB63yH2HrAvVBgcCFO1w8BrOAhbFqY/zN5ig0LDIGRZVNeHKI924jYMQqZFtS9EYrQLl+Fos+wNhomLcuJ02Nvzhyxi3AYOpTC1JmRaRBn2UZ+l7W/t5cOhrL4jw4SahKxkJn7TYMeHFfhqwkQnOBk3PYWEUfEcrmta0o7JumUZ2ijbx3UA6YOG43K5+eEPb6Gsxj6KeHPtOurrfezcvRuPx0Pu+bn20WlkneqqGkzTpKq8AoCg3099TQ3VpSXUVJRhhcMMSkvi3xf+hEsvuxzL0jhdTv7nwfupqavj/v/+TZcnT+lVCVD+cOOlbfZicYXYfNFedsb14+LPs5lYs5vs+MPExWqecn6XC676Ed85b0jXVfyBJKCtv6uCB6rsl4e32dfsxqXb5WB99/7QaevL5L34AOuKBzb9qGxAEWNveuDYvzzuJG1ZKCsMDidFBTsJ1ZYzbHAypI3m7y+9iCNYw7Tzh8GY2Tz/b3eRnBTDVV/LgIt+ynOL/4W0JDffGu+Da37P+8//gTRdyNnWJ3DLuxz8chvxu1eStHsF3L3T3uGau2H7K7Bkv11+/S7Y+Sbcvcsur7oD9v4dFu6wy3/5sf33//FHdvntn9vXZ1/3gl3+6DFY94jdCzta4hBIy7LHw+f80Z721IX2D3Ouf8kuP3kBZIyH7/yfXV59p10+/za7vPVlSB4OQ+xxW2ojP+Y5ifHr7mBZFqZlN4Jaa0zTwrI0WlsEQiZV9QGinQ7chqLCG2DHoSpGZ8QTH+XkYIWX9/OOMDM7neQYF/lFNbyy6SDzLxhGWpybz/eV8/z6/fxsVhb94qPYUFDK8k8OcN/lY0mOcfLpvnJe+fwgT940ibNGnYU3GKbGFyI9PgqHUvhCJvXBMEnRbpSCYNgiGDaJjZzfCJsWpqVxO+3vk7Y0msjvXY6Kea1ioNYtv71ac889P+OciROZM+d7rdb/859fIiUlhW98Y2bDCo1ff31UuWlGw9FJy3LDMkr9//bOPD6q6mzAz5k9k2Wyk5UdRAiLKKAgFkXQgohaPqWKSq3V1mLRz926tfq5VMWliq1arVatoiKKqIAIihsiq+xgSAjZ18lkMvs93x93cmeGhNWQYLiPP3/Je+89954bZt5zznvexUC3vKigrP1wuAVQupTC33pjX5aU92s1iz01dxf/6iMpcWfTZ+uJ7LH2ZqMjsp2XmxzHV7ef1X4df6IgkuUuGkc+3Lip/Z5zuGycp6aPcO49eJqJDsLvaSYYCGBPUr19Niz9GHtyMv1GnAbAf+++hbyBBYz9tVp84u8zL2bQuPGcNfNaAF664RoG/+JMRkwYj4zP4Jt3/kuPnpnkZjmQeafgqqkm3rkVo6caBk9TH7pxHjSWwuk3qvIXj0FTJUwK26E/+BOsfaXtqGtHDUy8Xx2cR/5Ovb74G7AmQFb4M6WEDpjiQqc1tLizxQAAIABJREFUbl+QKpePvJQ4zEYDxbVu1u1poL/VycCBA3H7gjg9AbKSbBgMgoZmPzVNfnpnxGMQgqpGL5WNPgpykxBCUOH0UO3ya3K500Ntk1/zKqtwemj0BunfTXUKqGny4fGHyE9V91ucngDBkEJD5V4mT57MqNNOY+4/XtAGlJCiIBAYDO0bQFjf7KfS6cUfUrAYDXRz2Eix7z+1wuEq/C5l0jnRUU1pcyIbG3KQqEuzTGsTJ9qcTKu38GW5kWKrkU1JA2PalTV42rzfETP+ntgkbKBG3I3/6ZsuP4khF3e6gt8XS5wdS1Qw4tAJv4w5/+v7I5uBUkp+dedfsSWoX1IlFCJ3QAGO7HxIyCTg9fDtu29ivvRKckecjb/ZzQuzruIXM67ilCnT8DW7+eDxBznlvAvpdfrFBHxefvx+FbmDZpKYlh6JeD7/abZ+u4ol5amtoq6JS+PEFh/xFnqcFivryv6wibea6GWNqKMeafH0SItn69ZG7Xx81Plku4XkKEWYmWQjI9GqRaynJVhxxJk12WEzYzVF/l1sZmPM9k9IUU1KLTibA3gCIU4IF0AprnVT2uDRBoiSOg/+kBIlNyOlpHs4Hqey0avqnyR11dbQ7McgBElxaoSwxx/EIARWs9onRUqczQFKG8Ib/YA/pFBar+qQAyn9w6FLJUrZ6sxgU0NWeFtH9aoo8zrYUJeFeW86DiXIxr7VSFtFTLuc5MMIfz4UhlwMU55WZ/QI9eeUp485ZftzQwhBTv8BpOaoeyoGo5Fzfv8n+p96OgAWWxw3vPEeJ/3yfPW8wciEa66nx1B1b8Pv8RDweVEUNT7CWVXJoqcfpXT7FgBqSop5+oppFK5dzcrq1g4AQWlkWWkuTXW1ADTV17Fj1Vd4m1QDscfVSPnO7QR8agBfwOvFVVtDKKju57RsQuscHaLTk5iNBuIskQHCbjWRGh9Rmsl2S8z3vluSjd4ZCZqcnxpHv8yInJVkIy8lcn1KvEVzlwWwmgxYzJHPiy8QwheM/FtXu3zUuSMeRCX1HioaI4GeOyubYpR9C4qUVDrbDgg9ErqUwv+8vBchWs+u1tfl0OCPY1hiA4G07cT3fJaEAbcT3+dh7CkbuOWcE9q/M0MuVs039zWoP3Vl3yEYDEZMZnUWZbbZGDL+HDK69wQgMS2dSx94nD4nq2GXyVk5XPnYs/Qcog4IFlscQ84+B0dmFi5Xc5v393n9OKurAKgs3MnCOQ/hrFInECWbN/LGXTfRUKnKu9as4vnrZtJQqXqIbFm5nDm/Pl87v/nzZfzj2stxN9QDsO2rz3ntjhvwutUBZOd3X7Pg0fu1AWT3uu/59F/PaQNIyZYfWPXePM0GXbFrB5s/j0R/1paWsCccZAbgqquhrmyvJvu9HnzNbb/n8Y4QseYaq9mIPWoAccSZY2bdmUk2spIiezDd0+I18xBA74wE8lIjA0ZuchyZUQNGWoKllbJvwR9qv0lCl1L4bqXtZY9fGslPcPLP5JMAA8KgIAQYLA3Ysudjdqzv2I7qHBOYzGbS83tgS1Bnco7Mboy74nek5eWTmNa2G25CajpZffoBkHfiYK74299JzVU313IHDOKi2+/DkaFuxGf36c+Ea2aRkKLmRsno0YvTpl1KXKJqBnBkdKP3ySMxWdQvvslqw+5IxhgOmPJ7PDRWV6lxDKgKfPs3KxFhRVS8cT1fzXtNm9lu//ZLPn1xrtbXjUs/5oPHH9TkVfPn8eY9t2ry8n8/z79v+oMmfzL3SV65+Y+a/NnL/+Tdh+7V5JX/fYXF/3g6cr8Fb/PVvNc1ecPSj1i/5CNN3vb1F+z87mtNLtq4jr3bNmty5e4fYwYgV20NHlejJoeCPy1g6ljCaBCYohwy4q2mmBVIeoIVi9GALeQjzV9Lpq+aNH8ttpAPi7H91HSXsuHbAkG8lrZzzr8bHMvm9C0YROxoGZA+nlr7FJN7T+6ILur8TBg7/QqWPP8MQX8ketNksXLGpVdiNKlfG6vdTkaPXtr5+OQUep0U2StLzsomOSuS2jazZ28ye/bW5LyBBeQNLNDkvqeMou8pozR50C/GM+gX4zX5lPMu5JTzLtTkMZfM4LRp0zV51IUXc9I5kWjP4ZOmMmBMJBnS4LMm0jNs3gI4YfQZZPeLJLPoMfQkbfBq6b/RHPk+7ZvRtb68lIAnsk+1a/W3SCkZNlGNpF370ftY4uz0GzkagJWv/5uE1FTyBqiRtR8/8zipOXmcf9OdALx9/51k9urLebPVQemlG67l5Cuu1e5fU1KM1W4nMS0DgLqyvVjtduKT1QG1oaIci92uOQA0VldhsduxxScgpcRdXxfeM4pDSonH1YjZasNstSKlxN/cjNFiwWQ2I6Uk6PerAX1GI1JKFCWkBgIeJU+6DEsIf7NL89wxSoXEoAtLQvvlw+9SXjrvTBxDcXJym3lFAsLEV4PLKcprvYQVCDZeufEn9VWn67F15XJWvvkqrtoaNZX29Cs4ceyZnd2tnw0BrxdFUbDaVdNGQ2UFQggcmWpm2bIdWzFZrNoguHPV19gSE8kfqHo7rf14IaacfIYMHQaoKwCTxaqtkBoqK7DExWkKvrZ0L7aEBOIdyUgpqdlThN3hID45FSkllYW7SEhNIyElFUVRqNr9I4lpacQnp6KEQlQVFZKYlkF8cjKhYJDq4t0kpWdidzgIBQJU7ykiKSMTe5KDYMBPbckekjK6EZeYSNDvp76ijKS0DKzx8QT9qukvMTUNS1wcQb+fpvpa4pNTMVutBAN+PE4ncUkOTBYLwUCAutI9KG2Yb4wmU8zEIprj2ktnb0oi+4ulM8sgp+xIa1PhW4wWpi6YytWDr8YgDDy19ikq3BVkxWcxe/jsLjP7X1S4qMu+29HgxLFn6gr+J2C2xcYVJHfLipFz+scqqn6jRsfIw385ha1bt2ryvma2fe+XFrU6EULEKEkhBN16993nfE/NXCYMBlJz87XVmzAYSM7K1sxtwmAgKT0DS/idhMGA3ZGMKWxREEJgsdkQRmPUM9DUkZQKQb9f27RXgiGaXY1Y41VzYijgb1PZA9qeTXvQpRR+Wxu20cR7DdiMNryhyK63zWhjXN44vq34lpc3vcwe1x58IXUZX+4u576v7wM4bMV4rCnXRYWLuO/r+7R3/ynvpqPzcyTaJCWEwGiKNVdZogYog8GALT7ipWMwGrE7IrnxjUZTzABkNJtxZEYGIJPFQmpOZAAyW22k50cy01ri4ujWq0+UbMdoMrWp3FsGofagS23aHgxzUir3jb6P7PhsBILs+GzuG30fj457lOfOfo4SV4mm7Fvwhrw8/N3DjP7vaEoa1WCqVeWruHPlnTR41ajZ3c7dLC5arLV9b+d73Pf1fZS7y5FITbkuKlzUZr8CoQDNgcjKw+V3Ud1crck1nhqKG4s1ucRVwra6bZq8vW4766rWafL6qvV8XRbZLPu67Gse+e6RmIGu5d2eWvsUxY3FlDaVascVqbsO6uh0JEIIElLTWpujW463E11L4R9kO2LiFb9hcu/JLJm2hI1XbmTJtCXa7LYgvaCVsm+hwdfAeb3Ow2FTbYXVnmrWVq3VUgF/XvI5N39+M4GQ6lXw6OpH96tcAZ5c8yQjXx+pnZuzZg5nvx1JtfjkmieZtnCaJj+99ml+u/i3mvzs+me5cfmNmvzCDy9w79cRb4qXNr3E498/rsn/2fIf6n31bb5bhbuCu7+6O6b9ZYsu4/plkeCim1bcxJzvI/m/n1zzJO/seEeT39v5HqvKV2nyhuoNlLgikcZN/iaC+yn2rqPTVZFSokhFc5tVpEJQCTJ69GhN9gV92gTLYw7SFBdEMYSvN0ia4oL4LO03AetSJp2DcTB7bFZ8FuXu8lbHrUYrdb46nt/wPNkJ2WTHZ/PEuCfU1MRSclH/ixidO5p4sxpl52qjiAqoyhVgRNYIrMaID+64/HHkJUaWf5N6T2Jo5lBNntZ/GuPyx2nyzEEzcfWLPOO6YdfhDUYGmNtG3kZIiRRfuX/M/Uz/cDqVzZVtvvP1J12vZncMc0HfC7CbIz7EKbYUkqxJmryuah3NwciK5O/r/s4ZeWcwKlv1MLl+2fVM7DmRu069C4CJ70xkat+p3DbyNgCmLpjKhX0vZGbBTKSU3PT5TZzT8xzO6XkOilT458Z/clr2aQzLHEZICfFl6Zf0TelLbkIuilSoaq4i2ZqMzXR0c88ca2a5nyO+kA8ppfZvVeupxSiMJNtU88iexj1YjBay4lVzyObazSSaE+me1F1r7w16tfZOnxOL0UKcSfVpr/PWYTPatM9rdXM1drOdeHM8UkqqmquIN8eTYElAkQoV7gqSLEkkWBIIKSHK3eU4rA4SLYkElSClTaWk2lJJtCQSUAKUuErIiMsg0ZKIP+SnuLGYrPgsEi2J+II+ihqLyEnIIdGSiCfoYbdzN/mJ+TFy96TumlzkLGLpiqUANAeaKW4sppejF3aznarmKkLmED5zbInUKrf6eW8PutgMf/9T/MR01ZXLuXAhO88az9YTB7LzrPE4Fy7Urpk9fDY2Y6wSsRqtTD9hOiO6jcBkMLGxeiPzd87n2fXPctdXd3HrF7fywsYXWF2xmuUly9lWt41u9n0KGYdp+VCPyR3DH4ZF/J9HZY/ishMv0+STu53M+X3O1+QhGUM4q3sk18+A1AGMyBqhyb0dvRmYFkkXkZuQq31hANLj0rnx5BtbvZvNaGP28NmMyBrBKVmRTf1LBlzClD5TNPmuU+/i6sFXa/Irv3yFO0fdqckLLljATafcpMlPnPkElw64VJOvG3YdZ+arg62UkoL0Au1vEZRBdjt3U+9VVyDeoJe56+eyvkqNjWgKNDHrs1ks36PmYq/31jPhnQks2LUAgEp3JWe8eQYfFar+31XNVVyz5Bq+K/8OUM1hc76fw456NZGa0+fk490fU9WsBk95gh4KnYV4grHpNVr2PA7VLBeNlFKb1QWUAC6/S5vFuQNuyprKtAG5zlvH9rrt2vnypnJWV6zW2u927tbeHWBL7RY+LPxQk9dUrmHe9nmavHLvSl7Z/IomLy5azHMbIpkW5++czxNrntDkVza/wkOrIrnY566fq+3tADzy3SP8+cs/a/Kfv/wzN39+sybPWjaL2Z/N1uTLP7qcPy6L+PJftugybv0i4vt/1eKruP/b+zX52qXXaitfgNmfzebFHyKpgOu99dR56zS5rKmMBl+DJle4K2j0R3z3q5qraPJHUmPWemtj/m1dflfMSt4T9MRMjkJKSPvbCwRGYWTL5i2MHj0aIQQ2k42N6zcyfvx4DMJAoiURk1DnzSZhItWWitmg7g34PX5umHEDY0aMoaCggAXvLCA7Pptuqap+KN9bzoVjLuT3V/+e/v37c/M1N/PN598wY9IMJo2cxA9rfwDUz1B70bVm+Psr8yYlY6dfgXPhQsrvvgfpVWfDwbIyyu9W89s4pkzRZm8Hm9W5/C7KmsqocFdQ4a6g3F3OhuoNfFP2DQAp1hT6r65g+ooQaY1QmwRvnWkidcoo3t7xNiZhwiAMGA1GjCLqf4Na8MMk1GIeLccNQi3QYRCGmGtjfrZ1XdT9DvXdjoQkS1KMfHK3k2PkGQNnaL8LIfi/0/9Pk80GM+9NfU+T7WY76y5fp33p7GY7b05+k0y7GswUZ4rj3tPu5aRMNXW02WhmYs+J5CTkAOAP+XEH3QTD6alrPbW8se0NTso8if4p/SlqLOLWL25l7vi5ZNoz2VK7hZmfzOT5Cc9zWs5prCpfxXWfXkeiJbFNs9zfVv+Np9c+zT8m/INejl4sKVrCfV/fx5vnvUn3pO68t/M97vn6Hhb/ajE5CTm8t/M97v/2fj77n8/IsGewYNcCHv7uYb6c/iUOq4MPdn3A42seZ9Wlq7Cb7SwsXMjf1/2dtTPWYjaa+Xj3xzy34Tk2XrERIQRLipbw6pZXOa+36m+/bM8y5u+cz8UnqJHcX+z9go+LPubKQWqyue8rvueb8m/4w1B1grGzficbayIuyNXN1TH7NwElEKNgEi2RimMAvRy9NNMlqKtVY1TN2fN6n4fVFFm9zhg4gwRzZPPzumHXxXxe7hh1R8zs9aGxD8XIabY00uPUzdGNyz6htqKUKgzsCn/XQ1KhGsFO0ZIlX1KLYEdUn2uBbVFyVdTvjm5ZJI9XA+lMBhO9kyNxEiaDiR5JPcgfmk9hYSEGaSA/MZ/Lb72cOXPmYDaatc8dqJ/FlokMwLKly+iZ35Oln6gzeqfTiSMuUhLUbDBT+GMh777zLoMGDWLI8CEsencR/1n0H5Z/spwXnnyBp199WhtA2oMO9cMXQpwLPAUYgRellA8f6PrD9cN//OLJbSt9Kblp3iJ2njWeYFlZq9OmnBz6fXbggsQHQ0qJK+CivKmc+g/eJ37Oq5j8kZmD32zg6yuGUjgyl5AMEVJChGToAHdsXwSC/t9XMur9nSTUeXGnxvH9hQMoGpWvVpBCYGhxUUNox1p+AmrQSfhY9HVttmvjHtH3in6mCBeZiG4Xfc+2nt1y/oDPjpJbrg0oARp9jSRZkogzx9Hkb+JH54/0Te6Lw+qgurma1ZWrWVGyYr9/yxFZI5jUaxKptlRKXCWsrljNhB4TcFgdlLhK+KH6B87MP5N4SzylrlK2129ndM5o4kxxVLgr2N24m5HdRmI2mqlyV1HWXMaQ9CEYDUZqPbXUemvpn9IfgzDg9Dpp9DfSPbE7QgjcATeeoEcbAL1BLwqKplQVqageKCLWYy36bx/994qWoz2ao/9u0f/e+94z+vi+n43wL62u2V/bVs8XgrriOk4YoKY+2fTZUhqrWpslD8a+/Y7GkdmNgvETY461df2ECRN4/PHH2bVzFwsXLuTlf7/MihUruPfeexk0cBCXTL+EcePGxbTZsWMH555zLhdffDGTz5vM2LFjEQgSExNxuVwUFRUxceJEduxQh6dfz/g1w8cOZ/K0yZQUlXDDzBuY//l8chJy9mvSOWb98IUQRuBZYAKwF1gthPhASrmlo/oQLG9tn285Hmpyq5WUQuEl3REMhHagDxnsfvkjgv5YZW4JKIx/v4Tf/fYZZCCAZ9NmzHm5GNPTCPm8NO/YjiEnC5mUgOLz4d9TjExPRSbaCfl8hKqqUFKSUGxmQn4fSkMDoQQ7isVE0O9Dut0EbSYUk5FQIIDi9xEyGQgZJUoohO2LdWS8/jkGvzo7S6jzcMZ/fqCPJZeGMYNQ50bh/2TsT0DL86FIRTumXaNIlHAd4Ni20SUhw+dRQIKCpOVOLdez32crUddErlefKdq8Trte7NPnqHNKOE+5RFJTF5nlGoGkkEVb+suo77/VaCVJsfLlj5EJgglYvjNS9g5g8fYPwn1VWeR8L+b8ezW7Y+Qd5bFps9eVrKKjkQdQjAekfTMEx3BJxqVUNKnf2/SRBaRTcJAWh0+Zq/Sg1ww8aSAffbaI//zrNV595xVKXXup9dRgspmoc9ViSjaytzE2Jbo9K44PVrzPZ0uXc9udtzLmF2OYfdtsJJIS1x7KmkoxmA2UuPYAECKI3WYPp102oISUAyr7I6EjTTojgV1SykIAIcSbwFSg3RS+UBSksbUvvlAUii69DGG1auacmPMWC2U339zq+JESrGx7FhKqqaH8zj+j+Hw0f/MN1n79MOfmoni9NH/7LdYTTsCcnY3S3Ezzd99hHTAAc1YW0u3Gt3o1toEDsWZmEnK58KxZg72gAFN6OiGnE8+6ddgGD8aUlkaooQHP+vXYhg7FlJJCsK4O78bWkcQGf5DuLy3lhHU1KC4XxpQURDv6/P6ckPv8Vunuzs6GnTEuqgZhoF9ydzLsrVdmkfoWbU8U9impsZ/2ra+Jvd3B7nGg9m2cO9h9tSIe+3unI+hTK/FA/YLQVZKM+tB+2h6M9rNejBswhGtvuY1rLp9BgS0d6oJMGjCc857/F5XVNdx+34O8/OScmKeWV1aSm5zM786eQp6I55V580irDSAkpNUGaGoIYgxJ0mrVSZjVp5DslvRwWaDZhsVoaVdlDx2r8HOB6CFwLzBq34uEENcA1wB0795939MHZPDeGjbmZ8RWjVIUhuytweMqwTp0KL61a2OfZzYTN3w4jl/9CmFWC1ojDHCYhQ2aV69GcTeTMO4XeH7YSKi2rtU1xpRkUi6fgQwEiD99DKZu3TClpKD4/dhHjcKcm4spNRXF6yXu5JOx9OiBKS0NpbkZz5AhWPv1UxW6qxHboIHYBg5UZacT6wknEDdsKKa0NIJ1dVj69sF+8smqXFVNeRsKH0D6fNhO6E/dK6+S/cD9mDIyaF69GueiRWTecAPG5GT8paUE9u7FPnw4Ipxn5KAc7Jp2+S4e7BlH/pAUoKniez78cSH1vgZSrMmc13sKA7JOPmjbyOM7OG3JT3nekTY9yu9YYo/HktJ+fuhHSsHwU7DabNxx+x1Y4+NjzmUlJBEErKmxkcA71m3g9t/+TitT+MycOdhSM0AIbKkZWF3NGIwm9RhgtNiwJDrUc03tXKMjTIfZ8IUQ04BzpZRXh+XLgVFSyln7a3O4Nvylp47gh/wMZJTCF4rCkJJqchuaVAWbnU1g715CtbWYsrNJmjyJuhdeJOexx3Ccd+gbmNLvx7N5M/aT1M3DvbNvIFBWRq+357XaHAYQNhvZ9/8Vx5Qp+7vlUeVA+xe9P/gAf3ERtv79EWYzTV9+RcNbb5Lz2GMYrFZqnnuO6qee5oQN61X5hRdoeGsefT7+CGE24/7uOwJ79qiDphBqicOjVapR57iiLRt1ZzBr1ixGjBjBlVdeqR2bP38+ixcvpqGhgT/84Q+tbPgdwTFrwwdKgejCsXnhY+3GjuzUGGUPIA0GtmenktvQRLCqin6fr2jVLnHcOOKGq1kEtapHbSAVBcKbgdXPPUft8y/Qb+UXmFJTyb7/rxha0uyGlXrVE08SLC/HlJ1N5o03dJqyB8i88YY2B6HMG2/AmBBP3KBB2vGE08eQcPoYTU6dOZPEc87FYFW9L6y9ehF/+hhEOJNi44eLcH36KcnT1GCxir/+lebvv6fPh6r7YOPiJShNLpJ/9SsAFL8fYTbv9++so3Os8OOPPzJ58mTGjBkTo+wBLrroIi666KJO6tmR0ZEKfzXQTwjRC1XRTwcuPXCTw8Nrbvt1Wo6bMjPbPG8/WV2mByoqKJ75G3UDtKYmRlF7Nm5k7/V/Iu/ZZ4krGETyRRdhHzYMYzhznzEp1jXRMWVKpyr4ffkpg5AhLg5r70giqsSzzybx7EhkcNbdd5E+K+J7bR8xIuZv7VywgGBlpabw986aheJupufrrwFQ98YbGOLsJF94AQAhpxNDYqK+StDpdPqESxx2FTpM4Uspg0KIWcBiVEeIl6SUmw/S7LCIMxjxtJEHxhYIghCEPJ4Dmhsa3n+fQHGxZpcMlpVR/mc1WjThjDOwFRRoHgmW/Hws+flt3udY5WgNQsJsxhyl4B2TY01jeXOfRXFHInOTJk1CBiK+3I0fLsKYkqIp/OLLr8DcPZ/8Z54BoOqpp7D26auZ3ALl5RjT0jBY2i9PuI7OsUCwoYFgZSUyEECYzaoZOrn9Nm47dAolpfxIStlfStlHSvl/B29xeJzo9GLYp2aoQVE4obwOpMRgMtG4aP+Rkg1vzWu1CSX9fqqeeBKjw0H+s8/EmD50Dg0hBMaEyEZX8gUXkPI//6PJPd94nbwnI9GfqTNnkhy1VHYtWYpnQ6RUX+HUC6h6OBLCUXbnn3F9+qkme3fsQHG72/09dHSOJsGGBgKlZdpkSAYCBErLCDY0HKTlodOl1sxZu0sYXFKNzR8AKbH5AwwOb9gChOrqKL/7nph0CtEcyE9f5+gioiorJV90IYlnRVJJ9Fn0Id3uvANQ91i63XEHSeepKxXF56N5zfcEStXtoFCTm93nT6XujTfU8243JX+4jqYvv1Lb+/14Nmwg1BQJv98fB0rDodM+yGAQGZUSONTYGDNYy1Ao5rzi9aJErQ5D7mYUv1ocXEpJyOVC8fkistOJEt63kopCsK4uVq6pQQlX7ZKhEIHKqogcDBIoL0cJ1/1VAgH8paUR2e/HX1ISkX0+fEVFEdnrxVdYGJGbm/Ht3KXdP+R2492+XZOD5RVqLFDMH0jZr5v3kdClFD5GI7kNTZy1dQ+TNhZy1tY9mrJvQXq9VD3xZJvNTdnZh3Vcp+PQIjOFIPnCC7APV72jDFYrfRcvJjW8oSZMRnLnPK4NGKHGRgJlZSjNqhLxl5RQdMl0mpavUOU9eyj+zW/wrF+vXe9e9R31b79N+d33qJ5NUmppOA5F6UslkiFR+v2EXK5I4Qu3m0B5uSYH6+vx7dypyYHKSprXRVJd+4uLcX8dSXXt3b4jZjXj2bAhpk/ub7+l/u23Ndn12XLqXv2PJjs/XETti1G5at6aR/XcSB3c2pdejvl+VD/9dyr/9qgmVzz4IBUPRurklt1xJ+V/+Ysml/xxlpauBFTzXNmdkVw8hedPpey22zV518SJlN91tyb/OGkylY/8TZODVVUEqyLJEHyFhYRqaiN/n6LdhOoimWD9xcWEnE5VkBJ/SQmhRpcmB8rKUFoGe0UhUFGhKWSpKASroxS+ohCsr9cGFBQFxeWKDEBSoni8yJbCJVJGAjdbiK6CYjAgrBYtG4AwGjHEx2tu5DLUdkbZaPPnT6VrKfzQoaUq2N+MPfPGGxD7VOlp8WTR+XlgsNlImjQJax+1uIQ5O5ve7y8gaaIaPm/q1o28uXOxj1TTUyvNzer+QvhL59mwkT1XXkn1k0+1CtKTXi+VDz7EzrFn4C9W6xM4P1zEtuEn49+rFuOuf2se2wYO0pRU/by32TFiJKHwsrz+rXnsOvMsTck0zHubwinna1/qhrffofjXl2oDQMP899hzTaSuq3PBAkpviSQjcy78kIr7H9Dkxo8+pvqbT51CAAALEklEQVSpSKFx19Kl1L78sia7V67E+f4HmuzZuCFmQPEXFeHbtUuTQw31hOr2iSmJ0mfG1BRMKSmabO3XF0uvyAa//bRTiRsyRJMdU88n/vTTNTntqt+SOHGCJmfM/hNJk34Zub8jGWOUDduSl4cxJUru0UOThRBYe/fG2NIfIbD27YspNSwbDFj794+cNxqxnXiiJguTCdugQZhS1Rq5BouFuIEDNRu6wWrFNmCA5qBhsFqx9e+HMVH1zjPYbFj79MEY9tM32GxYe/XCYI/TZEv37hjCOsZgs2HJy9O836JXudHs7/iR0KVq2u7P13xfDpQ7x7lw4THlTqnTsYQaG/Fu3syeq37bdlCRECRPm0b69bMwZ2bi+WETjYsWkXbtNZhSUvBs3kzT8hWkXnkFxsREvFu34l61ipRLLsEQF4d3+w48GzfgmDoVg8WC78cf8e3YQeKECQiTCX9REf6SEuJPPx0hBP69pQSrqrQVTaCyCqXRibWfmvArWF+P9Hoxh1ehituNDIU0pSSDqsOCaCMC/efAseKH3xG02PBjzDrCgDk3Z78bt4frh9+lFH5bAU/70tkBUDo/D45moj2dQ+d4Uvhw+F46x3Lg1VGnLV/zhF+cQdPnX+gzdp3D4kCBajrHLltXLmflm6/iqq0hMS2dsdOv+FkVojclJ7erG+a+dC0bPqrS7/fZMk7cuoV+ny0j+957Y2Rd2escCo4pU8i+/6+YcnJACEw5OfrK8Bhn68rlLHn+GVw11SAlrppqljz/DFtXLj944wOwadMmrSwhwNq1axk/fvxB2xUVFTFgwABmzpxJ//79ueyyy/j0008ZM2YM/fr147vv1CI9r732GiNHjmTYsGFce+21hEIh3G43kydPZujQoRQUFPDWW2/9pHdoocspfB2d9mLfyYOu7Duft/5yO5tWqF5KoWCQt/5yO1vCCn3lf18h6I+tSx30+1j+ygsANDc6eesvt/PjGjX1tLuh7TrP+zJw4EAKCwsJhZ1C/vd//5dHH330IK1Udu3axU033cS2bdvYtm0bb7zxBl9++SWPPfYYDz74IFu3buWtt97iq6++Yv369RiNRl5//XU++eQTcnJy2LBhA5s2beLcc889pOcdDF3h6+jodAlctbVtHve4Gts8fqgYDAYGDRrE5s2beffdd+nRowfDhw9nxYoVjB07lt///vesWLGizba9evVi8ODB2j3Gjx+PEILBgwdTVFTEsmXLWLNmDSNGjGDYsGEsW7aMwsJCBg8ezNKlS7nttttYuXIlDoejzfsfLl3Khq+jo9O1ueTeSIS10WSKkRPT01Vzzj601LO2Jzliro9PTml17f449dRT+eqrr5g7dy6ffKIWuxFCkJCQgNfrJS8vr812Vmuk3KPBYNBkg8FAMBhESsmVV17JQw891Krt2rVr+eijj7jrrrsYP34899xzT6trDhd9hq+jo9MlGDv9CkwWa8wxk8XK2OlX/OR7n3rqqdx1111ceOGF5Obmqs8bO5aPP/6YRx55hHvvvfeI7jt+/HjeeecdqsJxG3V1dRQXF1NWVobdbmfGjBnccsstrN2njseRos/wdXR0ugQt3jhHw0tnwIABWK1WbrvtNu2YIRysl5KSgs/n21/TAzJw4EAeeOABJk6ciKIomM1mnn32WZxOJ7fccotWPOW55577ye8AXcwPX0dHp2txrPjhd5UCKMe0whdCVAPFR9g8Hahpx+78HNDfuetzXL3v0qVLB2dkZGA0GttONHOU2bNnj7juuutsw4YNCz3wwAP+jnpuKBQy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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -1101,7 +900,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 34, "metadata": {}, "outputs": [ { @@ -1110,33 +909,33 @@ "text": [ "Hierarchical:\n", "# __Exp____ __Act______ __Err______ __RelErr___ __ID_______\n", - "0: 1.00000 1.79166 0.79166 0.79166 p1\n", - "1: 0.50000 0.59116 0.09116 0.18232 p2\n", - "2: 0.40000 0.70465 0.30465 0.76164 p3\n", - "3: 2.00000 2.10819 0.10819 0.05410 p4\n", - "4: 0.10000 0.11231 0.01231 0.12309 p5\n", - "5: 2.00000 0.02750 -1.97250 -0.98625 scaling_x1_common\n", - "6: 3.00000 3.02900 0.02900 0.00967 offset_x2_batch-0\n", - "7: 0.20000 0.18341 -0.01659 -0.08296 x1withsigma_sigma\n", - "8: 4.00000 4.01287 0.01287 0.00322 offset_x2_batch-1\n", + "0: 1.00000 0.30545 -0.69455 -0.69455 p1\n", + "1: 0.50000 0.30115 -0.19885 -0.39771 p2\n", + "2: 0.40000 0.16319 -0.23681 -0.59202 p3\n", + "3: 2.00000 1.81038 -0.18962 -0.09481 p4\n", + "4: 0.10000 0.04623 -0.05377 -0.53775 p5\n", + "5: 2.00000 0.16235 -1.83765 -0.91882 scaling_x1_common\n", + "6: 3.00000 2.99965 -0.00035 -0.00012 offset_x2_batch_0\n", + "7: 0.20000 0.13704 -0.06296 -0.31482 x1withsigma_sigma\n", + "8: 4.00000 4.00120 0.00120 0.00030 offset_x2_batch_1\n", "\n", "Status: 1\n", - "Cost: -368.648087 (expected: -0.000000)\n", + "Cost: -447.236053 (expected: -0.000000)\n", "\n", "Standard:\n", "# __Exp____ __Act______ __Err______ __RelErr___ __ID_______\n", - "0: 1.00000 2.02746 1.02746 1.02746 p1\n", - "1: 0.50000 0.58197 0.08197 0.16394 p2\n", - "2: 0.40000 0.79902 0.39902 0.99756 p3\n", - "3: 2.00000 2.07928 0.07928 0.03964 p4\n", - "4: 0.10000 0.11157 0.01157 0.11573 p5\n", - "5: 2.00000 0.02880 -1.97120 -0.98560 scaling_x1_common\n", - "6: 3.00000 3.03039 0.03039 0.01013 offset_x2_batch-0\n", - "7: 0.20000 0.18353 -0.01647 -0.08234 x1withsigma_sigma\n", - "8: 4.00000 4.01172 0.01172 0.00293 offset_x2_batch-1\n", + "0: 1.00000 0.27496 -0.72504 -0.72504 p1\n", + "1: 0.50000 0.30148 -0.19852 -0.39704 p2\n", + "2: 0.40000 0.14082 -0.25918 -0.64794 p3\n", + "3: 2.00000 1.80128 -0.19872 -0.09936 p4\n", + "4: 0.10000 0.04838 -0.05162 -0.51620 p5\n", + "5: 2.00000 0.17859 -1.82141 -0.91070 scaling_x1_common\n", + "6: 3.00000 3.00079 0.00079 0.00026 offset_x2_batch_0\n", + "7: 0.20000 0.13613 -0.06387 -0.31935 x1withsigma_sigma\n", + "8: 4.00000 4.00615 0.00615 0.00154 offset_x2_batch_1\n", "\n", "Status: 1\n", - "Cost: -368.587396 (expected: -0.000000)\n" + "Cost: -446.910816 (expected: -0.000000)\n" ] } ], @@ -1160,15 +959,13 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 35, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -1193,15 +990,19 @@ }, { "cell_type": "code", - "execution_count": 23, - "metadata": {}, + "execution_count": 36, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Best objective standard: -368.5873959718293\n", - "Best objective hierarchical: -368.6480872702808\n" + "Best objective standard: -446.9108155527413\n", + "Best objective hierarchical: -447.2360525867234\n" ] } ], @@ -1210,13 +1011,6 @@ "print('Best objective standard:', np.min(trajectories_standard))\n", "print('Best objective hierarchical:', np.min(trajectories_hierarchical))" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -1258,4 +1052,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/examples/parpeamici/steadystate/parpeExampleSteadystateMinibatch.ipynb b/examples/parpeamici/steadystate/parpeExampleSteadystateMinibatch.ipynb index cb5e769d3..5c71f5aa5 100644 --- a/examples/parpeamici/steadystate/parpeExampleSteadystateMinibatch.ipynb +++ b/examples/parpeamici/steadystate/parpeExampleSteadystateMinibatch.ipynb @@ -15,7 +15,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -30,12 +30,15 @@ "\n", "# set paths\n", "parpe_source_root = os.path.abspath('../../../')\n", - "parpe_build_root = os.path.join(parpe_source_root, 'build') \n", + "parpe_build_root = os.path.join(parpe_source_root, 'build')\n", "\n", "model_source_dir = f'{parpe_build_root}/examples/parpeamici/steadystate/steadystate_scaled-prefix/src/steadystate_scaled/model_steadystate_scaled'\n", "example_binary_dir = f'{parpe_build_root}/examples/parpeamici/steadystate/'\n", "example_data_dir = f'{parpe_build_root}/examples/parpeamici/steadystate/steadystate_scaled-prefix/src/steadystate_scaled'\n", - "optimizationOptionsPy = f'{parpe_source_root}/misc/optimizationOptions.py'\n", + "optimization_options_py = f'{parpe_source_root}/misc/optimizationOptions.py'\n", + "\n", + "# MPI launcher and options\n", + "mpiexec = \"mpiexec -n 4 --allow-run-as-root --oversubscribe\"\n", "\n", "# load parpe module from source tree\n", "sys.path.insert(0, os.path.join(parpe_source_root, 'python'))\n", @@ -44,41 +47,60 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[ 9%] Built target parpecommon\n", - "[ 20%] Built target parpeoptimization\n", - "[ 23%] Built target parpeloadbalancer\n", - "[ 35%] Built target parpeamici\n", - "[ 36%] Built target parpe\n", - "-- Found Git: /usr/bin/git (found version \"2.20.1\") \n", - "-- Building version parPE-v0.3.1-19-g9551-dirty\n", - "[ 36%] Built target get_version\n", - "[ 42%] Built target unittests_common\n", - "[ 47%] Built target unittests_loadbalancer\n", - "[ 54%] Built target unittests_optimization\n", - "\u001b[34m\u001b[1mSetting up virtual environment...\u001b[0m\n", - "[ 54%] Built target setup_venv\n", - "[ 55%] \u001b[34m\u001b[1mCreating test data using hierarchicalOptimizationTest.py\u001b[0m\n", - "...\n", - "----------------------------------------------------------------------\n", - "Ran 3 tests in 0.000s\n", - "\n", - "OK\n", - "[ 55%] Built target prepare_test_hierarchical_optimization\n", - "[ 63%] Built target unittests_amici\n", - "[ 65%] Built target example_loadbalancer\n", - "[ 76%] Built target steadystate_scaled\n", - "[ 79%] Built target example_steadystate_multi_simulator\n", - "[ 85%] Built target example_steadystate_parallel\n", - "[ 89%] Built target example_steadystate_multi\n", - "[ 92%] Built target example_steadystate\n", - "[100%] Built target test_steadystate\n" + "-- Found Git: /usr/bin/git (found version \"2.25.1\") \r\n", + "-- Building version parPE-v0.4.3-43-gdc50b-dirty\r\n", + "[ 0%] Built target get_version\r\n", + "[ 10%] Built target parpecommon\r\n", + "\u001B[35m\u001B[1mScanning dependencies of target parpeoptimization\u001B[0m\r\n", + "[ 11%] \u001B[32mBuilding CXX object src/parpeoptimization/CMakeFiles/parpeoptimization.dir/optimizationResultWriter.cpp.o\u001B[0m\r\n", + "[ 12%] \u001B[32m\u001B[1mLinking CXX static library libparpeoptimization-dbg.a\u001B[0m\r\n", + "[ 21%] Built target parpeoptimization\r\n", + "[ 25%] Built target parpeloadbalancer\r\n", + "\u001B[35m\u001B[1mScanning dependencies of target parpeamici\u001B[0m\r\n", + "[ 26%] \u001B[32mBuilding CXX object src/parpeamici/CMakeFiles/parpeamici.dir/optimizationApplication.cpp.o\u001B[0m\r\n", + "[ 27%] \u001B[32m\u001B[1mLinking CXX static library libparpeamici-dbg.a\u001B[0m\r\n", + "[ 37%] Built target parpeamici\r\n", + "[ 39%] Built target parpe\r\n", + "[ 45%] Built target unittests_common\r\n", + "[ 50%] Built target unittests_loadbalancer\r\n", + "[ 51%] \u001B[32m\u001B[1mLinking CXX executable unittests_optimization\u001B[0m\r\n", + "[ 58%] Built target unittests_optimization\r\n", + "\u001B[34m\u001B[1mSetting up virtual environment...\u001B[0m\r\n", + "[ 58%] Built target setup_venv\r\n", + "[ 59%] \u001B[34m\u001B[1mCreating test data using hierarchicalOptimizationTest.py\u001B[0m\r\n", + "...\r\n", + "----------------------------------------------------------------------\r\n", + "Ran 3 tests in 0.001s\r\n", + "\r\n", + "OK\r\n", + "[ 59%] Built target prepare_test_hierarchical_optimization\r\n", + "[ 60%] \u001B[32m\u001B[1mLinking CXX executable unittests_amici\u001B[0m\r\n", + "[ 67%] Built target unittests_amici\r\n", + "[ 69%] Built target example_loadbalancer\r\n", + "[ 70%] \u001B[34m\u001B[1mPerforming build step for 'steadystate_scaled'\u001B[0m\r\n", + "[ 90%] Built target model_steadystate_scaled\r\n", + "[ 94%] Built target simulate_model_steadystate_scaled\r\n", + "[ 96%] Built target model_steadystate_scaled_swig_compilation\r\n", + "[100%] Built target _model_steadystate_scaled\r\n", + "[ 72%] \u001B[34m\u001B[1mNo install step for 'steadystate_scaled'\u001B[0m\r\n", + "[ 73%] \u001B[34m\u001B[1mNo test step for 'steadystate_scaled'\u001B[0m\r\n", + "[ 74%] \u001B[34m\u001B[1mCompleted 'steadystate_scaled'\u001B[0m\r\n", + "[ 81%] Built target steadystate_scaled\r\n", + "[ 82%] \u001B[32m\u001B[1mLinking CXX executable example_steadystate\u001B[0m\r\n", + "[ 84%] Built target example_steadystate\r\n", + "[ 86%] \u001B[32m\u001B[1mLinking CXX executable example_steadystate_multi\u001B[0m\r\n", + "[ 88%] Built target example_steadystate_multi\r\n", + "[ 89%] \u001B[32m\u001B[1mLinking CXX executable example_steadystate_multi_simulator\u001B[0m\r\n", + "[ 92%] Built target example_steadystate_multi_simulator\r\n", + "[ 93%] \u001B[32m\u001B[1mLinking CXX executable test_steadystate\u001B[0m\r\n", + "[100%] Built target test_steadystate\r\n" ] } ], @@ -89,7 +111,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -106,7 +128,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -143,37 +165,37 @@ } ], "source": [ - "hdf5FileMinibatch = f'{example_data_dir}/example_data_minibatch.h5'\n", + "hdf5_file_minibatch = f'{example_data_dir}/example_data_minibatch.h5'\n", "!cp {example_data_dir}/example_data.h5 {hdf5FileMinibatch}\n", "\n", "# Generic options:\n", - "# One optimizer run \n", - "!{optimizationOptionsPy} {hdf5FileMinibatch} -s numStarts 1\n", + "# One optimizer run\n", + "!{optimization_options_py} {hdf5_file_minibatch} -s numStarts 1\n", "# Hierarchical optimization not yet supported with minibatch (#118)\n", - "!{optimizationOptionsPy} {hdf5FileMinibatch} -s hierarchicalOptimization 0\n", + "!{optimization_options_py} {hdf5_file_minibatch} -s hierarchicalOptimization 0\n", "# Do not repeat on failure\n", - "!{optimizationOptionsPy} {hdf5FileMinibatch} -s retryOptimization 0\n", + "!{optimization_options_py} {hdf5_file_minibatch} -s retryOptimization 0\n", "\n", "# Mini-batch options:\n", "# Select mini-batch optimizer\n", - "!{optimizationOptionsPy} {hdf5FileMinibatch} -s optimizer 10\n", + "!{optimization_options_py} {hdf5_file_minibatch} -s optimizer 10\n", "# Set number of epochs\n", - "!{optimizationOptionsPy} {hdf5FileMinibatch} -s minibatch/maxEpochs 40\n", + "!{optimization_options_py} {hdf5_file_minibatch} -s minibatch/maxEpochs 40\n", "# Set batch-size\n", - "!{optimizationOptionsPy} {hdf5FileMinibatch} -s minibatch/batchSize 2\n", + "!{optimization_options_py} {hdf5_file_minibatch} -s minibatch/batchSize 2\n", "# Set parameter updating scheme\n", - "!{optimizationOptionsPy} {hdf5FileMinibatch} -s minibatch/parameterUpdater Vanilla\n", + "!{optimization_options_py} {hdf5_file_minibatch} -s minibatch/parameterUpdater Vanilla\n", "# Set learning rate\n", - "!{optimizationOptionsPy} {hdf5FileMinibatch} -s minibatch/startLearningRate 1e-5\n", - "!{optimizationOptionsPy} {hdf5FileMinibatch} -s minibatch/endLearningRate 1e-5\n", + "!{optimization_options_py} {hdf5_file_minibatch} -s minibatch/startLearningRate 1e-5\n", + "!{optimization_options_py} {hdf5_file_minibatch} -s minibatch/endLearningRate 1e-5\n", "\n", "# Print settings\n", - "!{optimizationOptionsPy} {hdf5FileMinibatch}" + "!{optimization_options_py} {hdf5_file_minibatch}" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -187,12 +209,12 @@ ], "source": [ "# Optional\n", - "!{parpe_source_root}/misc/selectStartingPoints.py {hdf5FileMinibatch} 9 # select starting point" + "!{parpe_source_root}/misc/selectStartingPoints.py {hdf5_file_minibatch} 9 # select starting point" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 22, "metadata": { "scrolled": true }, @@ -201,70 +223,70 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32m[2019-06-05 20:20:25] [INF] [0/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:25] [INF] [0/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:25] [INF] [0/dweindl-ThinkPad-L480] [o0e0b1] iter: 0 cost: 440754 time_iter: wall: 0.172925s cpu: 0.323503s time_optim: wall: 0.172925s cpu: 0.323503s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:25] [INF] [0/dweindl-ThinkPad-L480] [o0e1b1] iter: 1 cost: 455293 time_iter: wall: 0.176629s cpu: 0.324911s time_optim: wall: 0.349555s cpu: 0.648414s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:25] [INF] [0/dweindl-ThinkPad-L480] [o0e2b1] iter: 2 cost: 440192 time_iter: wall: 0.168691s cpu: 0.312289s time_optim: wall: 0.518246s cpu: 0.960703s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:26] [INF] [0/dweindl-ThinkPad-L480] [o0e3b1] iter: 3 cost: 430821 time_iter: wall: 0.153559s cpu: 0.292556s time_optim: wall: 0.671805s cpu: 1.25326s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:26] [INF] [0/dweindl-ThinkPad-L480] [o0e4b1] iter: 4 cost: 440113 time_iter: wall: 0.152302s cpu: 0.294428s time_optim: wall: 0.824108s cpu: 1.54769s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:26] [INF] [0/dweindl-ThinkPad-L480] [o0e5b1] iter: 5 cost: 425501 time_iter: wall: 0.149848s cpu: 0.289802s time_optim: wall: 0.973956s cpu: 1.83749s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:26] [INF] [0/dweindl-ThinkPad-L480] [o0e6b1] iter: 6 cost: 440519 time_iter: wall: 0.152843s cpu: 0.292319s time_optim: wall: 1.1268s cpu: 2.12981s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:26] [INF] [0/dweindl-ThinkPad-L480] [o0e7b1] iter: 7 cost: 440480 time_iter: wall: 0.150403s cpu: 0.291789s time_optim: wall: 1.2772s cpu: 2.4216s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:26] [INF] [0/dweindl-ThinkPad-L480] [o0e8b1] iter: 8 cost: 455010 time_iter: wall: 0.156401s cpu: 0.299565s time_optim: wall: 1.4336s cpu: 2.72116s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:27] [INF] [0/dweindl-ThinkPad-L480] [o0e9b1] iter: 9 cost: 439917 time_iter: wall: 0.197744s cpu: 0.354646s time_optim: wall: 1.63135s cpu: 3.07581s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:27] [INF] [0/dweindl-ThinkPad-L480] [o0e10b1] iter: 10 cost: 440362 time_iter: wall: 0.156261s cpu: 0.298966s time_optim: wall: 1.78761s cpu: 3.37477s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:27] [INF] [0/dweindl-ThinkPad-L480] [o0e11b1] iter: 11 cost: 430514 time_iter: wall: 0.150483s cpu: 0.290099s time_optim: wall: 1.93809s cpu: 3.66487s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:27] [INF] [0/dweindl-ThinkPad-L480] [o0e12b1] iter: 12 cost: 440284 time_iter: wall: 0.150266s cpu: 0.289492s time_optim: wall: 2.08836s cpu: 3.95436s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:27] [INF] [0/dweindl-ThinkPad-L480] [o0e13b1] iter: 13 cost: 454807 time_iter: wall: 0.151596s cpu: 0.292897s time_optim: wall: 2.23995s cpu: 4.24726s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:27] [INF] [0/dweindl-ThinkPad-L480] [o0e14b1] iter: 14 cost: 454767 time_iter: wall: 0.151873s cpu: 0.293411s time_optim: wall: 2.39183s cpu: 4.54067s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:27] [INF] [0/dweindl-ThinkPad-L480] [o0e15b1] iter: 15 cost: 439682 time_iter: wall: 0.153192s cpu: 0.294006s time_optim: wall: 2.54502s cpu: 4.83468s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:28] [INF] [0/dweindl-ThinkPad-L480] [o0e16b1] iter: 16 cost: 440127 time_iter: wall: 0.152053s cpu: 0.29262s time_optim: wall: 2.69707s cpu: 5.1273s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:28] [INF] [0/dweindl-ThinkPad-L480] [o0e17b1] iter: 17 cost: 425047 time_iter: wall: 0.154976s cpu: 0.29661s time_optim: wall: 2.85205s cpu: 5.42391s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:28] [INF] [0/dweindl-ThinkPad-L480] [o0e18b1] iter: 18 cost: 430245 time_iter: wall: 0.153479s cpu: 0.295682s time_optim: wall: 3.00553s cpu: 5.71959s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:28] [INF] [0/dweindl-ThinkPad-L480] [o0e19b1] iter: 19 cost: 440010 time_iter: wall: 0.155457s cpu: 0.300795s time_optim: wall: 3.16099s cpu: 6.02039s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:28] [INF] [0/dweindl-ThinkPad-L480] [o0e20b1] iter: 20 cost: 449289 time_iter: wall: 0.154845s cpu: 0.296874s time_optim: wall: 3.31583s cpu: 6.31726s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:28] [INF] [0/dweindl-ThinkPad-L480] [o0e21b1] iter: 21 cost: 439932 time_iter: wall: 0.153743s cpu: 0.297275s time_optim: wall: 3.46958s cpu: 6.61454s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:29] [INF] [0/dweindl-ThinkPad-L480] [o0e22b1] iter: 22 cost: 439408 time_iter: wall: 0.154717s cpu: 0.298629s time_optim: wall: 3.62429s cpu: 6.91316s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:29] [INF] [0/dweindl-ThinkPad-L480] [o0e23b1] iter: 23 cost: 439369 time_iter: wall: 0.154002s cpu: 0.297291s time_optim: wall: 3.7783s cpu: 7.21045s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:29] [INF] [0/dweindl-ThinkPad-L480] [o0e24b1] iter: 24 cost: 439330 time_iter: wall: 0.154762s cpu: 0.29882s time_optim: wall: 3.93306s cpu: 7.50928s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:29] [INF] [0/dweindl-ThinkPad-L480] [o0e25b1] iter: 25 cost: 424744 time_iter: wall: 0.161927s cpu: 0.308217s time_optim: wall: 4.09499s cpu: 7.81749s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:29] [INF] [0/dweindl-ThinkPad-L480] [o0e26b1] iter: 26 cost: 439252 time_iter: wall: 0.15284s cpu: 0.295201s time_optim: wall: 4.24783s cpu: 8.11269s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:29] [INF] [0/dweindl-ThinkPad-L480] [o0e27b1] iter: 27 cost: 439213 time_iter: wall: 0.154125s cpu: 0.296932s time_optim: wall: 4.40195s cpu: 8.40962s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:29] [INF] [0/dweindl-ThinkPad-L480] [o0e28b1] iter: 28 cost: 448970 time_iter: wall: 0.153216s cpu: 0.295486s time_optim: wall: 4.55517s cpu: 8.70511s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:30] [INF] [0/dweindl-ThinkPad-L480] [o0e29b1] iter: 29 cost: 439619 time_iter: wall: 0.15378s cpu: 0.296995s time_optim: wall: 4.70895s cpu: 9.00211s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:30] [INF] [0/dweindl-ThinkPad-L480] [o0e30b1] iter: 30 cost: 429785 time_iter: wall: 0.153884s cpu: 0.295581s time_optim: wall: 4.86283s cpu: 9.29769s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:30] [INF] [0/dweindl-ThinkPad-L480] [o0e31b1] iter: 31 cost: 448851 time_iter: wall: 0.153055s cpu: 0.294579s time_optim: wall: 5.01589s cpu: 9.59227s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:30] [INF] [0/dweindl-ThinkPad-L480] [o0e32b1] iter: 32 cost: 439017 time_iter: wall: 0.154303s cpu: 0.296339s time_optim: wall: 5.17019s cpu: 9.88861s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:30] [INF] [0/dweindl-ThinkPad-L480] [o0e33b1] iter: 33 cost: 424442 time_iter: wall: 0.168635s cpu: 0.31999s time_optim: wall: 5.33883s cpu: 10.2086s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:30] [INF] [0/dweindl-ThinkPad-L480] [o0e34b1] iter: 34 cost: 448731 time_iter: wall: 0.154427s cpu: 0.297227s time_optim: wall: 5.49325s cpu: 10.5058s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:31] [INF] [0/dweindl-ThinkPad-L480] [o0e35b1] iter: 35 cost: 448691 time_iter: wall: 0.15451s cpu: 0.298087s time_optim: wall: 5.64776s cpu: 10.8039s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:31] [INF] [0/dweindl-ThinkPad-L480] [o0e36b1] iter: 36 cost: 429554 time_iter: wall: 0.153544s cpu: 0.295189s time_optim: wall: 5.80131s cpu: 11.0991s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:31] [INF] [0/dweindl-ThinkPad-L480] [o0e37b1] iter: 37 cost: 448612 time_iter: wall: 0.154655s cpu: 0.297543s time_optim: wall: 5.95596s cpu: 11.3966s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:31] [INF] [0/dweindl-ThinkPad-L480] [o0e38b1] iter: 38 cost: 439267 time_iter: wall: 0.157019s cpu: 0.302823s time_optim: wall: 6.11298s cpu: 11.6995s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:31] [INF] [0/dweindl-ThinkPad-L480] [o0e39b1] iter: 39 cost: 453756 time_iter: wall: 0.156108s cpu: 0.30078s time_optim: wall: 6.26909s cpu: 12.0002s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:31] [INF] [0/dweindl-ThinkPad-L480] [o0] Number of epochs exceeded.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:31] [INF] [0/dweindl-ThinkPad-L480] [o0] Optimizer status 1, final llh: 4.389663e+05, time: wall: 6.427294 cpu: 12.323105.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:33] [INF] [0/dweindl-ThinkPad-L480] Walltime on master: 8.289839s, CPU time of all processes: 33.250573s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:33] [INF] [0/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001b[0m\n" + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270737766336/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270737766336/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e0b1] iter: 0 cost: 3554.69 time_iter: wall: 0.0476933s cpu: 0.0854863s time_optim: wall: 0.0476936s cpu: 0.0854863s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e1b1] iter: 1 cost: 2584.42 time_iter: wall: 0.0437777s cpu: 0.0775371s time_optim: wall: 0.0914716s cpu: 0.163023s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e2b1] iter: 2 cost: 1628.43 time_iter: wall: 0.0415349s cpu: 0.0745043s time_optim: wall: 0.133007s cpu: 0.237528s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e3b1] iter: 3 cost: 1628.3 time_iter: wall: 0.0422477s cpu: 0.0746888s time_optim: wall: 0.175255s cpu: 0.312217s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e4b1] iter: 4 cost: 2584.01 time_iter: wall: 0.0575522s cpu: 0.097932s time_optim: wall: 0.232807s cpu: 0.410149s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e5b1] iter: 5 cost: 2583.87 time_iter: wall: 0.048339s cpu: 0.0843479s time_optim: wall: 0.281147s cpu: 0.494496s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e6b1] iter: 6 cost: 2598.01 time_iter: wall: 0.0445327s cpu: 0.0791551s time_optim: wall: 0.325679s cpu: 0.573652s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e7b1] iter: 7 cost: 2576.16 time_iter: wall: 0.0442095s cpu: 0.078626s time_optim: wall: 0.369889s cpu: 0.652278s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e8b1] iter: 8 cost: 2597.73 time_iter: wall: 0.0499246s cpu: 0.0864627s time_optim: wall: 0.419814s cpu: 0.73874s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e9b1] iter: 9 cost: 2575.88 time_iter: wall: 0.0454407s cpu: 0.0816869s time_optim: wall: 0.465255s cpu: 0.820427s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e10b1] iter: 10 cost: 2583.17 time_iter: wall: 0.0545201s cpu: 0.0869733s time_optim: wall: 0.519775s cpu: 0.907401s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e11b1] iter: 11 cost: 2575.6 time_iter: wall: 0.0554565s cpu: 0.0902942s time_optim: wall: 0.575232s cpu: 0.997695s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:20] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e12b1] iter: 12 cost: 1627.08 time_iter: wall: 0.0570406s cpu: 0.090515s time_optim: wall: 0.632273s cpu: 1.08821s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e13b1] iter: 13 cost: 3552.87 time_iter: wall: 0.0568286s cpu: 0.0945186s time_optim: wall: 0.689102s cpu: 1.18273s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e14b1] iter: 14 cost: 2582.62 time_iter: wall: 0.0467445s cpu: 0.082892s time_optim: wall: 0.735847s cpu: 1.26562s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e15b1] iter: 15 cost: 2596.78 time_iter: wall: 0.06091s cpu: 0.0964501s time_optim: wall: 0.796757s cpu: 1.36207s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e16b1] iter: 16 cost: 2596.65 time_iter: wall: 0.0507164s cpu: 0.0857777s time_optim: wall: 0.847473s cpu: 1.44785s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e17b1] iter: 17 cost: 2574.77 time_iter: wall: 0.0572344s cpu: 0.0915431s time_optim: wall: 0.904708s cpu: 1.53939s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e18b1] iter: 18 cost: 2574.63 time_iter: wall: 0.0548787s cpu: 0.0869427s time_optim: wall: 0.959587s cpu: 1.62633s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e19b1] iter: 19 cost: 2581.92 time_iter: wall: 0.0569721s cpu: 0.0896724s time_optim: wall: 1.01656s cpu: 1.71601s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e20b1] iter: 20 cost: 2581.78 time_iter: wall: 0.0576468s cpu: 0.0908332s time_optim: wall: 1.07421s cpu: 1.80684s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e21b1] iter: 21 cost: 2603.39 time_iter: wall: 0.0577943s cpu: 0.0928978s time_optim: wall: 1.132s cpu: 1.89974s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e22b1] iter: 22 cost: 2603.25 time_iter: wall: 0.0454081s cpu: 0.0805325s time_optim: wall: 1.17741s cpu: 1.98027s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e23b1] iter: 23 cost: 2573.93 time_iter: wall: 0.0424495s cpu: 0.0757748s time_optim: wall: 1.21986s cpu: 2.05604s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e24b1] iter: 24 cost: 2581.22 time_iter: wall: 0.0432327s cpu: 0.0768418s time_optim: wall: 1.26309s cpu: 2.13289s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e25b1] iter: 25 cost: 2602.84 time_iter: wall: 0.0578171s cpu: 0.0913525s time_optim: wall: 1.32091s cpu: 2.22424s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e26b1] iter: 26 cost: 3551.05 time_iter: wall: 0.0428939s cpu: 0.0763334s time_optim: wall: 1.3638s cpu: 2.30057s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e27b1] iter: 27 cost: 1625.04 time_iter: wall: 0.0448466s cpu: 0.0784589s time_optim: wall: 1.40865s cpu: 2.37903s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e28b1] iter: 28 cost: 1624.91 time_iter: wall: 0.0442186s cpu: 0.0786546s time_optim: wall: 1.45287s cpu: 2.45769s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e29b1] iter: 29 cost: 2573.11 time_iter: wall: 0.0588466s cpu: 0.0917757s time_optim: wall: 1.51172s cpu: 2.54946s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e30b1] iter: 30 cost: 2594.74 time_iter: wall: 0.0570472s cpu: 0.0894142s time_optim: wall: 1.56876s cpu: 2.63888s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:21] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e31b1] iter: 31 cost: 2594.61 time_iter: wall: 0.0437171s cpu: 0.0783228s time_optim: wall: 1.61248s cpu: 2.7172s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:22] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e32b1] iter: 32 cost: 1624.37 time_iter: wall: 0.0439255s cpu: 0.0783519s time_optim: wall: 1.65641s cpu: 2.79555s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:22] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e33b1] iter: 33 cost: 2572.55 time_iter: wall: 0.0425016s cpu: 0.0756871s time_optim: wall: 1.69891s cpu: 2.87124s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:22] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e34b1] iter: 34 cost: 2594.2 time_iter: wall: 0.0439749s cpu: 0.0782568s time_optim: wall: 1.74288s cpu: 2.94949s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:22] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e35b1] iter: 35 cost: 1623.97 time_iter: wall: 0.0482329s cpu: 0.08319s time_optim: wall: 1.79112s cpu: 3.03268s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:22] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e36b1] iter: 36 cost: 2601.35 time_iter: wall: 0.0563434s cpu: 0.0899884s time_optim: wall: 1.84746s cpu: 3.12267s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:22] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e37b1] iter: 37 cost: 2593.79 time_iter: wall: 0.0568368s cpu: 0.0906086s time_optim: wall: 1.9043s cpu: 3.21328s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:22] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e38b1] iter: 38 cost: 2593.66 time_iter: wall: 0.0575143s cpu: 0.0902695s time_optim: wall: 1.96181s cpu: 3.30355s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:22] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0e39b1] iter: 39 cost: 2579.14 time_iter: wall: 0.0555223s cpu: 0.0883681s time_optim: wall: 2.01733s cpu: 3.39192s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:22] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0] Number of epochs exceeded.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:22] [INF] [0:140270251255552/dweindl-ThinkPad-L480] [o0] Optimizer status 1, final llh: 2.586261e+03, time: wall: 2.059439 cpu: 3.479924.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:24] [INF] [0:140270737766336/dweindl-ThinkPad-L480] Walltime on master: 4.300712s, CPU time of all processes: 17.190522s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:03:24] [INF] [0:140270737766336/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001B[0m\r\n" ] } ], "source": [ - "!PARPE_MAX_SIMULATIONS_PER_PACKAGE=1 PARPE_NO_DEBUG=1 mpiexec -np 4 {example_binary_dir}/example_steadystate_multi -o deleteme-minibatch/ {hdf5FileMinibatch}" + "!PARPE_MAX_SIMULATIONS_PER_PACKAGE=1 PARPE_NO_DEBUG=1 \\\n", + " {mpiexec} {example_binary_dir}/example_steadystate_multi \\\n", + " --mpi -o deleteme-minibatch/ {hdf5_file_minibatch}" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 23, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -292,215 +314,197 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32m[2019-06-05 20:20:35] [INF] [0/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:35] [INF] [0/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:35] [INF] [0/dweindl-ThinkPad-L480] [o0e0b1] iter: 0 cost: 455334 time_iter: wall: 0.196381s cpu: 0.35513s time_optim: wall: 0.196382s cpu: 0.35513s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:35] [INF] [0/dweindl-ThinkPad-L480] [o0e1b1] iter: 1 cost: 440231 time_iter: wall: 0.198754s cpu: 0.365421s time_optim: wall: 0.395136s cpu: 0.720551s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:35] [INF] [0/dweindl-ThinkPad-L480] [o0e2b1] iter: 2 cost: 430860 time_iter: wall: 0.199417s cpu: 0.370409s time_optim: wall: 0.594553s cpu: 1.09096s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:35] [INF] [0/dweindl-ThinkPad-L480] [o0e3b1] iter: 3 cost: 449968 time_iter: wall: 0.174213s cpu: 0.334633s time_optim: wall: 0.768766s cpu: 1.42559s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:36] [INF] [0/dweindl-ThinkPad-L480] [o0e4b1] iter: 4 cost: 425539 time_iter: wall: 0.166797s cpu: 0.323408s time_optim: wall: 0.935564s cpu: 1.749s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:36] [INF] [0/dweindl-ThinkPad-L480] [o0e5b1] iter: 5 cost: 425501 time_iter: wall: 0.165411s cpu: 0.320791s time_optim: wall: 1.10098s cpu: 2.06979s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:36] [INF] [0/dweindl-ThinkPad-L480] [o0e6b1] iter: 6 cost: 455091 time_iter: wall: 0.176733s cpu: 0.336698s time_optim: wall: 1.27771s cpu: 2.40649s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:36] [INF] [0/dweindl-ThinkPad-L480] [o0e7b1] iter: 7 cost: 425425 time_iter: wall: 0.17722s cpu: 0.340303s time_optim: wall: 1.45493s cpu: 2.74679s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:36] [INF] [0/dweindl-ThinkPad-L480] [o0e8b1] iter: 8 cost: 430629 time_iter: wall: 0.169291s cpu: 0.325481s time_optim: wall: 1.62422s cpu: 3.07227s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:36] [INF] [0/dweindl-ThinkPad-L480] [o0e9b1] iter: 9 cost: 439917 time_iter: wall: 0.17405s cpu: 0.334018s time_optim: wall: 1.79827s cpu: 3.40629s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:37] [INF] [0/dweindl-ThinkPad-L480] [o0e10b1] iter: 10 cost: 425312 time_iter: wall: 0.168268s cpu: 0.323495s time_optim: wall: 1.96654s cpu: 3.72979s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:37] [INF] [0/dweindl-ThinkPad-L480] [o0e11b1] iter: 11 cost: 440323 time_iter: wall: 0.166594s cpu: 0.321899s time_optim: wall: 2.13313s cpu: 4.05169s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:37] [INF] [0/dweindl-ThinkPad-L480] [o0e12b1] iter: 12 cost: 449609 time_iter: wall: 0.170164s cpu: 0.325159s time_optim: wall: 2.3033s cpu: 4.37684s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:37] [INF] [0/dweindl-ThinkPad-L480] [o0e13b1] iter: 13 cost: 425198 time_iter: wall: 0.167336s cpu: 0.32342s time_optim: wall: 2.47064s cpu: 4.70026s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:37] [INF] [0/dweindl-ThinkPad-L480] [o0e14b1] iter: 14 cost: 439722 time_iter: wall: 0.166681s cpu: 0.321463s time_optim: wall: 2.63732s cpu: 5.02173s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:37] [INF] [0/dweindl-ThinkPad-L480] [o0e15b1] iter: 15 cost: 454726 time_iter: wall: 0.166881s cpu: 0.320373s time_optim: wall: 2.8042s cpu: 5.3421s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:38] [INF] [0/dweindl-ThinkPad-L480] [o0e16b1] iter: 16 cost: 425085 time_iter: wall: 0.165457s cpu: 0.320099s time_optim: wall: 2.96966s cpu: 5.6622s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:38] [INF] [0/dweindl-ThinkPad-L480] [o0e17b1] iter: 17 cost: 430283 time_iter: wall: 0.166482s cpu: 0.321317s time_optim: wall: 3.13614s cpu: 5.98352s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:38] [INF] [0/dweindl-ThinkPad-L480] [o0e18b1] iter: 18 cost: 449369 time_iter: wall: 0.168393s cpu: 0.323074s time_optim: wall: 3.30453s cpu: 6.30659s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:38] [INF] [0/dweindl-ThinkPad-L480] [o0e19b1] iter: 19 cost: 430207 time_iter: wall: 0.166339s cpu: 0.321067s time_optim: wall: 3.47087s cpu: 6.62766s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:38] [INF] [0/dweindl-ThinkPad-L480] [o0e20b1] iter: 20 cost: 439971 time_iter: wall: 0.167003s cpu: 0.322724s time_optim: wall: 3.63788s cpu: 6.95038s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:38] [INF] [0/dweindl-ThinkPad-L480] [o0e21b1] iter: 21 cost: 424896 time_iter: wall: 0.170954s cpu: 0.329293s time_optim: wall: 3.80883s cpu: 7.27967s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:39] [INF] [0/dweindl-ThinkPad-L480] [o0e22b1] iter: 22 cost: 449210 time_iter: wall: 0.173073s cpu: 0.332729s time_optim: wall: 3.9819s cpu: 7.6124s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:39] [INF] [0/dweindl-ThinkPad-L480] [o0e23b1] iter: 23 cost: 439854 time_iter: wall: 0.182179s cpu: 0.343759s time_optim: wall: 4.16408s cpu: 7.95616s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:39] [INF] [0/dweindl-ThinkPad-L480] [o0e24b1] iter: 24 cost: 449130 time_iter: wall: 0.169491s cpu: 0.325639s time_optim: wall: 4.33357s cpu: 8.2818s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:39] [INF] [0/dweindl-ThinkPad-L480] [o0e25b1] iter: 25 cost: 424744 time_iter: wall: 0.167955s cpu: 0.325094s time_optim: wall: 4.50153s cpu: 8.60689s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:39] [INF] [0/dweindl-ThinkPad-L480] [o0e26b1] iter: 26 cost: 439252 time_iter: wall: 0.167589s cpu: 0.324507s time_optim: wall: 4.66912s cpu: 8.9314s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:39] [INF] [0/dweindl-ThinkPad-L480] [o0e27b1] iter: 27 cost: 439213 time_iter: wall: 0.167739s cpu: 0.324963s time_optim: wall: 4.83686s cpu: 9.25637s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:40] [INF] [0/dweindl-ThinkPad-L480] [o0e28b1] iter: 28 cost: 429861 time_iter: wall: 0.169343s cpu: 0.324392s time_optim: wall: 5.0062s cpu: 9.58076s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:40] [INF] [0/dweindl-ThinkPad-L480] [o0e29b1] iter: 29 cost: 439619 time_iter: wall: 0.167995s cpu: 0.325313s time_optim: wall: 5.1742s cpu: 9.90607s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:40] [INF] [0/dweindl-ThinkPad-L480] [o0e30b1] iter: 30 cost: 439095 time_iter: wall: 0.168034s cpu: 0.323717s time_optim: wall: 5.34223s cpu: 10.2298s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:40] [INF] [0/dweindl-ThinkPad-L480] [o0e31b1] iter: 31 cost: 424518 time_iter: wall: 0.165788s cpu: 0.320322s time_optim: wall: 5.50802s cpu: 10.5501s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:40] [INF] [0/dweindl-ThinkPad-L480] [o0e32b1] iter: 32 cost: 424480 time_iter: wall: 0.167921s cpu: 0.323026s time_optim: wall: 5.67594s cpu: 10.8731s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:40] [INF] [0/dweindl-ThinkPad-L480] [o0e33b1] iter: 33 cost: 429670 time_iter: wall: 0.1679s cpu: 0.323762s time_optim: wall: 5.84384s cpu: 11.1969s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:41] [INF] [0/dweindl-ThinkPad-L480] [o0e34b1] iter: 34 cost: 429631 time_iter: wall: 0.167852s cpu: 0.322977s time_optim: wall: 6.01169s cpu: 11.5199s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:41] [INF] [0/dweindl-ThinkPad-L480] [o0e35b1] iter: 35 cost: 424367 time_iter: wall: 0.166955s cpu: 0.321559s time_optim: wall: 6.17865s cpu: 11.8414s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:41] [INF] [0/dweindl-ThinkPad-L480] [o0e36b1] iter: 36 cost: 424329 time_iter: wall: 0.170246s cpu: 0.327363s time_optim: wall: 6.3489s cpu: 12.1688s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:41] [INF] [0/dweindl-ThinkPad-L480] [o0e37b1] iter: 37 cost: 439306 time_iter: wall: 0.169348s cpu: 0.327646s time_optim: wall: 6.51824s cpu: 12.4964s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:41] [INF] [0/dweindl-ThinkPad-L480] [o0e38b1] iter: 38 cost: 448572 time_iter: wall: 0.174951s cpu: 0.336327s time_optim: wall: 6.6932s cpu: 12.8328s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:41] [INF] [0/dweindl-ThinkPad-L480] [o0e39b1] iter: 39 cost: 453756 time_iter: wall: 0.172614s cpu: 0.332367s time_optim: wall: 6.86581s cpu: 13.1651s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:42] [INF] [0/dweindl-ThinkPad-L480] [o0] Number of epochs exceeded.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:42] [INF] [0/dweindl-ThinkPad-L480] [o0] Optimizer status 1, final llh: 4.389664e+05, time: wall: 7.030382 cpu: 13.486563.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:44] [INF] [0/dweindl-ThinkPad-L480] Walltime on master: 9.289903s, CPU time of all processes: 37.251895s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:44] [INF] [0/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:45] [INF] [0/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:45] [INF] [0/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:45] [INF] [0/dweindl-ThinkPad-L480] [o0e0b1] iter: 0 cost: 440270 time_iter: wall: 0.24129s cpu: 0.443253s time_optim: wall: 0.241291s cpu: 0.443253s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:45] [INF] [0/dweindl-ThinkPad-L480] [o0e1b1] iter: 1 cost: 450048 time_iter: wall: 0.15515s cpu: 0.296463s time_optim: wall: 0.396441s cpu: 0.739716s\u001b[0m\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[32m[2019-06-05 20:20:46] [INF] [0/dweindl-ThinkPad-L480] [o0e2b1] iter: 2 cost: 455253 time_iter: wall: 0.15743s cpu: 0.300118s time_optim: wall: 0.553872s cpu: 1.03983s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:46] [INF] [0/dweindl-ThinkPad-L480] [o0e3b1] iter: 3 cost: 425577 time_iter: wall: 0.156741s cpu: 0.30122s time_optim: wall: 0.710614s cpu: 1.34105s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:46] [INF] [0/dweindl-ThinkPad-L480] [o0e4b1] iter: 4 cost: 430783 time_iter: wall: 0.154697s cpu: 0.29863s time_optim: wall: 0.865312s cpu: 1.63968s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:46] [INF] [0/dweindl-ThinkPad-L480] [o0e5b1] iter: 5 cost: 425501 time_iter: wall: 0.158478s cpu: 0.303047s time_optim: wall: 1.02379s cpu: 1.94273s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:46] [INF] [0/dweindl-ThinkPad-L480] [o0e6b1] iter: 6 cost: 455091 time_iter: wall: 0.16453s cpu: 0.310415s time_optim: wall: 1.18832s cpu: 2.25315s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:46] [INF] [0/dweindl-ThinkPad-L480] [o0e7b1] iter: 7 cost: 440480 time_iter: wall: 0.161794s cpu: 0.310021s time_optim: wall: 1.35011s cpu: 2.56317s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:46] [INF] [0/dweindl-ThinkPad-L480] [o0e8b1] iter: 8 cost: 449768 time_iter: wall: 0.157188s cpu: 0.302035s time_optim: wall: 1.5073s cpu: 2.8652s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:47] [INF] [0/dweindl-ThinkPad-L480] [o0e9b1] iter: 9 cost: 439917 time_iter: wall: 0.154961s cpu: 0.299797s time_optim: wall: 1.66226s cpu: 3.165s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:47] [INF] [0/dweindl-ThinkPad-L480] [o0e10b1] iter: 10 cost: 454929 time_iter: wall: 0.155074s cpu: 0.299132s time_optim: wall: 1.81734s cpu: 3.46413s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:47] [INF] [0/dweindl-ThinkPad-L480] [o0e11b1] iter: 11 cost: 439839 time_iter: wall: 0.157233s cpu: 0.301378s time_optim: wall: 1.97457s cpu: 3.76551s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:47] [INF] [0/dweindl-ThinkPad-L480] [o0e12b1] iter: 12 cost: 425236 time_iter: wall: 0.155003s cpu: 0.298961s time_optim: wall: 2.12958s cpu: 4.06447s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:47] [INF] [0/dweindl-ThinkPad-L480] [o0e13b1] iter: 13 cost: 439761 time_iter: wall: 0.155416s cpu: 0.300315s time_optim: wall: 2.28499s cpu: 4.36479s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:47] [INF] [0/dweindl-ThinkPad-L480] [o0e14b1] iter: 14 cost: 430398 time_iter: wall: 0.155605s cpu: 0.30081s time_optim: wall: 2.4406s cpu: 4.6656s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:48] [INF] [0/dweindl-ThinkPad-L480] [o0e15b1] iter: 15 cost: 449489 time_iter: wall: 0.156111s cpu: 0.301297s time_optim: wall: 2.59671s cpu: 4.96689s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:48] [INF] [0/dweindl-ThinkPad-L480] [o0e16b1] iter: 16 cost: 425085 time_iter: wall: 0.164785s cpu: 0.310591s time_optim: wall: 2.76149s cpu: 5.27748s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:48] [INF] [0/dweindl-ThinkPad-L480] [o0e17b1] iter: 17 cost: 425047 time_iter: wall: 0.15507s cpu: 0.299424s time_optim: wall: 2.91656s cpu: 5.57691s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:48] [INF] [0/dweindl-ThinkPad-L480] [o0e18b1] iter: 18 cost: 440049 time_iter: wall: 0.157183s cpu: 0.302516s time_optim: wall: 3.07375s cpu: 5.87942s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:48] [INF] [0/dweindl-ThinkPad-L480] [o0e19b1] iter: 19 cost: 454565 time_iter: wall: 0.159056s cpu: 0.306879s time_optim: wall: 3.2328s cpu: 6.1863s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:48] [INF] [0/dweindl-ThinkPad-L480] [o0e20b1] iter: 20 cost: 439487 time_iter: wall: 0.161435s cpu: 0.312322s time_optim: wall: 3.39424s cpu: 6.49862s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:49] [INF] [0/dweindl-ThinkPad-L480] [o0e21b1] iter: 21 cost: 430130 time_iter: wall: 0.168206s cpu: 0.323899s time_optim: wall: 3.56245s cpu: 6.82252s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:49] [INF] [0/dweindl-ThinkPad-L480] [o0e22b1] iter: 22 cost: 439893 time_iter: wall: 0.163873s cpu: 0.31472s time_optim: wall: 3.72632s cpu: 7.13724s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:49] [INF] [0/dweindl-ThinkPad-L480] [o0e23b1] iter: 23 cost: 430053 time_iter: wall: 0.162477s cpu: 0.311119s time_optim: wall: 3.8888s cpu: 7.44836s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:49] [INF] [0/dweindl-ThinkPad-L480] [o0e24b1] iter: 24 cost: 454362 time_iter: wall: 0.166653s cpu: 0.320311s time_optim: wall: 4.05545s cpu: 7.76867s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:49] [INF] [0/dweindl-ThinkPad-L480] [o0e25b1] iter: 25 cost: 424744 time_iter: wall: 0.1605s cpu: 0.309721s time_optim: wall: 4.21595s cpu: 8.07839s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:49] [INF] [0/dweindl-ThinkPad-L480] [o0e26b1] iter: 26 cost: 439252 time_iter: wall: 0.161664s cpu: 0.312725s time_optim: wall: 4.37762s cpu: 8.39112s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:50] [INF] [0/dweindl-ThinkPad-L480] [o0e27b1] iter: 27 cost: 439697 time_iter: wall: 0.158621s cpu: 0.306465s time_optim: wall: 4.53624s cpu: 8.69758s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:50] [INF] [0/dweindl-ThinkPad-L480] [o0e28b1] iter: 28 cost: 454201 time_iter: wall: 0.159152s cpu: 0.306061s time_optim: wall: 4.69539s cpu: 9.00364s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:50] [INF] [0/dweindl-ThinkPad-L480] [o0e29b1] iter: 29 cost: 439135 time_iter: wall: 0.158573s cpu: 0.305959s time_optim: wall: 4.85396s cpu: 9.3096s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:50] [INF] [0/dweindl-ThinkPad-L480] [o0e30b1] iter: 30 cost: 439095 time_iter: wall: 0.166642s cpu: 0.319387s time_optim: wall: 5.02061s cpu: 9.62899s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:50] [INF] [0/dweindl-ThinkPad-L480] [o0e31b1] iter: 31 cost: 454079 time_iter: wall: 0.166365s cpu: 0.319701s time_optim: wall: 5.18697s cpu: 9.94869s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:50] [INF] [0/dweindl-ThinkPad-L480] [o0e32b1] iter: 32 cost: 448811 time_iter: wall: 0.161845s cpu: 0.309606s time_optim: wall: 5.34882s cpu: 10.2583s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:50] [INF] [0/dweindl-ThinkPad-L480] [o0e33b1] iter: 33 cost: 453999 time_iter: wall: 0.161896s cpu: 0.310591s time_optim: wall: 5.51071s cpu: 10.5689s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:51] [INF] [0/dweindl-ThinkPad-L480] [o0e34b1] iter: 34 cost: 448731 time_iter: wall: 0.164305s cpu: 0.314392s time_optim: wall: 5.67502s cpu: 10.8833s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:51] [INF] [0/dweindl-ThinkPad-L480] [o0e35b1] iter: 35 cost: 448691 time_iter: wall: 0.160344s cpu: 0.309781s time_optim: wall: 5.83537s cpu: 11.1931s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:51] [INF] [0/dweindl-ThinkPad-L480] [o0e36b1] iter: 36 cost: 439345 time_iter: wall: 0.158242s cpu: 0.304632s time_optim: wall: 5.99361s cpu: 11.4977s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:51] [INF] [0/dweindl-ThinkPad-L480] [o0e37b1] iter: 37 cost: 438822 time_iter: wall: 0.15999s cpu: 0.309365s time_optim: wall: 6.1536s cpu: 11.8071s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:51] [INF] [0/dweindl-ThinkPad-L480] [o0e38b1] iter: 38 cost: 424253 time_iter: wall: 0.16091s cpu: 0.308606s time_optim: wall: 6.31451s cpu: 12.1157s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:51] [INF] [0/dweindl-ThinkPad-L480] [o0e39b1] iter: 39 cost: 429440 time_iter: wall: 0.16211s cpu: 0.31328s time_optim: wall: 6.47662s cpu: 12.4289s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:52] [INF] [0/dweindl-ThinkPad-L480] [o0] Number of epochs exceeded.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:52] [INF] [0/dweindl-ThinkPad-L480] [o0] Optimizer status 1, final llh: 4.389663e+05, time: wall: 6.641018 cpu: 12.755870.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:53] [INF] [0/dweindl-ThinkPad-L480] Walltime on master: 8.287756s, CPU time of all processes: 33.293285s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:53] [INF] [0/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:54] [INF] [0/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:54] [INF] [0/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:55] [INF] [0/dweindl-ThinkPad-L480] [o0e0b1] iter: 0 cost: 455334 time_iter: wall: 0.200714s cpu: 0.385595s time_optim: wall: 0.200715s cpu: 0.385595s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:55] [INF] [0/dweindl-ThinkPad-L480] [o0e1b1] iter: 1 cost: 430898 time_iter: wall: 0.161287s cpu: 0.309955s time_optim: wall: 0.362002s cpu: 0.695549s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:55] [INF] [0/dweindl-ThinkPad-L480] [o0e2b1] iter: 2 cost: 455253 time_iter: wall: 0.162918s cpu: 0.314487s time_optim: wall: 0.52492s cpu: 1.01004s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:55] [INF] [0/dweindl-ThinkPad-L480] [o0e3b1] iter: 3 cost: 425577 time_iter: wall: 0.16699s cpu: 0.323542s time_optim: wall: 0.69191s cpu: 1.33358s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:55] [INF] [0/dweindl-ThinkPad-L480] [o0e4b1] iter: 4 cost: 455172 time_iter: wall: 0.166479s cpu: 0.32128s time_optim: wall: 0.858389s cpu: 1.65486s\u001b[0m\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[32m[2019-06-05 20:20:56] [INF] [0/dweindl-ThinkPad-L480] [o0e5b1] iter: 5 cost: 425501 time_iter: wall: 0.167821s cpu: 0.323537s time_optim: wall: 1.02621s cpu: 1.9784s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:56] [INF] [0/dweindl-ThinkPad-L480] [o0e6b1] iter: 6 cost: 425463 time_iter: wall: 0.169986s cpu: 0.326242s time_optim: wall: 1.1962s cpu: 2.30464s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:56] [INF] [0/dweindl-ThinkPad-L480] [o0e7b1] iter: 7 cost: 439996 time_iter: wall: 0.165399s cpu: 0.319428s time_optim: wall: 1.3616s cpu: 2.62407s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:56] [INF] [0/dweindl-ThinkPad-L480] [o0e8b1] iter: 8 cost: 439957 time_iter: wall: 0.166337s cpu: 0.320366s time_optim: wall: 1.52793s cpu: 2.94443s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:56] [INF] [0/dweindl-ThinkPad-L480] [o0e9b1] iter: 9 cost: 449728 time_iter: wall: 0.169976s cpu: 0.328398s time_optim: wall: 1.69791s cpu: 3.27283s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:56] [INF] [0/dweindl-ThinkPad-L480] [o0e10b1] iter: 10 cost: 425312 time_iter: wall: 0.164675s cpu: 0.31668s time_optim: wall: 1.86258s cpu: 3.58951s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:57] [INF] [0/dweindl-ThinkPad-L480] [o0e11b1] iter: 11 cost: 430514 time_iter: wall: 0.164302s cpu: 0.318421s time_optim: wall: 2.02689s cpu: 3.90793s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:57] [INF] [0/dweindl-ThinkPad-L480] [o0e12b1] iter: 12 cost: 425236 time_iter: wall: 0.165511s cpu: 0.319563s time_optim: wall: 2.1924s cpu: 4.2275s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:57] [INF] [0/dweindl-ThinkPad-L480] [o0e13b1] iter: 13 cost: 430437 time_iter: wall: 0.165567s cpu: 0.319675s time_optim: wall: 2.35797s cpu: 4.54717s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:57] [INF] [0/dweindl-ThinkPad-L480] [o0e14b1] iter: 14 cost: 440206 time_iter: wall: 0.161149s cpu: 0.311079s time_optim: wall: 2.51911s cpu: 4.85825s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:57] [INF] [0/dweindl-ThinkPad-L480] [o0e15b1] iter: 15 cost: 425123 time_iter: wall: 0.162444s cpu: 0.313585s time_optim: wall: 2.68156s cpu: 5.17183s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:57] [INF] [0/dweindl-ThinkPad-L480] [o0e16b1] iter: 16 cost: 439643 time_iter: wall: 0.162659s cpu: 0.31457s time_optim: wall: 2.84422s cpu: 5.4864s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:57] [INF] [0/dweindl-ThinkPad-L480] [o0e17b1] iter: 17 cost: 439604 time_iter: wall: 0.172464s cpu: 0.333731s time_optim: wall: 3.01668s cpu: 5.82013s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:58] [INF] [0/dweindl-ThinkPad-L480] [o0e18b1] iter: 18 cost: 439565 time_iter: wall: 0.171969s cpu: 0.330958s time_optim: wall: 3.18865s cpu: 6.15109s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:58] [INF] [0/dweindl-ThinkPad-L480] [o0e19b1] iter: 19 cost: 439526 time_iter: wall: 0.171673s cpu: 0.33154s time_optim: wall: 3.36033s cpu: 6.48263s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:58] [INF] [0/dweindl-ThinkPad-L480] [o0e20b1] iter: 20 cost: 454524 time_iter: wall: 0.171283s cpu: 0.331534s time_optim: wall: 3.53161s cpu: 6.81417s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:58] [INF] [0/dweindl-ThinkPad-L480] [o0e21b1] iter: 21 cost: 449249 time_iter: wall: 0.171913s cpu: 0.330892s time_optim: wall: 3.70352s cpu: 7.14506s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:58] [INF] [0/dweindl-ThinkPad-L480] [o0e22b1] iter: 22 cost: 454443 time_iter: wall: 0.169961s cpu: 0.327461s time_optim: wall: 3.87348s cpu: 7.47252s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:59] [INF] [0/dweindl-ThinkPad-L480] [o0e23b1] iter: 23 cost: 454403 time_iter: wall: 0.171599s cpu: 0.330224s time_optim: wall: 4.04508s cpu: 7.80274s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:59] [INF] [0/dweindl-ThinkPad-L480] [o0e24b1] iter: 24 cost: 424782 time_iter: wall: 0.171697s cpu: 0.32919s time_optim: wall: 4.21678s cpu: 8.13193s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:59] [INF] [0/dweindl-ThinkPad-L480] [o0e25b1] iter: 25 cost: 429976 time_iter: wall: 0.172723s cpu: 0.333096s time_optim: wall: 4.3895s cpu: 8.46503s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:59] [INF] [0/dweindl-ThinkPad-L480] [o0e26b1] iter: 26 cost: 429938 time_iter: wall: 0.174159s cpu: 0.334919s time_optim: wall: 4.56366s cpu: 8.79995s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:59] [INF] [0/dweindl-ThinkPad-L480] [o0e27b1] iter: 27 cost: 454241 time_iter: wall: 0.177408s cpu: 0.339019s time_optim: wall: 4.74107s cpu: 9.13897s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:20:59] [INF] [0/dweindl-ThinkPad-L480] [o0e28b1] iter: 28 cost: 454201 time_iter: wall: 0.179392s cpu: 0.343854s time_optim: wall: 4.92046s cpu: 9.48282s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:00] [INF] [0/dweindl-ThinkPad-L480] [o0e29b1] iter: 29 cost: 424593 time_iter: wall: 0.174435s cpu: 0.334636s time_optim: wall: 5.0949s cpu: 9.81746s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:00] [INF] [0/dweindl-ThinkPad-L480] [o0e30b1] iter: 30 cost: 448891 time_iter: wall: 0.17157s cpu: 0.330714s time_optim: wall: 5.26647s cpu: 10.1482s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:00] [INF] [0/dweindl-ThinkPad-L480] [o0e31b1] iter: 31 cost: 424518 time_iter: wall: 0.171868s cpu: 0.332107s time_optim: wall: 5.43834s cpu: 10.4803s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:00] [INF] [0/dweindl-ThinkPad-L480] [o0e32b1] iter: 32 cost: 424480 time_iter: wall: 0.192099s cpu: 0.352483s time_optim: wall: 5.63043s cpu: 10.8328s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:00] [INF] [0/dweindl-ThinkPad-L480] [o0e33b1] iter: 33 cost: 429670 time_iter: wall: 0.173501s cpu: 0.334676s time_optim: wall: 5.80394s cpu: 11.1674s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:00] [INF] [0/dweindl-ThinkPad-L480] [o0e34b1] iter: 34 cost: 439423 time_iter: wall: 0.170402s cpu: 0.329005s time_optim: wall: 5.97434s cpu: 11.4964s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:01] [INF] [0/dweindl-ThinkPad-L480] [o0e35b1] iter: 35 cost: 424367 time_iter: wall: 0.171771s cpu: 0.329146s time_optim: wall: 6.14611s cpu: 11.8256s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:01] [INF] [0/dweindl-ThinkPad-L480] [o0e36b1] iter: 36 cost: 439345 time_iter: wall: 0.17237s cpu: 0.333518s time_optim: wall: 6.31848s cpu: 12.1591s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:01] [INF] [0/dweindl-ThinkPad-L480] [o0e37b1] iter: 37 cost: 448612 time_iter: wall: 0.170004s cpu: 0.326943s time_optim: wall: 6.48848s cpu: 12.486s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:01] [INF] [0/dweindl-ThinkPad-L480] [o0e38b1] iter: 38 cost: 448572 time_iter: wall: 0.168473s cpu: 0.325602s time_optim: wall: 6.65696s cpu: 12.8117s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:01] [INF] [0/dweindl-ThinkPad-L480] [o0e39b1] iter: 39 cost: 453756 time_iter: wall: 0.172964s cpu: 0.331264s time_optim: wall: 6.82992s cpu: 13.1429s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:01] [INF] [0/dweindl-ThinkPad-L480] [o0] Number of epochs exceeded.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:01] [INF] [0/dweindl-ThinkPad-L480] [o0] Optimizer status 1, final llh: 4.389664e+05, time: wall: 7.002541 cpu: 13.481624.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:03] [INF] [0/dweindl-ThinkPad-L480] Walltime on master: 9.313669s, CPU time of all processes: 37.343861s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:03] [INF] [0/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:05] [INF] [0/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:05] [INF] [0/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:05] [INF] [0/dweindl-ThinkPad-L480] [o0e0b1] iter: 0 cost: 440270 time_iter: wall: 0.224949s cpu: 0.435528s time_optim: wall: 0.224949s cpu: 0.435528s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:05] [INF] [0/dweindl-ThinkPad-L480] [o0e1b1] iter: 1 cost: 440715 time_iter: wall: 0.159836s cpu: 0.30886s time_optim: wall: 0.384786s cpu: 0.744388s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:06] [INF] [0/dweindl-ThinkPad-L480] [o0e2b1] iter: 2 cost: 430860 time_iter: wall: 0.169409s cpu: 0.324992s time_optim: wall: 0.554194s cpu: 1.06938s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:06] [INF] [0/dweindl-ThinkPad-L480] [o0e3b1] iter: 3 cost: 455212 time_iter: wall: 0.170146s cpu: 0.328251s time_optim: wall: 0.724341s cpu: 1.39763s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:06] [INF] [0/dweindl-ThinkPad-L480] [o0e4b1] iter: 4 cost: 440597 time_iter: wall: 0.168925s cpu: 0.326425s time_optim: wall: 0.893266s cpu: 1.72406s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:06] [INF] [0/dweindl-ThinkPad-L480] [o0e5b1] iter: 5 cost: 430744 time_iter: wall: 0.171206s cpu: 0.328558s time_optim: wall: 1.06447s cpu: 2.05261s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:06] [INF] [0/dweindl-ThinkPad-L480] [o0e6b1] iter: 6 cost: 425463 time_iter: wall: 0.169673s cpu: 0.328462s time_optim: wall: 1.23415s cpu: 2.38108s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:06] [INF] [0/dweindl-ThinkPad-L480] [o0e7b1] iter: 7 cost: 449808 time_iter: wall: 0.171005s cpu: 0.328183s time_optim: wall: 1.40515s cpu: 2.70926s\u001b[0m\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[32m[2019-06-05 20:21:07] [INF] [0/dweindl-ThinkPad-L480] [o0e8b1] iter: 8 cost: 440441 time_iter: wall: 0.1703s cpu: 0.330921s time_optim: wall: 1.57545s cpu: 3.04018s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:07] [INF] [0/dweindl-ThinkPad-L480] [o0e9b1] iter: 9 cost: 430591 time_iter: wall: 0.170494s cpu: 0.328734s time_optim: wall: 1.74595s cpu: 3.36891s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:07] [INF] [0/dweindl-ThinkPad-L480] [o0e10b1] iter: 10 cost: 439878 time_iter: wall: 0.180963s cpu: 0.342055s time_optim: wall: 1.92691s cpu: 3.71097s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:07] [INF] [0/dweindl-ThinkPad-L480] [o0e11b1] iter: 11 cost: 440323 time_iter: wall: 0.167945s cpu: 0.324897s time_optim: wall: 2.09485s cpu: 4.03587s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:07] [INF] [0/dweindl-ThinkPad-L480] [o0e12b1] iter: 12 cost: 454848 time_iter: wall: 0.166169s cpu: 0.321957s time_optim: wall: 2.26102s cpu: 4.35782s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:07] [INF] [0/dweindl-ThinkPad-L480] [o0e13b1] iter: 13 cost: 430437 time_iter: wall: 0.169159s cpu: 0.324902s time_optim: wall: 2.43018s cpu: 4.68273s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:08] [INF] [0/dweindl-ThinkPad-L480] [o0e14b1] iter: 14 cost: 425160 time_iter: wall: 0.166796s cpu: 0.322057s time_optim: wall: 2.59698s cpu: 5.00478s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:08] [INF] [0/dweindl-ThinkPad-L480] [o0e15b1] iter: 15 cost: 440167 time_iter: wall: 0.16766s cpu: 0.322013s time_optim: wall: 2.76464s cpu: 5.32679s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:08] [INF] [0/dweindl-ThinkPad-L480] [o0e16b1] iter: 16 cost: 440127 time_iter: wall: 0.167055s cpu: 0.323343s time_optim: wall: 2.9317s cpu: 5.65014s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:08] [INF] [0/dweindl-ThinkPad-L480] [o0e17b1] iter: 17 cost: 454645 time_iter: wall: 0.169417s cpu: 0.324327s time_optim: wall: 3.10111s cpu: 5.97446s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:08] [INF] [0/dweindl-ThinkPad-L480] [o0e18b1] iter: 18 cost: 454605 time_iter: wall: 0.168252s cpu: 0.323184s time_optim: wall: 3.26937s cpu: 6.29765s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:08] [INF] [0/dweindl-ThinkPad-L480] [o0e19b1] iter: 19 cost: 424971 time_iter: wall: 0.167606s cpu: 0.323179s time_optim: wall: 3.43697s cpu: 6.62083s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:09] [INF] [0/dweindl-ThinkPad-L480] [o0e20b1] iter: 20 cost: 439971 time_iter: wall: 0.166198s cpu: 0.321395s time_optim: wall: 3.60317s cpu: 6.94222s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:09] [INF] [0/dweindl-ThinkPad-L480] [o0e21b1] iter: 21 cost: 439447 time_iter: wall: 0.163419s cpu: 0.315485s time_optim: wall: 3.76659s cpu: 7.25771s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:09] [INF] [0/dweindl-ThinkPad-L480] [o0e22b1] iter: 22 cost: 439893 time_iter: wall: 0.163619s cpu: 0.315878s time_optim: wall: 3.93021s cpu: 7.57358s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:09] [INF] [0/dweindl-ThinkPad-L480] [o0e23b1] iter: 23 cost: 439853 time_iter: wall: 0.162468s cpu: 0.313858s time_optim: wall: 4.09268s cpu: 7.88744s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:09] [INF] [0/dweindl-ThinkPad-L480] [o0e24b1] iter: 24 cost: 424782 time_iter: wall: 0.162565s cpu: 0.314348s time_optim: wall: 4.25524s cpu: 8.20179s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:09] [INF] [0/dweindl-ThinkPad-L480] [o0e25b1] iter: 25 cost: 439775 time_iter: wall: 0.163988s cpu: 0.316044s time_optim: wall: 4.41923s cpu: 8.51783s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:10] [INF] [0/dweindl-ThinkPad-L480] [o0e26b1] iter: 26 cost: 449050 time_iter: wall: 0.164096s cpu: 0.315297s time_optim: wall: 4.58333s cpu: 8.83313s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:10] [INF] [0/dweindl-ThinkPad-L480] [o0e27b1] iter: 27 cost: 454241 time_iter: wall: 0.170059s cpu: 0.327366s time_optim: wall: 4.75339s cpu: 9.1605s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:10] [INF] [0/dweindl-ThinkPad-L480] [o0e28b1] iter: 28 cost: 429861 time_iter: wall: 0.172375s cpu: 0.334085s time_optim: wall: 4.92576s cpu: 9.49458s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:10] [INF] [0/dweindl-ThinkPad-L480] [o0e29b1] iter: 29 cost: 454160 time_iter: wall: 0.171252s cpu: 0.330834s time_optim: wall: 5.09702s cpu: 9.82542s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:10] [INF] [0/dweindl-ThinkPad-L480] [o0e30b1] iter: 30 cost: 439095 time_iter: wall: 0.171733s cpu: 0.331082s time_optim: wall: 5.26875s cpu: 10.1565s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:10] [INF] [0/dweindl-ThinkPad-L480] [o0e31b1] iter: 31 cost: 439056 time_iter: wall: 0.172902s cpu: 0.332932s time_optim: wall: 5.44165s cpu: 10.4894s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:11] [INF] [0/dweindl-ThinkPad-L480] [o0e32b1] iter: 32 cost: 439017 time_iter: wall: 0.168304s cpu: 0.324207s time_optim: wall: 5.60996s cpu: 10.8136s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:11] [INF] [0/dweindl-ThinkPad-L480] [o0e33b1] iter: 33 cost: 438978 time_iter: wall: 0.165162s cpu: 0.319611s time_optim: wall: 5.77512s cpu: 11.1332s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:11] [INF] [0/dweindl-ThinkPad-L480] [o0e34b1] iter: 34 cost: 438939 time_iter: wall: 0.164159s cpu: 0.316554s time_optim: wall: 5.93928s cpu: 11.4498s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:11] [INF] [0/dweindl-ThinkPad-L480] [o0e35b1] iter: 35 cost: 429593 time_iter: wall: 0.163785s cpu: 0.316307s time_optim: wall: 6.10306s cpu: 11.7661s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:11] [INF] [0/dweindl-ThinkPad-L480] [o0e36b1] iter: 36 cost: 429555 time_iter: wall: 0.170512s cpu: 0.327559s time_optim: wall: 6.27358s cpu: 12.0937s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:11] [INF] [0/dweindl-ThinkPad-L480] [o0e37b1] iter: 37 cost: 453837 time_iter: wall: 0.170765s cpu: 0.328881s time_optim: wall: 6.44434s cpu: 12.4225s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:12] [INF] [0/dweindl-ThinkPad-L480] [o0e38b1] iter: 38 cost: 438783 time_iter: wall: 0.168418s cpu: 0.32471s time_optim: wall: 6.61276s cpu: 12.7473s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:12] [INF] [0/dweindl-ThinkPad-L480] [o0e39b1] iter: 39 cost: 453756 time_iter: wall: 0.169132s cpu: 0.327465s time_optim: wall: 6.78189s cpu: 13.0747s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:12] [INF] [0/dweindl-ThinkPad-L480] [o0] Number of epochs exceeded.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:12] [INF] [0/dweindl-ThinkPad-L480] [o0] Optimizer status 1, final llh: 4.389663e+05, time: wall: 6.950631 cpu: 13.420584.\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:13] [INF] [0/dweindl-ThinkPad-L480] Walltime on master: 8.302560s, CPU time of all processes: 33.364525s\u001b[0m\n", - "\u001b[32m[2019-06-05 20:21:13] [INF] [0/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001b[0m\n" + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128563488704/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128563488704/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e0b1] iter: 0 cost: 1628.7 time_iter: wall: 0.0651095s cpu: 0.101819s time_optim: wall: 0.0651098s cpu: 0.101819s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e1b1] iter: 1 cost: 1628.57 time_iter: wall: 0.0477085s cpu: 0.0842107s time_optim: wall: 0.112819s cpu: 0.18603s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e2b1] iter: 2 cost: 2598.55 time_iter: wall: 0.0467025s cpu: 0.081893s time_optim: wall: 0.159521s cpu: 0.267923s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e3b1] iter: 3 cost: 2584.15 time_iter: wall: 0.0488849s cpu: 0.0847768s time_optim: wall: 0.208406s cpu: 0.3527s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e4b1] iter: 4 cost: 2598.28 time_iter: wall: 0.0470017s cpu: 0.0824214s time_optim: wall: 0.255408s cpu: 0.435121s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e5b1] iter: 5 cost: 3553.99 time_iter: wall: 0.0471031s cpu: 0.082031s time_optim: wall: 0.302512s cpu: 0.517152s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e6b1] iter: 6 cost: 2598.01 time_iter: wall: 0.0443932s cpu: 0.0794086s time_optim: wall: 0.346905s cpu: 0.596561s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e7b1] iter: 7 cost: 2597.87 time_iter: wall: 0.0585004s cpu: 0.0935554s time_optim: wall: 0.405406s cpu: 0.690116s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e8b1] iter: 8 cost: 3553.57 time_iter: wall: 0.0474411s cpu: 0.082477s time_optim: wall: 0.452847s cpu: 0.772593s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e9b1] iter: 9 cost: 2583.31 time_iter: wall: 0.0491929s cpu: 0.0852675s time_optim: wall: 0.50204s cpu: 0.857861s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e10b1] iter: 10 cost: 3553.3 time_iter: wall: 0.0506385s cpu: 0.0866106s time_optim: wall: 0.552679s cpu: 0.944471s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e11b1] iter: 11 cost: 2583.04 time_iter: wall: 0.0505453s cpu: 0.0842736s time_optim: wall: 0.603224s cpu: 1.02874s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e12b1] iter: 12 cost: 2597.19 time_iter: wall: 0.0515001s cpu: 0.0877196s time_optim: wall: 0.654725s cpu: 1.11646s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:11] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e13b1] iter: 13 cost: 1626.95 time_iter: wall: 0.0516208s cpu: 0.088255s time_optim: wall: 0.706346s cpu: 1.20472s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e14b1] iter: 14 cost: 2575.19 time_iter: wall: 0.0522611s cpu: 0.0872468s time_optim: wall: 0.758607s cpu: 1.29197s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e15b1] iter: 15 cost: 2604.21 time_iter: wall: 0.0539821s cpu: 0.0892329s time_optim: wall: 0.812589s cpu: 1.3812s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e16b1] iter: 16 cost: 2596.65 time_iter: wall: 0.0486306s cpu: 0.0838493s time_optim: wall: 0.86122s cpu: 1.46505s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e17b1] iter: 17 cost: 3552.32 time_iter: wall: 0.0468001s cpu: 0.0833688s time_optim: wall: 0.90802s cpu: 1.54842s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e18b1] iter: 18 cost: 3552.18 time_iter: wall: 0.0461051s cpu: 0.0819807s time_optim: wall: 0.954126s cpu: 1.6304s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e19b1] iter: 19 cost: 3552.04 time_iter: wall: 0.0565551s cpu: 0.0897935s time_optim: wall: 1.01068s cpu: 1.72019s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e20b1] iter: 20 cost: 2596.11 time_iter: wall: 0.0578384s cpu: 0.0915457s time_optim: wall: 1.06852s cpu: 1.81174s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e21b1] iter: 21 cost: 2603.4 time_iter: wall: 0.0575343s cpu: 0.0936316s time_optim: wall: 1.12605s cpu: 1.90537s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e22b1] iter: 22 cost: 1625.73 time_iter: wall: 0.0576452s cpu: 0.0938341s time_optim: wall: 1.1837s cpu: 1.9992s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e23b1] iter: 23 cost: 2595.7 time_iter: wall: 0.0573879s cpu: 0.0921114s time_optim: wall: 1.24109s cpu: 2.09131s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e24b1] iter: 24 cost: 1625.46 time_iter: wall: 0.0561392s cpu: 0.0893061s time_optim: wall: 1.29723s cpu: 2.18062s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e25b1] iter: 25 cost: 2595.43 time_iter: wall: 0.0546376s cpu: 0.0916923s time_optim: wall: 1.35187s cpu: 2.27231s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e26b1] iter: 26 cost: 2602.72 time_iter: wall: 0.0581859s cpu: 0.0912279s time_optim: wall: 1.41005s cpu: 2.36354s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e27b1] iter: 27 cost: 2602.58 time_iter: wall: 0.0470694s cpu: 0.0836855s time_optim: wall: 1.45712s cpu: 2.44723s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e28b1] iter: 28 cost: 2573.25 time_iter: wall: 0.0480904s cpu: 0.0840095s time_optim: wall: 1.50521s cpu: 2.53124s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e29b1] iter: 29 cost: 2602.31 time_iter: wall: 0.0588577s cpu: 0.103163s time_optim: wall: 1.56407s cpu: 2.6344s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e30b1] iter: 30 cost: 2594.75 time_iter: wall: 0.058872s cpu: 0.0957537s time_optim: wall: 1.62294s cpu: 2.73015s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:12] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e31b1] iter: 31 cost: 2594.61 time_iter: wall: 0.057997s cpu: 0.0920542s time_optim: wall: 1.68094s cpu: 2.82221s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:13] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e32b1] iter: 32 cost: 2572.7 time_iter: wall: 0.0587806s cpu: 0.0933812s time_optim: wall: 1.73972s cpu: 2.91559s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:13] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e33b1] iter: 33 cost: 1624.24 time_iter: wall: 0.0493689s cpu: 0.0846965s time_optim: wall: 1.78909s cpu: 3.00028s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:13] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e34b1] iter: 34 cost: 1624.11 time_iter: wall: 0.0479775s cpu: 0.0844509s time_optim: wall: 1.83707s cpu: 3.08474s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:13] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e35b1] iter: 35 cost: 2594.07 time_iter: wall: 0.0559033s cpu: 0.0929584s time_optim: wall: 1.89297s cpu: 3.17769s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:13] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e36b1] iter: 36 cost: 2579.57 time_iter: wall: 0.0611445s cpu: 0.108288s time_optim: wall: 1.95411s cpu: 3.28598s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:13] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e37b1] iter: 37 cost: 2593.8 time_iter: wall: 0.0492099s cpu: 0.0865385s time_optim: wall: 2.00332s cpu: 3.37252s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:13] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e38b1] iter: 38 cost: 1623.57 time_iter: wall: 0.0489464s cpu: 0.0848573s time_optim: wall: 2.05227s cpu: 3.45738s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:13] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0e39b1] iter: 39 cost: 2600.95 time_iter: wall: 0.0451686s cpu: 0.079828s time_optim: wall: 2.09744s cpu: 3.53721s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:13] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0] Number of epochs exceeded.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:13] [INF] [0:140128139867904/dweindl-ThinkPad-L480] [o0] Optimizer status 1, final llh: 2.586273e+03, time: wall: 2.148572 cpu: 3.630505.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:15] [INF] [0:140128563488704/dweindl-ThinkPad-L480] Walltime on master: 4.318119s, CPU time of all processes: 16.971442s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:15] [INF] [0:140128563488704/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040514709440/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040514709440/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e0b1] iter: 0 cost: 1628.7 time_iter: wall: 0.0620374s cpu: 0.0965123s time_optim: wall: 0.0620377s cpu: 0.0965123s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e1b1] iter: 1 cost: 2606.12 time_iter: wall: 0.0619933s cpu: 0.0968211s time_optim: wall: 0.124031s cpu: 0.193333s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e2b1] iter: 2 cost: 1628.43 time_iter: wall: 0.062497s cpu: 0.0970936s time_optim: wall: 0.186528s cpu: 0.290427s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e3b1] iter: 3 cost: 2584.15 time_iter: wall: 0.0628173s cpu: 0.0975342s time_optim: wall: 0.249346s cpu: 0.387961s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e4b1] iter: 4 cost: 2576.57 time_iter: wall: 0.0630493s cpu: 0.102265s time_optim: wall: 0.312428s cpu: 0.490226s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e5b1] iter: 5 cost: 2598.14 time_iter: wall: 0.0627134s cpu: 0.10023s time_optim: wall: 0.375142s cpu: 0.590456s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e6b1] iter: 6 cost: 2605.44 time_iter: wall: 0.0462647s cpu: 0.0822424s time_optim: wall: 0.421407s cpu: 0.672698s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e7b1] iter: 7 cost: 2576.15 time_iter: wall: 0.0446779s cpu: 0.0798674s time_optim: wall: 0.466085s cpu: 0.752566s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e8b1] iter: 8 cost: 2605.16 time_iter: wall: 0.0459914s cpu: 0.0820788s time_optim: wall: 0.512076s cpu: 0.834645s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e9b1] iter: 9 cost: 2605.03 time_iter: wall: 0.0460034s cpu: 0.0822501s time_optim: wall: 0.55808s cpu: 0.916895s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e10b1] iter: 10 cost: 2583.17 time_iter: wall: 0.0485059s cpu: 0.086197s time_optim: wall: 0.606586s cpu: 1.00309s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:18] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e11b1] iter: 11 cost: 2583.03 time_iter: wall: 0.0455353s cpu: 0.0812845s time_optim: wall: 0.652122s cpu: 1.08438s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e12b1] iter: 12 cost: 2575.46 time_iter: wall: 0.0487622s cpu: 0.0848217s time_optim: wall: 0.700884s cpu: 1.1692s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e13b1] iter: 13 cost: 2597.05 time_iter: wall: 0.0459065s cpu: 0.0815944s time_optim: wall: 0.746791s cpu: 1.25079s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e14b1] iter: 14 cost: 2575.18 time_iter: wall: 0.0538032s cpu: 0.0896016s time_optim: wall: 0.800594s cpu: 1.34039s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e15b1] iter: 15 cost: 3552.59 time_iter: wall: 0.0570818s cpu: 0.090847s time_optim: wall: 0.857676s cpu: 1.43124s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e16b1] iter: 16 cost: 2604.07 time_iter: wall: 0.0582828s cpu: 0.0929545s time_optim: wall: 0.915959s cpu: 1.5242s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e17b1] iter: 17 cost: 2603.93 time_iter: wall: 0.0572582s cpu: 0.0936604s time_optim: wall: 0.973218s cpu: 1.61786s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e18b1] iter: 18 cost: 3552.17 time_iter: wall: 0.0604522s cpu: 0.0956316s time_optim: wall: 1.03367s cpu: 1.71349s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e19b1] iter: 19 cost: 2574.49 time_iter: wall: 0.0533441s cpu: 0.0905578s time_optim: wall: 1.08701s cpu: 1.80405s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e20b1] iter: 20 cost: 1625.99 time_iter: wall: 0.0601746s cpu: 0.0969461s time_optim: wall: 1.14719s cpu: 1.90099s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e21b1] iter: 21 cost: 2574.21 time_iter: wall: 0.0592998s cpu: 0.105119s time_optim: wall: 1.20649s cpu: 2.00611s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e22b1] iter: 22 cost: 1625.72 time_iter: wall: 0.0596036s cpu: 0.0961369s time_optim: wall: 1.26609s cpu: 2.10225s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e23b1] iter: 23 cost: 2573.94 time_iter: wall: 0.0591221s cpu: 0.0945617s time_optim: wall: 1.32522s cpu: 2.19681s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e24b1] iter: 24 cost: 2595.56 time_iter: wall: 0.0595344s cpu: 0.0985397s time_optim: wall: 1.38475s cpu: 2.29535s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e25b1] iter: 25 cost: 2581.08 time_iter: wall: 0.0579072s cpu: 0.0970798s time_optim: wall: 1.44266s cpu: 2.39243s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e26b1] iter: 26 cost: 2602.71 time_iter: wall: 0.0517033s cpu: 0.0917851s time_optim: wall: 1.49436s cpu: 2.48421s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e27b1] iter: 27 cost: 2573.38 time_iter: wall: 0.0583215s cpu: 0.102639s time_optim: wall: 1.55268s cpu: 2.58685s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:19] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e28b1] iter: 28 cost: 3550.77 time_iter: wall: 0.0573798s cpu: 0.0999289s time_optim: wall: 1.61006s cpu: 2.68678s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e29b1] iter: 29 cost: 1624.78 time_iter: wall: 0.055416s cpu: 0.0946081s time_optim: wall: 1.66548s cpu: 2.78139s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e30b1] iter: 30 cost: 2594.74 time_iter: wall: 0.0597373s cpu: 0.0974391s time_optim: wall: 1.72522s cpu: 2.87883s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e31b1] iter: 31 cost: 2602.03 time_iter: wall: 0.059422s cpu: 0.0976637s time_optim: wall: 1.78464s cpu: 2.97649s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e32b1] iter: 32 cost: 2594.47 time_iter: wall: 0.0603956s cpu: 0.096248s time_optim: wall: 1.84504s cpu: 3.07274s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e33b1] iter: 33 cost: 2579.97 time_iter: wall: 0.059686s cpu: 0.0955575s time_optim: wall: 1.90472s cpu: 3.1683s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e34b1] iter: 34 cost: 3549.94 time_iter: wall: 0.059981s cpu: 0.0954454s time_optim: wall: 1.9647s cpu: 3.26374s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e35b1] iter: 35 cost: 1623.97 time_iter: wall: 0.0601407s cpu: 0.0941339s time_optim: wall: 2.02484s cpu: 3.35788s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e36b1] iter: 36 cost: 2572.14 time_iter: wall: 0.0590763s cpu: 0.0937153s time_optim: wall: 2.08392s cpu: 3.45159s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e37b1] iter: 37 cost: 3549.52 time_iter: wall: 0.0544017s cpu: 0.0886217s time_optim: wall: 2.13832s cpu: 3.54021s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e38b1] iter: 38 cost: 2571.86 time_iter: wall: 0.0442645s cpu: 0.079001s time_optim: wall: 2.18259s cpu: 3.61922s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0e39b1] iter: 39 cost: 2593.52 time_iter: wall: 0.0511828s cpu: 0.0884544s time_optim: wall: 2.23377s cpu: 3.70767s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0] Number of epochs exceeded.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:20] [INF] [0:140040025929472/dweindl-ThinkPad-L480] [o0] Optimizer status 1, final llh: 2.586263e+03, time: wall: 2.275734 cpu: 3.796501.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:22] [INF] [0:140040514709440/dweindl-ThinkPad-L480] Walltime on master: 4.291548s, CPU time of all processes: 17.236513s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:22] [INF] [0:140040514709440/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:25] [INF] [0:139861087696832/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:25] [INF] [0:139861087696832/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:25] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e0b1] iter: 0 cost: 2598.82 time_iter: wall: 0.0622845s cpu: 0.0999832s time_optim: wall: 0.0622848s cpu: 0.0999832s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:25] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e1b1] iter: 1 cost: 2606.12 time_iter: wall: 0.0630269s cpu: 0.102431s time_optim: wall: 0.125312s cpu: 0.202415s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:25] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e2b1] iter: 2 cost: 2598.55 time_iter: wall: 0.0628939s cpu: 0.099197s time_optim: wall: 0.188206s cpu: 0.301612s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:25] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e3b1] iter: 3 cost: 2598.41 time_iter: wall: 0.0632113s cpu: 0.0997596s time_optim: wall: 0.251418s cpu: 0.401371s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:25] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e4b1] iter: 4 cost: 2598.27 time_iter: wall: 0.0630509s cpu: 0.100739s time_optim: wall: 0.314469s cpu: 0.50211s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:25] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e5b1] iter: 5 cost: 2583.86 time_iter: wall: 0.0630902s cpu: 0.0993292s time_optim: wall: 0.37756s cpu: 0.601439s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:25] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e6b1] iter: 6 cost: 2583.72 time_iter: wall: 0.0641154s cpu: 0.106232s time_optim: wall: 0.441675s cpu: 0.707671s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:25] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e7b1] iter: 7 cost: 2597.86 time_iter: wall: 0.063322s cpu: 0.104737s time_optim: wall: 0.504998s cpu: 0.812409s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:25] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e8b1] iter: 8 cost: 1627.61 time_iter: wall: 0.0602295s cpu: 0.10042s time_optim: wall: 0.565227s cpu: 0.912828s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e9b1] iter: 9 cost: 1627.48 time_iter: wall: 0.0614533s cpu: 0.100033s time_optim: wall: 0.626681s cpu: 1.01286s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e10b1] iter: 10 cost: 1627.35 time_iter: wall: 0.0613093s cpu: 0.0965668s time_optim: wall: 0.68799s cpu: 1.10943s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e11b1] iter: 11 cost: 2597.32 time_iter: wall: 0.0610382s cpu: 0.100296s time_optim: wall: 0.749029s cpu: 1.20972s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e12b1] iter: 12 cost: 3553.01 time_iter: wall: 0.0620061s cpu: 0.0983909s time_optim: wall: 0.811035s cpu: 1.30811s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e13b1] iter: 13 cost: 2597.05 time_iter: wall: 0.0660115s cpu: 0.118999s time_optim: wall: 0.877047s cpu: 1.42711s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e14b1] iter: 14 cost: 2582.61 time_iter: wall: 0.0636964s cpu: 0.111761s time_optim: wall: 0.940744s cpu: 1.53888s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e15b1] iter: 15 cost: 3552.59 time_iter: wall: 0.0719714s cpu: 0.111735s time_optim: wall: 1.01272s cpu: 1.65061s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e16b1] iter: 16 cost: 2582.34 time_iter: wall: 0.0763708s cpu: 0.11809s time_optim: wall: 1.08909s cpu: 1.7687s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e17b1] iter: 17 cost: 2574.77 time_iter: wall: 0.0676391s cpu: 0.114936s time_optim: wall: 1.15673s cpu: 1.88364s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e18b1] iter: 18 cost: 1626.27 time_iter: wall: 0.0677754s cpu: 0.120742s time_optim: wall: 1.2245s cpu: 2.00438s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e19b1] iter: 19 cost: 2596.24 time_iter: wall: 0.0628398s cpu: 0.101457s time_optim: wall: 1.28734s cpu: 2.10583s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e20b1] iter: 20 cost: 3551.9 time_iter: wall: 0.0641185s cpu: 0.111732s time_optim: wall: 1.35146s cpu: 2.21757s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e21b1] iter: 21 cost: 2574.22 time_iter: wall: 0.0664898s cpu: 0.12155s time_optim: wall: 1.41795s cpu: 2.33912s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e22b1] iter: 22 cost: 3551.62 time_iter: wall: 0.0676231s cpu: 0.121595s time_optim: wall: 1.48557s cpu: 2.46071s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:26] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e23b1] iter: 23 cost: 2573.94 time_iter: wall: 0.0675655s cpu: 0.121896s time_optim: wall: 1.55314s cpu: 2.58261s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e24b1] iter: 24 cost: 2595.56 time_iter: wall: 0.0685067s cpu: 0.122986s time_optim: wall: 1.62165s cpu: 2.70559s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e25b1] iter: 25 cost: 1625.32 time_iter: wall: 0.0680839s cpu: 0.123413s time_optim: wall: 1.68973s cpu: 2.82901s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e26b1] iter: 26 cost: 3551.06 time_iter: wall: 0.0672257s cpu: 0.122315s time_optim: wall: 1.75696s cpu: 2.95132s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e27b1] iter: 27 cost: 3550.93 time_iter: wall: 0.066949s cpu: 0.121663s time_optim: wall: 1.82391s cpu: 3.07299s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e28b1] iter: 28 cost: 2580.68 time_iter: wall: 0.0670295s cpu: 0.122009s time_optim: wall: 1.89094s cpu: 3.195s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e29b1] iter: 29 cost: 2602.31 time_iter: wall: 0.0672325s cpu: 0.122463s time_optim: wall: 1.95817s cpu: 3.31746s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e30b1] iter: 30 cost: 2594.75 time_iter: wall: 0.0673297s cpu: 0.122729s time_optim: wall: 2.0255s cpu: 3.44019s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e31b1] iter: 31 cost: 3550.37 time_iter: wall: 0.0686383s cpu: 0.125382s time_optim: wall: 2.09414s cpu: 3.56557s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e32b1] iter: 32 cost: 2601.9 time_iter: wall: 0.0725371s cpu: 0.127239s time_optim: wall: 2.16667s cpu: 3.69281s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e33b1] iter: 33 cost: 2594.34 time_iter: wall: 0.0698901s cpu: 0.127167s time_optim: wall: 2.23656s cpu: 3.81997s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e34b1] iter: 34 cost: 2579.84 time_iter: wall: 0.0696602s cpu: 0.127001s time_optim: wall: 2.30623s cpu: 3.94698s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e35b1] iter: 35 cost: 3549.81 time_iter: wall: 0.0690396s cpu: 0.125777s time_optim: wall: 2.37527s cpu: 4.07275s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e36b1] iter: 36 cost: 2572.15 time_iter: wall: 0.0686984s cpu: 0.125473s time_optim: wall: 2.44396s cpu: 4.19823s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e37b1] iter: 37 cost: 2572.01 time_iter: wall: 0.0689723s cpu: 0.126265s time_optim: wall: 2.51294s cpu: 4.32449s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:27] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e38b1] iter: 38 cost: 3549.39 time_iter: wall: 0.0690215s cpu: 0.126387s time_optim: wall: 2.58196s cpu: 4.45088s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:28] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0e39b1] iter: 39 cost: 2593.53 time_iter: wall: 0.0673973s cpu: 0.122811s time_optim: wall: 2.64936s cpu: 4.57369s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:28] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0] Number of epochs exceeded.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:28] [INF] [0:139860668487424/dweindl-ThinkPad-L480] [o0] Optimizer status 1, final llh: 2.586273e+03, time: wall: 2.705125 cpu: 4.687131.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:29] [INF] [0:139861087696832/dweindl-ThinkPad-L480] Walltime on master: 4.296504s, CPU time of all processes: 17.140153s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:29] [INF] [0:139861087696832/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:32] [INF] [0:139846431197120/dweindl-ThinkPad-L480] Running with 4 MPI processes.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:32] [INF] [0:139846431197120/dweindl-ThinkPad-L480] Reading random initial theta 0 from /optimizationOptions/randomStarts\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:32] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e0b1] iter: 0 cost: 2606.26 time_iter: wall: 0.0724632s cpu: 0.128046s time_optim: wall: 0.0724636s cpu: 0.128046s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:32] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e1b1] iter: 1 cost: 2576.99 time_iter: wall: 0.0686715s cpu: 0.119099s time_optim: wall: 0.141135s cpu: 0.247144s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:32] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e2b1] iter: 2 cost: 2584.28 time_iter: wall: 0.0659187s cpu: 0.107962s time_optim: wall: 0.207054s cpu: 0.355107s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:32] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e3b1] iter: 3 cost: 2605.84 time_iter: wall: 0.0734749s cpu: 0.122744s time_optim: wall: 0.280529s cpu: 0.477851s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:32] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e4b1] iter: 4 cost: 2584 time_iter: wall: 0.0733659s cpu: 0.129842s time_optim: wall: 0.353896s cpu: 0.607693s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:32] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e5b1] iter: 5 cost: 2576.43 time_iter: wall: 0.0822124s cpu: 0.138493s time_optim: wall: 0.436108s cpu: 0.746185s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:32] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e6b1] iter: 6 cost: 1627.88 time_iter: wall: 0.0684215s cpu: 0.117872s time_optim: wall: 0.50453s cpu: 0.864057s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:32] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e7b1] iter: 7 cost: 3553.71 time_iter: wall: 0.0669413s cpu: 0.113626s time_optim: wall: 0.571471s cpu: 0.977683s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e8b1] iter: 8 cost: 2576.02 time_iter: wall: 0.0643325s cpu: 0.112588s time_optim: wall: 0.635804s cpu: 1.09027s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e9b1] iter: 9 cost: 1627.48 time_iter: wall: 0.0634549s cpu: 0.10862s time_optim: wall: 0.699259s cpu: 1.19889s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e10b1] iter: 10 cost: 2604.89 time_iter: wall: 0.0794393s cpu: 0.122471s time_optim: wall: 0.778699s cpu: 1.32136s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e11b1] iter: 11 cost: 2604.75 time_iter: wall: 0.078345s cpu: 0.131707s time_optim: wall: 0.857044s cpu: 1.45307s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e12b1] iter: 12 cost: 3553.01 time_iter: wall: 0.0711897s cpu: 0.118781s time_optim: wall: 0.928234s cpu: 1.57185s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e13b1] iter: 13 cost: 2582.75 time_iter: wall: 0.0768808s cpu: 0.125589s time_optim: wall: 1.00512s cpu: 1.69744s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e14b1] iter: 14 cost: 2604.35 time_iter: wall: 0.0849613s cpu: 0.127864s time_optim: wall: 1.09008s cpu: 1.8253s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e15b1] iter: 15 cost: 2582.47 time_iter: wall: 0.0600042s cpu: 0.106648s time_optim: wall: 1.15008s cpu: 1.93195s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e16b1] iter: 16 cost: 2604.07 time_iter: wall: 0.0570566s cpu: 0.101367s time_optim: wall: 1.20714s cpu: 2.03332s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e17b1] iter: 17 cost: 2582.19 time_iter: wall: 0.0716678s cpu: 0.116911s time_optim: wall: 1.27881s cpu: 2.15023s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e18b1] iter: 18 cost: 2582.05 time_iter: wall: 0.0645508s cpu: 0.113642s time_optim: wall: 1.34336s cpu: 2.26387s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e19b1] iter: 19 cost: 1626.13 time_iter: wall: 0.0627529s cpu: 0.108511s time_optim: wall: 1.40611s cpu: 2.37238s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e20b1] iter: 20 cost: 2581.78 time_iter: wall: 0.064229s cpu: 0.105655s time_optim: wall: 1.47034s cpu: 2.47804s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:33] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e21b1] iter: 21 cost: 2574.21 time_iter: wall: 0.0626647s cpu: 0.104949s time_optim: wall: 1.533s cpu: 2.58298s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e22b1] iter: 22 cost: 2581.5 time_iter: wall: 0.0644101s cpu: 0.115989s time_optim: wall: 1.59742s cpu: 2.69897s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e23b1] iter: 23 cost: 2595.69 time_iter: wall: 0.0647155s cpu: 0.118407s time_optim: wall: 1.66213s cpu: 2.81738s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e24b1] iter: 24 cost: 2595.55 time_iter: wall: 0.0649485s cpu: 0.119045s time_optim: wall: 1.72708s cpu: 2.93643s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e25b1] iter: 25 cost: 2573.65 time_iter: wall: 0.066019s cpu: 0.120768s time_optim: wall: 1.7931s cpu: 3.05719s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e26b1] iter: 26 cost: 2580.94 time_iter: wall: 0.0654555s cpu: 0.114922s time_optim: wall: 1.85855s cpu: 3.17212s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e27b1] iter: 27 cost: 3550.91 time_iter: wall: 0.0661213s cpu: 0.108651s time_optim: wall: 1.92468s cpu: 3.28077s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e28b1] iter: 28 cost: 2595.01 time_iter: wall: 0.0608098s cpu: 0.101498s time_optim: wall: 1.98549s cpu: 3.38226s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e29b1] iter: 29 cost: 2580.52 time_iter: wall: 0.0558579s cpu: 0.100219s time_optim: wall: 2.04134s cpu: 3.48248s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e30b1] iter: 30 cost: 2572.96 time_iter: wall: 0.0576749s cpu: 0.0964017s time_optim: wall: 2.09902s cpu: 3.57888s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e31b1] iter: 31 cost: 2602.02 time_iter: wall: 0.0658728s cpu: 0.116765s time_optim: wall: 2.16489s cpu: 3.69565s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e32b1] iter: 32 cost: 3550.21 time_iter: wall: 0.0657637s cpu: 0.110906s time_optim: wall: 2.23066s cpu: 3.80656s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e33b1] iter: 33 cost: 1624.23 time_iter: wall: 0.0642731s cpu: 0.102772s time_optim: wall: 2.29493s cpu: 3.90933s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e34b1] iter: 34 cost: 3549.94 time_iter: wall: 0.064435s cpu: 0.105091s time_optim: wall: 2.35937s cpu: 4.01442s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e35b1] iter: 35 cost: 2594.06 time_iter: wall: 0.0647286s cpu: 0.110586s time_optim: wall: 2.42409s cpu: 4.125s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e36b1] iter: 36 cost: 3549.66 time_iter: wall: 0.0652132s cpu: 0.113212s time_optim: wall: 2.48931s cpu: 4.23822s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:34] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e37b1] iter: 37 cost: 2579.42 time_iter: wall: 0.0674677s cpu: 0.114828s time_optim: wall: 2.55678s cpu: 4.35304s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:35] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e38b1] iter: 38 cost: 1623.56 time_iter: wall: 0.0658553s cpu: 0.114328s time_optim: wall: 2.62263s cpu: 4.46737s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:35] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0e39b1] iter: 39 cost: 1623.43 time_iter: wall: 0.0654116s cpu: 0.112918s time_optim: wall: 2.68804s cpu: 4.58029s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:35] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0] Number of epochs exceeded.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:35] [INF] [0:139846005810944/dweindl-ThinkPad-L480] [o0] Optimizer status 1, final llh: 2.586267e+03, time: wall: 2.752903 cpu: 4.703666.\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:36] [INF] [0:139846431197120/dweindl-ThinkPad-L480] Walltime on master: 4.303210s, CPU time of all processes: 16.887346s\u001B[0m\r\n", + "\u001B[32m[2020-06-24 18:04:36] [INF] [0:139846431197120/dweindl-ThinkPad-L480] Sent termination signal to workers.\u001B[0m\r\n" ] } ], @@ -512,20 +516,24 @@ " !cp {hdf5FileMinibatch} {curInputFile}\n", " !{optimizationOptionsPy} {curInputFile} -s minibatch/startLearningRate learningRate\n", " !{optimizationOptionsPy} {curInputFile} -s minibatch/endLearningRate 1e-5\n", - " !PARPE_MAX_SIMULATIONS_PER_PACKAGE=1 PARPE_NO_DEBUG=1 mpiexec -np 4 {example_binary_dir}/example_steadystate_multi -o {outprefix} {hdf5FileMinibatch}" + " !PARPE_MAX_SIMULATIONS_PER_PACKAGE=1 PARPE_NO_DEBUG=1 \\\n", + " {mpiexec} {example_binary_dir}/example_steadystate_multi \\\n", + " --mpi -o {outprefix} {hdf5FileMinibatch}" ] }, { "cell_type": "code", - "execution_count": 9, - "metadata": {}, + "execution_count": 26, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "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VuU49UzVRtTUYdL9Gnb/ljKXbwbucPf7EdAhIpuA64HvqOoZ1zj7DvCSatV7JXn44Yd58pOfTG9vL295y1sW7E2oKm95y1vo7e3lKU95Co888kh+3e23305fXx99fX3cfvvty5Z75swZrrvuOvr6+rjuuusYH3ds3UQiwbOe9SwikQh/8Rd/ccnx7733XmKxGL29vXzoQx/y/fyWI5NMOtchnWb6yJGS928EUomE8yGTYXr//tWtjGGsImnvWaDguWgyvI5b7sIFchcvVvVY2VGn/a3mtZ52jTS49Pc1Zqlq1KeIBEXkUeA0jrH1gLvqA+705kdEJOIu2wIcLdj9mLtsseV1jarypje9iU9/+tOMjIwwMjLCvQsM53/zm9/Mr//Upz7Fm970JsAxum677TYeeOABHnzwQW677ba84bVYuR/60Id40YtexMjICC960YvyhldnZycf+9jHePvb337JsbPZLG9+85v55je/yeOPP86//uu/8vjjjxd9jsWc33JkkmP5z836EKcGExBwHtVUYmiVa2MYq0fh/Z9u0mchlRjMf86MjS2xZWXkpqbITU25x6xe25saLDS+m/M3XY6qGmqqmlXVq4CtwDNE5ErgXUAcuAboBP7Qj2OJyOtF5CEReWh0dNSPIn3n0KFDxGIxbrnlFnp7exkdHeXaa69FRLjlllv46le/Om+fu+++m1tuuQUR4dprr+Xs2bOcPHmSb33rW1x33XV0dnayYcMGrrvuOu69915OnjzJxMTEguXefffd3Hqr4+J366235pdfdtllXHPNNfMiLx988EF6e3vZvXs3LS0tvPKVr+Tuu++eV8eTJ0/ycz/3c1x11VVceeWVfP/731+yHqXgjagBpIaGS96/EUglBmm9+mlINNq0xqphgNNZC/X0ELr88uYdUSswbDJVfNcVGoHVbHdSiUGktZXwtm2kh8xQW4gVcfhR1bMi8j3gJarqza2lReSzgDeMcxzYVrDbVnfZceAFc5bfv8AxPgV8CmDv3r1LzrGd+uAHL7nZ/SAyEOfyP1o+CmlkZITbb7+dt7zlLbzznbNRjFu3buX48ePztj9+/Djbtm2bt91Sy7cWzPEXlvvEE0+wadMmAC6//HKeeOKJJeu60DEeeOCBedv9y7/8C9dffz3vfve7yWazTE1NMTQ0tGg9SiE75hhqoY0bm9JI0WyW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\n" }, "metadata": { "needs_background": "light" @@ -549,13 +557,6 @@ " ax.legend()\n", "plt.subplots_adjust(hspace=0.5)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -592,4 +593,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/examples/parpeamici/steadystate/steadyStateMultiConditionDataprovider.cpp b/examples/parpeamici/steadystate/steadyStateMultiConditionDataprovider.cpp index 41aaab9b6..a1cd4129f 100644 --- a/examples/parpeamici/steadystate/steadyStateMultiConditionDataprovider.cpp +++ b/examples/parpeamici/steadystate/steadyStateMultiConditionDataprovider.cpp @@ -9,38 +9,27 @@ SteadyStateMultiConditionDataProvider::SteadyStateMultiConditionDataProvider( std::unique_ptr model, std::string const& hdf5Filename, std::string const& rootPath) - : MultiConditionDataProviderHDF5(std::move(model), hdf5Filename, rootPath), - solver(this->model->getSolver()) + : MultiConditionDataProviderHDF5(std::move(model), hdf5Filename, rootPath) { - setupModelAndSolver(*this->model, *this->solver); - + solver_ = MultiConditionDataProviderHDF5::getModel()->getSolver(); + setupModelAndSolver(); } -std::unique_ptr SteadyStateMultiConditionDataProvider::getModel() const -{ - return std::unique_ptr(model->clone()); -} std::unique_ptr SteadyStateMultiConditionDataProvider::getSolver() const { - return std::unique_ptr(solver->clone()); + return std::unique_ptr(solver_->clone()); } -void SteadyStateMultiConditionDataProvider::setupModelAndSolver(amici::Model &model, amici::Solver &solver) const { - //hsize_t m = 0, n = 0; - //model.setTimepoints(amici::hdf5::getDoubleDataset2D(fileId, rootPath + "/parameters/t", m, n)); - // set model constants - +void SteadyStateMultiConditionDataProvider::setupModelAndSolver() const { // calculate sensitivities for all parameters - model.requireSensitivitiesForAllParameters(); - //model.setParameterScale(amici::AMICI_SCALING_LOG10); - - solver.setSensitivityOrder(amici::SensitivityOrder::first); - //solver.setSensitivityMethod(amici::AMICI_SENSI_FSA); - solver.setSensitivityMethod(amici::SensitivityMethod::adjoint); - solver.setMaxSteps(10000); - solver.setNewtonMaxLinearSteps(100); - solver.setNewtonMaxSteps(40); + //model.requireSensitivitiesForAllParameters(); + + solver_->setSensitivityOrder(amici::SensitivityOrder::first); + solver_->setSensitivityMethod(amici::SensitivityMethod::adjoint); + solver_->setMaxSteps(10000); + solver_->setNewtonMaxLinearSteps(100); + solver_->setNewtonMaxSteps(40); } diff --git a/examples/parpeamici/steadystate/steadyStateMultiConditionDataprovider.h b/examples/parpeamici/steadystate/steadyStateMultiConditionDataprovider.h index 14bc413fc..698e54eff 100644 --- a/examples/parpeamici/steadystate/steadyStateMultiConditionDataprovider.h +++ b/examples/parpeamici/steadystate/steadyStateMultiConditionDataprovider.h @@ -20,17 +20,17 @@ class SteadyStateMultiConditionDataProvider public: SteadyStateMultiConditionDataProvider(std::unique_ptr model, - const std::string &hdf5Filename, const std::string &rootPath = ""); + const std::string &hdf5Filename, + const std::string &rootPath = ""); - std::unique_ptr getModel() const override; std::unique_ptr getSolver() const override; ~SteadyStateMultiConditionDataProvider() override = default; private: - void setupModelAndSolver(amici::Model& model, amici::Solver& solver) const; + void setupModelAndSolver() const; - std::unique_ptr solver; + std::unique_ptr solver_; }; diff --git a/examples/parpeamici/steadystate/steadystateProblem.cpp b/examples/parpeamici/steadystate/steadystateProblem.cpp index b95eb76a7..2f455e6da 100644 --- a/examples/parpeamici/steadystate/steadystateProblem.cpp +++ b/examples/parpeamici/steadystate/steadystateProblem.cpp @@ -17,13 +17,13 @@ ExampleSteadystateProblem::ExampleSteadystateProblem(const std::string &dataFile auto lock = parpe::hdf5MutexGetLock(); file.openFile(dataFileName, H5F_ACC_RDONLY); - auto optimizationOptions = getOptimizationOptions(); + auto optimizationOptions = OptimizationProblem::getOptimizationOptions(); optimizationOptions.optimizer = parpe::optimizerName::OPTIMIZER_IPOPT; optimizationOptions.printToStdout = true; optimizationOptions.maxOptimizerIterations = 100; - setOptimizationOptions(optimizationOptions); + OptimizationProblem::setOptimizationOptions(optimizationOptions); - costFun = std::make_unique(file.getId()); + cost_fun_ = std::make_unique(file.getId()); } void ExampleSteadystateProblem::fillInitialParameters(gsl::span buffer) const @@ -74,6 +74,11 @@ void ExampleSteadystateGradientFunction::setupExpData(int conditionIdx) { readMeasurement(conditionIdx); } +std::vector ExampleSteadystateGradientFunction::getParameterIds() const +{ + return parpe::hdf5Read1dStringDataset(fileId, "/parameters/parameterNames"); +} + void ExampleSteadystateGradientFunction::readFixedParameters(int conditionIdx) const { std::vector k(model->nk()); @@ -94,7 +99,7 @@ void ExampleSteadystateGradientFunction::readMeasurement(int conditionIdx) const } ExampleSteadystateGradientFunction::ExampleSteadystateGradientFunction(hid_t fileId) - : fileId(fileId), model(getModel()), solver(model->getSolver()) + : fileId(fileId), model(amici::generic_model::getModel()), solver(model->getSolver()) { setupUserData(0); setupExpData(0); diff --git a/examples/parpeamici/steadystate/steadystateProblem.h b/examples/parpeamici/steadystate/steadystateProblem.h index c7d0bfee4..e39dc665d 100644 --- a/examples/parpeamici/steadystate/steadystateProblem.h +++ b/examples/parpeamici/steadystate/steadystateProblem.h @@ -13,7 +13,10 @@ */ class ExampleSteadystateGradientFunction : public parpe::GradientFunction { public: - ExampleSteadystateGradientFunction(hid_t fileId); + explicit ExampleSteadystateGradientFunction(hid_t fileId); + + using GradientFunction::evaluate; + parpe::FunctionEvaluationStatus evaluate( gsl::span parameters, double &fval, @@ -24,6 +27,8 @@ class ExampleSteadystateGradientFunction : public parpe::GradientFunction { void setupUserData(int conditionIdx); void setupExpData(int conditionIdx); + std::vector getParameterIds() const override; + private: void requireSensitivities(bool sensitivitiesRequired) const; void readFixedParameters(int conditionIdx) const; @@ -43,7 +48,7 @@ class ExampleSteadystateGradientFunction : public parpe::GradientFunction { class ExampleSteadystateProblem : public parpe::OptimizationProblem { public: - ExampleSteadystateProblem(std::string const& dataFileName); + explicit ExampleSteadystateProblem(std::string const& dataFileName); void fillInitialParameters(gsl::span buffer) const override; void fillParametersMin(gsl::span buffer) const override; diff --git a/examples/parpeamici/steadystate/test_steadystate.py b/examples/parpeamici/steadystate/test_steadystate.py index 61b979c63..031b972c3 100644 --- a/examples/parpeamici/steadystate/test_steadystate.py +++ b/examples/parpeamici/steadystate/test_steadystate.py @@ -4,13 +4,13 @@ Expects to be run from within the steadystate example build directory """ -import sys import contextlib -import subprocess import os import shutil +import subprocess +import h5py - +# General setup script_path = os.path.dirname(os.path.abspath(__name__)) # test executables are expected in working directory cwd = os.getcwd() @@ -21,28 +21,18 @@ cwd, 'steadystate_scaled-prefix/src/steadystate_scaled/', 'example_data-testset.h5') -MPIEXEC = ['mpiexec', '--oversubscribe', '-n', '5'] +MPIEXEC = os.environ.get('PARPE_TESTS_MPIEXEC', + "mpiexec -n 5 --oversubscribe").split(" ") optim_exe = './example_steadystate_multi' sim_exe = './example_steadystate_multi_simulator' print('Files:', HDF5_FILE, HDF5_FILE_TEST, MPIEXEC) -with contextlib.suppress(subprocess.CalledProcessError): - # Allow running as root in docker - subprocess.run('grep docker /proc/1/cgroup -qa', shell=True, check=True) - MPIEXEC.append("--allow-run-as-root") - - # If we are running in docker, we generally don't have SYS_PTRACE permissions - # and thus, cannot use vader. Also disable Infiniband. - subprocess.run('mpiexec --version | grep open-mpi', shell=True, check=True) - MPIEXEC.extend(["--oversubscribe", - "--mca", "btl_vader_single_copy_mechanism", "none", - "--mca", "btl", "^openib", - "--mca", "oob_tcp_if_include", "lo", - "--mca", "btl_tcp_if_include", "lo", - "--mca", "orte_base_help_aggregate", "0"]) +result_filename = '_rank00000.h5' def test_nompi_gradient_check(): + """Test gradient check without MPI""" + outdir = 'example_steadystate_multi-test-gradient' shutil.rmtree(outdir, ignore_errors=True) ret = subprocess.run(f'{optim_exe} -t gradient_check' @@ -53,35 +43,42 @@ def test_nompi_gradient_check(): def test_nompi_optimization(): - """Run optimization with default settings""" + """Run optimization and simulation without MPI with default settings""" + outdir = 'example_steadystate_multi-test-optimize' shutil.rmtree(outdir, ignore_errors=True) + ret = subprocess.run([optim_exe, '-o', outdir + '/', HDF5_FILE], capture_output=True, check=True, encoding="utf-8") assert '[ERR]' not in ret.stdout + check_optimization_results( + filename=os.path.join(outdir, result_filename)) # Simulate at optimum - sim_file = 'simulate1.h5' + sim_file = os.path.abspath('simulate1.h5') with contextlib.suppress(FileNotFoundError): os.remove(sim_file) - cmd = [sim_exe, outdir + '/_rank00000.h5', '/', sim_file, '/', - '--at-optimum', '--nompi'] + cmd = [sim_exe, + os.path.join(outdir, result_filename), '/inputData', + os.path.join(outdir, result_filename), '/', + sim_file, '/', + '--at-optimum', '--nompi', '--compute-inner'] ret = subprocess.run(cmd, capture_output=True, check=True, encoding="utf-8") assert os.path.isfile(sim_file) assert '[ERR]' not in ret.stdout assert '[WRN]' not in ret.stdout assert 'exception' not in ret.stdout - # test dataset exists - subprocess.run(['h5dump', '-d', '/multistarts/0/yMes/3', sim_file], - check=True) + + check_simulation_results(filename=sim_file, sim_type="at-optimum") def test_mpi_optimization(): + """Test optimization and simulation with MPI""" + # Run optimization with default settings - """Run optimization with default settings""" outdir = 'example_steadystate_multi-test-optimize' shutil.rmtree(outdir, ignore_errors=True) cmd = [*MPIEXEC, optim_exe, '--mpi', '-o', outdir + '/', HDF5_FILE] @@ -90,37 +87,78 @@ def test_mpi_optimization(): assert 'Maximum Number of Iterations Exceeded' in ret.stdout \ or 'Solved To Acceptable Level' in ret.stdout + check_optimization_results( + filename=os.path.join(outdir, result_filename)) + # Simulate along trajectory - sim_file = 'simulate2.h5' + sim_file = os.path.abspath('simulate2.h5') with contextlib.suppress(FileNotFoundError): os.remove(sim_file) - cmd = [*MPIEXEC, sim_exe, outdir + '/_rank00000.h5', '/', sim_file, '/', - '--along-trajectory', '--mpi'] + cmd = [*MPIEXEC, sim_exe, + os.path.join(outdir, result_filename), '/inputData', + os.path.join(outdir, result_filename), '/', + sim_file, '/', + '--along-trajectory', '--mpi', '--nocompute-inner'] ret = subprocess.run(cmd, capture_output=True, check=True, encoding="utf-8") + assert os.path.isfile(sim_file) assert '[ERR]' not in ret.stdout assert '[WRN]' not in ret.stdout assert 'exception' not in ret.stdout - # test dataset exists - subprocess.run(['h5dump', '-d', '/multistarts/0/iter/1/yMes/3', sim_file], - check=True) + + check_simulation_results(filename=sim_file, sim_type="along-trajectory") # Simulate on test set - sim_file = 'simulate3.h5' + sim_file = os.path.abspath('simulate3.h5') with contextlib.suppress(FileNotFoundError): os.remove(sim_file) - cmd = [*MPIEXEC, sim_exe, HDF5_FILE_TEST, '/', - outdir + '/_rank00000.h5', '/', sim_file, '/', - '--at-optimum', '--mpi'] + cmd = [*MPIEXEC, sim_exe, + HDF5_FILE_TEST, '/', + os.path.join(outdir, result_filename), '/', + sim_file, '/', + '--at-optimum', '--mpi', '--compute-inner'] ret = subprocess.run(cmd, capture_output=True, check=True, encoding="utf-8") assert os.path.isfile(sim_file) assert '[ERR]' not in ret.stdout assert '[WRN]' not in ret.stdout assert 'exception' not in ret.stdout - # test dataset exists - subprocess.run(['h5dump', '-d', '/multistarts/0/yMes/3', sim_file], - check=True) + + check_simulation_results(filename=sim_file, sim_type="at-optimum") + + +def check_optimization_results(filename: str) -> None: + """Check for presence of optimization results""" + + try: + with h5py.File(filename, "r") as f: + # TODO: extend checks + assert f["/multistarts/0/iterCostFunParameters"].size > 0 + except Exception as e: + import sys + raise type(e)(str(e) + f' occurred in {filename}') \ + .with_traceback(sys.exc_info()[2]) + + +def check_simulation_results(filename: str, sim_type: str) -> None: + """Check for presence of simulation results""" + + try: + with h5py.File(filename, "r") as f: + # TODO: extend checks + if sim_type == "at-optimum": + assert len(f["/multistarts/0/yMes"])\ + == len(f["/multistarts/0/ySim"]) + elif sim_type == "along-trajectory": + assert len(f["/multistarts/0/iter/0/yMes"])\ + == len(f["/multistarts/0/iter/0/ySim"]) + else: + raise ValueError(f"Unknown sim_type: {sim_type}") + + except Exception as e: + import sys + raise type(e)(str(e) + f' occurred in {filename}') \ + .with_traceback(sys.exc_info()[2]) diff --git a/examples/parpeloadbalancer/main.cpp b/examples/parpeloadbalancer/main.cpp index 0687ce5da..b3d220d8a 100644 --- a/examples/parpeloadbalancer/main.cpp +++ b/examples/parpeloadbalancer/main.cpp @@ -7,7 +7,7 @@ #include -#define NUM_JOBS 1000 +constexpr int NUM_JOBS = 1000; /* * Testing code for MPI load balancing. diff --git a/include/parpeamici/amiciSimulationRunner.h b/include/parpeamici/amiciSimulationRunner.h index 7c57ec342..0c4fa3bf9 100644 --- a/include/parpeamici/amiciSimulationRunner.h +++ b/include/parpeamici/amiciSimulationRunner.h @@ -65,6 +65,7 @@ class AmiciSimulationRunner double simulationTimeSeconds; std::vector gradient; std::vector modelOutput; + std::vector modelSigmas; std::vector modelStates; int status; }; @@ -129,19 +130,19 @@ class AmiciSimulationRunner const std::vector& conditionIndices); #endif - std::vector const& optimizationParameters; - amici::SensitivityOrder sensitivityOrder; - std::vector const& conditionIndices; + std::vector const& optimization_parameters_; + amici::SensitivityOrder sensitivity_order_; + std::vector const& condition_indices_; - callbackJobFinishedType callbackJobFinished = nullptr; - callbackAllFinishedType aggregate = nullptr; - int errors = 0; - std::string logPrefix; + callbackJobFinishedType callback_job_finished_ = nullptr; + callbackAllFinishedType aggregate_ = nullptr; + int errors_ = 0; + std::string log_prefix_; }; void swap(AmiciSimulationRunner::AmiciResultPackageSimple& first, - AmiciSimulationRunner::AmiciResultPackageSimple& second); + AmiciSimulationRunner::AmiciResultPackageSimple& second) noexcept; bool operator==(AmiciSimulationRunner::AmiciResultPackageSimple const& lhs, @@ -156,7 +157,7 @@ template void serialize(Archive& ar, parpe::AmiciSimulationRunner::AmiciWorkPackageSimple& u, - const unsigned int version) + const unsigned int /*version*/) { ar& u.optimizationParameters; ar& u.sensitivityOrder; @@ -168,12 +169,13 @@ template void serialize(Archive& ar, parpe::AmiciSimulationRunner::AmiciResultPackageSimple& u, - const unsigned int version) + const unsigned int /*version*/) { ar& u.llh; ar& u.simulationTimeSeconds; ar& u.gradient; ar& u.modelOutput; + ar& u.modelSigmas; ar& u.modelStates; ar& u.status; } diff --git a/include/parpeamici/hierarchicalOptimization.h b/include/parpeamici/hierarchicalOptimization.h index 52335a1da..7df863154 100644 --- a/include/parpeamici/hierarchicalOptimization.h +++ b/include/parpeamici/hierarchicalOptimization.h @@ -1,22 +1,23 @@ #ifndef HIERARCHICALOPTIMIZATION_H #define HIERARCHICALOPTIMIZATION_H -#include +#include #include +#include #include -#include #include +#include #include -#include namespace parpe { -// Currently using enum from amici enum class ParameterTransformation { none, log10 }; - -enum class ErrorModel { normal }; // TODO logNormal, laplace +enum class ErrorModel +{ + normal +}; // TODO logNormal, laplace class AnalyticalParameterProvider; class AnalyticalParameterHdf5Reader; @@ -24,16 +25,18 @@ class HierarchicalOptimizationProblemWrapper; class HierarchicalOptimizationWrapper; /** - * @brief The HierarchicalOptimizationWrapper class is a wrapper for hierarchical optimization of - * scaling parameters. + * @brief The HierarchicalOptimizationWrapper class is a wrapper for + * hierarchical optimization of scaling parameters. * - * Parameters with the given indices are hidden by the wrapper and computed analytically internally. + * Parameters with the given indices are hidden by the wrapper and computed + * analytically internally. * - * Computes the negative log likelihood for normally distributed measurement (others to be added). + * Computes the negative log likelihood for normally distributed measurement + * (others to be added). */ class HierarchicalOptimizationWrapper : public GradientFunction { -public: + public: /** * @brief For testing * @param fun @@ -41,9 +44,10 @@ class HierarchicalOptimizationWrapper : public GradientFunction * @param numObservables * @param numTimepoints */ - HierarchicalOptimizationWrapper(std::unique_ptr fun, - int numConditions = 0, - int numObservables = 0); + HierarchicalOptimizationWrapper( + AmiciSummedGradientFunction *wrapped_function, + int numConditions = 0, + int numObservables = 0); /** * @brief Get information on analytically computed parameters from HDF5 file @@ -54,15 +58,17 @@ class HierarchicalOptimizationWrapper : public GradientFunction * @param numObservables * @param errorModel */ - HierarchicalOptimizationWrapper(std::unique_ptr fun, - const H5::H5File &file, - const std::string &hdf5RootPath, - int numConditions, - int numObservables, - ErrorModel errorModel); + HierarchicalOptimizationWrapper( + AmiciSummedGradientFunction *wrapped_function, + const H5::H5File& file, + const std::string& hdf5RootPath, + int numConditions, + int numObservables, + ErrorModel errorModel); /** - * @brief Get information on analytically computed parameters from the provided objects. + * @brief Get information on analytically computed parameters from the + * provided objects. * @param fun * @param scalingReader * @param offsetReader @@ -70,13 +76,16 @@ class HierarchicalOptimizationWrapper : public GradientFunction * @param numObservables * @param errorModel */ - HierarchicalOptimizationWrapper(std::unique_ptr fun, - std::unique_ptr scalingReader, - std::unique_ptr offsetReader, - std::unique_ptr sigmaReader, - int numConditions, - int numObservables, - ErrorModel errorModel); + HierarchicalOptimizationWrapper( + AmiciSummedGradientFunction *wrapped_function, + std::unique_ptr scalingReader, + std::unique_ptr offsetReader, + std::unique_ptr sigmaReader, + int numConditions, + int numObservables, + ErrorModel errorModel); + + using GradientFunction::evaluate; /** * @brief See base class @@ -85,21 +94,19 @@ class HierarchicalOptimizationWrapper : public GradientFunction * @param gradient * @return */ - FunctionEvaluationStatus evaluate( - gsl::span parameters, - double &fval, - gsl::span gradient, - Logger *logger, - double *cpuTime) const override; - - FunctionEvaluationStatus evaluate( - gsl::span reducedParameters, - double &fval, - gsl::span gradient, - std::vector &fullParameters, - std::vector &fullGradient, - Logger *logger, - double *cpuTime) const; + FunctionEvaluationStatus evaluate(gsl::span parameters, + double& fval, + gsl::span gradient, + Logger* logger, + double* cpuTime) const override; + + FunctionEvaluationStatus evaluate(gsl::span reducedParameters, + double& fval, + gsl::span gradient, + std::vector& fullParameters, + std::vector& fullGradient, + Logger* logger, + double* cpuTime) const; /** * @brief Get parameters for initial function evaluation @@ -116,66 +123,85 @@ class HierarchicalOptimizationWrapper : public GradientFunction std::vector getDefaultSigmaParameters() const; /** - * @brief Run simulations with scaling parameters set to 1.0 and collect model outputs - * @param reducedParameters parameter vector for `fun` without scaling parameters - * @return Vector of double vectors containing AMICI ReturnData::y (nt x ny, column-major) + * @brief Run simulations with scaling parameters set to 1.0 and collect + * model outputs + * @param reducedParameters parameter vector for `fun` without scaling + * parameters + * @return Vector of double vectors containing AMICI ReturnData::y (nt x ny, + * column-major) */ - std::vector > getUnscaledModelOutputs(const gsl::span reducedParameters, Logger *logger, double *cpuTime) const; - + std::tuple>, + std::vector>> + getUnscaledModelOutputsAndSigmas( + const gsl::span reducedParameters, + Logger* logger, + double* cpuTime) const; /** * @brief Compute proportionality factors * @param modelOutputs Model outputs as provided by getModelOutputs * @return the computed scaling factors */ - std::vector computeAnalyticalScalings(std::vector> const& measurements, - std::vector> const& modelOutputsUnscaled) const; - - void applyOptimalScalings(std::vector const& proportionalityFactors, - std::vector > &modelOutputs) const; + std::vector computeAnalyticalScalings( + std::vector> const& measurements, + std::vector> const& modelOutputsUnscaled) const; + void applyOptimalScalings( + std::vector const& proportionalityFactors, + std::vector>& modelOutputs) const; /** * @brief Compute offset parameters * @param modelOutputs Model outputs as provided by getModelOutputs * @return the computed offset parameters */ - std::vector computeAnalyticalOffsets(const std::vector > &measurements, - std::vector >& modelOutputsUnscaled) const; + std::vector computeAnalyticalOffsets( + const std::vector>& measurements, + std::vector>& modelOutputsUnscaled) const; - std::vector computeAnalyticalSigmas(std::vector > const& measurements, - const std::vector > &modelOutputsScaled) const; + std::vector computeAnalyticalSigmas( + std::vector> const& measurements, + const std::vector>& modelOutputsScaled) const; - void applyOptimalOffsets(std::vector const& offsetParameters, - std::vector > &modelOutputs) const; + void applyOptimalOffsets( + std::vector const& offsetParameters, + std::vector>& modelOutputs) const; /** - * @brief Create vector with sigma matrix for each condition and timepoints from the given analytically computed sigmas + * @brief Create vector with sigma matrix for each condition and timepoints + * from the given analytically computed sigmas * @param sigmas * @return */ - void fillInAnalyticalSigmas(std::vector > &allSigmas, - const std::vector &analyticalSigmas) const; + void fillInAnalyticalSigmas( + std::vector>& allSigmas, + const std::vector& analyticalSigmas) const; /** - * @brief Evaluate `fun` using the computed optimal scaling and offset parameters. - * @param reducedParameters Parameter vector without scaling and offset parameters + * @brief Evaluate `fun` using the computed optimal scaling and offset + * parameters. + * @param reducedParameters Parameter vector without scaling and offset + * parameters * @param scalings Optimal scaling parameters * @param offsets Optimal offset parameters - * @param modelOutputsUnscaled Model outputs before applying optimal offset and scaling parameters + * @param modelOutputsUnscaled Model outputs before applying optimal offset + * and scaling parameters * @param fval out: computed function value * @param gradient out: computed function gradient * @return */ virtual FunctionEvaluationStatus evaluateWithOptimalParameters( - std::vector const& fullParameters, - std::vector const& sigmas, - std::vector> const& measurements, - std::vector> const& modelOutputsScaled, - double &fval, - const gsl::span gradient, std::vector &fullGradient, - Logger *logger, double *cpuTime) const; + std::vector const& fullParameters, + std::vector const& sigmas, + std::vector> const& measurements, + std::vector> const& modelOutputsScaled, + std::vector > &fullSigmaMatrices, + double& fval, + const gsl::span gradient, + std::vector& fullGradient, + Logger* logger, + double* cpuTime) const; /** * @brief Get number of parameters the function expects @@ -197,10 +223,14 @@ class HierarchicalOptimizationWrapper : public GradientFunction std::vector getAnalyticalParameterIndices() const; - std::unique_ptr fun; + AmiciSummedGradientFunction* getWrappedFunction() const; -private: + std::vector getParameterIds() const override; + + private: void init(); + /** Objective function of inner optimization problem */ + AmiciSummedGradientFunction *wrapped_function_; /** Reads scaling parameter information from HDF5 file */ std::unique_ptr scalingReader; @@ -209,7 +239,8 @@ class HierarchicalOptimizationWrapper : public GradientFunction std::unique_ptr sigmaReader; /** Sorted list of the indices of the scaling parameters - * (sorting makes it easier to splice scaling and remaining parameters in getFullParameters) */ + * (sorting makes it easier to splice scaling and remaining parameters in + * getFullParameters) */ std::vector proportionalityFactorIndices; std::vector offsetParameterIndices; std::vector sigmaParameterIndices; @@ -219,157 +250,34 @@ class HierarchicalOptimizationWrapper : public GradientFunction /** Total number of observables occuring in `fun` */ int numObservables; - /** Error model to use for computing analytical parameters and negative log-likelihood */ + /** Error model to use for computing analytical parameters and negative + * log-likelihood */ ErrorModel errorModel = ErrorModel::normal; }; /** - * @brief The AnalyticalParameterProvider class is an interface for providing information on - * optimization parameters to be computed analytically (proportionality factors, offsets, sigmas, ...). - */ -class AnalyticalParameterProvider { -public: - - virtual ~AnalyticalParameterProvider() {} - - /** - * @brief Get vector of condition indices for which the parameter with the given index is used. - * @param parameterIndex referring to the index in the analytical parameter list in the hdf5 file - * (*not* the optimization parameter index). - * @return Vector of condition indice - */ - virtual std::vector getConditionsForParameter(int parameterIndex) const = 0; - - /** - * @brief Get vector of observable indices for the specified condition for which the specified parameter is used. - * @param parameterIndex - * @return - */ - virtual std::vector const& getObservablesForParameter(int parameterIndex, int conditionIdx) const = 0; - - /** - * @brief Vector with indices of the of the analytically determined parameters within the - * overall optimization parameter vector - * @return - */ - virtual std::vector getOptimizationParameterIndices() const = 0; - -}; - - - -class AnalyticalParameterProviderDefault : public AnalyticalParameterProvider { -public: - AnalyticalParameterProviderDefault() = default; - - std::vector getConditionsForParameter(int parameterIndex) const override; - - std::vector const& getObservablesForParameter(int parameterIndex, int conditionIdx) const override; - - std::vector getOptimizationParameterIndices() const override; - - // TODO private - std::vector > conditionsForParameter; - std::vector optimizationParameterIndices; - // x[scalingIdx][conditionIdx] -> std::vector of observableIndicies - std::vector>> mapping; -}; - - -/** - * @brief The AnalyticalParameterHdf5Reader class reads from an HDF5 file the dependencies of experimental conditions - * and observables on parameters which are to be computed analytically. - * - */ -class AnalyticalParameterHdf5Reader : public AnalyticalParameterProvider { -public: - AnalyticalParameterHdf5Reader() = default; - - /** - * @brief AnalyticalParameterHdf5Reader - * @param file - * @param scalingParameterIndicesPath location in hdf5 file of the list of indices - * of the analytically determined parameters within the overall optimization parameters - * @param mapPath path of to the dataset with the parameter-oberservable-condition mapping - */ - AnalyticalParameterHdf5Reader(const H5::H5File &file, - std::string analyticalParameterIndicesPath, - std::string mapPath); - - AnalyticalParameterHdf5Reader(AnalyticalParameterHdf5Reader const&) = delete; - - /** - * @brief Get vector of condition indices for which the parameter with the given index is used. - * @param parameterIndex referring to the index in the analytical parameter list in the hdf5 file - * (*not* the optimization parameter index). - * @return Vector of condition indice - */ - std::vector getConditionsForParameter(int parameterIndex) const override; - - /** - * @brief Get vector of observable indices for the specified condition for which the specified parameter is used. - * @param parameterIndex - * @return - */ - std::vector const& getObservablesForParameter(int parameterIndex, int conditionIdx) const override; - - /** - * @brief Vector with indices of the of the analytically determined parameters within the - * overall optimization parameter vector - * @return - */ - std::vector getOptimizationParameterIndices() const override; - -private: - /** - * @brief Get number of analytically computed parameters - * @param dataset Read information from this dataset. - * @return - */ - int getNumAnalyticalParameters() const; - - /** - * @brief Read mapping of parameter to model outputs. - * - * Data is expected to come as matrix/table with the following columns: - * - scalingParameterIndex: 0-based index referring to entries in the - * parameter index list - * - conditionIdx: condition index - * - observableIdx: index of model output - */ - void readParameterConditionObservableMappingFromFile(); - std::vector readRawMap(H5::DataSet& dataset, hsize_t &nRows, hsize_t &nCols); - - H5::H5File file; - std::string rootPath; - std::string mapPath; - std::string analyticalParameterIndicesPath; - - // x[scalingIdx][conditionIdx] -> std::vector of observableIndicies - std::vector>> mapping; -}; - - -/** - * @brief The HierarchicalOptimizationProblemWrapper class wraps an OptimizationProblem - * and hides the analytically optimizated parameters (from starting point, parameter bounds, ...) + * @brief The HierarchicalOptimizationProblemWrapper class wraps an + * OptimizationProblem and hides the analytically optimizated parameters (from + * starting point, parameter bounds, ...) * */ -class HierarchicalOptimizationProblemWrapper : public OptimizationProblem { -public: +class HierarchicalOptimizationProblemWrapper : public OptimizationProblem +{ + public: HierarchicalOptimizationProblemWrapper() = default; - HierarchicalOptimizationProblemWrapper(std::unique_ptr problemToWrap, - const MultiConditionDataProviderHDF5 *dataProvider); - - HierarchicalOptimizationProblemWrapper(std::unique_ptr problemToWrap, - std::unique_ptr costFun, - std::unique_ptr logger); + HierarchicalOptimizationProblemWrapper( + std::unique_ptr problemToWrap, + const MultiConditionDataProviderHDF5* dataProvider); - HierarchicalOptimizationProblemWrapper(HierarchicalOptimizationProblemWrapper const& other) = delete; + HierarchicalOptimizationProblemWrapper( + std::unique_ptr problemToWrap, + std::unique_ptr costFun, + std::unique_ptr logger); - virtual ~HierarchicalOptimizationProblemWrapper() override; + HierarchicalOptimizationProblemWrapper( + HierarchicalOptimizationProblemWrapper const& other) = delete; virtual void fillInitialParameters(gsl::span buffer) const override; @@ -377,162 +285,274 @@ class HierarchicalOptimizationProblemWrapper : public OptimizationProblem { virtual void fillParametersMax(gsl::span buffer) const override; - void fillFilteredParams(std::vector const& fullParams, gsl::span buffer) const; + void fillFilteredParams(std::vector const& fullParams, + gsl::span buffer) const; - OptimizationOptions const& getOptimizationOptions() const override { return wrappedProblem->getOptimizationOptions(); } - void setOptimizationOptions(OptimizationOptions const& options) override { wrappedProblem->setOptimizationOptions(options); } + OptimizationOptions const& getOptimizationOptions() const override + { + return wrapped_problem_->getOptimizationOptions(); + } + void setOptimizationOptions(OptimizationOptions const& options) override + { + wrapped_problem_->setOptimizationOptions(options); + } - // TODO: need to ensure that this will work with the reduced number of parameters + // TODO: need to ensure that this will work with the reduced number of + // parameters virtual std::unique_ptr getReporter() const override; -private: - std::unique_ptr wrappedProblem; + private: + std::unique_ptr wrapped_problem_; }; - /** - * @brief The HierarchicalOptimizationReporter class saves optimization parameters - * of the inner optimization problem on each function evaluation which would be - * hidden from the (outer) optimizer otherwise. + * @brief The HierarchicalOptimizationReporter class saves optimization + * parameters of the inner optimization problem on each function evaluation + * which would be hidden from the (outer) optimizer otherwise. */ -class HierarchicalOptimizationReporter : public OptimizationReporter { -public: - HierarchicalOptimizationReporter(HierarchicalOptimizationWrapper *gradFun, - std::unique_ptr rw, - std::unique_ptr logger); - - FunctionEvaluationStatus evaluate( - gsl::span parameters, double &fval, - gsl::span gradient, - Logger *logger = nullptr, - double *cpuTime = nullptr) const override; +class HierarchicalOptimizationReporter : public OptimizationReporter +{ + public: + HierarchicalOptimizationReporter( + HierarchicalOptimizationWrapper* gradFun, + std::unique_ptr rw, + std::unique_ptr logger); + + using GradientFunction::evaluate; + + FunctionEvaluationStatus evaluate(gsl::span parameters, + double& fval, + gsl::span gradient, + Logger* logger = nullptr, + double* cpuTime = nullptr) const override; // bool starting(gsl::span initialParameters) const override; // TODO: always update final parameters - virtual bool iterationFinished(gsl::span parameters, - double objectiveFunctionValue, - gsl::span objectiveFunctionGradient) const override; - - // virtual bool beforeCostFunctionCall(gsl::span parameters) const override; + virtual bool iterationFinished( + gsl::span parameters, + double objectiveFunctionValue, + gsl::span objectiveFunctionGradient) const override; - virtual bool afterCostFunctionCall(gsl::span parameters, - double objectiveFunctionValue, - gsl::span objectiveFunctionGradient) const override; + virtual bool afterCostFunctionCall( + gsl::span parameters, + double objectiveFunctionValue, + gsl::span objectiveFunctionGradient) const override; - void finished(double optimalCost, gsl::span parameters, int exitStatus) const override; + void finished(double optimalCost, + gsl::span parameters, + int exitStatus) const override; std::vector const& getFinalParameters() const override; - HierarchicalOptimizationWrapper *hierarchicalWrapper = nullptr; + HierarchicalOptimizationWrapper* hierarchical_wrapper_ = nullptr; /* In addition to the vectors for the outer optimization problem, * we also keep the complete ones. */ - mutable std::vector cachedFullParameters; - mutable std::vector cachedFullGradient; + mutable std::vector cached_full_parameters_; + mutable std::vector cached_full_gradient_; // TODO should override other functions as well - // TODO: in all functions, we need to check of the provided parameters or functio nvalues match - // To cached ones, if we want to provide all together to downstreams - + // TODO: in all functions, we need to check of the provided parameters or + // functio nvalues match To cached ones, if we want to provide all together + // to downstreams }; /** - * @brief Filter a vector using a list of exclude-indices. Write filter list to buffer. + * @brief Filter a vector using a list of exclude-indices. Write filter list to + * buffer. * @param valuesToFilter Original list * @param sortedIndicesToExclude Blacklist of indices - * @param result Buffer to write the filtered list to. Must be at least of length valuesToFilter.size()-sortedIndicesToExclude.size(). + * @param result Buffer to write the filtered list to. Must be at least of + * length valuesToFilter.size()-sortedIndicesToExclude.size(). */ -void fillFilteredParams(std::vector const& valuesToFilter, - const std::vector &sortedIndicesToExclude, - gsl::span result); +void +fillFilteredParams(std::vector const& valuesToFilter, + const std::vector& sortedIndicesToExclude, + gsl::span result); -double getDefaultScalingFactor(amici::ParameterScaling scaling); +/** + * @brief Get value to use for scaling parameter during simulation prior to + * computing optimal values. + * @param scaling Expected scale of the parameter + * @return default value + */ +double +getDefaultScalingFactor(amici::ParameterScaling scaling); -double getDefaultOffsetParameter(amici::ParameterScaling scaling); +/** + * @brief Get value to use for offset parameter during simulation prior to + * computing optimal values. + * @param scaling Expected scale of the parameter + * @return default value + */ +double +getDefaultOffsetParameter(amici::ParameterScaling scaling); /** * @brief Compute the proportionality factor for the given observable. * * See Supplement 1.1 of [1]. * - * [1] Loos, Krause, Hasenauer. Hierarchical optimization for the efficient parametrization of ODE models. + * [1] Loos, Krause, Hasenauer. Hierarchical optimization for the efficient + * parametrization of ODE models. * * @param scalingIdx - * @param modelOutputsUnscaled - * @param measurements + * @param modelOutputsUnscaled Unscaled model outputs + * @param measurements Measurements * @param scalingReader - * @param numObservables + * @param numObservables Number of observables * @return */ -double computeAnalyticalScalings(int scalingIdx, - const std::vector > &modelOutputsUnscaled, - const std::vector > &measurements, - const AnalyticalParameterProvider &scalingReader, - int numObservables); - -double computeAnalyticalOffsets(int offsetIdx, - const std::vector > &modelOutputsUnscaled, - const std::vector > &measurements, - AnalyticalParameterProvider& offsetReader, - int numObservables); - -double computeAnalyticalSigmas(int sigmaIdx, - const std::vector > &modelOutputsScaled, - const std::vector > &measurements, - const AnalyticalParameterProvider &sigmaReader, - int numObservables, - double epsilonAbs = 1e-12, double epsilonRel = 0.01); - -void applyOptimalScaling(int scalingIdx, double scalingLin, - std::vector > &modelOutputs, - AnalyticalParameterProvider const& scalingReader, - int numObservables); - -void applyOptimalOffset(int offsetIdx, double offsetLin, - std::vector > &modelOutputs, - AnalyticalParameterProvider const& offsetReader, - int numObservables); +double +computeAnalyticalScalings( + int scalingIdx, + const std::vector>& modelOutputsUnscaled, + const std::vector>& measurements, + const AnalyticalParameterProvider& scalingReader, + int numObservables); + +double +computeAnalyticalOffsets( + int offsetIdx, + const std::vector>& modelOutputsUnscaled, + const std::vector>& measurements, + AnalyticalParameterProvider& offsetReader, + int numObservables); + +double +computeAnalyticalSigmas( + int sigmaIdx, + const std::vector>& modelOutputsScaled, + const std::vector>& measurements, + const AnalyticalParameterProvider& sigmaReader, + int numObservables, + double epsilonAbs = 1e-12, + double epsilonRel = 0.01); + +void +applyOptimalScaling(int scalingIdx, + double scalingLin, + std::vector>& modelOutputs, + AnalyticalParameterProvider const& scalingReader, + int numObservables); + +void +applyOptimalOffset(int offsetIdx, + double offsetLin, + std::vector>& modelOutputs, + AnalyticalParameterProvider const& offsetReader, + int numObservables); /** - * @brief Assemble full parameter vector of wrapped problem from scaling parameters and numerically optimized parameters + * @brief Assemble full parameter vector of wrapped problem from scaling + * parameters and numerically optimized parameters * @param reducedParameters * @param scalingFactors * @return Full parameter vector for `fun` */ -std::vector spliceParameters(const gsl::span reducedParameters, - const std::vector &proportionalityFactorIndices, - const std::vector &offsetParameterIndices, - const std::vector &sigmaParameterIndices, - const std::vector &scalingFactors, - const std::vector &offsetParameters, - const std::vector &sigmaParameters); +std::vector +spliceParameters(const gsl::span reducedParameters, + const std::vector& proportionalityFactorIndices, + const std::vector& offsetParameterIndices, + const std::vector& sigmaParameterIndices, + const std::vector& scalingFactors, + const std::vector& offsetParameters, + const std::vector& sigmaParameters); /** - * @brief Compute negative log-likelihood for normal distribution based on the model outputs and measurements for multiple conditions. + * @brief Remove inner parameters + * @return Outer parameters + */ +template +std::vector +removeInnerParameters(const gsl::span allParameters, + const std::vector& proportionalityFactorIndices, + const std::vector& offsetParameterIndices, + const std::vector& sigmaParameterIndices) +{ + std::vector outerParameters( + allParameters.size() - proportionalityFactorIndices.size() - + offsetParameterIndices.size() - sigmaParameterIndices.size()); + + int idxOuter = 0; + for(int idxFull = 0; idxFull < static_cast(allParameters.size()); + ++idxFull) { + if(std::find(proportionalityFactorIndices.begin(), + proportionalityFactorIndices.end(), idxOuter) + != std::end(proportionalityFactorIndices)) + continue; + if(std::find(offsetParameterIndices.begin(), + offsetParameterIndices.end(), idxOuter) + != std::end(offsetParameterIndices)) + continue; + if(std::find(sigmaParameterIndices.begin(), + sigmaParameterIndices.end(), idxOuter) + != std::end(sigmaParameterIndices)) + continue; + outerParameters[idxOuter] = allParameters[idxFull]; + ++idxOuter; + } + + Ensures(idxOuter == static_cast(outerParameters.size())); + return outerParameters; +} + +/** + * @brief From the given parameter vector, extract outer optimization + * parameters, as defined in the file HDF5 file parameterFile + * @param fullParameters + * @param parameterFile + * @param parameterPath + * @return + */ +std::vector +getOuterParameters(std::vector const& fullParameters, + H5::H5File const& parameterFile, + std::string const& parameterPath); + + +/** + * @brief Compute negative log-likelihood for normal distribution based on the + * model outputs and measurements for multiple conditions. * @param measurements * @param modelOutputsScaled * @param sigmas * @return */ -double computeNegLogLikelihood(std::vector > const& measurements, - std::vector > const& modelOutputsScaled, - const std::vector > &sigmas); +double +computeNegLogLikelihood( + std::vector> const& measurements, + std::vector> const& modelOutputsScaled, + const std::vector>& sigmas); /** - * @brief Compute negative log-likelihood for normal distribution based on the model outputs and measurements for a single condition. + * @brief Compute negative log-likelihood for normal distribution based on the + * model outputs and measurements for a single condition. * @param measurements * @param modelOutputsScaled * @param sigmas - * @return + * @return Negative log-likelihood for the given measurements and simulations, + * assuming independently normally distributed noise */ -double computeNegLogLikelihood(std::vector const& measurements, - std::vector const& modelOutputsScaled, - const std::vector &sigmas); +double +computeNegLogLikelihood(std::vector const& measurements, + std::vector const& modelOutputsScaled, + const std::vector& sigmas); -void checkGradientForAnalyticalParameters(std::vector const& gradient, - std::vector const& analyticalIndices, double threshold); +/** + * @brief If sensitivities are computed w.r.t. analytically computed parameters + * (which is unneccessary), this function checks they are below the given + * threshold. + * @param gradient + * @param analyticalIndices + * @param threshold + */ +void +checkGradientForAnalyticalParameters(std::vector const& gradient, + std::vector const& analyticalIndices, + double threshold); -} //namespace parpe +} // namespace parpe #endif // HIERARCHICALOPTIMIZATION_H diff --git a/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h b/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h new file mode 100644 index 000000000..d99091087 --- /dev/null +++ b/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h @@ -0,0 +1,160 @@ +#ifndef HIERARCHICALOPTIMIZATIONANALYTICALPARAMETERPROVIDER_H +#define HIERARCHICALOPTIMIZATIONANALYTICALPARAMETERPROVIDER_H + +#include +#include + +#include + +namespace parpe { + + +/** + * @brief The AnalyticalParameterProvider class is an interface for providing + * information on optimization parameters to be computed analytically + * (proportionality factors, offsets, sigmas, ...). + */ +class AnalyticalParameterProvider +{ + public: + virtual ~AnalyticalParameterProvider() {} + + /** + * @brief Get vector of condition indices for which the parameter with the + * given index is used. + * @param parameterIndex referring to the index in the analytical parameter + * list in the hdf5 file + * (*not* the optimization parameter index). + * @return Vector of condition indice + */ + virtual std::vector getConditionsForParameter( + int parameterIndex) const = 0; + + /** + * @brief Get vector of observable indices for the specified condition for + * which the specified parameter is used. + * @param parameterIndex + * @return + */ + virtual std::vector const& getObservablesForParameter( + int parameterIndex, + int conditionIdx) const = 0; + + /** + * @brief Vector with indices of the of the analytically determined + * parameters within the overall optimization parameter vector + * @return + */ + virtual std::vector getOptimizationParameterIndices() const = 0; +}; + +class AnalyticalParameterProviderDefault : public AnalyticalParameterProvider +{ + public: + AnalyticalParameterProviderDefault() = default; + + std::vector getConditionsForParameter( + int parameterIndex) const override; + + std::vector const& getObservablesForParameter( + int parameterIndex, + int conditionIdx) const override; + + std::vector getOptimizationParameterIndices() const override; + + // TODO private + std::vector> conditionsForParameter; + std::vector optimizationParameterIndices; + // x[scalingIdx][conditionIdx] -> std::vector of observableIndicies + std::vector>> mapping; +}; + +/** + * @brief The AnalyticalParameterHdf5Reader class reads from an HDF5 file the + * dependencies of experimental conditions and observables on parameters which + * are to be computed analytically. + * + */ +class AnalyticalParameterHdf5Reader : public AnalyticalParameterProvider +{ + public: + AnalyticalParameterHdf5Reader() = default; + + /** + * @brief AnalyticalParameterHdf5Reader + * @param file + * @param scalingParameterIndicesPath location in hdf5 file of the list of + * indices of the analytically determined parameters within the overall + * optimization parameters + * @param mapPath path of to the dataset with the + * parameter-oberservable-condition mapping + */ + AnalyticalParameterHdf5Reader(const H5::H5File& file, + std::string analyticalParameterIndicesPath, + std::string mapPath); + + AnalyticalParameterHdf5Reader(AnalyticalParameterHdf5Reader const&) = + delete; + + /** + * @brief Get vector of condition indices for which the parameter with the + * given index is used. + * @param parameterIndex referring to the index in the analytical parameter + * list in the hdf5 file + * (*not* the optimization parameter index). + * @return Vector of condition indice + */ + std::vector getConditionsForParameter( + int parameterIndex) const override; + + /** + * @brief Get vector of observable indices for the specified condition for + * which the specified parameter is used. + * @param parameterIndex + * @return + */ + std::vector const& getObservablesForParameter( + int parameterIndex, + int conditionIdx) const override; + + /** + * @brief Vector with indices of the of the analytically determined + * parameters within the overall optimization parameter vector + * @return + */ + std::vector getOptimizationParameterIndices() const override; + + private: + /** + * @brief Get number of analytically computed parameters + * @param dataset Read information from this dataset. + * @return + */ + int getNumAnalyticalParameters() const; + + /** + * @brief Read mapping of parameter to model outputs. + * + * Data is expected to come as matrix/table with the following columns: + * - scalingParameterIndex: 0-based index referring to entries in the + * parameter index list + * - conditionIdx: condition index + * - observableIdx: index of model output + */ + void readParameterConditionObservableMappingFromFile(); + std::vector readRawMap(H5::DataSet& dataset, + hsize_t& nRows, + hsize_t& nCols); + + H5::H5File file; + std::string rootPath; + std::string mapPath; + std::string analyticalParameterIndicesPath; + + // x[scalingIdx][conditionIdx] -> std::vector of observableIndicies + std::vector>> mapping; +}; + + +} +#endif // HIERARCHICALOPTIMIZATIONANALYTICALPARAMETERPROVIDER_H diff --git a/include/parpeamici/multiConditionDataProvider.h b/include/parpeamici/multiConditionDataProvider.h index 09eb03ab4..de8ae5680 100644 --- a/include/parpeamici/multiConditionDataProvider.h +++ b/include/parpeamici/multiConditionDataProvider.h @@ -19,9 +19,9 @@ namespace parpe { /** * @brief The MultiConditionDataProvider interface */ -class MultiConditionDataProvider { +class MultiConditionDataProvider +{ public: - virtual ~MultiConditionDataProvider() = default; /** @@ -31,31 +31,39 @@ class MultiConditionDataProvider { */ virtual int getNumberOfSimulationConditions() const = 0; + /** + * @brief Get mapping vector simulation_parameter_idx -> + * optimization_parameter_idx for the given condition index. + * @param conditionIdx + * @return Mapping vector + */ virtual std::vector getSimulationToOptimizationParameterMapping( - int conditionIdx) const = 0; + int conditionIdx) const = 0; virtual void mapSimulationToOptimizationGradientAddMultiply( - int conditionIdx, gsl::span simulation, - gsl::span optimization, - gsl::span parameters, double coefficient = 1.0 - ) const = 0; + int conditionIdx, + gsl::span simulation, + gsl::span optimization, + gsl::span parameters, + double coefficient = 1.0) const = 0; virtual void mapAndSetOptimizationToSimulationVariables( - int conditionIdx, gsl::span optimization, - gsl::span simulation, - gsl::span optimizationScale, - gsl::span simulationScale) const = 0; + int conditionIdx, + gsl::span optimization, + gsl::span simulation, + gsl::span optimizationScale, + gsl::span simulationScale) const = 0; /** * @brief Get the parameter scale for the given optimization parameter * @param simulationIdx - * @return + * @return Parameter scale */ virtual amici::ParameterScaling getParameterScaleOpt( - int parameterIdx) const = 0; + int parameterIdx) const = 0; - virtual std::vector - getParameterScaleOpt() const = 0; + virtual std::vector getParameterScaleOpt() + const = 0; /** * @brief Get the parameter scale vector for the given simulation @@ -63,25 +71,27 @@ class MultiConditionDataProvider { * @return */ virtual std::vector getParameterScaleSim( - int simulationIdx) const = 0; + int simulationIdx) const = 0; /** * @brief Get the parameter scale for the given parameter and simulation * @param simulationIdx * @return */ - virtual amici::ParameterScaling getParameterScaleSim(int simulationIdx, - int modelParameterIdx) const = 0; + virtual amici::ParameterScaling getParameterScaleSim( + int simulationIdx, + int modelParameterIdx) const = 0; virtual void updateSimulationParametersAndScale( - int conditionIndex, gsl::span optimizationParams, - amici::Model &model) const = 0; + int conditionIndex, + gsl::span optimizationParams, + amici::Model& model) const = 0; virtual std::unique_ptr getExperimentalDataForCondition( - int conditionIdx) const = 0; + int conditionIdx) const = 0; - virtual std::vector > getAllMeasurements() const = 0; - virtual std::vector > getAllSigmas() const = 0; + virtual std::vector> getAllMeasurements() const = 0; + virtual std::vector> getAllSigmas() const = 0; /** * @brief Returns the number of optimization parameters of this problem @@ -89,6 +99,7 @@ class MultiConditionDataProvider { */ virtual int getNumOptimizationParameters() const = 0; + virtual std::vector getProblemParameterIds() const = 0; /** * @brief Returns a pointer to the underlying AMICI model @@ -96,13 +107,17 @@ class MultiConditionDataProvider { */ virtual std::unique_ptr getModel() const = 0; - virtual std::unique_ptr getSolver() const = 0; - }; -class MultiConditionDataProviderDefault : public MultiConditionDataProvider { +/** + * @brief In-memory data. + * + * !!Very limited implementation, currently only for testing!! + */ +class MultiConditionDataProviderDefault : public MultiConditionDataProvider +{ public: MultiConditionDataProviderDefault(std::unique_ptr model, std::unique_ptr solver); @@ -119,42 +134,46 @@ class MultiConditionDataProviderDefault : public MultiConditionDataProvider { virtual int getNumberOfSimulationConditions() const override; virtual std::vector getSimulationToOptimizationParameterMapping( - int conditionIdx) const override; + int conditionIdx) const override; virtual void mapSimulationToOptimizationGradientAddMultiply( - int conditionIdx, gsl::span simulation, - gsl::span optimization, - gsl::span parameters, - double coefficient = 1.0) const override; + int conditionIdx, + gsl::span simulation, + gsl::span optimization, + gsl::span parameters, + double coefficient = 1.0) const override; virtual void mapAndSetOptimizationToSimulationVariables( - int conditionIdx, gsl::span optimization, - gsl::span simulation, - gsl::span optimizationScale, - gsl::span simulationScale) const override; + int conditionIdx, + gsl::span optimization, + gsl::span simulation, + gsl::span optimizationScale, + gsl::span simulationScale) const override; - virtual std::vector - getParameterScaleOpt() const override; + virtual std::vector getParameterScaleOpt() + const override; virtual amici::ParameterScaling getParameterScaleOpt( - int optimizationParameterIndex) const override; + int optimizationParameterIndex) const override; - virtual amici::ParameterScaling getParameterScaleSim(int simulationIdx, - int optimizationParameterIndex) const override; + virtual amici::ParameterScaling getParameterScaleSim( + int simulationIdx, + int optimizationParameterIndex) const override; virtual std::vector getParameterScaleSim( - int simulationIdx) const override; + int) const override; virtual void updateSimulationParametersAndScale( - int conditionIndex, - gsl::span optimizationParams, - amici::Model &model) const override; + int conditionIndex, + gsl::span optimizationParams, + amici::Model& model) const override; virtual std::unique_ptr getExperimentalDataForCondition( - int conditionIdx) const override; + int conditionIdx) const override; - virtual std::vector > getAllMeasurements() const override; - virtual std::vector > getAllSigmas() const override; + virtual std::vector> getAllMeasurements() + const override; + virtual std::vector> getAllSigmas() const override; /** * @brief Returns the number of optimization parameters of this problem @@ -162,31 +181,31 @@ class MultiConditionDataProviderDefault : public MultiConditionDataProvider { */ virtual int getNumOptimizationParameters() const override; - /** * @brief Returns a pointer to the underlying AMICI model * @return The model */ virtual std::unique_ptr getModel() const override; - virtual std::unique_ptr getSolver() const override; + std::vector getProblemParameterIds() const override; + // TODO private - std::vector edata; + std::vector edata_; -private: - std::unique_ptr model; - std::unique_ptr solver; + private: + std::unique_ptr model_; + std::unique_ptr solver_; }; - /** * @brief The MultiConditionDataProvider class reads simulation data for * MultiConditionOptimizationProblem from a HDF5 file. * * This class assumes a certain layout of the underlying HDF5 file. Der dataset * names can be modified in hdf5*Path members. + * * Required dimensions: * * hdf5MeasurementPath, hdf5MeasurementSigmaPath: numObservables x * numConditions @@ -200,7 +219,8 @@ class MultiConditionDataProviderDefault : public MultiConditionDataProvider { */ // TODO split; separate optimization from simulation -class MultiConditionDataProviderHDF5 : public MultiConditionDataProvider { +class MultiConditionDataProviderHDF5 : public MultiConditionDataProvider +{ public: MultiConditionDataProviderHDF5() = default; @@ -212,7 +232,7 @@ class MultiConditionDataProviderHDF5 : public MultiConditionDataProvider { * read */ MultiConditionDataProviderHDF5(std::unique_ptr model, - const std::string &hdf5Filename); + const std::string& hdf5Filename); /** * @brief See above. @@ -225,17 +245,11 @@ class MultiConditionDataProviderHDF5 : public MultiConditionDataProvider { std::string const& hdf5Filename, std::string const& rootPath); - MultiConditionDataProviderHDF5(MultiConditionDataProviderHDF5 const&) = delete; + MultiConditionDataProviderHDF5(MultiConditionDataProviderHDF5 const&) = + delete; virtual ~MultiConditionDataProviderHDF5() override = default; - /** - * @brief - * @param hdf5Filename Filename from where to read data - */ - - void openHdf5File(const std::string &hdf5Filename); - /** * @brief Get the number of simulations required for objective function * evaluation. Currently, this amounts to the number @@ -253,31 +267,34 @@ class MultiConditionDataProviderHDF5 : public MultiConditionDataProvider { * @return */ virtual std::vector getSimulationToOptimizationParameterMapping( - int conditionIdx) const override; + int conditionIdx) const override; virtual void mapSimulationToOptimizationGradientAddMultiply( - int conditionIdx, gsl::span simulation, - gsl::span optimization, - gsl::span parameters, double coefficient = 1.0 - ) const override; + int conditionIdx, + gsl::span simulation, + gsl::span optimization, + gsl::span parameters, + double coefficient = 1.0) const override; virtual void mapAndSetOptimizationToSimulationVariables( - int conditionIdx, gsl::span optimization, - gsl::span simulation, - gsl::span optimizationScale, - gsl::span simulationScale) const override; + int conditionIdx, + gsl::span optimization, + gsl::span simulation, + gsl::span optimizationScale, + gsl::span simulationScale) const override; - virtual std::vector - getParameterScaleOpt() const override; + virtual std::vector getParameterScaleOpt() + const override; virtual amici::ParameterScaling getParameterScaleOpt( - int parameterIdx) const override; + int parameterIdx) const override; virtual std::vector getParameterScaleSim( - int simulationIdx) const override; + int simulationIdx) const override; - virtual amici::ParameterScaling getParameterScaleSim(int simulationIdx, - int modelParameterIdx) const override; + virtual amici::ParameterScaling getParameterScaleSim( + int simulationIdx, + int modelParameterIdx) const override; /** * @brief Check if the data in the HDF5 file has consistent dimensions. @@ -291,31 +308,28 @@ class MultiConditionDataProviderHDF5 : public MultiConditionDataProvider { gsl::span buffer) const; virtual std::unique_ptr getExperimentalDataForCondition( - int conditionIdx) const override; + int conditionIdx) const override; - std::vector > getAllMeasurements() const override; - std::vector > getAllSigmas() const override; + std::vector> getAllMeasurements() const override; + std::vector> getAllSigmas() const override; std::vector getSigmaForSimulationIndex(int simulationIdx) const; - std::vector getMeasurementForSimulationIndex(int conditionIdx) const; + std::vector getMeasurementForSimulationIndex( + int conditionIdx) const; /** - * @brief getOptimizationParametersLowerBounds Get lower parameter bounds - * NOTE: Currently the same bounds are assumed for kinetic parameters and - * scaling parameters, ... - * @param dataPath (not yet used) + * @brief Writes lower parameter bounds into the provided buffer * @param buffer allocated memory to write parameter bounds */ virtual void getOptimizationParametersLowerBounds( - gsl::span buffer) const; + gsl::span buffer) const; /** - * @brief getOptimizationParametersUpperBounds Get upper parameter bounds - * @param dataPath (not yet used) + * @brief Writes upper parameter bounds into the provided buffer * @param buffer allocated memory to write parameter bounds */ virtual void getOptimizationParametersUpperBounds( - gsl::span buffer) const; + gsl::span buffer) const; /** * @brief Returns the number of optimization parameters of this problem @@ -323,7 +337,6 @@ class MultiConditionDataProviderHDF5 : public MultiConditionDataProvider { */ virtual int getNumOptimizationParameters() const override; - /** * @brief Returns a pointer to a copy of the underlying AMICI model * as provided to the constructor @@ -331,7 +344,6 @@ class MultiConditionDataProviderHDF5 : public MultiConditionDataProvider { */ virtual std::unique_ptr getModel() const override; - virtual std::unique_ptr getSolver() const override; /** @@ -341,61 +353,81 @@ class MultiConditionDataProviderHDF5 : public MultiConditionDataProvider { * @param optimizationParams * @param udata */ - void updateSimulationParametersAndScale(int simulationIdx, - gsl::span optimizationParams, - amici::Model &model) const override; + void updateSimulationParametersAndScale( + int simulationIdx, + gsl::span optimizationParams, + amici::Model& model) const override; - void copyInputData(const H5::H5File &target); + void copyInputData(const H5::H5File& target); - void getSimAndPreeqConditions(const int simulationIdx, - int &preequilibrationConditionIdx, - int &simulationConditionIdx, bool &reinitializeFixedParameterInitialStates) const; + void getSimAndPreeqConditions( + const int simulationIdx, + int& preequilibrationConditionIdx, + int& simulationConditionIdx, + bool& reinitializeFixedParameterInitialStates) const; /** - * @brief Get the identifier of the used HDF5 file. Does not reopen. Do not close file. + * @brief Get the identifier of the used HDF5 file. Does not reopen. + * Does not close file. * @return The file ID */ hid_t getHdf5FileId() const; -protected: + void setModel(std::unique_ptr model); + + std::vector getProblemParameterIds() const override; + + protected: + /** + * @brief Update the contstants in AMICI ExpData object. Reads a slab for the + * given simulation from fixed parameters matrix. + * + * @param simulationIdx Index of the experimental condition for which the + * parameters should be taken. + * @param edata The object to be updated. + */ void updateFixedSimulationParameters(int conditionIdx, - amici::ExpData &edata) const; + amici::ExpData& edata) const; + + private: /** * @brief The model for which the data is to be read */ - std::unique_ptr model; + std::unique_ptr model_; /** * @brief Absolute paths in the HDF5 file to the datasets * from which the respective data is to be read */ - std::string rootPath = "/"; - std::string hdf5MeasurementPath; - std::string hdf5MeasurementSigmaPath; - std::string hdf5ConditionPath; - std::string hdf5ReferenceConditionPath; - std::string hdf5AmiciOptionPath; - std::string hdf5ParameterPath; - std::string hdf5ParameterMinPath; - std::string hdf5ParameterMaxPath; - std::string hdf5ParameterScaleSimulationPath; - std::string hdf5ParameterScaleOptimizationPath; - std::string hdf5SimulationToOptimizationParameterMappingPath; - std::string hdf5ParameterOverridesPath; + std::string root_path_ = "/"; + std::string hdf5_measurement_path_; + std::string hdf5_measurement_sigma_path_; + std::string hdf5_condition_path_; + std::string hdf5_reference_condition_path_; + std::string hdf5_amici_options_path_; + std::string hdf5_parameter_path_; + std::string hdf5_parameter_min_path_; + std::string hdf5_parameter_max_path_; + std::string hdf5_parameter_scale_simulation_path_; + std::string hdf5_parameter_scale_optimization_path_; + std::string hdf5_simulation_to_optimization_parameter_mapping_path_; + std::string hdf5_parameter_overrides_path; + std::string hdf5_parameter_ids_path_; /** * @brief HDF5 file handles for C++ and C API */ - H5::H5File file; + H5::H5File file_; - std::unique_ptr optimizationOptions; + std::unique_ptr optimization_options_; }; - -double applyChainRule(double gradient, double parameter, - amici::ParameterScaling oldScale, - amici::ParameterScaling newScale); +double +applyChainRule(double gradient, + double parameter, + amici::ParameterScaling oldScale, + amici::ParameterScaling newScale); } // namespace parpe diff --git a/include/parpeamici/multiConditionProblem.h b/include/parpeamici/multiConditionProblem.h index f3ccb553e..805bafcc4 100644 --- a/include/parpeamici/multiConditionProblem.h +++ b/include/parpeamici/multiConditionProblem.h @@ -65,14 +65,15 @@ AmiciSimulationRunner::AmiciResultPackageSimple runAndLogSimulation(amici::Solve * @param cpuTime * @return Simulation status */ -FunctionEvaluationStatus getModelOutputs( +FunctionEvaluationStatus getModelOutputsAndSigmas( MultiConditionDataProvider *dataProvider, LoadBalancerMaster *loadBalancer, int maxSimulationsPerPackage, OptimizationResultWriter *resultWriter, bool logLineSearch, gsl::span parameters, - std::vector > &modelOutput, + std::vector > &modelOutputs, + std::vector > &modelSigmas, Logger *logger, double *cpuTime, bool sendStates); /** @@ -135,6 +136,8 @@ class AmiciSummedGradientFunction : public SummedGradientFunction { */ virtual int numParameters() const override; + std::vector getParameterIds() const override; + /** * @brief Run simulations (no gradient) with given parameters and collect * model outputs @@ -144,13 +147,12 @@ class AmiciSummedGradientFunction : public SummedGradientFunction { * (nt x ny, column-major) * @return Simulation status */ - virtual FunctionEvaluationStatus getModelOutputs( - gsl::span parameters, - std::vector > &modelOutput, - Logger *logger, - double *cpuTime) const; - - virtual std::vector> getAllSigmas() const; + virtual FunctionEvaluationStatus getModelOutputsAndSigmas( + gsl::span parameters, + std::vector > &modelOutputs, + std::vector > &modelSigmas, + Logger *logger, + double *cpuTime) const; virtual std::vector> getAllMeasurements() const; @@ -249,7 +251,7 @@ class MultiConditionProblem public: MultiConditionProblem() = default; - MultiConditionProblem(MultiConditionDataProvider *dp); + explicit MultiConditionProblem(MultiConditionDataProvider *dp); MultiConditionProblem( MultiConditionDataProvider *dp, @@ -281,12 +283,12 @@ class MultiConditionProblem std::unique_ptr getReporter() const override; std::vector getTrainingData() const override; -protected: + +private: //TODO std::unique_ptr validationProblem; MultiConditionDataProvider *dataProvider = nullptr; -private: std::unique_ptr resultWriter; std::vector startingPoint; @@ -321,20 +323,17 @@ class MultiConditionProblemMultiStartOptimizationProblem int multiStartIndex) const override; private: - MultiConditionDataProviderHDF5 *dp = nullptr; - OptimizationOptions options; - OptimizationResultWriter *resultWriter = nullptr; - LoadBalancerMaster *loadBalancer = nullptr; - std::unique_ptr logger; + MultiConditionDataProviderHDF5 *data_provider_ = nullptr; + OptimizationOptions options_; + OptimizationResultWriter *result_writer_ = nullptr; + LoadBalancerMaster *load_balancer_ = nullptr; + std::unique_ptr logger_; }; -void saveSimulation( - H5::H5File const& file, const std::string &pathStr, +void saveSimulation(H5::H5File const& file, const std::string &pathStr, const std::vector ¶meters, double llh, - gsl::span gradient, double timeElapsedInSeconds, - gsl::span states, - gsl::span stateSensi, gsl::span outputs, + gsl::span gradient, double timeElapsedInSeconds, gsl::span, gsl::span, gsl::span, int jobId, int status, const std::string &label); diff --git a/include/parpeamici/standaloneSimulator.h b/include/parpeamici/standaloneSimulator.h index 95ba9f54f..a01ef5894 100644 --- a/include/parpeamici/standaloneSimulator.h +++ b/include/parpeamici/standaloneSimulator.h @@ -25,7 +25,7 @@ namespace parpe { class StandaloneSimulator { public: - StandaloneSimulator(MultiConditionDataProvider* dp); + explicit StandaloneSimulator(MultiConditionDataProvider* dp); /** * @brief Run simulations for the given parameter and write results to an @@ -42,10 +42,10 @@ class StandaloneSimulator */ int run(const std::string& resultFile, const std::string& resultPath, - std::vector const& optimizationParameters, + std::map &optimizationParameters, LoadBalancerMaster* loadBalancer, const H5::H5File& conditionFile, - std::string conditionFilePath); + std::string conditionFilePath, bool computeInnerParameters); void messageHandler(std::vector& buffer, int jobId); @@ -90,7 +90,8 @@ runFinalParameters(parpe::StandaloneSimulator& sim, const std::string& parameterFilePath, const std::string& resultFileName, const std::string& resultPath, - parpe::LoadBalancerMaster* loadBalancer); + parpe::LoadBalancerMaster* loadBalancer, + bool computeInnerParameters); int runAlongTrajectory(parpe::StandaloneSimulator& sim, @@ -100,7 +101,8 @@ runAlongTrajectory(parpe::StandaloneSimulator& sim, const std::string& parameterFilePath, std::string const& resultFileName, std::string const& resultPath, - parpe::LoadBalancerMaster* loadBalancer); + parpe::LoadBalancerMaster* loadBalancer, + bool computeInnerParameters); int runSimulator(MultiConditionDataProvider& dp, @@ -110,20 +112,9 @@ runSimulator(MultiConditionDataProvider& dp, const std::string& parameterFileName, const std::string& parameterFilePath, std::string const& resultFileName, - std::string const& resultPath); + std::string const& resultPath, + bool computeInnerParameters); -/** - * @brief From the given parameter vector, extract outer optimization - * parameters, as defined in the file HDF5 file parameterFile - * @param fullParameters - * @param parameterFile - * @param parameterPath - * @return - */ -std::vector -getOuterParameters(std::vector const& fullParameters, - H5::H5File const& parameterFile, - std::string const& parameterPath); } // namespace parpe #endif // STANDALONESIMULATOR_H diff --git a/include/parpeamici/steadystateSimulator.h b/include/parpeamici/steadystateSimulator.h deleted file mode 100644 index 0b5e01ff1..000000000 --- a/include/parpeamici/steadystateSimulator.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef STEADYSTATESIMULATOR_H -#define STEADYSTATESIMULATOR_H - -#include - -#include - -namespace parpe { - - -/** - * @brief The SteadystateSimulator class runs an AMICI simulation until a - * steady-state is reached. - */ -class SteadystateSimulator { - public: - /** - * @brief SteadystateSimulator::getSteadystateSolution - * @param model Note: Content of model->x0 will be overwritten. - * @param edata - * @param status - * @param iterationDone - * @return - */ - - static std::unique_ptr getSteadystateSolution( - amici::Model &model, - amici::Solver &solver, - amici::ExpData *edata, int *status, - int *iterationDone); - - /** - * @brief getSteadystateSolution Simulate the model until steady state - * @param model: Model data and options - * @param edata: ExpData TODO: could remove in case of no events? - * @param status: return status, 0 if successful - * @param iterationDone: Iterations of simulation to t=10^9 until - * steady-state is reached - * @return - */ - static bool reachedSteadyState(const double *xdot, const double *x, - int numTimepoints, int numStates, - double tolerance); - - protected: - /** - * @brief Replace old UserData::x0 by result of last simulation - * @param destination - * @param src - * @param count - */ - static void updateInitialConditions(double destination[], - const double src[], int count); -}; - -} // namespace parpe - -#endif // STEADYSTATESIMULATOR_H diff --git a/include/parpecommon/functions.h b/include/parpecommon/functions.h index 630968224..0e858d80e 100644 --- a/include/parpecommon/functions.h +++ b/include/parpecommon/functions.h @@ -50,6 +50,8 @@ class GradientFunction virtual int numParameters() const = 0; + virtual std::vector getParameterIds() const = 0; + virtual ~GradientFunction() = default; }; @@ -110,6 +112,8 @@ class SummedGradientFunction */ virtual int numParameters() const = 0; + virtual std::vector getParameterIds() const = 0; + virtual ~SummedGradientFunction() = default; }; @@ -133,8 +137,8 @@ class SummedGradientFunctionGradientFunctionAdapter SummedGradientFunctionGradientFunctionAdapter( std::unique_ptr> gradFun, std::vector datasets) - : gradFun(std::move(gradFun)) - , datasets(datasets) + : grad_fun_(std::move(gradFun)) + , datasets_(datasets) {} FunctionEvaluationStatus evaluate(gsl::span parameters, @@ -143,8 +147,8 @@ class SummedGradientFunctionGradientFunctionAdapter Logger* logger = nullptr, double* cpuTime = nullptr) const override { - return gradFun->evaluate( - parameters, datasets, fval, gradient, logger, cpuTime); + return grad_fun_->evaluate( + parameters, datasets_, fval, gradient, logger, cpuTime); } FunctionEvaluationStatus evaluate(gsl::span parameters, @@ -154,7 +158,7 @@ class SummedGradientFunctionGradientFunctionAdapter Logger* logger, double* cpuTime) const override { - return gradFun->evaluate( + return grad_fun_->evaluate( parameters, dataset, fval, gradient, logger, cpuTime); } @@ -165,11 +169,16 @@ class SummedGradientFunctionGradientFunctionAdapter Logger* logger, double* cpuTime) const override { - return gradFun->evaluate( + return grad_fun_->evaluate( parameters, datasets, fval, gradient, logger, cpuTime); } - int numParameters() const override { return gradFun->numParameters(); } + int numParameters() const override { return grad_fun_->numParameters(); } + + std::vector getParameterIds() const override + { + return grad_fun_->getParameterIds(); + } /** * @brief Return pointer to the wrapped function (non-owning). @@ -177,15 +186,15 @@ class SummedGradientFunctionGradientFunctionAdapter */ SummedGradientFunction* getWrappedFunction() const { - return gradFun.get(); + return grad_fun_.get(); } private: /** Wrapped function */ - std::unique_ptr> gradFun; + std::unique_ptr> grad_fun_; /** Datasets to evaluate function on */ - std::vector datasets; + std::vector datasets_; }; } diff --git a/include/parpecommon/hdf5Misc.h b/include/parpecommon/hdf5Misc.h index d9492be70..83b7131da 100644 --- a/include/parpecommon/hdf5Misc.h +++ b/include/parpecommon/hdf5Misc.h @@ -16,9 +16,9 @@ namespace parpe { class HDF5Exception : public std::exception { public: - HDF5Exception(std::string msg = ""); + explicit HDF5Exception(std::string msg = ""); - HDF5Exception(const char *format, ...); + explicit HDF5Exception(const char *format, ...); const char* what() const noexcept; @@ -42,7 +42,7 @@ std::unique_lock hdf5MutexGetLock(); #define H5_RESTORE_ERROR_HANDLER H5Eset_auto1(old_func, old_client_data) herr_t -hdf5ErrorStackWalker_cb(unsigned int n, const H5E_error_t *err_desc, void *); // TODO: also use for resultwriter +hdf5ErrorStackWalker_cb(unsigned int n, const H5E_error_t *err_desc, void *); bool hdf5DatasetExists(hid_t file_id, std::string const& datasetName); @@ -52,6 +52,9 @@ bool hdf5DatasetExists(H5::H5File const& file, const std::string &datasetName); bool hdf5GroupExists(hid_t file_id, const char *groupName); +bool hdf5GroupExists(H5::H5File const& file, + const std::string &groupName); + void hdf5EnsureGroupExists(hid_t file_id, const char *groupName); void hdf5EnsureGroupExists(hid_t file_id, const std::string &groupName); @@ -72,7 +75,10 @@ void hdf5CreateGroup(hid_t file_id, const char *groupPath, bool recursively = fa * @return HDF5 file handle of the created/opened file */ hid_t hdf5CreateFile(const char *filename, - bool overwrite = false); + bool overwrite = false); + +hid_t hdf5CreateFile(std::string const& filename, + bool overwrite = false); H5::H5File hdf5OpenForReading(std::string const& hdf5Filename); diff --git a/include/parpecommon/logging.h b/include/parpecommon/logging.h index 0acccaa9d..219b302df 100644 --- a/include/parpecommon/logging.h +++ b/include/parpecommon/logging.h @@ -7,13 +7,13 @@ namespace parpe { -#define ANSI_COLOR_RED "\x1b[31m" -#define ANSI_COLOR_GREEN "\x1b[32m" -#define ANSI_COLOR_YELLOW "\x1b[33m" -#define ANSI_COLOR_BLUE "\x1b[34m" -#define ANSI_COLOR_MAGENTA "\x1b[35m" -#define ANSI_COLOR_CYAN "\x1b[36m" -#define ANSI_COLOR_RESET "\x1b[0m" +constexpr const char ANSI_COLOR_RED[] = "\x1b[31m"; +constexpr const char ANSI_COLOR_GREEN[] = "\x1b[32m"; +constexpr const char ANSI_COLOR_YELLOW[] = "\x1b[33m"; +constexpr const char ANSI_COLOR_BLUE[] = "\x1b[34m"; +constexpr const char ANSI_COLOR_MAGENTA[] = "\x1b[35m"; +constexpr const char ANSI_COLOR_CYAN[] = "\x1b[36m"; +constexpr const char ANSI_COLOR_RESET[] = "\x1b[0m"; std::string printfToString(const char *fmt, va_list ap); @@ -51,7 +51,7 @@ void warning(const char *message); class Logger { public: Logger() = default; - Logger(std::string prefix); + explicit Logger(std::string prefix); std::unique_ptr getChild(std::string const& appendedPrefix) const; diff --git a/include/parpecommon/misc.h b/include/parpecommon/misc.h index d8fdd8928..dbfcb44fb 100644 --- a/include/parpecommon/misc.h +++ b/include/parpecommon/misc.h @@ -3,28 +3,32 @@ #include -#include -#include -#include #include -#include +#include +#include #include +#include +#include #include template -std::ostream& operator <<(std::ostream& o, std::vector const& v) { +std::ostream& +operator<<(std::ostream& o, std::vector const& v) +{ o << "[ "; - for(auto const& e: v) + for (auto const& e : v) o << e << " "; o << "]"; return o; } template -std::ostream& operator <<(std::ostream& o, gsl::span const& v) { +std::ostream& +operator<<(std::ostream& o, gsl::span const& v) +{ o << "[ "; - for(auto const& e: v) + for (auto const& e : v) o << e << " "; o << "]"; return o; @@ -32,8 +36,9 @@ std::ostream& operator <<(std::ostream& o, gsl::span const& v) { namespace parpe { -class WallTimer { -public: +class WallTimer +{ + public: WallTimer(); void reset(); @@ -44,11 +49,11 @@ class WallTimer { std::chrono::time_point start; std::chrono::time_point roundStart; - }; -class CpuTimer { -public: +class CpuTimer +{ + public: CpuTimer() = default; void reset(); @@ -61,13 +66,16 @@ class CpuTimer { clock_t roundStart = clock(); }; - -#define RELEASE_ASSERT(expr, msg) \ - if(!(expr)) { \ - /* NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay, cppcoreguidelines-pro-type-vararg) */ \ - printf("CRITICAL: Assertion %s in %s:%d failed (%s)\n", \ - (#expr), __FILE__, __LINE__, msg); \ - abort(); \ +#define RELEASE_ASSERT(expr, msg) \ + if (!(expr)) { \ + /* NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay, \ + * cppcoreguidelines-pro-type-vararg) */ \ + printf("CRITICAL: Assertion %s in %s:%d failed (%s)\n", \ + (#expr), \ + __FILE__, \ + __LINE__, \ + msg); \ + abort(); \ } // void printMatlabArray(const double *buffer, int len); @@ -77,24 +85,34 @@ class CpuTimer { * @param name * @return True if exists, false if not */ -bool fileExists(const char *name); +bool +fileExists(const char* name); -int mkpath(char *file_path, mode_t mode); +int +mkpath(char* file_path, mode_t mode); -int mkpathConstChar(const char *file_path, mode_t mode); +int +mkpathConstChar(const char* file_path, mode_t mode); -void createDirectoryIfNotExists(char *dirName); +void +createDirectoryIfNotExists(char* dirName); -void strFormatCurrentLocaltime(gsl::span buffer, const char *format); +void +strFormatCurrentLocaltime(gsl::span buffer, const char* format); -void runInParallelAndWaitForFinish(void *(*function)(void *), - void **args, int numArgs); +void +runInParallelAndWaitForFinish(void* (*function)(void*), + void** args, + int numArgs); -void printBacktrace(int nMaxFrames = 20); +void +printBacktrace(int nMaxFrames = 20); -std::string getBacktrace(int nMaxFrames = 20); +std::string +getBacktrace(int nMaxFrames = 20); -double randDouble(double min, double max); +double +randDouble(double min, double max); /** * @brief fillArrayRandomDoubleIndividualInterval Fill "buffer" with @@ -103,50 +121,54 @@ double randDouble(double min, double max); * @param max * @param buffer */ -void fillArrayRandomDoubleIndividualInterval(gsl::span min, - gsl::span max, - gsl::span buffer); - -void fillArrayRandomDoubleSameInterval(double min, double max, gsl::span buffer); - -int getMpiRank(); -int getMpiCommSize(); -int getMpiActive(); - -/** - * @brief Was application launched by mpiexec? - * - * Make an educated guess if the application was launched with mpiexec - * or similar and therefore require MPI_INIT. - * @return True if probably launched by mpiexec - */ -bool launchedWithMpi(); - -void initMpiIfNeeded(int *argc, char ***argv); -void finalizeMpiIfNeeded(); - -template -bool withinBounds(long int n, T_TEST const *x, const T_BOUNDS *min, const T_BOUNDS *max ) { - for(int i = 0; i < n; ++i) - if(x[i] < min[i]) +void +fillArrayRandomDoubleIndividualInterval(gsl::span min, + gsl::span max, + gsl::span buffer); + +void +fillArrayRandomDoubleSameInterval(double min, + double max, + gsl::span buffer); + +int +getMpiRank(); +int +getMpiCommSize(); +int +getMpiActive(); + +void +finalizeMpiIfNeeded(); + +template +bool +withinBounds(long int n, + T_TEST const* x, + const T_BOUNDS* min, + const T_BOUNDS* max) +{ + for (int i = 0; i < n; ++i) + if (x[i] < min[i]) return false; - for(int i = 0; i < n; ++i) - if(x[i] > max[i]) + for (int i = 0; i < n; ++i) + if (x[i] > max[i]) return false; return true; } - /** - * @brief The Like std::unique_lock, but unlocking a mutex on construction and locking on destruction. + * @brief The Like std::unique_lock, but unlocking a mutex on construction and + * locking on destruction. */ template -class InverseUniqueLock { -public: - InverseUniqueLock(MUTEX *mutex) - : mutex(mutex) +class InverseUniqueLock +{ + public: + explicit InverseUniqueLock(MUTEX* mutex) + : mutex(mutex) { mutex->unlock(); } @@ -155,20 +177,18 @@ class InverseUniqueLock { InverseUniqueLock& operator=(const InverseUniqueLock& other) = delete; - InverseUniqueLock(InverseUniqueLock &&other) noexcept { + InverseUniqueLock(InverseUniqueLock&& other) noexcept + { mutex = other.mutex; other.mutex = nullptr; } - InverseUniqueLock const & operator=(InverseUniqueLock &&fp) = delete; + InverseUniqueLock const& operator=(InverseUniqueLock&& fp) = delete; - ~InverseUniqueLock() - { - mutex->lock(); - } + ~InverseUniqueLock() { mutex->lock(); } -private: - MUTEX *mutex = nullptr; + private: + MUTEX* mutex = nullptr; }; /** @@ -177,7 +197,8 @@ class InverseUniqueLock { * @param b * @return */ -bool almostEqual(double a, double b); +bool +almostEqual(double a, double b); } // namespace parpe @@ -185,7 +206,8 @@ bool almostEqual(double a, double b); // custom make_unique while we are still using c++11 namespace std { template -std::unique_ptr make_unique(Args&&... args) +std::unique_ptr +make_unique(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } diff --git a/include/parpecommon/model.h b/include/parpecommon/model.h index ecf2db420..121bbbe10 100644 --- a/include/parpecommon/model.h +++ b/include/parpecommon/model.h @@ -63,7 +63,7 @@ class LinearModel : public Model> class LinearModelMSE : public SummedGradientFunction { public: - LinearModelMSE(int numParameters) + explicit LinearModelMSE(int numParameters) :numParameters_(numParameters) {} // SummedGradientFunction @@ -88,6 +88,13 @@ class LinearModelMSE : public SummedGradientFunction int numParameters() const override {return numParameters_;} + std::vector getParameterIds() const override { + std::vector ids(numParameters()); + for(int i = 0; i < static_cast(ids.size()); ++i) + ids[i] = std::string("p") + std::to_string(i); + return ids; + } + int numParameters_ = 0; std::vector> datasets; diff --git a/include/parpecommon/parpeException.h b/include/parpecommon/parpeException.h index 99bff212f..0ef006eb0 100644 --- a/include/parpecommon/parpeException.h +++ b/include/parpecommon/parpeException.h @@ -8,15 +8,15 @@ namespace parpe { class ParPEException : public std::exception { public: - ParPEException(const char *message); + explicit ParPEException(const char *message); - ParPEException(std::string message); + explicit ParPEException(std::string message); virtual ~ParPEException() throw() {} virtual const char *what() const noexcept override; - protected: + private: std::string message; }; diff --git a/include/parpeloadbalancer/loadBalancerWorker.h b/include/parpeloadbalancer/loadBalancerWorker.h index e4c5af003..ee14ba7ac 100644 --- a/include/parpeloadbalancer/loadBalancerWorker.h +++ b/include/parpeloadbalancer/loadBalancerWorker.h @@ -6,7 +6,7 @@ #include #include -#define MPI_TAG_EXIT_SIGNAL 0 +constexpr int MPI_TAG_EXIT_SIGNAL = 0; namespace parpe { diff --git a/include/parpeoptimization/localOptimizationIpoptTNLP.h b/include/parpeoptimization/localOptimizationIpoptTNLP.h index 30bb5c9ed..e9e2351d0 100644 --- a/include/parpeoptimization/localOptimizationIpoptTNLP.h +++ b/include/parpeoptimization/localOptimizationIpoptTNLP.h @@ -15,9 +15,6 @@ namespace parpe { -using namespace Ipopt; - - /** Mutex for managing access to IpOpt routines which are not thread-safe */ typedef std::recursive_mutex mutexIpOptType; @@ -43,20 +40,24 @@ class LocalOptimizationIpoptTNLP : public Ipopt::TNLP { virtual ~LocalOptimizationIpoptTNLP() override = default; - virtual bool get_nlp_info(Index &n, Index &m, Index &nnz_jac_g, - Index &nnz_h_lag, + virtual bool get_nlp_info(Ipopt::Index &n, Ipopt::Index &m, + Ipopt::Index &nnz_jac_g, + Ipopt::Index &nnz_h_lag, IndexStyleEnum &index_style) override; - virtual bool get_bounds_info(Index n, Number *x_l, Number *x_u, Index m, - Number *g_l, Number *g_u) override; + virtual bool get_bounds_info(Ipopt::Index n, Ipopt::Number *x_l, + Ipopt::Number *x_u, Ipopt::Index m, + Ipopt::Number *g_l, Ipopt::Number *g_u) override; - virtual bool get_starting_point(Index n, bool init_x, Number *x, - bool init_z, Number *z_L, Number *z_U, - Index m, bool init_lambda, - Number *lambda) override; + virtual bool get_starting_point(Ipopt::Index n, bool init_x, + Ipopt::Number *x, + bool init_z, Ipopt::Number *z_L, + Ipopt::Number *z_U, + Ipopt::Index m, bool init_lambda, + Ipopt::Number *lambda) override; - virtual bool eval_f(Index n, const Number *x, bool new_x, - Number &obj_value) override; + virtual bool eval_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, + Ipopt::Number &obj_value) override; /** * @brief See Ipopt::TNLP::eval_grad_f. @@ -71,28 +72,35 @@ class LocalOptimizationIpoptTNLP : public Ipopt::TNLP { * @param grad_f * @return */ - virtual bool eval_grad_f(Index n, const Number *x, bool new_x, - Number *grad_f) override; + virtual bool eval_grad_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, + Ipopt::Number *grad_f) override; - virtual bool eval_g(Index n, const Number *x, bool new_x, Index m, - Number *g) override; + virtual bool eval_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, + Ipopt::Index m, + Ipopt::Number *g) override; - virtual bool eval_jac_g(Index n, const Number *x, bool new_x, Index m, - Index nele_jac, Index *iRow, Index *jCol, - Number *values) override; + virtual bool eval_jac_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, + Ipopt::Index m, + Ipopt::Index nele_jac, Ipopt::Index *iRow, + Ipopt::Index *jCol, + Ipopt::Number *values) override; virtual bool intermediate_callback( - AlgorithmMode mode, Index iter, Number obj_value, Number inf_pr, - Number inf_du, Number mu, Number d_norm, Number regularization_size, - Number alpha_du, Number alpha_pr, Index ls_trials, - const IpoptData *ip_data, IpoptCalculatedQuantities *ip_cq) override; - - virtual void finalize_solution(SolverReturn status, Index n, - const Number *x, const Number *z_L, - const Number *z_U, Index m, const Number *g, - const Number *lambda, Number obj_value, - const IpoptData *ip_data, - IpoptCalculatedQuantities *ip_cq) override; + Ipopt::AlgorithmMode mode, Ipopt::Index iter, Ipopt::Number obj_value, + Ipopt::Number inf_pr, Ipopt::Number inf_du, Ipopt::Number mu, + Ipopt::Number d_norm, Ipopt::Number regularization_size, + Ipopt::Number alpha_du, Ipopt::Number alpha_pr, Ipopt::Index ls_trials, + const Ipopt::IpoptData *ip_data, Ipopt::IpoptCalculatedQuantities *ip_cq) override; + + virtual void finalize_solution(Ipopt::SolverReturn status, Ipopt::Index n, + const Ipopt::Number *x, + const Ipopt::Number *z_L, + const Ipopt::Number *z_U, Ipopt::Index m, + const Ipopt::Number *g, + const Ipopt::Number *lambda, + Ipopt::Number obj_value, + const Ipopt::IpoptData *ip_data, + Ipopt::IpoptCalculatedQuantities *ip_cq) override; private: OptimizationProblem &problem; OptimizationReporter &reporter; @@ -102,7 +110,8 @@ class LocalOptimizationIpoptTNLP : public Ipopt::TNLP { }; -void setIpOptOption(const std::pair &pair, SmartPtr* o); +void setIpOptOption(const std::pair &pair, + Ipopt::SmartPtr* o); } // namespace parpe diff --git a/include/parpeoptimization/minibatchOptimization.h b/include/parpeoptimization/minibatchOptimization.h index db0af7fe0..3dfc2ce20 100755 --- a/include/parpeoptimization/minibatchOptimization.h +++ b/include/parpeoptimization/minibatchOptimization.h @@ -14,6 +14,7 @@ #include #include #include +#include namespace parpe { @@ -64,8 +65,8 @@ class MinibatchOptimizationProblem: public OptimizationProblem { /** mini batch cost function */ SummedGradientFunction* getGradientFunction() const { - auto summedGradientFunction = dynamic_cast*>(costFun.get()); - RELEASE_ASSERT(summedGradientFunction, ""); + auto summedGradientFunction = dynamic_cast*>(cost_fun_.get()); + Ensures(summedGradientFunction != nullptr); return summedGradientFunction; } }; @@ -418,7 +419,7 @@ class MinibatchOptimizer { gsl::span upperParameterBounds, OptimizationReporter *reporter, Logger *logger_) { - RELEASE_ASSERT((unsigned) f.numParameters() == initialParameters.size(), ""); + Expects((unsigned) f.numParameters() == initialParameters.size()); Logger logger = logger_ ? *logger_ : Logger(); // We don't change the user inputs but work with copies @@ -438,8 +439,8 @@ class MinibatchOptimizer { if (reporter) { reporter->starting(initialParameters); - reporter->resultWriter->setLoggingEachFunctionEvaluation(false, true); - reporter->resultWriter->setLoggingEachIteration(false); + reporter->result_writer_->setLoggingEachFunctionEvaluation(false, true); + reporter->result_writer_->setLoggingEachIteration(false); } for (int epoch = 0; epoch < maxEpochs; ++epoch) { @@ -521,7 +522,7 @@ class MinibatchOptimizer { OptimizationReporter *reporter) const { if (reporter) { reporter->beforeCostFunctionCall(parameters); - reporter->logger->setPrefix(logger->getPrefix()); + reporter->logger_->setPrefix(logger->getPrefix()); } double cpuTime = 0.0; @@ -534,8 +535,8 @@ class MinibatchOptimizer { g /= batchSize; if (reporter) { - reporter->cpuTimeIterationSec += cpuTime; - reporter->cpuTimeTotalSec += cpuTime; + reporter->cpu_time_iteration_sec_ += cpuTime; + reporter->cpu_time_total_sec_ += cpuTime; reporter->afterCostFunctionCall(parameters, cost, gradient); } @@ -606,7 +607,7 @@ class MinibatchOptimizer { if (reporter) { reporter->beforeCostFunctionCall(parameters); - reporter->logger->setPrefix(logger->getPrefix()); + reporter->logger_->setPrefix(logger->getPrefix()); } // debug output @@ -987,8 +988,8 @@ void clipToBounds(gsl::span lowerBounds, if (lowerBounds.empty() && upperBounds.empty()) return; - RELEASE_ASSERT(lowerBounds.size() == upperBounds.size(), ""); - RELEASE_ASSERT(lowerBounds.size() == x.size(), ""); + Expects(lowerBounds.size() == upperBounds.size()); + Expects(lowerBounds.size() == x.size()); for (int i = 0; static_cast::index_type>(i) < x.size(); ++i) x[i] = std::min(std::max(lowerBounds[i], x[i]), upperBounds[i]); diff --git a/include/parpeoptimization/optimizationProblem.h b/include/parpeoptimization/optimizationProblem.h index 69eb86b7a..621b9559a 100644 --- a/include/parpeoptimization/optimizationProblem.h +++ b/include/parpeoptimization/optimizationProblem.h @@ -91,11 +91,13 @@ class OptimizationReporter: public GradientFunction { void setGradientFunction(GradientFunction *gradFun) const; - std::unique_ptr resultWriter; + std::vector getParameterIds() const override; - mutable double cpuTimeTotalSec = 0.0; - mutable double cpuTimeIterationSec = 0.0; - std::unique_ptr logger; + std::unique_ptr result_writer_; + + mutable double cpu_time_total_sec_ = 0.0; + mutable double cpu_time_iteration_sec_ = 0.0; + std::unique_ptr logger_; protected: void printObjectiveFunctionFailureMessage() const; @@ -103,30 +105,30 @@ class OptimizationReporter: public GradientFunction { // data members are mutable, because we inherit from GradientFunction, // and evaluate() is const there. This could probably be solved better.... - mutable WallTimer wallTimer; + mutable WallTimer wall_timer_; - mutable int numFunctionCalls = 0; - mutable int numIterations = 0; - mutable int numParameters_ = 0; + mutable int num_function_calls_ = 0; + mutable int num_iterations_ = 0; + mutable int num_parameters_ = 0; - mutable bool started = false; + mutable bool started_ = false; // non-owning - mutable GradientFunction *gradFun = nullptr; + mutable GradientFunction *grad_fun_ = nullptr; // for caching - mutable bool haveCachedCost = false; - mutable bool haveCachedGradient = false; - mutable std::vector cachedGradient; - mutable double cachedCost = std::numeric_limits::infinity(); - mutable FunctionEvaluationStatus cachedStatus = functionEvaluationSuccess; + mutable bool have_cached_cost_ = false; + mutable bool have_cached_gradient_ = false; + mutable std::vector cached_gradient_; + mutable double cached_cost_ = std::numeric_limits::infinity(); + mutable FunctionEvaluationStatus cached_status_ = functionEvaluationSuccess; - mutable double finalCost = std::numeric_limits::quiet_NaN(); + mutable double final_cost_ = std::numeric_limits::quiet_NaN(); // keeps the most recent parameters, assuming they are the final ones - mutable std::vector cachedParameters; + mutable std::vector cached_parameters_; - std::string defaultLoggerPrefix; + std::string default_logger_prefix_; }; @@ -168,12 +170,12 @@ class OptimizationProblem { virtual std::unique_ptr getReporter() const; // const? - std::unique_ptr costFun; + std::unique_ptr cost_fun_; - std::unique_ptr logger; + std::unique_ptr logger_; private: - OptimizationOptions optimizationOptions; + OptimizationOptions optimization_options_; }; diff --git a/include/parpeoptimization/optimizationResultWriter.h b/include/parpeoptimization/optimizationResultWriter.h index 0946f5230..d91338663 100644 --- a/include/parpeoptimization/optimizationResultWriter.h +++ b/include/parpeoptimization/optimizationResultWriter.h @@ -17,24 +17,19 @@ namespace parpe { class OptimizationResultWriter { public: - /** - * @brief Default constructor, for testing only - */ - OptimizationResultWriter() = default; - /** * @brief Write to pre-opened HDF5 file (will be re-opened) - * @param problem - * @param file_id + * @param file + * @param rootPath */ OptimizationResultWriter(const H5::H5File &file, std::string rootPath); /** * @brief Open HDF5 file and write there - * @param problem * @param filename Name of the result file * @param overwrite Overwrite output file if already exists + * @param rootPath */ OptimizationResultWriter(const std::string &filename, bool overwrite, @@ -53,7 +48,7 @@ class OptimizationResultWriter { * @param objectiveFunctionValue f(x) * @param objectiveFunctionGradient f'(x) or NULL * @param numFunctionCalls Number of times the objective function has been - * called (f(x) and f'(x) are counter individually (?)) + * called (f(x) and f'(x) are counted individually (?)) * @param timeElapsedInSeconds CPU time for the last objective function * evaluation (wall time) */ @@ -124,6 +119,10 @@ class OptimizationResultWriter { bool logGradientEachIteration = true; + /** + * @brief Set root path in HDF5 file and create the respective group. + * @param path + */ void setRootPath(std::string const& path); protected: diff --git a/misc/README.md b/misc/README.md index 34340c1f1..8455a7155 100644 --- a/misc/README.md +++ b/misc/README.md @@ -1,9 +1,5 @@ # `/misc` Various helper scripts -- amiciHelper.py - - Module for parsing AMICI source files - - createJobsForScalingStudy.sh Script for creating job file templates for scaling tests @@ -24,10 +20,6 @@ - parPE.R (Outdated) example for plotting parPE parameter estimation results in R - -- runExamples.sh - - Run parPE examples for testing - run_in_venv.sh diff --git a/misc/amiciHelper.py b/misc/amiciHelper.py deleted file mode 100755 index d90d58756..000000000 --- a/misc/amiciHelper.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python3 -""" -Parse AMICI syms file -2017 Daniel Weindl - -""" - -import numpy as np -import pandas as pd -from libsbml import SBMLReader -import h5py -import sys -import re -import os - -class AmiciSyms: - symsFileName = '' - - def __init__(self, symsFileName): - self.symsFileName = symsFileName - - def readFixedParameterNames(self): - """ - Read parameter names from _syms file model.sym.k. - """ - with open(self.symsFileName, 'r') as f: - for l in f: - if not l.startswith("model.sym.k"): - continue - - # remove "model.sym.k = [" and "]:\n" - l = l[15:-3] - return [s.strip() for s in l.split(",")] - - def readParameterNames(self): - """ - Read parameter names from _syms file model.sym.p. - """ - with open(self.symsFileName, 'r') as f: - for l in f: - if not l.startswith("model.sym.p"): - continue - - # remove "model.sym.p = [" and "]:\n" - l = l[15:-3] - return [s.strip() for s in l.split(",")] - - - - def readObservables(self): - """ - Read IDs of observables as defined in the provided AMICI syms file - """ - y = "" - with open(self.symsFileName, 'r') as f: - it = iter(f) - for l in it: - if not l.startswith("model.sym.y"): - continue - y += l.strip() - if l.find("];") >= 0: - break - - for l in it: - y += l.strip() - if l.find("];") >= 0: - break - # remove "model.sym.y = [" and "];" - y = y[15:-2] - y = y.replace("...", "") - return [o.strip() for o in y.split(",")] - - def readStateNames(self): - x = "" - with open(self.symsFileName, 'r') as f: - it = iter(f) - for l in it: - if not l.startswith("model.sym.x "): - continue - x += l.strip() - if l.find("];") >= 0: - break - for l in it: - x += l.strip() - if l.find("];") >= 0: - break - # remove "model.sym.x = [" and "];" - x = x[15:-2] - x = x.replace("...", "") - return [o.strip() for o in x.split(",")] - - -def unique(seq): - """ - Make unique, preserving order - """ - seen = {} - uni = [] - for item in seq: - if item in seen: - continue - seen[item] = True - uni.append(item) - return uni - - -def main(): - pass - -if __name__ == "__main__": - main() - #a = AmiciSyms() - #a.symsFileName = '/home/dweindl/src/CanPathPro-WP6-Leonard/Mouse_Models/Speedy_v3_r403445/Speedy_v3_r403445_v1_syms.m' - #[ print(x) for x in a.readStateNames() ] diff --git a/misc/rebuild_amici.sh b/misc/rebuild_amici.sh new file mode 100755 index 000000000..d01a93e5a --- /dev/null +++ b/misc/rebuild_amici.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Rebuild AMICI and dependencies + +set -euo pipefail + +script_dir=$(dirname "$0") +script_dir=$(cd "$script_dir" && pwd) + +build_dir="${script_dir}/../build" +amici_dir="${script_dir}/../deps/AMICI" + +printf '=%.0s' {1..100} +echo "Suitesparse...." +"${amici_dir}/scripts/buildSuiteSparse.sh" + +printf '=%.0s' {1..100} +echo "Sundials...." +"${amici_dir}/scripts/buildSundials.sh" + +printf '=%.0s' {1..100} +echo "AMICI C++...." +# delete old swig-generated files which can lead to ImportErrors during +# installation if the swig interface changed +set -x +rm -f "${amici_dir}/python/sdist/amici/amici_without_hdf5.py" +rm -f "${amici_dir}/python/sdist/amici/amici.py" +rm -f "${amici_dir}/python/sdist/amici/amici_wrap_without_hdf5.cxx" +rm -f "${amici_dir}/python/sdist/amici/amici_wrap.cxx" +rm -f "${amici_dir}"/python/sdist/amici/_amici.*.so +ls -l ${amici_dir}/python/sdist/amici +# rebuild +"${amici_dir}/scripts/buildAmici.sh" + +printf '=%.0s' {1..100} +echo "AMICI Python...." +# reinstall +"${script_dir}/run_in_venv.sh" "${build_dir}"/venv pip3 install -ve "${amici_dir}/python/sdist" + + +printf '=%.0s' {1..100} diff --git a/misc/runExamples.sh b/misc/runExamples.sh deleted file mode 100755 index 3a7476bbd..000000000 --- a/misc/runExamples.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -set -e -set -x - -mpiexec -n 5 loadbalancer/examples/loadbalancer/example_loadbalancer - -amici/examples/steadystate/example_steadystate - -amici/examples/steadystate/example_steadystate_parallel - -mpiexec -n 5 amici/examples/steadystate/example_steadystate_parallel - -mpiexec -n 5 amici/examples/steadystate/example_steadystate_multi -o deleteme ../amici/examples/steadystate/data.h5 - diff --git a/misc/run_in_venv.sh b/misc/run_in_venv.sh index e0dbec478..66a637daf 100755 --- a/misc/run_in_venv.sh +++ b/misc/run_in_venv.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Run a given command in the given Python virtual environment -set -e +set -euo pipefail # invalid options: if [[ $# -lt 2 ]]; then @@ -10,5 +10,5 @@ if [[ $# -lt 2 ]]; then exit 1; fi -source $1/bin/activate +source "$1/bin/activate" "${@:2}" diff --git a/misc/run_notebook.sh b/misc/run_notebook.sh new file mode 100755 index 000000000..ed76f6f6b --- /dev/null +++ b/misc/run_notebook.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# Run jupyter notebooks as given on command line, show output only on error. +# If a directory is provided, run all contained notebooks non-recursively. +set -euo pipefail +set -x +script_path=$(dirname $BASH_SOURCE) +parpe_path=$(cd "$script_path/.." && pwd) + +runNotebook () { + set +e + tempfile=$(mktemp) + jupyter nbconvert --debug --stdout --execute --ExecutePreprocessor.timeout=300 --to markdown "$@" &> $tempfile + ret=$? + if [[ $ret != 0 ]]; then + cat "$tempfile" + echo "Error running" "$@" + exit $ret + fi + rm "$tempfile" + set -e +} + +if [ $# -eq 0 ]; then + echo "Usage: $0 [notebook.ipynb] [dirContainingNotebooks/]" + exit 1 +fi + +source "${parpe_path}/build/venv/bin/activate" +pip3 show ipython \ + || (pip3 install --upgrade jupyter jupyter_contrib_nbextensions \ + && python3 -m ipykernel install --user \ + --name parpe --display-name "Python (parpe)") + +for arg in "$@"; do + if [ -d $arg ]; then + for notebook in $(ls -1 $arg | grep -E ipynb\$); do + runNotebook "$arg/$notebook" + done + elif [ -f "$arg" ]; then + runNotebook "$arg" + else + echo "$arg is neither file nor directory." + exit 1 + fi +done diff --git a/misc/setup_amici_model.sh b/misc/setup_amici_model.sh index ea4d6e90b..13a07b747 100755 --- a/misc/setup_amici_model.sh +++ b/misc/setup_amici_model.sh @@ -1,51 +1,51 @@ #!/usr/bin/env bash # For an AMICI-imported model, set up parPE build -set -e +set -euo pipefail # invalid options: if [[ $# -lt 2 ]] || [[ $# -gt 2 ]]; then echo "For an AMICI-imported model, set up parPE build" - echo "USAGE: $(basename "$0") MODEL_DIR OUTPUT_DIR" + echo "USAGE: $(basename "$0") model_dir output_dir" exit 1; fi -SCRIPT_PATH=$(dirname $BASH_SOURCE) -MODEL_DIR=$1 -OUTPUT_DIR=$2 -TEMPLATE_DIR=${SCRIPT_PATH}/../templates -MODEL_NAME=$(basename ${MODEL_DIR}) +script_path=$(realpath $(dirname "$BASH_SOURCE")) +model_dir="$1" +output_dir="$2" +template_dir="${script_path}/../templates" +model_name=$(basename "${model_dir}") -if [[ ! -d ${MODEL_DIR} ]]; then - echo "ERROR: Model directory ${MODEL_DIR} does not exist." +if [[ ! -d "${model_dir}" ]]; then + echo "ERROR: Model directory ${model_dir} does not exist." exit 1 fi -if [[ -e ${OUTPUT_DIR} ]]; then - echo "ERROR: Output directory ${OUTPUT_DIR} exists. Change or delete." +if [[ -e "${output_dir}" ]]; then + echo "ERROR: Output directory ${output_dir} exists. Change or delete." exit 1 fi -echo "Copying model to output directory $OUTPUT_DIR ..." -mkdir -p ${OUTPUT_DIR} -cp -R ${MODEL_DIR} ${OUTPUT_DIR}/model +echo "Copying model to output directory ${output_dir} ..." +mkdir -p "${output_dir}" +cp -R "${model_dir}" "${output_dir}/model" echo "Adding CMake and source files ..." -cp ${TEMPLATE_DIR}/CMakeLists.template.txt ${OUTPUT_DIR}/CMakeLists.txt -sed -ri "s/mymodel/${MODEL_NAME}/" ${OUTPUT_DIR}/CMakeLists.txt +cp "${template_dir}/CMakeLists.template.txt" "${output_dir}/CMakeLists.txt" +sed -ri "s/mymodel/${model_name}/" "${output_dir}/CMakeLists.txt" # TODO change in AMICI to avoid naming conflicts -sed -ri "s/simulate_/amici_/" ${OUTPUT_DIR}/model/CMakeLists.txt -cp ${TEMPLATE_DIR}/main*.cpp ${OUTPUT_DIR} +sed -ri "s/simulate_/amici_/" "${output_dir}/model/CMakeLists.txt" +cp "${template_dir}"/main*.cpp "${output_dir}" echo "Setting up build ..." -mkdir ${OUTPUT_DIR}/build -cd ${OUTPUT_DIR}/build -if [[ -z "${AMICI_ROOT}" ]] - then AMICI_ROOT=${SCRIPT_PATH}/../deps/AMICI/ -fi +amici_root=${AMICI_ROOT:-${script_path}/../deps/AMICI/} -CC=mpicc CXX=mpiCC cmake -DAmici_DIR=${AMICI_ROOT}/build -DParPE_DIR=${SCRIPT_PATH}/../build .. +CC=mpicc CXX=mpiCC \ + cmake -S "${output_dir}" \ + -B "${output_dir}/build" \ + -DAmici_DIR="${amici_root}/build" \ + -DParPE_DIR="${script_path}/../build" echo "Building ..." -make ${MAKE_OPTS} +cmake --build "${output_dir}/build" -- VERBOSE=1 diff --git a/misc/venv.sh b/misc/venv.sh index be2ad4b8c..81177c23e 100755 --- a/misc/venv.sh +++ b/misc/venv.sh @@ -1,41 +1,43 @@ -#!/bin/bash +#!/usr/bin/env bash # # Setup virtual environment for building/testing parPE # +set -euo pipefail -SCRIPT_PATH=$(dirname $BASH_SOURCE) -PARPE_ROOT=$(cd ${SCRIPT_PATH}/.. && pwd) -BUILD_DIR=$1 +script_path=$(dirname "$BASH_SOURCE") +parpe_root=$(cd "${script_path}/.." && pwd) + +build_dir=${1:-"${parpe_root}/build"} +venv_dir="${build_dir}/venv" -# set default build dir if not provided -if [[ -z "${BUILD_DIR}" ]]; then BUILD_DIR="${PARPE_ROOT}/build"; fi # Save the time for installing AMICI if the venv already exists # NOTE: Must remove folder if AMICI is updated -if [[ ! -d ${BUILD_DIR}/venv ]]; then +if [[ ! -d "${venv_dir}" ]]; then # create venv - python3 -m venv ${BUILD_DIR}/venv 2>/dev/null + set +e + python3 -m venv "${venv_dir}" 2>/dev/null # in case this fails (usually due to missing ensurepip), try getting pip # manually if [[ $? ]]; then set -e - python3 -m venv ${BUILD_DIR}/venv --clear --without-pip - source ${BUILD_DIR}/venv/bin/activate - curl https://bootstrap.pypa.io/get-pip.py -o ${BUILD_DIR}/get-pip.py - python3 ${BUILD_DIR}/get-pip.py + python3 -m venv "${venv_dir}" --clear --without-pip + source "${venv_dir}/bin/activate" + curl https://bootstrap.pypa.io/get-pip.py -o "${build_dir}/get-pip.py" + python3 "${build_dir}/get-pip.py" else set -e - source ${BUILD_DIR}/venv/bin/activate + source "${venv_dir}/bin/activate" fi pip3 install wheel pytest # install AMICI - cd ${PARPE_ROOT}/deps/AMICI/python/sdist + cd "${parpe_root}/deps/AMICI/python/sdist" pip3 install -e . # install parPE - cd ${PARPE_ROOT}/python + cd "${parpe_root}/python" pip3 install -e . #pip3 install https://github.com/ICB-DCM/PEtab/archive/develop.zip fi diff --git a/python/parpe/dataprovider.py b/python/parpe/dataprovider.py index cc37bd9ce..1a9d3b056 100644 --- a/python/parpe/dataprovider.py +++ b/python/parpe/dataprovider.py @@ -45,12 +45,14 @@ def get_expdata_for_condition( y[:, :] = self._get_measurement_sigmas(f, condition_idx) edata.setObservedDataStdDev(y.flatten()) - preeq_cond_idx, sim_cond_idx = \ + preeq_cond_idx, sim_cond_idx, reinit_states_flag = \ self._get_fixed_par_indices(f, condition_idx) edata.fixedParameters = self._get_fixed_parameters(f, sim_cond_idx) if preeq_cond_idx > 0: edata.fixedParametersPreequilibration = \ self._get_fixed_parameters(f, preeq_cond_idx) + if reinit_states_flag > 0: + edata.reinitializeFixedParameterInitialStates = True return edata @@ -60,9 +62,9 @@ def _get_fixed_parameters(f: h5py.File, idx: int): @staticmethod def _get_fixed_par_indices(f, simulation_idx): - preeq_cond_idx, sim_cond_idx = \ + preeq_cond_idx, sim_cond_idx, reinit_states_flag = \ f['/fixedParameters/simulationConditions'][simulation_idx, :] - return preeq_cond_idx, sim_cond_idx + return preeq_cond_idx, sim_cond_idx, reinit_states_flag @staticmethod def _get_measurements(f, simulation_idx): diff --git a/python/parpe/hdf5.py b/python/parpe/hdf5.py index baa849d7a..0a61d6159 100644 --- a/python/parpe/hdf5.py +++ b/python/parpe/hdf5.py @@ -17,7 +17,7 @@ def write_string_array(f: h5py.Group, """ dt = h5py.special_dtype(vlen=str) dset = f.create_dataset(path, (len(strings),), dtype=dt) - dset[:] = [s.encode('utf8') for s in strings] + dset[:] = [str(s).encode('utf8') for s in strings] f.file.flush() diff --git a/python/parpe/hdf5_pe_input.py b/python/parpe/hdf5_pe_input.py index 2c7ec5028..4aa3c20db 100644 --- a/python/parpe/hdf5_pe_input.py +++ b/python/parpe/hdf5_pe_input.py @@ -567,8 +567,9 @@ def _generate_simulation_condition_map(self): # Mind different ordering preeq/sim sim/preeq here and in PEtab! for sim_idx, (sim_id, preeq_id) \ in enumerate(simulations.iloc[:, 0:2].values): - condition_map[sim_idx] = [condition_id_to_idx[preeq_id], - condition_id_to_idx[sim_id]] + if preeq_id: + condition_map[sim_idx, 0] = condition_id_to_idx[preeq_id] + condition_map[sim_idx, 1] = condition_id_to_idx[sim_id] print(Fore.CYAN + "Number of simulation conditions:", len(simulations)) @@ -876,8 +877,9 @@ def _write_amici_options(self) -> None: Write simulation options """ g = self.f.require_group("/amiciOptions") - g.attrs['sensi'] = amici.SensitivityOrder_first - g.attrs['sensi_meth'] = amici.SensitivityMethod_adjoint + g.attrs['sensi'] = amici.SensitivityOrder.first + g.attrs['sensi_meth'] = amici.SensitivityMethod.adjoint + g.attrs['sensi_meth_preeq'] = amici.SensitivityMethod.adjoint # TODO PEtab support: get from file g.attrs['tstart'] = 0.0 g.attrs['atol'] = 1e-14 diff --git a/python/parpe/hierarchical_optimization.py b/python/parpe/hierarchical_optimization.py index 24a58ae2f..1c7e6a7bb 100644 --- a/python/parpe/hierarchical_optimization.py +++ b/python/parpe/hierarchical_optimization.py @@ -4,10 +4,11 @@ """ from typing import Tuple, Dict, List - +import numpy as np import pandas as pd import petab.C as ptc import sympy as sp +from numbers import Number from numpy import isnan from petab import split_parameter_replacement_list @@ -137,6 +138,24 @@ def get_candidates_for_hierarchical( raise RuntimeError( f"Determined {x} as candidate for both scaling and sigma.") + # TODO Can't use hierarchical optimization with non-normal or + # transformation yet + if (offset_candidates or scaling_candidates or sigma_candidates): + not_normal = ptc.NOISE_DISTRIBUTION in observable_df \ + and not np.all(x == ptc.NORMAL + or (isinstance(x, Number) and np.isnan(x)) + for x + in observable_df[ptc.NOISE_DISTRIBUTION]) + not_lin = ptc.OBSERVABLE_TRANSFORMATION in observable_df \ + and not np.all(x == ptc.LIN + or (isinstance(x, Number) and np.isnan(x)) + for x in observable_df[ + ptc.OBSERVABLE_TRANSFORMATION]) + if not_normal or not_lin: + raise ValueError("Can't use hierarchical optimization with " + "non-normal noise or observable transformation " + "yet.") + return (list(offset_candidates), list(scaling_candidates), list(sigma_candidates)) @@ -185,7 +204,8 @@ def _get_overrides(): sim_cond_idx = \ condition_id_to_index[row.simulationConditionId] preeq_cond_idx = no_preeq_condition_idx - if not isnan(row.preequilibrationConditionId): + if not (isinstance(row.preequilibrationConditionId, Number) + and isnan(row.preequilibrationConditionId)): preeq_cond_idx = condition_id_to_index[ row.preequilibrationConditionId] diff --git a/python/parpe/misc.py b/python/parpe/misc.py index c221f2ec6..fa51b8f1f 100644 --- a/python/parpe/misc.py +++ b/python/parpe/misc.py @@ -337,7 +337,8 @@ def simulation_to_df(mes_df, sim, result_file, start, observable_ids, (condition_names[preeq_idx] if not np.isnan( preeq_idx) and preeq_idx >= 0 else -1.0, condition_names[sim_idx] if sim_idx >= 0 else -1.0): comb_idx - for comb_idx, (preeq_idx, sim_idx) in enumerate(simulation_conditions)} + for comb_idx, (preeq_idx, sim_idx, _) in enumerate( + simulation_conditions)} obs_id_to_idx = {id_: idx for idx, id_ in enumerate(observable_ids)} mes_df[MEASUREMENT] = np.nan diff --git a/python/setup.py b/python/setup.py index f9346cff5..0fc99516c 100644 --- a/python/setup.py +++ b/python/setup.py @@ -18,7 +18,7 @@ 'termcolor>=1.1.0', 'colorama>=0.4.3', 'petab>=0.1.7', - 'amici>=0.10.21', + 'amici>=0.11.2', 'h5py>=2.10.0', 'python-libsbml>=5.17.0', 'jinja2>=2.11.1', diff --git a/sonar-project.properties b/sonar-project.properties index 89d52c279..b58b6ab19 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -11,8 +11,11 @@ sonar.projectKey=ICB-DCM_parPE sonar.sources=. sonar.exclusions=build/**,ThirdParty/**,deps/** -sonar.cfamily.threads=2 sonar.sourceEncoding=UTF-8 +sonar.cfamily.threads=2 sonar.cfamily.gcov.reportsPath=build/Testing/CoverageInfo/ +sonar.cfamily.cache.enabled=true +sonar.cfamily.cache.path=sonar_cache + sonar.python.coverage.reportPaths=build/coverage_py.xml diff --git a/src/parpeamici/CMakeLists.txt b/src/parpeamici/CMakeLists.txt index df0a8b0e5..dd50e3820 100644 --- a/src/parpeamici/CMakeLists.txt +++ b/src/parpeamici/CMakeLists.txt @@ -1,6 +1,8 @@ +# dependency: AMICI find_package(Amici HINTS ${CMAKE_SOURCE_DIR}/deps/AMICI/build) +# dependecy: BOOST if(CMAKE_BUILD_TYPE MATCHES Release) set(Boost_USE_STATIC_LIBS TRUE) else() @@ -9,18 +11,19 @@ else() endif() find_package(Boost COMPONENTS serialization REQUIRED) + project(parpeamici) set(SRC_LIST multiConditionDataProvider.cpp multiConditionProblem.cpp - steadystateSimulator.cpp optimizationApplication.cpp amiciSimulationRunner.cpp simulationResultWriter.cpp standaloneSimulator.cpp amiciMisc.cpp hierarchicalOptimization.cpp + hierarchicalOptimizationAnalyticalParameterProvider.cpp ) add_library(${PROJECT_NAME} ${SRC_LIST}) @@ -38,6 +41,10 @@ target_link_libraries(${PROJECT_NAME} PUBLIC ${Boost_SERIALIZATION_LIBRARY_RELEASE} ) +if (${OpenMP_FOUND}) + target_link_libraries(${PROJECT_NAME} INTERFACE OpenMP::OpenMP_CXX) +endif() + install(TARGETS ${PROJECT_NAME} EXPORT ParPETargets LIBRARY DESTINATION lib ARCHIVE DESTINATION lib diff --git a/src/parpeamici/amiciSimulationRunner.cpp b/src/parpeamici/amiciSimulationRunner.cpp index 5b98871ac..ab71e7e45 100644 --- a/src/parpeamici/amiciSimulationRunner.cpp +++ b/src/parpeamici/amiciSimulationRunner.cpp @@ -12,23 +12,25 @@ namespace parpe { -AmiciSimulationRunner::AmiciSimulationRunner(std::vector const& optimizationParameters, - amici::SensitivityOrder sensitivityOrder, - std::vector const& conditionIndices, - AmiciSimulationRunner::callbackJobFinishedType callbackJobFinished, - AmiciSimulationRunner::callbackAllFinishedType aggregate, std::string logPrefix) - : optimizationParameters(optimizationParameters), - sensitivityOrder(sensitivityOrder), - conditionIndices(conditionIndices), - callbackJobFinished(std::move(std::move(callbackJobFinished))), - aggregate(std::move(std::move(aggregate))), - logPrefix(std::move(logPrefix)) -{ - -} +AmiciSimulationRunner::AmiciSimulationRunner( + std::vector const& optimizationParameters, + amici::SensitivityOrder sensitivityOrder, + std::vector const& conditionIndices, + AmiciSimulationRunner::callbackJobFinishedType callbackJobFinished, + AmiciSimulationRunner::callbackAllFinishedType aggregate, + std::string logPrefix) + : optimization_parameters_(optimizationParameters) + , sensitivity_order_(sensitivityOrder) + , condition_indices_(conditionIndices) + , callback_job_finished_(std::move(std::move(callbackJobFinished))) + , aggregate_(std::move(std::move(aggregate))) + , log_prefix_(std::move(logPrefix)) +{} #ifdef PARPE_ENABLE_MPI -int AmiciSimulationRunner::runDistributedMemory(LoadBalancerMaster *loadBalancer, const int maxSimulationsPerPackage) +int +AmiciSimulationRunner::runDistributedMemory(LoadBalancerMaster* loadBalancer, + const int maxSimulationsPerPackage) { #ifdef PARPE_SIMULATION_RUNNER_DEBUG printf("runDistributedMemory\n"); @@ -40,24 +42,33 @@ int AmiciSimulationRunner::runDistributedMemory(LoadBalancerMaster *loadBalancer // multiple simulations may be grouped into one work package auto numJobsTotal = static_cast( - std::ceil( - static_cast(conditionIndices.size()) - / maxSimulationsPerPackage)); - std::vector jobs {static_cast(numJobsTotal)}; + std::ceil(static_cast(condition_indices_.size()) / + maxSimulationsPerPackage)); + std::vector jobs{ static_cast( + numJobsTotal) }; int numJobsFinished = 0; int numConditionsSent = 0; // prepare and queue work package for (int jobIdx = 0; jobIdx < numJobsTotal; ++jobIdx) { - int simulationsLeft = static_cast(conditionIndices.size()) - numConditionsSent; - int simulationsCurrentPackage = std::min(simulationsLeft, maxSimulationsPerPackage); + int simulationsLeft = + static_cast(condition_indices_.size()) - numConditionsSent; + int simulationsCurrentPackage = + std::min(simulationsLeft, maxSimulationsPerPackage); auto currentConditions = std::vector( - &conditionIndices[static_cast::size_type>(numConditionsSent)], - &conditionIndices[numConditionsSent + simulationsCurrentPackage]); - queueSimulation(loadBalancer, &jobs[jobIdx], - &numJobsFinished, &simulationsCond, &simulationsMutex, - jobIdx, optimizationParameters, sensitivityOrder, currentConditions); + &condition_indices_[static_cast::size_type>( + numConditionsSent)], + &condition_indices_[numConditionsSent + simulationsCurrentPackage]); + queueSimulation(loadBalancer, + &jobs[jobIdx], + &numJobsFinished, + &simulationsCond, + &simulationsMutex, + jobIdx, + optimization_parameters_, + sensitivity_order_, + currentConditions); numConditionsSent += simulationsCurrentPackage; // printf("Queued work: "); printDatapath(path); @@ -74,88 +85,109 @@ int AmiciSimulationRunner::runDistributedMemory(LoadBalancerMaster *loadBalancer pthread_cond_destroy(&simulationsCond); // unpack - if(aggregate) - errors += aggregate(jobs); + if (aggregate_) + errors_ += aggregate_(jobs); - return errors; + return errors_; } #endif -int AmiciSimulationRunner::runSharedMemory(const messageHandlerFunc& messageHandler, bool sequential) +int +AmiciSimulationRunner::runSharedMemory(const messageHandlerFunc& messageHandler, + bool sequential) { #ifdef PARPE_SIMULATION_RUNNER_DEBUG printf("runSharedMemory\n"); #endif - std::vector jobs {static_cast(conditionIndices.size())}; + std::vector jobs{ static_cast( + condition_indices_.size()) }; #if defined(_OPENMP) - if(sequential) + if (sequential) omp_set_num_threads(1); - #pragma omp parallel for +#pragma omp parallel for #endif - for (int simulationIdx = 0; simulationIdx < (signed)conditionIndices.size(); ++simulationIdx) { - // to resuse the parallel code and for debugging we still serialze the job data here - auto curConditionIndices = std::vector {simulationIdx}; - AmiciWorkPackageSimple work {optimizationParameters, sensitivityOrder, curConditionIndices, logPrefix}; + for (int simulationIdx = 0; + simulationIdx < (signed)condition_indices_.size(); + ++simulationIdx) { + // to reuse the parallel code and for debugging we still serialze the + // job data here + auto curConditionIndices = std::vector{ simulationIdx }; + AmiciWorkPackageSimple work{ optimization_parameters_, + sensitivity_order_, + curConditionIndices, + log_prefix_ }; auto buffer = amici::serializeToStdVec(work); messageHandler(buffer, simulationIdx); jobs[simulationIdx].recvBuffer = buffer; - if(callbackJobFinished) - callbackJobFinished(&jobs[simulationIdx], simulationIdx); + if (callback_job_finished_) + callback_job_finished_(&jobs[simulationIdx], simulationIdx); } // unpack - if(aggregate) - errors = aggregate(jobs); - - return errors; + if (aggregate_) + errors_ = aggregate_(jobs); + return errors_; } #ifdef PARPE_ENABLE_MPI -void AmiciSimulationRunner::queueSimulation(LoadBalancerMaster *loadBalancer, - JobData *d, int *jobDone, - pthread_cond_t *jobDoneChangedCondition, pthread_mutex_t *jobDoneChangedMutex, int jobIdx, - std::vector const& optimizationParameters, - amici::SensitivityOrder sensitivityOrder, - std::vector const& conditionIndices) +void +AmiciSimulationRunner::queueSimulation( + LoadBalancerMaster* loadBalancer, + JobData* d, + int* jobDone, + pthread_cond_t* jobDoneChangedCondition, + pthread_mutex_t* jobDoneChangedMutex, + int jobIdx, + std::vector const& optimizationParameters, + amici::SensitivityOrder sensitivityOrder, + std::vector const& conditionIndices) { - // TODO avoid copy optimizationParameters; reuse;; for const& in work package need to split into(de)serialize + // TODO avoid copy optimizationParameters; reuse;; for const& in work + // package need to split into(de)serialize *d = JobData(jobDone, jobDoneChangedCondition, jobDoneChangedMutex); - AmiciWorkPackageSimple work {optimizationParameters, sensitivityOrder, conditionIndices, logPrefix}; + AmiciWorkPackageSimple work{ + optimizationParameters, sensitivityOrder, conditionIndices, log_prefix_ + }; d->sendBuffer = amici::serializeToStdVec(work); // TODO: must ignore 2nd argument for SimulationRunnerSimple - if(callbackJobFinished) - d->callbackJobFinished = std::bind2nd(callbackJobFinished, jobIdx); + if (callback_job_finished_) + d->callbackJobFinished = std::bind2nd(callback_job_finished_, jobIdx); loadBalancer->queueJob(d); - } #endif -void swap(AmiciSimulationRunner::AmiciResultPackageSimple &first, AmiciSimulationRunner::AmiciResultPackageSimple &second) { +void +swap(AmiciSimulationRunner::AmiciResultPackageSimple& first, + AmiciSimulationRunner::AmiciResultPackageSimple& second) noexcept +{ using std::swap; swap(first.llh, second.llh); swap(first.simulationTimeSeconds, second.simulationTimeSeconds); swap(first.gradient, second.gradient); swap(first.modelOutput, second.modelOutput); swap(first.modelStates, second.modelStates); + swap(first.modelSigmas, second.modelSigmas); swap(first.status, second.status); } -bool operator==(const AmiciSimulationRunner::AmiciResultPackageSimple &lhs, const AmiciSimulationRunner::AmiciResultPackageSimple &rhs) { - return lhs.llh == rhs.llh - && lhs.status == rhs.status - && lhs.gradient == rhs.gradient - && lhs.modelOutput == rhs.modelOutput - && lhs.modelStates == rhs.modelStates - && lhs.simulationTimeSeconds == rhs.simulationTimeSeconds; +bool +operator==(const AmiciSimulationRunner::AmiciResultPackageSimple& lhs, + const AmiciSimulationRunner::AmiciResultPackageSimple& rhs) +{ + return lhs.llh == rhs.llh && lhs.status == rhs.status && + lhs.gradient == rhs.gradient && lhs.modelOutput == rhs.modelOutput && + lhs.modelStates == rhs.modelStates && + lhs.modelSigmas == rhs.modelSigmas && + lhs.simulationTimeSeconds == rhs.simulationTimeSeconds; } } // namespace parpe diff --git a/src/parpeamici/hierarchicalOptimization.cpp b/src/parpeamici/hierarchicalOptimization.cpp index 2bd4f56a4..67d2eae1f 100644 --- a/src/parpeamici/hierarchicalOptimization.cpp +++ b/src/parpeamici/hierarchicalOptimization.cpp @@ -1,13 +1,14 @@ #include -#include +#include #include +#include #include #include -#include -#include +#include #include +#include #ifndef __cpp_constexpr // constexpr did not work on icc (ICC) 16.0.4 20160811 @@ -17,73 +18,74 @@ namespace parpe { HierarchicalOptimizationWrapper::HierarchicalOptimizationWrapper( - std::unique_ptr fun, - int numConditions, - int numObservables) - : fun(std::move(fun)), - numConditions(numConditions), - numObservables(numObservables) + AmiciSummedGradientFunction* wrapped_function, + int numConditions, + int numObservables) + : wrapped_function_(wrapped_function) + , numConditions(numConditions) + , numObservables(numObservables) { scalingReader = std::make_unique(); - offsetReader = std::make_unique(); - sigmaReader = std::make_unique(); + offsetReader = std::make_unique(); + sigmaReader = std::make_unique(); - if(fun) + if (wrapped_function) init(); } - HierarchicalOptimizationWrapper::HierarchicalOptimizationWrapper( - std::unique_ptr fun, - H5::H5File const& file, - std::string const& hdf5RootPath, - int numConditions, int numObservables, - ErrorModel errorModel) - : fun(std::move(fun)), - numConditions(numConditions), - numObservables(numObservables), - errorModel(errorModel) + AmiciSummedGradientFunction* wrapped_function, + H5::H5File const& file, + std::string const& hdf5RootPath, + int numConditions, + int numObservables, + ErrorModel errorModel) + : wrapped_function_(wrapped_function) + , numConditions(numConditions) + , numObservables(numObservables) + , errorModel(errorModel) { scalingReader = std::make_unique( - file, - hdf5RootPath + "/scalingParameterIndices", - hdf5RootPath + "/scalingParametersMapToObservables"); + file, + hdf5RootPath + "/scalingParameterIndices", + hdf5RootPath + "/scalingParametersMapToObservables"); offsetReader = std::make_unique( - file, - hdf5RootPath + "/offsetParameterIndices", - hdf5RootPath + "/offsetParametersMapToObservables"); + file, + hdf5RootPath + "/offsetParameterIndices", + hdf5RootPath + "/offsetParametersMapToObservables"); sigmaReader = std::make_unique( - file, - hdf5RootPath + "/sigmaParameterIndices", - hdf5RootPath + "/sigmaParametersMapToObservables"); + file, + hdf5RootPath + "/sigmaParameterIndices", + hdf5RootPath + "/sigmaParametersMapToObservables"); init(); } - HierarchicalOptimizationWrapper::HierarchicalOptimizationWrapper( - std::unique_ptr fun, - std::unique_ptr scalingReader, - std::unique_ptr offsetReader, - std::unique_ptr sigmaReader, - int numConditions, int numObservables, - ErrorModel errorModel) - : fun(std::move(fun)), - scalingReader(std::move(scalingReader)), - offsetReader(std::move(offsetReader)), - sigmaReader(std::move(sigmaReader)), - numConditions(numConditions), - numObservables(numObservables), - errorModel(errorModel) + AmiciSummedGradientFunction* wrapped_function, + std::unique_ptr scalingReader, + std::unique_ptr offsetReader, + std::unique_ptr sigmaReader, + int numConditions, + int numObservables, + ErrorModel errorModel) + : wrapped_function_(wrapped_function) + , scalingReader(std::move(scalingReader)) + , offsetReader(std::move(offsetReader)) + , sigmaReader(std::move(sigmaReader)) + , numConditions(numConditions) + , numObservables(numObservables) + , errorModel(errorModel) { init(); } - -void HierarchicalOptimizationWrapper::init() { - if(errorModel != ErrorModel::normal) { +void +HierarchicalOptimizationWrapper::init() +{ + if (errorModel != ErrorModel::normal) { throw ParPEException("Only gaussian noise is supported so far."); } @@ -91,184 +93,195 @@ void HierarchicalOptimizationWrapper::init() { * ensure sorting right away (if sorting here, also need to reorder/reindex * scalingFactorIdx in mapping table -> difficult) */ proportionalityFactorIndices = - this->scalingReader->getOptimizationParameterIndices(); - RELEASE_ASSERT( - std::is_sorted(this->proportionalityFactorIndices.begin(), - this->proportionalityFactorIndices.end()), ""); + this->scalingReader->getOptimizationParameterIndices(); + Expects(std::is_sorted(this->proportionalityFactorIndices.begin(), + this->proportionalityFactorIndices.end())); offsetParameterIndices = - this->offsetReader->getOptimizationParameterIndices(); - RELEASE_ASSERT( - std::is_sorted(this->offsetParameterIndices.begin(), - this->offsetParameterIndices.end()), ""); + this->offsetReader->getOptimizationParameterIndices(); + Expects(std::is_sorted(this->offsetParameterIndices.begin(), + this->offsetParameterIndices.end())); sigmaParameterIndices = - this->sigmaReader->getOptimizationParameterIndices(); - RELEASE_ASSERT(std::is_sorted(this->sigmaParameterIndices.begin(), - this->sigmaParameterIndices.end()), ""); + this->sigmaReader->getOptimizationParameterIndices(); + Expects(std::is_sorted(this->sigmaParameterIndices.begin(), + this->sigmaParameterIndices.end())); - if(fun) { + if (wrapped_function_) { std::stringstream ss; - ss<<"HierarchicalOptimizationWrapper parameters: " - <numParameters()<<" total, " - <numParameters() << " total, " << numParameters() + << " numerical, " << proportionalityFactorIndices.size() + << " proportionality, " << offsetParameterIndices.size() + << " offset, " << sigmaParameterIndices.size() << " sigma\n"; Logger logger; logger.logmessage(LOGLVL_DEBUG, ss.str()); } } - -FunctionEvaluationStatus HierarchicalOptimizationWrapper::evaluate( - gsl::span parameters, - double &fval, - gsl::span gradient, - Logger *logger, - double *cpuTime) const { +FunctionEvaluationStatus +HierarchicalOptimizationWrapper::evaluate(gsl::span parameters, + double& fval, + gsl::span gradient, + Logger* logger, + double* cpuTime) const +{ std::vector fullParameters; std::vector fullGradient; - return evaluate(parameters, fval, gradient, fullParameters, - fullGradient, logger, cpuTime); + return evaluate(parameters, + fval, + gradient, + fullParameters, + fullGradient, + logger, + cpuTime); } FunctionEvaluationStatus HierarchicalOptimizationWrapper::evaluate( - gsl::span reducedParameters, - double &fval, - gsl::span gradient, - std::vector &fullParameters, - std::vector &fullGradient, Logger *logger, double *cpuTime) const + gsl::span reducedParameters, + double& fval, + gsl::span gradient, + std::vector& fullParameters, + std::vector& fullGradient, + Logger* logger, + double* cpuTime) const { WallTimer walltimer; FunctionEvaluationStatus status; - if(reducedParameters.size() != (unsigned)numParameters()) { - throw ParPEException("Reduced parameter vector size " - + std::to_string(reducedParameters.size()) - + " does not match numParameters " - + std::to_string(numParameters())); + if (reducedParameters.size() != (unsigned)numParameters()) { + throw ParPEException("Reduced parameter vector size " + + std::to_string(reducedParameters.size()) + + " does not match numParameters " + + std::to_string(numParameters())); } - RELEASE_ASSERT(gradient.empty() - || gradient.size() == reducedParameters.size(), ""); + Expects(gradient.empty() || gradient.size() == reducedParameters.size()); - if(numProportionalityFactors() == 0 - && numOffsetParameters() == 0 - && numSigmaParameters() == 0) { - // nothing to do, just pass through + if (numProportionalityFactors() == 0 && numOffsetParameters() == 0 && + numSigmaParameters() == 0) { + // nothing to do, only fill parameters / gradient and pass through + fullParameters.assign(reducedParameters.begin(), + reducedParameters.end()); + fullGradient.assign(gradient.begin(), gradient.end()); // evaluate for all conditions std::vector dataIndices(numConditions); std::iota(dataIndices.begin(), dataIndices.end(), 0); - return fun->evaluate(reducedParameters, dataIndices, - fval, gradient, logger, cpuTime); + return wrapped_function_->evaluate( + reducedParameters, dataIndices, fval, gradient, logger, cpuTime); } - // evaluate with scaling parameters set to 1 and offsets to 0 - std::vector > modelOutput; + std::vector> modelOutputs; + std::vector> modelSigmas; try { - modelOutput = getUnscaledModelOutputs(reducedParameters, logger, cpuTime); - } catch (ParPEException const &e) { + std::tie(modelOutputs, modelSigmas) = + getUnscaledModelOutputsAndSigmas(reducedParameters, logger, cpuTime); + } catch (ParPEException const& e) { return FunctionEvaluationStatus::functionEvaluationFailure; } - auto measurements = fun->getAllMeasurements(); + auto measurements = wrapped_function_->getAllMeasurements(); // compute correct scaling factors analytically - auto scalings = computeAnalyticalScalings(measurements, modelOutput); + auto scalings = computeAnalyticalScalings(measurements, modelOutputs); // compute correct offset parameters analytically - auto offsets = computeAnalyticalOffsets(measurements, modelOutput); + auto offsets = computeAnalyticalOffsets(measurements, modelOutputs); // std::cout << "offsets:" << offsets; // Scale model outputs - applyOptimalScalings(scalings, modelOutput); - applyOptimalOffsets(offsets, modelOutput); + applyOptimalScalings(scalings, modelOutputs); + applyOptimalOffsets(offsets, modelOutputs); // needs scaled outputs - auto sigmas = computeAnalyticalSigmas(measurements, modelOutput); + auto sigmas = computeAnalyticalSigmas(measurements, modelOutputs); - if(logger) { + if (logger) { std::stringstream ss; - ss<<"scalings "<logmessage(LOGLVL_DEBUG, ss.str()); ss.str(std::string()); - ss<<"sigmas "<logmessage(LOGLVL_DEBUG, ss.str()); } // splice parameter vector we get from optimizer with analytically // computed parameters - fullParameters = spliceParameters( - reducedParameters, proportionalityFactorIndices, - offsetParameterIndices, sigmaParameterIndices, - scalings, offsets, sigmas); - + fullParameters = spliceParameters(reducedParameters, + proportionalityFactorIndices, + offsetParameterIndices, + sigmaParameterIndices, + scalings, + offsets, + sigmas); // evaluate with analytical scaling parameters double cpuTimeInner = 0.0; - status = evaluateWithOptimalParameters(fullParameters, sigmas, - measurements, modelOutput, - fval, gradient, - fullGradient, logger, &cpuTimeInner); - - if(cpuTime) + status = evaluateWithOptimalParameters(fullParameters, + sigmas, + measurements, + modelOutputs, + modelSigmas, + fval, + gradient, + fullGradient, + logger, + &cpuTimeInner); + + if (cpuTime) *cpuTime += cpuTimeInner + walltimer.getTotal(); return status; } - std::vector HierarchicalOptimizationWrapper::getDefaultScalingFactors() const { auto result = std::vector(numProportionalityFactors()); - for(int i = 0; i < numProportionalityFactors(); ++i) { + for (int i = 0; i < numProportionalityFactors(); ++i) { result[i] = getDefaultScalingFactor( - fun->getParameterScaling(proportionalityFactorIndices[i])); + wrapped_function_->getParameterScaling(proportionalityFactorIndices[i])); } return result; } - std::vector HierarchicalOptimizationWrapper::getDefaultOffsetParameters() const { auto result = std::vector(numOffsetParameters()); - for(int i = 0; i < numOffsetParameters(); ++i) { + for (int i = 0; i < numOffsetParameters(); ++i) { result[i] = getDefaultOffsetParameter( - fun->getParameterScaling(offsetParameterIndices[i])); + wrapped_function_->getParameterScaling(offsetParameterIndices[i])); } return result; } - std::vector HierarchicalOptimizationWrapper::getDefaultSigmaParameters() const { auto result = std::vector(numSigmaParameters()); - for(int i = 0; i < numSigmaParameters(); ++i) { + for (int i = 0; i < numSigmaParameters(); ++i) { // default sigma is the same as default scaling result[i] = getDefaultScalingFactor( - fun->getParameterScaling(sigmaParameterIndices[i])); + wrapped_function_->getParameterScaling(sigmaParameterIndices[i])); } return result; - } -std::vector > -HierarchicalOptimizationWrapper::getUnscaledModelOutputs( - const gsl::span reducedParameters, Logger *logger, - double *cpuTime) const +std::tuple>,std::vector>> +HierarchicalOptimizationWrapper::getUnscaledModelOutputsAndSigmas( + const gsl::span reducedParameters, + Logger* logger, + double* cpuTime) const { // run simulations, collect outputs auto scalingDummy = getDefaultScalingFactors(); @@ -276,164 +289,172 @@ HierarchicalOptimizationWrapper::getUnscaledModelOutputs( auto sigmaDummy = getDefaultSigmaParameters(); // splice hidden scaling parameter and external parameters - auto fullParameters = spliceParameters( - reducedParameters, proportionalityFactorIndices, - offsetParameterIndices, sigmaParameterIndices, - scalingDummy, offsetDummy, sigmaDummy); - - std::vector > modelOutput(numConditions); - auto status = fun->getModelOutputs(fullParameters, modelOutput, - logger, cpuTime); - if(status != FunctionEvaluationStatus::functionEvaluationSuccess) + auto fullParameters = spliceParameters(reducedParameters, + proportionalityFactorIndices, + offsetParameterIndices, + sigmaParameterIndices, + scalingDummy, + offsetDummy, + sigmaDummy); + + std::vector> modelOutputs(numConditions); + std::vector> modelSigmas(numConditions); + auto status = + wrapped_function_->getModelOutputsAndSigmas(fullParameters, modelOutputs, + modelSigmas, logger, cpuTime); + if (status != FunctionEvaluationStatus::functionEvaluationSuccess) throw ParPEException("Function evaluation failed."); - return modelOutput; + return std::make_tuple(modelOutputs, modelSigmas); } -std::vector HierarchicalOptimizationWrapper::computeAnalyticalScalings( - std::vector> const& measurements, - std::vector> const& modelOutputsUnscaled) const +std::vector +HierarchicalOptimizationWrapper::computeAnalyticalScalings( + std::vector> const& measurements, + std::vector> const& modelOutputsUnscaled) const { int numProportionalityFactors = proportionalityFactorIndices.size(); std::vector proportionalityFactors(numProportionalityFactors); - for(int scalingIdx = 0; scalingIdx < numProportionalityFactors; - ++scalingIdx) { - - auto proportionalityFactor = parpe::computeAnalyticalScalings( - scalingIdx, modelOutputsUnscaled, measurements, - *scalingReader, numObservables); - auto scale = fun->getParameterScaling( - proportionalityFactorIndices[scalingIdx]); + for (int scalingIdx = 0; scalingIdx < numProportionalityFactors; + ++scalingIdx) { + + auto proportionalityFactor = + parpe::computeAnalyticalScalings(scalingIdx, + modelOutputsUnscaled, + measurements, + *scalingReader, + numObservables); + auto scale = + wrapped_function_->getParameterScaling(proportionalityFactorIndices[scalingIdx]); proportionalityFactors[scalingIdx] = - getScaledParameter(proportionalityFactor, scale); + getScaledParameter(proportionalityFactor, scale); } return proportionalityFactors; } -void HierarchicalOptimizationWrapper::applyOptimalScalings( - std::vector const& proportionalityFactors, - std::vector > &modelOutputs) const { +void +HierarchicalOptimizationWrapper::applyOptimalScalings( + std::vector const& proportionalityFactors, + std::vector>& modelOutputs) const +{ - for(int i = 0; (unsigned) i < proportionalityFactors.size(); ++i) { + for (int i = 0; (unsigned)i < proportionalityFactors.size(); ++i) { double scaling = getUnscaledParameter( - proportionalityFactors[i], - fun->getParameterScaling(proportionalityFactorIndices[i])); + proportionalityFactors[i], + wrapped_function_->getParameterScaling(proportionalityFactorIndices[i])); - applyOptimalScaling(i, scaling, modelOutputs, - *scalingReader, numObservables); + applyOptimalScaling( + i, scaling, modelOutputs, *scalingReader, numObservables); } } - -std::vector HierarchicalOptimizationWrapper::computeAnalyticalOffsets( - std::vector> const& measurements, - std::vector > &modelOutputsUnscaled) const +std::vector +HierarchicalOptimizationWrapper::computeAnalyticalOffsets( + std::vector> const& measurements, + std::vector>& modelOutputsUnscaled) const { int numOffsetParameters = offsetParameterIndices.size(); std::vector offsetParameters(numOffsetParameters); - for(int i = 0; i < numOffsetParameters; ++i) { + for (int i = 0; i < numOffsetParameters; ++i) { auto offsetParameter = parpe::computeAnalyticalOffsets( - i, modelOutputsUnscaled, measurements, - *offsetReader, numObservables); - auto scale = fun->getParameterScaling(offsetParameterIndices[i]); + i, modelOutputsUnscaled, measurements, *offsetReader, numObservables); + auto scale = wrapped_function_->getParameterScaling(offsetParameterIndices[i]); offsetParameters[i] = getScaledParameter(offsetParameter, scale); } return offsetParameters; } -std::vector HierarchicalOptimizationWrapper::computeAnalyticalSigmas( - const std::vector > &measurements, - std::vector > const &modelOutputsScaled) const +std::vector +HierarchicalOptimizationWrapper::computeAnalyticalSigmas( + const std::vector>& measurements, + std::vector> const& modelOutputsScaled) const { int numSigmas = sigmaParameterIndices.size(); std::vector sigmas(numSigmas); - for(int i = 0; i < numSigmas; ++i) { + for (int i = 0; i < numSigmas; ++i) { auto sigma = parpe::computeAnalyticalSigmas( - i, - modelOutputsScaled, measurements, - *sigmaReader, numObservables); - auto scale = fun->getParameterScaling(sigmaParameterIndices[i]); + i, modelOutputsScaled, measurements, *sigmaReader, numObservables); + auto scale = wrapped_function_->getParameterScaling(sigmaParameterIndices[i]); sigmas[i] = getScaledParameter(sigma, scale); } return sigmas; } -void HierarchicalOptimizationWrapper::applyOptimalOffsets( - std::vector const& offsetParameters, - std::vector > &modelOutputs) const { +void +HierarchicalOptimizationWrapper::applyOptimalOffsets( + std::vector const& offsetParameters, + std::vector>& modelOutputs) const +{ - for(int i = 0; (unsigned) i < offsetParameters.size(); ++i) { + for (int i = 0; (unsigned)i < offsetParameters.size(); ++i) { double offset = getUnscaledParameter( - offsetParameters[i], - fun->getParameterScaling(offsetParameterIndices[i])); - applyOptimalOffset(i, offset, modelOutputs, - *offsetReader, numObservables); + offsetParameters[i], + wrapped_function_->getParameterScaling(offsetParameterIndices[i])); + applyOptimalOffset( + i, offset, modelOutputs, *offsetReader, numObservables); } } -void HierarchicalOptimizationWrapper::fillInAnalyticalSigmas( - std::vector > &allSigmas, - std::vector const& analyticalSigmas) const +void +HierarchicalOptimizationWrapper::fillInAnalyticalSigmas( + std::vector>& allSigmas, + std::vector const& analyticalSigmas) const { - for(int sigmaParameterIdx = 0; - (unsigned) sigmaParameterIdx < analyticalSigmas.size(); - ++sigmaParameterIdx) { + for (int sigmaParameterIdx = 0; + (unsigned)sigmaParameterIdx < analyticalSigmas.size(); + ++sigmaParameterIdx) { // sigma value will be used for likelihood computation // and not passed to AMICI -> unscale auto sigmaParameterValue = getUnscaledParameter( - analyticalSigmas[sigmaParameterIdx], - fun->getParameterScaling( - sigmaParameterIndices[sigmaParameterIdx])); + analyticalSigmas[sigmaParameterIdx], + wrapped_function_->getParameterScaling(sigmaParameterIndices[sigmaParameterIdx])); auto dependentConditions = - sigmaReader->getConditionsForParameter(sigmaParameterIdx); + sigmaReader->getConditionsForParameter(sigmaParameterIdx); - for (auto const conditionIdx: dependentConditions) { + for (auto const conditionIdx : dependentConditions) { int numTimepoints = allSigmas[conditionIdx].size() / numObservables; - auto dependentObservables = - sigmaReader->getObservablesForParameter( - sigmaParameterIdx, conditionIdx); + auto dependentObservables = sigmaReader->getObservablesForParameter( + sigmaParameterIdx, conditionIdx); - for(auto const observableIdx: dependentObservables) { + for (auto const observableIdx : dependentObservables) { - RELEASE_ASSERT(observableIdx < numObservables, ""); + Expects(observableIdx < numObservables); - for(int timeIdx = 0; timeIdx < numTimepoints; ++timeIdx) { + for (int timeIdx = 0; timeIdx < numTimepoints; ++timeIdx) { // NOTE: this must be in sync with data ordering in AMICI // (assumes row-major) - RELEASE_ASSERT( - std::isnan( - allSigmas[conditionIdx][observableIdx + timeIdx * numObservables]), - "Expected NaN value for sigma parameters being " - "estimated, but got non-NAN."); - allSigmas[conditionIdx][observableIdx + timeIdx * numObservables] = sigmaParameterValue; + int flat_index = observableIdx + timeIdx * numObservables; + allSigmas[conditionIdx][flat_index] = sigmaParameterValue; } } } } } - FunctionEvaluationStatus HierarchicalOptimizationWrapper::evaluateWithOptimalParameters( - std::vector const& fullParameters, - std::vector const& sigmas, - std::vector> const& measurements, - std::vector> const& modelOutputsScaled, - double &fval, - const gsl::span gradient, - std::vector& fullGradient, - Logger *logger, double *cpuTime) const { - - if(!gradient.empty()) { + std::vector const& fullParameters, + std::vector const& sigmas, + std::vector> const& measurements, + std::vector> const& modelOutputsScaled, + std::vector> & fullSigmaMatrices, + double& fval, + const gsl::span gradient, + std::vector& fullGradient, + Logger* logger, + double* cpuTime) const +{ + + if (!gradient.empty()) { fval = NAN; // simulate with updated theta for sensitivities // simulate all datasets @@ -443,9 +464,9 @@ HierarchicalOptimizationWrapper::evaluateWithOptimalParameters( // Need intermediary buffer because optimizer expects // fewer parameters than `fun` delivers fullGradient.resize(fullParameters.size()); - auto status = fun->evaluate(fullParameters, dataIndices, fval, - fullGradient, logger, cpuTime); - if(status != functionEvaluationSuccess) + auto status = wrapped_function_->evaluate( + fullParameters, dataIndices, fval, fullGradient, logger, cpuTime); + if (status != functionEvaluationSuccess) return status; // Filter gradient for those parameters expected by the optimizer @@ -454,75 +475,65 @@ HierarchicalOptimizationWrapper::evaluateWithOptimalParameters( // Check if gradient w.r.t. analytical parameters is 0 checkGradientForAnalyticalParameters( - fullGradient, analyticalParameterIndices, 1e-8); + fullGradient, analyticalParameterIndices, 1e-8); } else { - auto fullSigmaMatrices = fun->getAllSigmas(); - if(!sigmaParameterIndices.empty()) { + if (!sigmaParameterIndices.empty()) { fillInAnalyticalSigmas(fullSigmaMatrices, sigmas); } // ... to compute negative log-likelihood - fval = computeNegLogLikelihood(measurements, modelOutputsScaled, - fullSigmaMatrices); + fval = computeNegLogLikelihood( + measurements, modelOutputsScaled, fullSigmaMatrices); } - return std::isfinite(fval) ? - functionEvaluationSuccess : functionEvaluationFailure; + return std::isfinite(fval) ? functionEvaluationSuccess + : functionEvaluationFailure; } - -int HierarchicalOptimizationWrapper::numParameters() const { - return fun->numParameters() - numProportionalityFactors() - - numOffsetParameters() - numSigmaParameters(); +int +HierarchicalOptimizationWrapper::numParameters() const +{ + return wrapped_function_->numParameters() - numProportionalityFactors() - + numOffsetParameters() - numSigmaParameters(); } -int HierarchicalOptimizationWrapper::numProportionalityFactors() const { +int +HierarchicalOptimizationWrapper::numProportionalityFactors() const +{ return proportionalityFactorIndices.size(); } -const std::vector & +const std::vector& HierarchicalOptimizationWrapper::getProportionalityFactorIndices() const { return proportionalityFactorIndices; } - -AnalyticalParameterHdf5Reader::AnalyticalParameterHdf5Reader( - H5::H5File const& file, - std::string analyticalParameterIndicesPath, - std::string mapPath) - : mapPath(std::move(mapPath)), - analyticalParameterIndicesPath(std::move(analyticalParameterIndicesPath)) +int +HierarchicalOptimizationWrapper::numOffsetParameters() const { - auto lock = hdf5MutexGetLock(); - this->file = file; // copy while mutex is locked! - readParameterConditionObservableMappingFromFile(); -} - - -int HierarchicalOptimizationWrapper::numOffsetParameters() const { return offsetParameterIndices.size(); } -int HierarchicalOptimizationWrapper::numSigmaParameters() const +int +HierarchicalOptimizationWrapper::numSigmaParameters() const { return sigmaParameterIndices.size(); } -const std::vector & +const std::vector& HierarchicalOptimizationWrapper::getOffsetParameterIndices() const { return offsetParameterIndices; } -const std::vector & +const std::vector& HierarchicalOptimizationWrapper::getSigmaParameterIndices() const { return sigmaParameterIndices; } - std::vector HierarchicalOptimizationWrapper::getAnalyticalParameterIndices() const { @@ -538,232 +549,113 @@ HierarchicalOptimizationWrapper::getAnalyticalParameterIndices() const return combinedIndices; } - -std::vector -AnalyticalParameterHdf5Reader::getConditionsForParameter( - int parameterIndex) const { - std::vector result; - result.reserve(mapping[parameterIndex].size()); - for (auto const& kvp : mapping[parameterIndex]) - result.push_back(kvp.first); - return result; -} - - -const std::vector & -AnalyticalParameterHdf5Reader::getObservablesForParameter( - int parameterIndex, int conditionIdx) const { - return mapping[parameterIndex].at(conditionIdx); -} - - -std::vector -AnalyticalParameterHdf5Reader::getOptimizationParameterIndices() const { - auto lock = hdf5MutexGetLock(); - std::vector analyticalParameterIndices; - H5_SAVE_ERROR_HANDLER; // don't show error if dataset is missing - try { - auto dataset = file.openDataSet(analyticalParameterIndicesPath); - auto dataspace = dataset.getSpace(); - - auto ndims = dataspace.getSimpleExtentNdims(); - if(ndims != 1) - throw ParPEException( - "Invalid dimension in getOptimizationParameterIndices."); - hsize_t numScalings = 0; - dataspace.getSimpleExtentDims(&numScalings); - - analyticalParameterIndices.resize(numScalings); - dataset.read(analyticalParameterIndices.data(), - H5::PredType::NATIVE_INT); - } catch (H5::FileIException&) { - // we just return an empty list - } - H5_RESTORE_ERROR_HANDLER; - - return analyticalParameterIndices; -} - -int AnalyticalParameterHdf5Reader::getNumAnalyticalParameters() const +AmiciSummedGradientFunction *HierarchicalOptimizationWrapper::getWrappedFunction() const { - hsize_t numAnalyticalParameters = 0; - auto lock = hdf5MutexGetLock(); - - H5_SAVE_ERROR_HANDLER; // don't show error if dataset is missing - try { - auto dataset = file.openDataSet(analyticalParameterIndicesPath); - auto dataspace = dataset.getSpace(); - auto ndims = dataspace.getSimpleExtentNdims(); - if(ndims != 1) - throw ParPEException( - "Invalid dimension in getOptimizationParameterIndices."); - dataspace.getSimpleExtentDims(&numAnalyticalParameters); - } catch (H5::FileIException&) { - // 0 - } - H5_RESTORE_ERROR_HANDLER; - - return numAnalyticalParameters; + return wrapped_function_; } -void -AnalyticalParameterHdf5Reader::readParameterConditionObservableMappingFromFile() +std::vector HierarchicalOptimizationWrapper::getParameterIds() const { - auto lock = hdf5MutexGetLock(); - H5_SAVE_ERROR_HANDLER; - try { - int numScalings = getNumAnalyticalParameters(); - auto dataset = file.openDataSet(mapPath); - if(numScalings == 0) - return; - - // column indices in dataspace - constexpr int parameterCol = 0; - constexpr int conditionCol = 1; - constexpr int observableCol = 2; - - mapping.resize(numScalings); - - hsize_t nRows = 0, nCols = 0; - auto rawMap = readRawMap(dataset, nRows, nCols); - - for(int i = 0; (unsigned)i < nRows; ++i) { - int scalingIdx = rawMap[i * nCols + parameterCol]; - int conditionIdx = rawMap[i * nCols + conditionCol]; - int observableIdx = rawMap[i * nCols + observableCol]; - mapping[scalingIdx][conditionIdx].push_back(observableIdx); - } - } catch (H5::FileIException&) { - return; - } - H5_RESTORE_ERROR_HANDLER; - -} - -std::vector AnalyticalParameterHdf5Reader::readRawMap( - H5::DataSet& dataset, hsize_t& nRows, hsize_t& nCols) -{ - auto dataspace = dataset.getSpace(); - auto ndims = dataspace.getSimpleExtentNdims(); - if(ndims != 2) - throw ParPEException( - "Invalid dimension for analytical parameter map, expected 2."); - - hsize_t dims[ndims]; - dataspace.getSimpleExtentDims(dims); - nRows = dims[0]; - nCols = dims[1]; - if(nRows && nCols != 3) - throw ParPEException( - "Invalid dimension for analytical parameter map, " - "expected 3 columns."); - - std::vector rawMap(nRows * nCols); - dataset.read(rawMap.data(), H5::PredType::NATIVE_INT); - - return rawMap; + return removeInnerParameters( + wrapped_function_->getParameterIds(), + proportionalityFactorIndices, + offsetParameterIndices, + sigmaParameterIndices); } HierarchicalOptimizationProblemWrapper::HierarchicalOptimizationProblemWrapper( - std::unique_ptr problemToWrap, - const MultiConditionDataProviderHDF5 *dataProvider) - : wrappedProblem(std::move(problemToWrap)) + std::unique_ptr problemToWrap, + const MultiConditionDataProviderHDF5* dataProvider) + : wrapped_problem_(std::move(problemToWrap)) { - logger = std::make_unique(*wrappedProblem->logger); + logger_ = std::make_unique(*wrapped_problem_->logger_); auto wrappedFun = - dynamic_cast*>( - wrappedProblem->costFun.get()); + dynamic_cast*>( + wrapped_problem_->cost_fun_.get()); auto model = dataProvider->getModel(); auto lock = hdf5MutexGetLock(); - costFun.reset( - new HierarchicalOptimizationWrapper( - std::unique_ptr( - dynamic_cast( - wrappedFun->getWrappedFunction())), - dataProvider->getHdf5FileId(), "/", - dataProvider->getNumberOfSimulationConditions(), - model->nytrue, - ErrorModel::normal)); + cost_fun_.reset( + new HierarchicalOptimizationWrapper( + dynamic_cast( + wrappedFun->getWrappedFunction()), + dataProvider->getHdf5FileId(), + "/", + dataProvider->getNumberOfSimulationConditions(), + model->nytrue, + ErrorModel::normal)); } HierarchicalOptimizationProblemWrapper::HierarchicalOptimizationProblemWrapper( - std::unique_ptr problemToWrap, - std::unique_ptr costFun, - std::unique_ptr logger) - : OptimizationProblem(std::move(costFun), - std::move(logger)), - wrappedProblem(std::move(problemToWrap)) -{ - -} + std::unique_ptr problemToWrap, + std::unique_ptr costFun, + std::unique_ptr logger) + : OptimizationProblem(std::move(costFun), std::move(logger)) + , wrapped_problem_(std::move(problemToWrap)) +{} -HierarchicalOptimizationProblemWrapper -::~HierarchicalOptimizationProblemWrapper() -{ - // Avoid double delete. - // This will be destroyed when wrappedProblem goes out of scope! - dynamic_cast( - costFun.get())->fun.release(); -} - -void HierarchicalOptimizationProblemWrapper::fillInitialParameters( - gsl::span buffer) const +void +HierarchicalOptimizationProblemWrapper::fillInitialParameters( + gsl::span buffer) const { - std::vector full(wrappedProblem->costFun->numParameters()); - wrappedProblem->fillInitialParameters(full); + std::vector full(wrapped_problem_->cost_fun_->numParameters()); + wrapped_problem_->fillInitialParameters(full); fillFilteredParams(full, buffer); } -void HierarchicalOptimizationProblemWrapper::fillParametersMax( - gsl::span buffer) const +void +HierarchicalOptimizationProblemWrapper::fillParametersMax( + gsl::span buffer) const { - std::vector full(wrappedProblem->costFun->numParameters()); - wrappedProblem->fillParametersMax(full); + std::vector full(wrapped_problem_->cost_fun_->numParameters()); + wrapped_problem_->fillParametersMax(full); fillFilteredParams(full, buffer); } -void HierarchicalOptimizationProblemWrapper::fillParametersMin( - gsl::span buffer) const +void +HierarchicalOptimizationProblemWrapper::fillParametersMin( + gsl::span buffer) const { - std::vector full(wrappedProblem->costFun->numParameters()); - wrappedProblem->fillParametersMin(full); + std::vector full(wrapped_problem_->cost_fun_->numParameters()); + wrapped_problem_->fillParametersMin(full); fillFilteredParams(full, buffer); } -void HierarchicalOptimizationProblemWrapper::fillFilteredParams( - const std::vector &fullParams, - gsl::span buffer) const +void +HierarchicalOptimizationProblemWrapper::fillFilteredParams( + const std::vector& fullParams, + gsl::span buffer) const { - auto hierarchical = dynamic_cast( - costFun.get()); + auto hierarchical = + dynamic_cast(cost_fun_.get()); auto combinedIndices = hierarchical->getAnalyticalParameterIndices(); parpe::fillFilteredParams(fullParams, combinedIndices, buffer); } std::unique_ptr -HierarchicalOptimizationProblemWrapper::getReporter() const { - auto innerReporter = wrappedProblem->getReporter(); +HierarchicalOptimizationProblemWrapper::getReporter() const +{ + auto innerReporter = wrapped_problem_->getReporter(); auto outerReporter = std::unique_ptr( - new HierarchicalOptimizationReporter( - dynamic_cast(costFun.get()), - std::move(innerReporter->resultWriter), - std::make_unique(*logger) - )); + new HierarchicalOptimizationReporter( + dynamic_cast(cost_fun_.get()), + std::move(innerReporter->result_writer_), + std::make_unique(*logger_))); return outerReporter; } -void fillFilteredParams(std::vector const& valuesToFilter, - std::vector const& sortedIndicesToExclude, - gsl::span result) +void +fillFilteredParams(std::vector const& valuesToFilter, + std::vector const& sortedIndicesToExclude, + gsl::span result) { // adapt to offsets unsigned int nextFilterIdx = 0; unsigned int resultIdx = 0; - for(int i = 0; (unsigned)i < valuesToFilter.size(); ++i) { - if(nextFilterIdx < sortedIndicesToExclude.size() - && sortedIndicesToExclude[nextFilterIdx] == i) { + for (int i = 0; (unsigned)i < valuesToFilter.size(); ++i) { + if (nextFilterIdx < sortedIndicesToExclude.size() && + sortedIndicesToExclude[nextFilterIdx] == i) { // skip ++nextFilterIdx; } else { @@ -772,14 +664,13 @@ void fillFilteredParams(std::vector const& valuesToFilter, ++resultIdx; } } - RELEASE_ASSERT(nextFilterIdx == sortedIndicesToExclude.size(), ""); - RELEASE_ASSERT(resultIdx == - (unsigned) valuesToFilter.size() - - sortedIndicesToExclude.size(), - ""); + Ensures(nextFilterIdx == sortedIndicesToExclude.size()); + Ensures(resultIdx == + (unsigned)valuesToFilter.size() - sortedIndicesToExclude.size()); } -double getDefaultScalingFactor(amici::ParameterScaling scaling) +double +getDefaultScalingFactor(amici::ParameterScaling scaling) { switch (scaling) { case amici::ParameterScaling::none: @@ -788,12 +679,13 @@ double getDefaultScalingFactor(amici::ParameterScaling scaling) return 0.0; default: throw ParPEException( - "Parameter scaling must be ParameterScaling::log10 " - "or ParameterScaling::none."); + "Parameter scaling must be ParameterScaling::log10 " + "or ParameterScaling::none."); } } -double getDefaultOffsetParameter(amici::ParameterScaling scaling) +double +getDefaultOffsetParameter(amici::ParameterScaling scaling) { switch (scaling) { case amici::ParameterScaling::none: @@ -802,55 +694,67 @@ double getDefaultOffsetParameter(amici::ParameterScaling scaling) return -std::numeric_limits::infinity(); default: throw ParPEException( - "Parameter scaling must be ParameterScaling::log10 " - "or ParameterScaling::none."); + "Parameter scaling must be ParameterScaling::log10 " + "or ParameterScaling::none."); } } - -double computeAnalyticalScalings( - int scalingIdx, - const std::vector > &modelOutputsUnscaled, - const std::vector > &measurements, - AnalyticalParameterProvider const& scalingReader, - int numObservables) { +double +computeAnalyticalScalings( + int scalingIdx, + const std::vector>& modelOutputsUnscaled, + const std::vector>& measurements, + AnalyticalParameterProvider const& scalingReader, + int numObservables) +{ auto dependentConditions = - scalingReader.getConditionsForParameter(scalingIdx); + scalingReader.getConditionsForParameter(scalingIdx); double enumerator = 0.0; double denominator = 0.0; - for (auto const conditionIdx: dependentConditions) { + for (auto const conditionIdx : dependentConditions) { auto dependentObservables = - scalingReader.getObservablesForParameter( - scalingIdx, conditionIdx); + scalingReader.getObservablesForParameter(scalingIdx, conditionIdx); int numTimepoints = measurements[conditionIdx].size() / numObservables; - for(auto const observableIdx: dependentObservables) { - for(int timeIdx = 0; timeIdx < numTimepoints; ++timeIdx) { + for (auto const observableIdx : dependentObservables) { + for (int timeIdx = 0; timeIdx < numTimepoints; ++timeIdx) { - double mes = measurements[conditionIdx][observableIdx + timeIdx * numObservables]; - if(!std::isnan(mes)) { - // NOTE: this must be in sync with data ordering in AMICI (assumes row-major) - double sim = modelOutputsUnscaled[conditionIdx][observableIdx + timeIdx * numObservables]; + double mes = + measurements[conditionIdx] + [observableIdx + timeIdx * numObservables]; + if (!std::isnan(mes)) { + // NOTE: this must be in sync with data ordering in AMICI + // (assumes row-major) + double sim = modelOutputsUnscaled[conditionIdx] + [observableIdx + + timeIdx * numObservables]; // std::cout< -1e-18) { + if (sim < 0 && sim > -1e-18) { // negative values due to numerical errors // TODO: some outputs may be validly < 0 logmessage(LOGLVL_WARNING, "In computeAnalyticalScalings %d: " "Simulation is %g < 0 for condition %d " "observable %d timepoint %d. " - "Setting to 0.0.", scalingIdx, sim, - conditionIdx, observableIdx, timeIdx); + "Setting to 0.0.", + scalingIdx, + sim, + conditionIdx, + observableIdx, + timeIdx); sim = 0.0; } @@ -861,64 +765,70 @@ double computeAnalyticalScalings( } } - if(denominator == 0.0) { + if (denominator == 0.0) { logmessage(LOGLVL_WARNING, "In computeAnalyticalScalings: denominator is 0.0 for " - "scaling parameter " + std::to_string(scalingIdx) - + ". Probably model output is always 0.0 and scaling, " - "thus, not used. Setting scaling parameter to 1.0."); + "scaling parameter " + + std::to_string(scalingIdx) + + ". Probably model output is always 0.0 and scaling, " + "thus, not used. Setting scaling parameter to 1.0."); return 1.0; } double scaling = enumerator / denominator; return scaling; -// constexpr double upper_bound = 1e10; - -// // too large values of scaling parameters cause problems in backwards -// // integration for adjoint sensitivities -// if(upper_bound > scaling) -// return scaling; - -// logmessage(LOGLVL_WARNING, -// "In computeAnalyticalScalings: force-bounding scaling parameter " -// + std::to_string(scalingIdx) + " which was " -// + std::to_string(scaling) + " to " -// + std::to_string(upper_bound)); -// return upper_bound; + // constexpr double upper_bound = 1e10; + + // // too large values of scaling parameters cause problems in backwards + // // integration for adjoint sensitivities + // if(upper_bound > scaling) + // return scaling; + + // logmessage(LOGLVL_WARNING, + // "In computeAnalyticalScalings: force-bounding scaling + // parameter " + // + std::to_string(scalingIdx) + " which was " + // + std::to_string(scaling) + " to " + // + std::to_string(upper_bound)); + // return upper_bound; } - -double computeAnalyticalOffsets( - int offsetIdx, - std::vector> const& modelOutputsUnscaled, - std::vector> const& measurements, - AnalyticalParameterProvider& offsetReader, - int numObservables) +double +computeAnalyticalOffsets( + int offsetIdx, + std::vector> const& modelOutputsUnscaled, + std::vector> const& measurements, + AnalyticalParameterProvider& offsetReader, + int numObservables) { auto dependentConditions = - offsetReader.getConditionsForParameter(offsetIdx); + offsetReader.getConditionsForParameter(offsetIdx); double enumerator = 0.0; double denominator = 0.0; - for (auto const conditionIdx: dependentConditions) { + for (auto const conditionIdx : dependentConditions) { auto dependentObservables = - offsetReader.getObservablesForParameter( - offsetIdx, conditionIdx); + offsetReader.getObservablesForParameter(offsetIdx, conditionIdx); int numTimepoints = measurements[conditionIdx].size() / numObservables; - for(auto const observableIdx: dependentObservables) { - for(int timeIdx = 0; timeIdx < numTimepoints; ++timeIdx) { + for (auto const observableIdx : dependentObservables) { + for (int timeIdx = 0; timeIdx < numTimepoints; ++timeIdx) { double mes = - measurements[conditionIdx][observableIdx + timeIdx * numObservables]; - if(!std::isnan(mes)) { - double sim = - modelOutputsUnscaled[conditionIdx][observableIdx + timeIdx * numObservables]; - if(std::isnan(sim)) { + measurements[conditionIdx] + [observableIdx + timeIdx * numObservables]; + if (!std::isnan(mes)) { + double sim = modelOutputsUnscaled[conditionIdx] + [observableIdx + + timeIdx * numObservables]; + if (std::isnan(sim)) { logmessage(LOGLVL_WARNING, "In computeAnalyticalOffsets %d: " "Simulation is NaN for condition %d " - "observable %d timepoint %d", offsetIdx, - conditionIdx, observableIdx, timeIdx); + "observable %d timepoint %d", + offsetIdx, + conditionIdx, + observableIdx, + timeIdx); } enumerator += mes - sim; denominator += 1.0; @@ -927,25 +837,28 @@ double computeAnalyticalOffsets( } } - if(denominator == 0.0) { + if (denominator == 0.0) { logmessage(LOGLVL_WARNING, "In computeAnalyticalOffsets: denominator is 0.0 " - "for offset parameter " + std::to_string(offsetIdx) - + ". This probably means that there exists no measurement " - "using this parameter. Setting offset to 0.0."); + "for offset parameter " + + std::to_string(offsetIdx) + + ". This probably means that there exists no measurement " + "using this parameter. Setting offset to 0.0."); return 0.0; } return enumerator / denominator; } -double computeAnalyticalSigmas( - int sigmaIdx, - const std::vector > &modelOutputsScaled, - const std::vector > &measurements, - AnalyticalParameterProvider const& sigmaReader, - int numObservables, - double epsilonAbs, double epsilonRel) +double +computeAnalyticalSigmas( + int sigmaIdx, + const std::vector>& modelOutputsScaled, + const std::vector>& measurements, + AnalyticalParameterProvider const& sigmaReader, + int numObservables, + double epsilonAbs, + double epsilonRel) { auto dependentConditions = sigmaReader.getConditionsForParameter(sigmaIdx); @@ -954,187 +867,259 @@ double computeAnalyticalSigmas( double maxAbsMeasurement = 0.0; - for (auto const conditionIdx: dependentConditions) { + for (auto const conditionIdx : dependentConditions) { auto dependentObservables = - sigmaReader.getObservablesForParameter(sigmaIdx, conditionIdx); + sigmaReader.getObservablesForParameter(sigmaIdx, conditionIdx); int numTimepoints = measurements[conditionIdx].size() / numObservables; - for(auto const observableIdx: dependentObservables) { - if(observableIdx >= numObservables) { + for (auto const observableIdx : dependentObservables) { + if (observableIdx >= numObservables) { throw ParPEException("computeAnalyticalSigmas: Invalid " "observableIdx >= numObservables."); } - for(int timeIdx = 0; timeIdx < numTimepoints; ++timeIdx) { - double mes = measurements[conditionIdx][observableIdx + timeIdx * numObservables]; - if(!std::isnan(mes)) { - double scaledSim = modelOutputsScaled[conditionIdx][observableIdx + timeIdx * numObservables]; - // std::cout< > &modelOutputs, - AnalyticalParameterProvider const& scalingReader, - int numObservables) { - auto dependentConditions = scalingReader.getConditionsForParameter(scalingIdx); - for (auto const conditionIdx: dependentConditions) { +void +applyOptimalScaling(int scalingIdx, + double scalingLin, + std::vector>& modelOutputs, + AnalyticalParameterProvider const& scalingReader, + int numObservables) +{ + auto dependentConditions = + scalingReader.getConditionsForParameter(scalingIdx); + for (auto const conditionIdx : dependentConditions) { int numTimepoints = modelOutputs[conditionIdx].size() / numObservables; - auto dependentObservables = scalingReader.getObservablesForParameter(scalingIdx, conditionIdx); - for(auto const observableIdx: dependentObservables) { - if(observableIdx >= numObservables) { - throw ParPEException("applyOptimalOffset: Invalid observableIdx >= numObservables."); + auto dependentObservables = + scalingReader.getObservablesForParameter(scalingIdx, conditionIdx); + for (auto const observableIdx : dependentObservables) { + if (observableIdx >= numObservables) { + throw ParPEException("applyOptimalOffset: Invalid " + "observableIdx >= numObservables."); } - for(int timeIdx = 0; timeIdx < numTimepoints; ++timeIdx) { - // NOTE: this must be in sync with data ordering in AMICI (assumes row-major) - modelOutputs[conditionIdx][observableIdx + timeIdx * numObservables] *= scalingLin; + for (int timeIdx = 0; timeIdx < numTimepoints; ++timeIdx) { + // NOTE: this must be in sync with data ordering in AMICI + // (assumes row-major) + modelOutputs[conditionIdx] + [observableIdx + timeIdx * numObservables] *= + scalingLin; } } } } - - -void applyOptimalOffset(int offsetIdx, double offsetLin, - std::vector > &modelOutputs, - const AnalyticalParameterProvider &offsetReader, - int numObservables) { - auto dependentConditions = offsetReader.getConditionsForParameter(offsetIdx); - for (auto const conditionIdx: dependentConditions) { +void +applyOptimalOffset(int offsetIdx, + double offsetLin, + std::vector>& modelOutputs, + const AnalyticalParameterProvider& offsetReader, + int numObservables) +{ + auto dependentConditions = + offsetReader.getConditionsForParameter(offsetIdx); + for (auto const conditionIdx : dependentConditions) { int numTimepoints = modelOutputs[conditionIdx].size() / numObservables; - auto dependentObservables = offsetReader.getObservablesForParameter(offsetIdx, conditionIdx); - for(auto const observableIdx: dependentObservables) { - if(observableIdx >= numObservables) { - throw ParPEException("applyOptimalOffset: Invalid observableIdx >= numObservables."); + auto dependentObservables = + offsetReader.getObservablesForParameter(offsetIdx, conditionIdx); + for (auto const observableIdx : dependentObservables) { + if (observableIdx >= numObservables) { + throw ParPEException("applyOptimalOffset: Invalid " + "observableIdx >= numObservables."); } - for(int timeIdx = 0; timeIdx < numTimepoints; ++timeIdx) { - modelOutputs[conditionIdx][observableIdx + timeIdx * numObservables] += offsetLin; + for (int timeIdx = 0; timeIdx < numTimepoints; ++timeIdx) { + modelOutputs[conditionIdx] + [observableIdx + timeIdx * numObservables] += + offsetLin; } } } } - - -std::vector spliceParameters(const gsl::span reducedParameters, - const std::vector &proportionalityFactorIndices, - const std::vector &offsetParameterIndices, - const std::vector &sigmaParameterIndices, - const std::vector &scalingFactors, - const std::vector &offsetParameters, - const std::vector &sigmaParameters) { +std::vector +spliceParameters(const gsl::span reducedParameters, + const std::vector& proportionalityFactorIndices, + const std::vector& offsetParameterIndices, + const std::vector& sigmaParameterIndices, + const std::vector& scalingFactors, + const std::vector& offsetParameters, + const std::vector& sigmaParameters) +{ std::vector fullParameters( - reducedParameters.size() + scalingFactors.size() - + offsetParameters.size() + sigmaParameters.size()); + reducedParameters.size() + scalingFactors.size() + + offsetParameters.size() + sigmaParameters.size()); int idxScaling = 0; int idxOffset = 0; int idxSigma = 0; int idxRegular = 0; - for(int i = 0; i < (signed) fullParameters.size(); ++i) { - if((unsigned)idxScaling < proportionalityFactorIndices.size() - && proportionalityFactorIndices[idxScaling] == i) + for (int i = 0; i < (signed)fullParameters.size(); ++i) { + if ((unsigned)idxScaling < proportionalityFactorIndices.size() && + proportionalityFactorIndices[idxScaling] == i) fullParameters[i] = scalingFactors.at(idxScaling++); - else if((unsigned)idxOffset < offsetParameterIndices.size() - && offsetParameterIndices[idxOffset] == i) + else if ((unsigned)idxOffset < offsetParameterIndices.size() && + offsetParameterIndices[idxOffset] == i) fullParameters[i] = offsetParameters.at(idxOffset++); - else if((unsigned)idxSigma < sigmaParameterIndices.size() - && sigmaParameterIndices[idxSigma] == i) + else if ((unsigned)idxSigma < sigmaParameterIndices.size() && + sigmaParameterIndices[idxSigma] == i) fullParameters[i] = sigmaParameters.at(idxSigma++); - else if((unsigned)idxRegular < reducedParameters.size()) - fullParameters[i] = reducedParameters.at(idxRegular++); + else if ((unsigned)idxRegular < reducedParameters.size()) + fullParameters[i] = reducedParameters[idxRegular++]; else throw std::exception(); } - RELEASE_ASSERT((unsigned) idxScaling == proportionalityFactorIndices.size(), - "") - RELEASE_ASSERT((unsigned) idxOffset == offsetParameterIndices.size(), "") - RELEASE_ASSERT((unsigned) idxSigma == sigmaParameterIndices.size(), "") - RELEASE_ASSERT((unsigned) idxRegular == reducedParameters.size(), "") + Ensures((unsigned) idxScaling == proportionalityFactorIndices.size()); + Ensures((unsigned) idxOffset == offsetParameterIndices.size()); + Ensures((unsigned) idxSigma == sigmaParameterIndices.size()); + Ensures((unsigned) idxRegular == reducedParameters.size()); return fullParameters; } double computeNegLogLikelihood( - std::vector> const& measurements, - std::vector> const& modelOutputsScaled, - std::vector> const& sigmas) { - RELEASE_ASSERT(measurements.size() == modelOutputsScaled.size(), ""); + std::vector> const& measurements, + std::vector> const& modelOutputsScaled, + std::vector> const& sigmas) { + Expects(measurements.size() == modelOutputsScaled.size()); double nllh = 0.0; - for (int conditionIdx = 0; - (unsigned) conditionIdx < measurements.size(); ++conditionIdx) { - nllh += computeNegLogLikelihood - (measurements[conditionIdx], modelOutputsScaled[conditionIdx], - sigmas[conditionIdx]); - if(std::isnan(nllh)) + for (int conditionIdx = 0; (unsigned)conditionIdx < measurements.size(); + ++conditionIdx) { + nllh += computeNegLogLikelihood(measurements[conditionIdx], + modelOutputsScaled[conditionIdx], + sigmas[conditionIdx]); + if (std::isnan(nllh)) return nllh; } return nllh; } -double computeNegLogLikelihood(std::vector const& measurements, - std::vector const& modelOutputsScaled, - std::vector const& sigmas) { - double nllh = 0.0; - RELEASE_ASSERT(measurements.size() == modelOutputsScaled.size(), - "measurement/simulation output dimension mismatch"); +std::vector +getOuterParameters(const std::vector& fullParameters, + const H5::H5File& parameterFile, + const std::string& parameterPath) +{ + // auto options = OptimizationOptions::fromHDF5(parameterFile.getId(), + // parameterPath + "/optimizationOptions"); + AnalyticalParameterHdf5Reader hierarchicalScalingReader( + parameterFile, + parameterPath + "/scalingParameterIndices", + parameterPath + "/scalingParametersMapToObservables"); + AnalyticalParameterHdf5Reader hierarchicalOffsetReader( + parameterFile, + parameterPath + "/offsetParameterIndices", + parameterPath + "/offsetParametersMapToObservables"); + AnalyticalParameterHdf5Reader hierarchicalSigmaReader( + parameterFile, + parameterPath + "/sigmaParameterIndices", + parameterPath + "/sigmaParametersMapToObservables"); + + auto proportionalityFactorIndices = + hierarchicalScalingReader.getOptimizationParameterIndices(); + auto offsetParameterIndices = + hierarchicalOffsetReader.getOptimizationParameterIndices(); + auto sigmaParameterIndices = + hierarchicalSigmaReader.getOptimizationParameterIndices(); - for(int i = 0; (unsigned) i < measurements.size(); ++i) { + auto combinedIndices = proportionalityFactorIndices; + combinedIndices.insert(combinedIndices.end(), + offsetParameterIndices.begin(), + offsetParameterIndices.end()); + combinedIndices.insert(combinedIndices.end(), + sigmaParameterIndices.begin(), + sigmaParameterIndices.end()); + std::sort(combinedIndices.begin(), combinedIndices.end()); + + std::vector result(fullParameters.size() - combinedIndices.size()); + parpe::fillFilteredParams(fullParameters, combinedIndices, result); + + return result; +} + +double +computeNegLogLikelihood(std::vector const& measurements, + std::vector const& modelOutputsScaled, + std::vector const& sigmas) +{ + + // measurement/simulation output dimension mismatch + Expects(measurements.size() == modelOutputsScaled.size()); + + double nllh = 0.0; + + for (int i = 0; (unsigned)i < measurements.size(); ++i) { double mes = measurements[i]; - if(!std::isnan(mes)) { + if (!std::isnan(mes)) { double sim = modelOutputsScaled[i]; double sigmaSquared = sigmas[i] * sigmas[i]; - if(std::isnan(sim)) { - logmessage(LOGLVL_WARNING, "Simulation is NaN for data point %d", i); + if (std::isnan(sim)) { + logmessage( + LOGLVL_WARNING, "Simulation is NaN for data point %d", i); return std::numeric_limits::quiet_NaN(); } - if(std::isnan(sigmaSquared)) { + if (std::isnan(sigmaSquared)) { logmessage(LOGLVL_WARNING, "Sigma is NaN for data point %d", i); return std::numeric_limits::quiet_NaN(); } - if(sigmaSquared < 0.0) { - logmessage(LOGLVL_WARNING, "Negative sigma for data point %d", i); + if (sigmaSquared < 0.0) { + logmessage( + LOGLVL_WARNING, "Negative sigma for data point %d", i); return std::numeric_limits::quiet_NaN(); } @@ -1148,211 +1133,237 @@ double computeNegLogLikelihood(std::vector const& measurements, return nllh; } -std::vector -AnalyticalParameterProviderDefault::getConditionsForParameter( - int parameterIndex) const { - return conditionsForParameter[parameterIndex]; -} - -const std::vector & -AnalyticalParameterProviderDefault::getObservablesForParameter( - int parameterIndex, int conditionIdx) const { - return mapping[parameterIndex].at(conditionIdx); -} - -std::vector AnalyticalParameterProviderDefault::getOptimizationParameterIndices() const { - return optimizationParameterIndices; -} - HierarchicalOptimizationReporter::HierarchicalOptimizationReporter( - HierarchicalOptimizationWrapper *gradFun, - std::unique_ptr rw, - std::unique_ptr logger) + HierarchicalOptimizationWrapper* gradFun, + std::unique_ptr rw, + std::unique_ptr logger) : OptimizationReporter(gradFun, std::move(rw), std::move(logger)) { - hierarchicalWrapper = gradFun; + hierarchical_wrapper_ = gradFun; } -FunctionEvaluationStatus HierarchicalOptimizationReporter::evaluate( - gsl::span parameters, - double &fval, gsl::span gradient, Logger *logger, - double *cpuTime) const +FunctionEvaluationStatus +HierarchicalOptimizationReporter::evaluate(gsl::span parameters, + double& fval, + gsl::span gradient, + Logger* logger, + double* cpuTime) const { double myCpuTimeSec = 0.0; - if(cpuTime) + if (cpuTime) *cpuTime = 0.0; - if(beforeCostFunctionCall(parameters) != 0) + if (beforeCostFunctionCall(parameters) != 0) return functionEvaluationFailure; - if(gradient.data()) { - if (!haveCachedGradient || !std::equal(parameters.begin(), parameters.end(), - cachedParameters.begin())) { + if (gradient.data()) { + if (!have_cached_gradient_ || !std::equal(parameters.begin(), + parameters.end(), + cached_parameters_.begin())) { // Have to compute anew - cachedStatus = hierarchicalWrapper->evaluate( - parameters, cachedCost, cachedGradient, - cachedFullParameters, cachedFullGradient, - logger ? logger : this->logger.get(), &myCpuTimeSec); - haveCachedCost = true; - haveCachedGradient = true; + cached_status_ = hierarchical_wrapper_->evaluate( + parameters, + cached_cost_, + cached_gradient_, + cached_full_parameters_, + cached_full_gradient_, + logger ? logger : this->logger_.get(), + &myCpuTimeSec); + have_cached_cost_ = true; + have_cached_gradient_ = true; } // recycle old result - std::copy(cachedGradient.begin(), cachedGradient.end(), gradient.begin()); - fval = cachedCost; + std::copy( + cached_gradient_.begin(), cached_gradient_.end(), gradient.begin()); + fval = cached_cost_; } else { - if (!haveCachedCost || !std::equal(parameters.begin(), parameters.end(), - cachedParameters.begin())) { + if (!have_cached_cost_ || !std::equal(parameters.begin(), + parameters.end(), + cached_parameters_.begin())) { // Have to compute anew - cachedStatus = hierarchicalWrapper->evaluate( - parameters, cachedCost, gsl::span(), - cachedFullParameters, cachedFullGradient, - logger ? logger : this->logger.get(), &myCpuTimeSec); - haveCachedCost = true; - haveCachedGradient = false; + cached_status_ = hierarchical_wrapper_->evaluate( + parameters, + cached_cost_, + gsl::span(), + cached_full_parameters_, + cached_full_gradient_, + logger ? logger : this->logger_.get(), + &myCpuTimeSec); + have_cached_cost_ = true; + have_cached_gradient_ = false; } - fval = cachedCost; + fval = cached_cost_; } // update cached parameters - cachedParameters.resize(numParameters_); - std::copy(parameters.begin(), parameters.end(), cachedParameters.begin()); + cached_parameters_.resize(num_parameters_); + std::copy(parameters.begin(), parameters.end(), cached_parameters_.begin()); - cpuTimeIterationSec += myCpuTimeSec; - cpuTimeTotalSec += myCpuTimeSec; - if(cpuTime) + cpu_time_iteration_sec_ += myCpuTimeSec; + cpu_time_total_sec_ += myCpuTimeSec; + if (cpuTime) *cpuTime = myCpuTimeSec; - if(afterCostFunctionCall( - parameters, cachedCost, - gradient.data() ? cachedFullGradient : gsl::span() - ) != 0) + if (afterCostFunctionCall(parameters, + cached_cost_, + gradient.data() ? cached_full_gradient_ + : gsl::span()) != 0) return functionEvaluationFailure; - return cachedStatus; + return cached_status_; } -void HierarchicalOptimizationReporter::finished( - double optimalCost, gsl::span parameters, int exitStatus) const +void +HierarchicalOptimizationReporter::finished(double optimalCost, + gsl::span parameters, + int exitStatus) const { - double timeElapsed = wallTimer.getTotal(); - - if(cachedCost > optimalCost) { - // the optimal value is not from the cached parameters and we did not get - // the optimal full parameter vector. since we don't know them, rather set to nan - cachedFullParameters.assign(cachedFullParameters.size(), NAN); - std::copy(parameters.begin(), parameters.end(), cachedParameters.data()); - if(logger) logger->logmessage(LOGLVL_INFO, "cachedCost != optimalCost"); - cachedCost = NAN; + double timeElapsed = wall_timer_.getTotal(); + + if (cached_cost_ > optimalCost) { + // the optimal value is not from the cached parameters and we did not + // get the optimal full parameter vector. since we don't know them, + // rather set to nan + // NOTE: This happens if line search steps are worse than the previous + // iteration. TODO: recompute inner parameters + cached_full_parameters_.assign(cached_full_parameters_.size(), NAN); + std::copy( + parameters.begin(), parameters.end(), cached_parameters_.data()); + if (logger_) + logger_->logmessage(LOGLVL_INFO, "cachedCost != optimalCost"); + cached_cost_ = NAN; } - if(logger) - logger->logmessage(LOGLVL_INFO, "Optimizer status %d, final llh: %e, time: wall: %f cpu: %f.", - exitStatus, cachedCost, timeElapsed, cpuTimeTotalSec); - - if(resultWriter) - resultWriter->saveOptimizerResults(cachedCost, cachedFullParameters, - timeElapsed, cpuTimeTotalSec, exitStatus); + if (logger_) + logger_->logmessage( + LOGLVL_INFO, + "Optimizer status %d, final llh: %e, time: wall: %f cpu: %f.", + exitStatus, + cached_cost_, + timeElapsed, + cpu_time_total_sec_); + + if (result_writer_) + result_writer_->saveOptimizerResults(cached_cost_, + cached_full_parameters_, + timeElapsed, + cpu_time_total_sec_, + exitStatus); } -const std::vector &HierarchicalOptimizationReporter::getFinalParameters() const +const std::vector& +HierarchicalOptimizationReporter::getFinalParameters() const { - return cachedFullParameters; + return cached_full_parameters_; } -bool HierarchicalOptimizationReporter::iterationFinished( - gsl::span parameters, - double objectiveFunctionValue, - gsl::span /*objectiveFunctionGradient*/) const +bool +HierarchicalOptimizationReporter::iterationFinished( + gsl::span parameters, + double objectiveFunctionValue, + gsl::span /*objectiveFunctionGradient*/) const { - double wallTimeIter = wallTimer.getRound(); - double wallTimeOptim = wallTimer.getTotal(); - - if(logger) - logger->logmessage(LOGLVL_INFO, - "iter: %d cost: %g " - "time_iter: wall: %gs cpu: %gs " - "time_optim: wall: %gs cpu: %gs", - numIterations, objectiveFunctionValue, - wallTimeIter, cpuTimeIterationSec, - wallTimeOptim, cpuTimeTotalSec); - - if(resultWriter) { - /* check if the optimizer-reported cost matches the last function evaluation. - * if so, we can log our cached parameter and gradient, otherwise we need to rely on what - * the optimizer provided us. if no parameters are provided, we will still save the cached - * one, even if the cost does not match, since this is the best parameter guess we have. + double wallTimeIter = wall_timer_.getRound(); + double wallTimeOptim = wall_timer_.getTotal(); + + if (logger_) + logger_->logmessage(LOGLVL_INFO, + "iter: %d cost: %g " + "time_iter: wall: %gs cpu: %gs " + "time_optim: wall: %gs cpu: %gs", + num_iterations_, + objectiveFunctionValue, + wallTimeIter, + cpu_time_iteration_sec_, + wallTimeOptim, + cpu_time_total_sec_); + + if (result_writer_) { + /* check if the optimizer-reported cost matches the last function + * evaluation. if so, we can log our cached parameter and gradient, + * otherwise we need to rely on what the optimizer provided us. if no + * parameters are provided, we will still save the cached one, even if + * the cost does not match, since this is the best parameter guess we + * have. */ - if(almostEqual(objectiveFunctionValue, cachedCost) - && (parameters.empty() - || std::equal(parameters.begin(), parameters.end(), - cachedParameters.begin()))) { - resultWriter->logOptimizerIteration( - numIterations, - cachedFullParameters, - objectiveFunctionValue, - // This might be misleading, the gradient could have been - // evaluated at other parameters if there was a line search inbetween - cachedFullGradient, - wallTimeIter, - cpuTimeIterationSec); + if (almostEqual(objectiveFunctionValue, cached_cost_) && + (parameters.empty() || std::equal(parameters.begin(), + parameters.end(), + cached_parameters_.begin()))) { + result_writer_->logOptimizerIteration( + num_iterations_, + cached_full_parameters_, + objectiveFunctionValue, + // This might be misleading, the gradient could have been + // evaluated at other parameters if there was a line search + // inbetween + cached_full_gradient_, + wallTimeIter, + cpu_time_iteration_sec_); } else { - // We don't have the full parameter vector, only the outer parameters - // so we can't append them due to different dimension - // TODO: save both, outer + combined? can easily save outer + inner separetly - std::vector nanParameters(cachedFullParameters.size(), NAN); - - resultWriter->logOptimizerIteration(numIterations, - nanParameters, - objectiveFunctionValue, - nanParameters, - wallTimeIter, - cpuTimeIterationSec); + // We don't have the full parameter vector, only the outer + // parameters so we can't append them due to different dimension + // TODO: save both, outer + combined? can easily save outer + inner + // separetly + std::vector nanParameters(cached_full_parameters_.size(), + NAN); + + result_writer_->logOptimizerIteration(num_iterations_, + nanParameters, + objectiveFunctionValue, + nanParameters, + wallTimeIter, + cpu_time_iteration_sec_); } } - ++numIterations; + ++num_iterations_; - logger->setPrefix(defaultLoggerPrefix + "i" + std::to_string(numIterations)); - cpuTimeIterationSec = 0.0; + logger_->setPrefix(default_logger_prefix_ + "i" + + std::to_string(num_iterations_)); + cpu_time_iteration_sec_ = 0.0; return false; - } -bool HierarchicalOptimizationReporter::afterCostFunctionCall( - gsl::span /*parameters*/, - double objectiveFunctionValue, - gsl::span objectiveFunctionGradient) const +bool +HierarchicalOptimizationReporter::afterCostFunctionCall( + gsl::span /*parameters*/, + double objectiveFunctionValue, + gsl::span objectiveFunctionGradient) const { - double wallTime = wallTimer.getTotal(); - //(double)(timeCostEvaluationEnd - timeCostEvaluationBegin) / CLOCKS_PER_SEC; + double wallTime = wall_timer_.getTotal(); - if(!std::isfinite(objectiveFunctionValue)) + if (!std::isfinite(objectiveFunctionValue)) printObjectiveFunctionFailureMessage(); - if(resultWriter) { - resultWriter->logObjectiveFunctionEvaluation( - cachedFullParameters, cachedCost, - objectiveFunctionGradient, numIterations, - numFunctionCalls, wallTime); + if (result_writer_) { + result_writer_->logObjectiveFunctionEvaluation( + cached_full_parameters_, + cached_cost_, + objectiveFunctionGradient, + num_iterations_, + num_function_calls_, + wallTime); } return false; } -void checkGradientForAnalyticalParameters( - const std::vector &gradient, - const std::vector &analyticalIndices, double threshold) +void +checkGradientForAnalyticalParameters(const std::vector& gradient, + const std::vector& analyticalIndices, + double threshold) { - for(auto const idx: analyticalIndices) { + for (auto const idx : analyticalIndices) { auto curGradient = gradient[idx]; - //std::cout<<" : "< threshold) + // std::cout<<" : "< threshold) logmessage(LOGLVL_WARNING, "Gradient w.r.t. analytically computed parameter " - "%d is %f, exceeding threshold %g", idx, curGradient, + "%d is %f, exceeding threshold %g", + idx, + curGradient, threshold); } } - - } // namespace parpe diff --git a/src/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.cpp b/src/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.cpp new file mode 100644 index 000000000..e3801cc33 --- /dev/null +++ b/src/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.cpp @@ -0,0 +1,163 @@ +#include + +#include +#include + +namespace parpe { + + +std::vector +AnalyticalParameterProviderDefault::getConditionsForParameter( + int parameterIndex) const +{ + return conditionsForParameter[parameterIndex]; +} + +const std::vector& +AnalyticalParameterProviderDefault::getObservablesForParameter( + int parameterIndex, + int conditionIdx) const +{ + return mapping[parameterIndex].at(conditionIdx); +} + +std::vector +AnalyticalParameterProviderDefault::getOptimizationParameterIndices() const +{ + return optimizationParameterIndices; +} + +AnalyticalParameterHdf5Reader::AnalyticalParameterHdf5Reader( + H5::H5File const& file, + std::string analyticalParameterIndicesPath, + std::string mapPath) + : mapPath(std::move(mapPath)) + , analyticalParameterIndicesPath(std::move(analyticalParameterIndicesPath)) +{ + auto lock = hdf5MutexGetLock(); + this->file = file; // copy while mutex is locked! + readParameterConditionObservableMappingFromFile(); +} + + +std::vector +AnalyticalParameterHdf5Reader::getConditionsForParameter( + int parameterIndex) const +{ + std::vector result; + result.reserve(mapping[parameterIndex].size()); + for (auto const& kvp : mapping[parameterIndex]) + result.push_back(kvp.first); + return result; +} + +const std::vector& +AnalyticalParameterHdf5Reader::getObservablesForParameter( + int parameterIndex, + int conditionIdx) const +{ + return mapping[parameterIndex].at(conditionIdx); +} + +std::vector +AnalyticalParameterHdf5Reader::getOptimizationParameterIndices() const +{ + auto lock = hdf5MutexGetLock(); + std::vector analyticalParameterIndices; + + if (file.nameExists(analyticalParameterIndicesPath)) { + auto dataset = file.openDataSet(analyticalParameterIndicesPath); + auto dataspace = dataset.getSpace(); + + auto ndims = dataspace.getSimpleExtentNdims(); + if (ndims != 1) + throw ParPEException( + "Invalid dimension in getOptimizationParameterIndices."); + hsize_t numScalings = 0; + dataspace.getSimpleExtentDims(&numScalings); + + analyticalParameterIndices.resize(numScalings); + dataset.read(analyticalParameterIndices.data(), + H5::PredType::NATIVE_INT); + } + return analyticalParameterIndices; +} + +int +AnalyticalParameterHdf5Reader::getNumAnalyticalParameters() const +{ + hsize_t numAnalyticalParameters = 0; + auto lock = hdf5MutexGetLock(); + + if (file.nameExists(analyticalParameterIndicesPath)) { + auto dataset = file.openDataSet(analyticalParameterIndicesPath); + auto dataspace = dataset.getSpace(); + auto ndims = dataspace.getSimpleExtentNdims(); + if (ndims != 1) + throw ParPEException( + "Invalid dimension in getOptimizationParameterIndices."); + dataspace.getSimpleExtentDims(&numAnalyticalParameters); + } + + return numAnalyticalParameters; +} + +void +AnalyticalParameterHdf5Reader::readParameterConditionObservableMappingFromFile() +{ + auto lock = hdf5MutexGetLock(); + H5_SAVE_ERROR_HANDLER; + try { + int numScalings = getNumAnalyticalParameters(); + auto dataset = file.openDataSet(mapPath); + if (numScalings == 0) + return; + + // column indices in dataspace + constexpr int parameterCol = 0; + constexpr int conditionCol = 1; + constexpr int observableCol = 2; + + mapping.resize(numScalings); + + hsize_t nRows = 0, nCols = 0; + auto rawMap = readRawMap(dataset, nRows, nCols); + + for (int i = 0; (unsigned)i < nRows; ++i) { + int scalingIdx = rawMap[i * nCols + parameterCol]; + int conditionIdx = rawMap[i * nCols + conditionCol]; + int observableIdx = rawMap[i * nCols + observableCol]; + mapping[scalingIdx][conditionIdx].push_back(observableIdx); + } + } catch (H5::FileIException&) { + return; + } + H5_RESTORE_ERROR_HANDLER; +} + +std::vector +AnalyticalParameterHdf5Reader::readRawMap(H5::DataSet& dataset, + hsize_t& nRows, + hsize_t& nCols) +{ + auto dataspace = dataset.getSpace(); + auto ndims = dataspace.getSimpleExtentNdims(); + if (ndims != 2) + throw ParPEException( + "Invalid dimension for analytical parameter map, expected 2."); + + hsize_t dims[ndims]; + dataspace.getSimpleExtentDims(dims); + nRows = dims[0]; + nCols = dims[1]; + if (nRows && nCols != 3) + throw ParPEException("Invalid dimension for analytical parameter map, " + "expected 3 columns."); + + std::vector rawMap(nRows * nCols); + dataset.read(rawMap.data(), H5::PredType::NATIVE_INT); + + return rawMap; +} + +} diff --git a/src/parpeamici/multiConditionDataProvider.cpp b/src/parpeamici/multiConditionDataProvider.cpp index 1c9b6148e..f08247dcc 100644 --- a/src/parpeamici/multiConditionDataProvider.cpp +++ b/src/parpeamici/multiConditionDataProvider.cpp @@ -9,127 +9,143 @@ #include #include -#include #include +#include #include namespace parpe { MultiConditionDataProviderHDF5::MultiConditionDataProviderHDF5( - std::unique_ptr model, - std::string const& hdf5Filename) - : MultiConditionDataProviderHDF5(std::move(model), hdf5Filename, "") {} + std::unique_ptr model, + std::string const& hdf5Filename) + : MultiConditionDataProviderHDF5(std::move(model), hdf5Filename, "") +{} MultiConditionDataProviderHDF5::MultiConditionDataProviderHDF5( - std::unique_ptr model, - std::string const& hdf5Filename, - std::string const& rootPath) - : model(std::move(model)), rootPath(rootPath) { + std::unique_ptr model, + std::string const& hdf5Filename, + std::string const& rootPath) + : model_(std::move(model)) + , root_path_(rootPath) +{ auto lock = hdf5MutexGetLock(); - file = hdf5OpenForReading(hdf5Filename); - - optimizationOptions = parpe::OptimizationOptions::fromHDF5(getHdf5FileId()); - - hdf5MeasurementPath = rootPath + "/measurements/y"; - hdf5MeasurementSigmaPath = rootPath + "/measurements/ysigma"; - hdf5ConditionPath = rootPath + "/fixedParameters/k"; - hdf5ReferenceConditionPath = rootPath - + "/fixedParameters/simulationConditions"; - hdf5AmiciOptionPath = rootPath + "/amiciOptions"; - hdf5ParameterPath = rootPath + "/parameters"; - hdf5ParameterMinPath = hdf5ParameterPath + "/lowerBound"; - hdf5ParameterMaxPath = hdf5ParameterPath + "/upperBound"; - hdf5ParameterScaleSimulationPath = hdf5ParameterPath + "/pscaleSimulation"; - hdf5ParameterScaleOptimizationPath = - hdf5ParameterPath + "/pscaleOptimization"; - hdf5SimulationToOptimizationParameterMappingPath = rootPath - + "/parameters/optimizationSimulationMapping"; - hdf5ParameterOverridesPath = rootPath - + "/parameters/parameterOverrides"; - + file_ = hdf5OpenForReading(hdf5Filename); + + optimization_options_ = + parpe::OptimizationOptions::fromHDF5(getHdf5FileId()); + + hdf5_measurement_path_ = rootPath + "/measurements/y"; + hdf5_measurement_sigma_path_ = rootPath + "/measurements/ysigma"; + hdf5_condition_path_ = rootPath + "/fixedParameters/k"; + hdf5_reference_condition_path_ = + rootPath + "/fixedParameters/simulationConditions"; + hdf5_amici_options_path_ = rootPath + "/amiciOptions"; + hdf5_parameter_path_ = rootPath + "/parameters"; + hdf5_parameter_min_path_ = hdf5_parameter_path_ + "/lowerBound"; + hdf5_parameter_max_path_ = hdf5_parameter_path_ + "/upperBound"; + hdf5_parameter_scale_simulation_path_ = + hdf5_parameter_path_ + "/pscaleSimulation"; + hdf5_parameter_scale_optimization_path_ = + hdf5_parameter_path_ + "/pscaleOptimization"; + hdf5_simulation_to_optimization_parameter_mapping_path_ = + rootPath + "/parameters/optimizationSimulationMapping"; + hdf5_parameter_overrides_path = rootPath + "/parameters/parameterOverrides"; + hdf5_parameter_ids_path_ = rootPath + "/parameters/parameterNames"; checkDataIntegrity(); - amici::hdf5::readModelDataFromHDF5(file, *this->model, hdf5AmiciOptionPath); + amici::hdf5::readModelDataFromHDF5( + file_, *this->model_, hdf5_amici_options_path_); } -int MultiConditionDataProviderHDF5::getNumberOfSimulationConditions() const { - // TODO: add additional layer for selection of condition indices (for testing - // and later for minibatch) +int +MultiConditionDataProviderHDF5::getNumberOfSimulationConditions() const +{ + // TODO: add additional layer for selection of condition indices (for + // testing and later for minibatch) // -> won't need different file for testing/validation splits // TODO: cache auto lock = hdf5MutexGetLock(); int d1, d2; - hdf5GetDatasetDimensions(file.getId(), hdf5ReferenceConditionPath.c_str(), - 2, &d1, &d2); + hdf5GetDatasetDimensions( + file_.getId(), hdf5_reference_condition_path_.c_str(), 2, &d1, &d2); return d1; } - - std::vector MultiConditionDataProviderHDF5::getSimulationToOptimizationParameterMapping( - int conditionIdx) const { - std::string path = hdf5SimulationToOptimizationParameterMappingPath; + int conditionIdx) const +{ + std::string path = hdf5_simulation_to_optimization_parameter_mapping_path_; - if(hdf5DatasetExists(file, path)) { - return hdf5Read2DIntegerHyperslab(file, path, model->np(), 1, 0, conditionIdx); + if (hdf5DatasetExists(file_, path)) { + return hdf5Read2DIntegerHyperslab( + file_, path, model_->np(), 1, 0, conditionIdx); } // return trivial default mapping - std::vector defaultMap(model->np()); + std::vector defaultMap(model_->np()); std::iota(defaultMap.begin(), defaultMap.end(), 0); return defaultMap; } - void -MultiConditionDataProviderHDF5::mapSimulationToOptimizationGradientAddMultiply(int conditionIdx, gsl::span simulation, - gsl::span optimization, - gsl::span parameters, double coefficient) const { +MultiConditionDataProviderHDF5::mapSimulationToOptimizationGradientAddMultiply( + int conditionIdx, + gsl::span simulation, + gsl::span optimization, + gsl::span parameters, + double coefficient) const +{ auto mapping = getSimulationToOptimizationParameterMapping(conditionIdx); // Need to consider varying scaling auto scaleOpt = getParameterScaleOpt(); auto scaleSim = getParameterScaleSim(conditionIdx); - for(int i = 0; i < model->np(); ++i) { + for (int i = 0; i < model_->np(); ++i) { // some model parameter are not mapped if there is no respective data - if(mapping[i] >= 0) { - double newGrad = applyChainRule(simulation[i], parameters[i], - scaleSim[i], scaleOpt[mapping[i]]); + if (mapping[i] >= 0) { + double newGrad = applyChainRule( + simulation[i], parameters[i], scaleSim[i], scaleOpt[mapping[i]]); optimization[mapping[i]] += coefficient * newGrad; } } } -void MultiConditionDataProviderHDF5::mapAndSetOptimizationToSimulationVariables( - int conditionIdx, gsl::span optimization, - gsl::span simulation, - gsl::span optimizationScale, - gsl::span simulationScale) const +void +MultiConditionDataProviderHDF5::mapAndSetOptimizationToSimulationVariables( + int conditionIdx, + gsl::span optimization, + gsl::span simulation, + gsl::span optimizationScale, + gsl::span simulationScale) const { auto mapping = getSimulationToOptimizationParameterMapping(conditionIdx); std::vector overrides; - if(hdf5DatasetExists(file, hdf5ParameterOverridesPath)) { - overrides.resize(model->np()); - hdf5Read2DDoubleHyperslab( - file.getId(), hdf5ParameterOverridesPath.c_str(), - model->np(), 1, 0, conditionIdx, overrides); + if (hdf5DatasetExists(file_, hdf5_parameter_overrides_path)) { + overrides.resize(model_->np()); + hdf5Read2DDoubleHyperslab(file_.getId(), + hdf5_parameter_overrides_path.c_str(), + model_->np(), + 1, + 0, + conditionIdx, + overrides); } - for(int i = 0; i < model->np(); ++i) { - if(mapping[i] >= 0) { + for (int i = 0; i < model_->np(); ++i) { + if (mapping[i] >= 0) { // map from optimization parameters simulation[i] = getScaledParameter( - getUnscaledParameter( - optimization[mapping[i]], - optimizationScale[mapping[i]]), simulationScale[i]); + getUnscaledParameter(optimization[mapping[i]], + optimizationScale[mapping[i]]), + simulationScale[i]); } else if (!overrides.empty()) { // TODO do we need to rescale here? or done in PEtab? simulation[i] = overrides[i]; @@ -139,119 +155,143 @@ void MultiConditionDataProviderHDF5::mapAndSetOptimizationToSimulationVariables( } } -std::vector MultiConditionDataProviderHDF5::getParameterScaleOpt() const +std::vector +MultiConditionDataProviderHDF5::getParameterScaleOpt() const { auto lock = hdf5MutexGetLock(); auto resInt = amici::hdf5::getIntDataset1D( - file, hdf5ParameterScaleOptimizationPath); + file_, hdf5_parameter_scale_optimization_path_); std::vector res(resInt.size()); - for(unsigned int i = 0; i < resInt.size(); ++i) + for (unsigned int i = 0; i < resInt.size(); ++i) res[i] = static_cast(resInt[i]); return res; } -amici::ParameterScaling MultiConditionDataProviderHDF5::getParameterScaleOpt( - int parameterIdx) const +amici::ParameterScaling +MultiConditionDataProviderHDF5::getParameterScaleOpt(int parameterIdx) const { - auto res = hdf5Read1DIntegerHyperslab( - file, hdf5ParameterScaleOptimizationPath, - 1, parameterIdx).at(0); + auto res = + hdf5Read1DIntegerHyperslab( + file_, hdf5_parameter_scale_optimization_path_, 1, parameterIdx) + .at(0); return static_cast(res); } std::vector MultiConditionDataProviderHDF5::getParameterScaleSim(int simulationIdx) const { - auto resInt = hdf5Read2DIntegerHyperslab( - file, hdf5ParameterScaleSimulationPath, - 1, model->np(), simulationIdx, 0); + auto resInt = + hdf5Read2DIntegerHyperslab(file_, + hdf5_parameter_scale_simulation_path_, + 1, + model_->np(), + simulationIdx, + 0); std::vector res(resInt.size()); - for(unsigned int i = 0; i < resInt.size(); ++i) + for (unsigned int i = 0; i < resInt.size(); ++i) res[i] = static_cast(resInt[i]); return res; } -amici::ParameterScaling MultiConditionDataProviderHDF5::getParameterScaleSim( - int simulationIdx, - int modelParameterIdx) const +amici::ParameterScaling +MultiConditionDataProviderHDF5::getParameterScaleSim( + int simulationIdx, + int modelParameterIdx) const { - auto res = hdf5Read2DIntegerHyperslab( - file, hdf5ParameterScaleSimulationPath, - 1, 1, simulationIdx, modelParameterIdx).at(0); + auto res = hdf5Read2DIntegerHyperslab(file_, + hdf5_parameter_scale_simulation_path_, + 1, + 1, + simulationIdx, + modelParameterIdx) + .at(0); return static_cast(res); } -/** - * @brief Update the contstants in AMICI ExpData object. Reads a slab for the - * given simulation from fixed parameters matrix. - * - * @param simulationIdx Index of the experimental condition for which the - * parameters should be taken. - * @param edata The object to be updated. - */ -void MultiConditionDataProviderHDF5::updateFixedSimulationParameters( - int simulationIdx, amici::ExpData &edata) const { - edata.fixedParameters.resize(model->nk()); +void +MultiConditionDataProviderHDF5::updateFixedSimulationParameters( + int simulationIdx, + amici::ExpData& edata) const +{ + edata.fixedParameters.resize(model_->nk()); // TODO cache int conditionIdxPreeq, conditionIdxSim; - getSimAndPreeqConditions(simulationIdx, conditionIdxPreeq, conditionIdxSim, + getSimAndPreeqConditions(simulationIdx, + conditionIdxPreeq, + conditionIdxSim, edata.reinitializeFixedParameterInitialStates); - if(conditionIdxPreeq >= 0) { + if (conditionIdxPreeq >= 0) { // -1 means no preequilibration - edata.fixedParametersPreequilibration.resize(model->nk()); - readFixedSimulationParameters( - conditionIdxPreeq, - edata.fixedParametersPreequilibration); + edata.fixedParametersPreequilibration.resize(model_->nk()); + readFixedSimulationParameters(conditionIdxPreeq, + edata.fixedParametersPreequilibration); } else { edata.fixedParametersPreequilibration.resize(0); } readFixedSimulationParameters(conditionIdxSim, edata.fixedParameters); } -void MultiConditionDataProviderHDF5::readFixedSimulationParameters( - int conditionIdx, gsl::span buffer) const +void MultiConditionDataProviderHDF5::setModel(std::unique_ptr model) { - if(!model->nk()) + model_ = std::move(model); +} + +std::vector MultiConditionDataProviderHDF5::getProblemParameterIds() const +{ + return hdf5Read1dStringDataset(file_, hdf5_parameter_ids_path_); + +} + +void +MultiConditionDataProviderHDF5::readFixedSimulationParameters( + int conditionIdx, + gsl::span buffer) const +{ + if (!model_->nk()) return; auto lock = hdf5MutexGetLock(); H5_SAVE_ERROR_HANDLER; - hdf5Read2DDoubleHyperslab(file.getId(), hdf5ConditionPath.c_str(), - model->nk(), 1, - 0, conditionIdx, buffer); + hdf5Read2DDoubleHyperslab(file_.getId(), + hdf5_condition_path_.c_str(), + model_->nk(), + 1, + 0, + conditionIdx, + buffer); if (H5Eget_num(H5E_DEFAULT)) { logmessage(LOGLVL_CRITICAL, "Problem in readFixedParameters (row %d, nk %d)\n", - conditionIdx, model->nk()); + conditionIdx, + model_->nk()); printBacktrace(20); - H5Ewalk2(H5E_DEFAULT, H5E_WALK_DOWNWARD, hdf5ErrorStackWalker_cb, nullptr); + H5Ewalk2( + H5E_DEFAULT, H5E_WALK_DOWNWARD, hdf5ErrorStackWalker_cb, nullptr); abort(); } H5_RESTORE_ERROR_HANDLER; - if(H5Eget_num(H5E_DEFAULT)) - throw ParPEException("MultiConditionDataProviderHDF5::updateFixedSimulationParameters unable to read data"); + if (H5Eget_num(H5E_DEFAULT)) + throw ParPEException("MultiConditionDataProviderHDF5::" + "updateFixedSimulationParameters " + "unable to read data"); } std::unique_ptr MultiConditionDataProviderHDF5::getExperimentalDataForCondition( int simulationIdx) const { - auto lock = hdf5MutexGetLock(); + auto edata = std::make_unique(*model_); - auto edata = std::make_unique(*model); - RELEASE_ASSERT(edata, "Failed getting experimental data. Check data file."); - { - auto lock = hdf5MutexGetLock(); - edata->setTimepoints( - amici::hdf5::getDoubleDataset1D( - file, rootPath + "/measurements/t/" - + std::to_string(simulationIdx))); - } + auto lock = hdf5MutexGetLock(); + edata->setTimepoints( + amici::hdf5::getDoubleDataset1D( + file_, root_path_ + "/measurements/t/" + + std::to_string(simulationIdx))); edata->setObservedData(getMeasurementForSimulationIndex(simulationIdx)); edata->setObservedDataStdDev(getSigmaForSimulationIndex(simulationIdx)); updateFixedSimulationParameters(simulationIdx, *edata); @@ -259,105 +299,125 @@ std::unique_ptr MultiConditionDataProviderHDF5::getExperimentalD return edata; } -std::vector > MultiConditionDataProviderHDF5::getAllMeasurements() const { +std::vector> +MultiConditionDataProviderHDF5::getAllMeasurements() const +{ std::vector> result(getNumberOfSimulationConditions()); - for(int conditionIdx = 0; (unsigned) conditionIdx < result.size(); ++conditionIdx) { + for (int conditionIdx = 0; (unsigned)conditionIdx < result.size(); + ++conditionIdx) { result[conditionIdx] = getMeasurementForSimulationIndex(conditionIdx); } return result; } -std::vector > MultiConditionDataProviderHDF5::getAllSigmas() const +std::vector> +MultiConditionDataProviderHDF5::getAllSigmas() const { - // TODO: how to deal with sigma parameters vs table std::vector> result(getNumberOfSimulationConditions()); - for(int conditionIdx = 0; (unsigned) conditionIdx < result.size(); ++conditionIdx) { - result[conditionIdx]= getSigmaForSimulationIndex(conditionIdx); + for (int conditionIdx = 0; (unsigned)conditionIdx < result.size(); + ++conditionIdx) { + result[conditionIdx] = getSigmaForSimulationIndex(conditionIdx); } return result; } -std::vector MultiConditionDataProviderHDF5::getSigmaForSimulationIndex(int simulationIdx) const +std::vector +MultiConditionDataProviderHDF5::getSigmaForSimulationIndex( + int simulationIdx) const { hsize_t dim1, dim2; auto lock = hdf5MutexGetLock(); - return amici::hdf5::getDoubleDataset2D( - file, - hdf5MeasurementSigmaPath + "/" + std::to_string(simulationIdx), - dim1, dim2); + return amici::hdf5::getDoubleDataset2D(file_, + hdf5_measurement_sigma_path_ + "/" + + std::to_string(simulationIdx), + dim1, + dim2); } -std::vector MultiConditionDataProviderHDF5::getMeasurementForSimulationIndex(int simulationIdx) const +std::vector +MultiConditionDataProviderHDF5::getMeasurementForSimulationIndex( + int simulationIdx) const { hsize_t dim1, dim2; auto lock = hdf5MutexGetLock(); - return amici::hdf5::getDoubleDataset2D( - file, hdf5MeasurementPath + "/" + std::to_string(simulationIdx), - dim1, dim2); + return amici::hdf5::getDoubleDataset2D(file_, + hdf5_measurement_path_ + "/" + + std::to_string(simulationIdx), + dim1, + dim2); } -void MultiConditionDataProviderHDF5::getOptimizationParametersLowerBounds( - gsl::span buffer) const { +void +MultiConditionDataProviderHDF5::getOptimizationParametersLowerBounds( + gsl::span buffer) const +{ auto lock = hdf5MutexGetLock(); - auto dataset = file.openDataSet(hdf5ParameterMinPath); + auto dataset = file_.openDataSet(hdf5_parameter_min_path_); auto dataspace = dataset.getSpace(); - RELEASE_ASSERT(dataspace.getSimpleExtentNdims() == 1, - "hdf5ParameterMinPath dimensions dont match"); + // hdf5ParameterMinPath dimensions don't match + Expects(dataspace.getSimpleExtentNdims() == 1); hsize_t dim = 0; dataspace.getSimpleExtentDims(&dim); - RELEASE_ASSERT(dim == (unsigned) getNumOptimizationParameters(), - "hdf5ParameterMinPath dimensions dont match"); - RELEASE_ASSERT(dim == buffer.size(), ""); + Expects(dim == (unsigned)getNumOptimizationParameters()); + Expects(dim == buffer.size()); dataset.read(buffer.data(), H5::PredType::NATIVE_DOUBLE); } -void MultiConditionDataProviderHDF5::getOptimizationParametersUpperBounds( - gsl::span buffer) const { +void +MultiConditionDataProviderHDF5::getOptimizationParametersUpperBounds( + gsl::span buffer) const +{ auto lock = hdf5MutexGetLock(); - auto dataset = file.openDataSet(hdf5ParameterMaxPath); + auto dataset = file_.openDataSet(hdf5_parameter_max_path_); auto dataspace = dataset.getSpace(); - RELEASE_ASSERT(dataspace.getSimpleExtentNdims() == 1, - "hdf5ParameterMaxPath dimensions dont match"); + // hdf5ParameterMaxPath dimensions dont match + Expects(dataspace.getSimpleExtentNdims() == 1); hsize_t dim = 0; dataspace.getSimpleExtentDims(&dim); - RELEASE_ASSERT(dim == (unsigned) getNumOptimizationParameters(), - "hdf5ParameterMaxPath dimensions dont match"); - RELEASE_ASSERT(dim == buffer.size(), ""); + Expects(dim == (unsigned)getNumOptimizationParameters()); + Expects(dim == buffer.size()); dataset.read(buffer.data(), H5::PredType::NATIVE_DOUBLE); } -int MultiConditionDataProviderHDF5::getNumOptimizationParameters() const { - std::string path = rootPath + "/parameters/parameterNames"; +int +MultiConditionDataProviderHDF5::getNumOptimizationParameters() const +{ + std::string path = root_path_ + "/parameters/parameterNames"; int size = 0; - hdf5GetDatasetDimensions(file.getId(), path.c_str(), 1, &size); + hdf5GetDatasetDimensions(file_.getId(), path.c_str(), 1, &size); return size; } - -std::unique_ptr MultiConditionDataProviderHDF5::getModel() const { - return std::unique_ptr(model->clone()); +std::unique_ptr +MultiConditionDataProviderHDF5::getModel() const +{ + return std::unique_ptr(model_->clone()); } -std::unique_ptr MultiConditionDataProviderHDF5::getSolver() const +std::unique_ptr +MultiConditionDataProviderHDF5::getSolver() const { - auto solver = model->getSolver(); + auto solver = model_->getSolver(); auto lock = hdf5MutexGetLock(); - amici::hdf5::readSolverSettingsFromHDF5(file, *solver, hdf5AmiciOptionPath); + amici::hdf5::readSolverSettingsFromHDF5( + file_, *solver, hdf5_amici_options_path_); return solver; } - -void MultiConditionDataProviderHDF5::updateSimulationParametersAndScale( - int simulationIdx, gsl::span optimizationParams, - amici::Model &model) const +void +MultiConditionDataProviderHDF5::updateSimulationParametersAndScale( + int simulationIdx, + gsl::span optimizationParams, + amici::Model& model) const { // int conditionIdxPreeq, conditionIdxSim; - // getSimAndPreeqConditions(simulationIdx, conditionIdxPreeq, conditionIdxSim); + // getSimAndPreeqConditions(simulationIdx, conditionIdxPreeq, + // conditionIdxSim); auto scaleSim = getParameterScaleSim(simulationIdx); auto p = model.getParameters(); @@ -365,33 +425,44 @@ void MultiConditionDataProviderHDF5::updateSimulationParametersAndScale( model.setParameterScale(scaleSim); mapAndSetOptimizationToSimulationVariables( - simulationIdx, optimizationParams, p, scaleOpt, - scaleSim); + simulationIdx, optimizationParams, p, scaleOpt, scaleSim); model.setParameters(p); } -void MultiConditionDataProviderHDF5::copyInputData(H5::H5File const& target) +void +MultiConditionDataProviderHDF5::copyInputData(H5::H5File const& target) { - H5Ocopy(file.getId(), "/", target.getId(), "/inputData", H5P_DEFAULT, H5P_DEFAULT); + H5Ocopy(file_.getId(), + "/", + target.getId(), + "/inputData", + H5P_DEFAULT, + H5P_DEFAULT); H5Fflush(target.getId(), H5F_SCOPE_LOCAL); } -void MultiConditionDataProviderHDF5::getSimAndPreeqConditions( - const int simulationIdx, int &preequilibrationConditionIdx, - int &simulationConditionIdx, bool &reinitializeFixedParameterInitialStates) const +void +MultiConditionDataProviderHDF5::getSimAndPreeqConditions( + const int simulationIdx, + int& preequilibrationConditionIdx, + int& simulationConditionIdx, + bool& reinitializeFixedParameterInitialStates) const { - auto tmp = hdf5Read2DIntegerHyperslab(file, hdf5ReferenceConditionPath, - 1, 3, simulationIdx, 0); + auto tmp = hdf5Read2DIntegerHyperslab( + file_, hdf5_reference_condition_path_, 1, 3, simulationIdx, 0); preequilibrationConditionIdx = tmp[0]; simulationConditionIdx = tmp[1]; reinitializeFixedParameterInitialStates = tmp[2]; } -hid_t MultiConditionDataProviderHDF5::getHdf5FileId() const { return file.getId(); } - +hid_t +MultiConditionDataProviderHDF5::getHdf5FileId() const +{ + return file_.getId(); +} -//void MultiConditionDataProvider::printInfo() const { +// void MultiConditionDataProvider::printInfo() const { // int maxwidth = 25; // int numMultiStartRuns = getNumMultiStartRuns(); // logmessage(LOGLVL_INFO, "%*s: %d", maxwidth, "Num multistart optims", @@ -409,207 +480,246 @@ hid_t MultiConditionDataProviderHDF5::getHdf5FileId() const { return file.getId( // getMaxIter()); //} - - -void MultiConditionDataProviderHDF5::checkDataIntegrity() const { +void +MultiConditionDataProviderHDF5::checkDataIntegrity() const +{ // check matching IDs - std::string modelParameterIdsPath = rootPath + "/model/parameterIds"; - auto dataParameterIds = hdf5Read1dStringDataset(file, - modelParameterIdsPath); - auto modelParameterIds = this->model->getParameterIds(); + std::string modelParameterIdsPath = root_path_ + "/model/parameterIds"; + auto dataParameterIds = + hdf5Read1dStringDataset(file_, modelParameterIdsPath); + auto modelParameterIds = this->model_->getParameterIds(); RELEASE_ASSERT(dataParameterIds == modelParameterIds, "Parameter IDs do not match."); - std::string speciesIdsPath = rootPath + "/model/stateIds"; - auto dataSpeciesIds = hdf5Read1dStringDataset(file, speciesIdsPath); - RELEASE_ASSERT(dataSpeciesIds == model->getStateIds(), + std::string speciesIdsPath = root_path_ + "/model/stateIds"; + auto dataSpeciesIds = hdf5Read1dStringDataset(file_, speciesIdsPath); + RELEASE_ASSERT(dataSpeciesIds == model_->getStateIds(), "State IDs do not match."); - std::string fixedParIdsPath = rootPath + "/model/fixedParameterIds"; - auto fixedParIds = hdf5Read1dStringDataset(file, fixedParIdsPath); - RELEASE_ASSERT(fixedParIds == model->getFixedParameterIds(), + std::string fixedParIdsPath = root_path_ + "/model/fixedParameterIds"; + auto fixedParIds = hdf5Read1dStringDataset(file_, fixedParIdsPath); + RELEASE_ASSERT(fixedParIds == model_->getFixedParameterIds(), "Fixed parameter IDs do not match."); - std::string observableIdsPath = rootPath + "/model/observableIds"; - auto observableIds = hdf5Read1dStringDataset(file, observableIdsPath); - RELEASE_ASSERT(observableIds == model->getObservableIds(), + std::string observableIdsPath = root_path_ + "/model/observableIds"; + auto observableIds = hdf5Read1dStringDataset(file_, observableIdsPath); + RELEASE_ASSERT(observableIds == model_->getObservableIds(), "Observable IDs do not match."); - //int numConditions = getNumberOfSimulationConditions(); + // int numConditions = getNumberOfSimulationConditions(); - int d1, d2;//, d3; + int d1, d2; //, d3; auto lock = hdf5MutexGetLock(); - assert(H5Lexists(file.getId(), hdf5MeasurementPath.c_str(), H5P_DEFAULT)); - assert(H5Lexists(file.getId(), hdf5MeasurementSigmaPath.c_str(), H5P_DEFAULT)); - -// parpe::hdf5GetDatasetDimensions(file.getId(), hdf5MeasurementPath.c_str(), -// 3, &d1, &d2, &d3); -// RELEASE_ASSERT(d1 >= numConditions, ""); -// RELEASE_ASSERT(d2 == model->nytrue, ""); -// RELEASE_ASSERT(d3 >= model->nt(), ""); - -// parpe::hdf5GetDatasetDimensions(file.getId(), hdf5MeasurementSigmaPath.c_str(), -// 3, &d1, &d2, &d3); -// RELEASE_ASSERT(d1 >= numConditions, ""); -// RELEASE_ASSERT(d2 == model->nytrue, ""); -// RELEASE_ASSERT(d3 >= model->nt(), ""); - - if(model->nk()) { - parpe::hdf5GetDatasetDimensions(file.getId(), hdf5ConditionPath.c_str(), - 2, &d1, &d2); - RELEASE_ASSERT(d1 == model->nk(), ""); + Ensures( + H5Lexists(file_.getId(), hdf5_measurement_path_.c_str(), H5P_DEFAULT)); + Ensures(H5Lexists( + file_.getId(), hdf5_measurement_sigma_path_.c_str(), H5P_DEFAULT)); + + // parpe::hdf5GetDatasetDimensions(file.getId(), + // hdf5MeasurementPath.c_str(), + // 3, &d1, &d2, &d3); + // RELEASE_ASSERT(d1 >= numConditions, ""); + // RELEASE_ASSERT(d2 == model->nytrue, ""); + // RELEASE_ASSERT(d3 >= model->nt(), ""); + + // parpe::hdf5GetDatasetDimensions(file.getId(), + // hdf5MeasurementSigmaPath.c_str(), + // 3, &d1, &d2, &d3); + // RELEASE_ASSERT(d1 >= numConditions, ""); + // RELEASE_ASSERT(d2 == model->nytrue, ""); + // RELEASE_ASSERT(d3 >= model->nt(), ""); + + if (model_->nk()) { + parpe::hdf5GetDatasetDimensions( + file_.getId(), hdf5_condition_path_.c_str(), 2, &d1, &d2); + Expects(d1 == model_->nk()); } } +MultiConditionDataProviderDefault::MultiConditionDataProviderDefault( + std::unique_ptr model, + std::unique_ptr solver) + : model_(std::move(model)) + , solver_(std::move(solver)) +{} -MultiConditionDataProviderDefault::MultiConditionDataProviderDefault(std::unique_ptr model, std::unique_ptr solver) - :model(std::move(model)), solver(std::move(solver)) +int +MultiConditionDataProviderDefault::getNumberOfSimulationConditions() const { - -} - -int MultiConditionDataProviderDefault::getNumberOfSimulationConditions() const -{ - return edata.size(); + return edata_.size(); } std::vector MultiConditionDataProviderDefault::getSimulationToOptimizationParameterMapping( - int /*conditionIdx*/) const + int /*conditionIdx*/) const { - std::vector mapping(model->np()); + std::vector mapping(model_->np()); std::iota(mapping.begin(), mapping.end(), 0); return mapping; } -void MultiConditionDataProviderDefault -::mapSimulationToOptimizationGradientAddMultiply(int conditionIdx, gsl::span simulation, - gsl::span optimization, - gsl::span parameters, double coefficient) const +void +MultiConditionDataProviderDefault :: + mapSimulationToOptimizationGradientAddMultiply( + int conditionIdx, + gsl::span simulation, + gsl::span optimization, + gsl::span /*parameters*/, + double coefficient) const { // TODO redundant auto mapping = getSimulationToOptimizationParameterMapping(conditionIdx); - for(int i = 0; i < model->np(); ++i) { + for (int i = 0; i < model_->np(); ++i) { optimization[mapping[i]] = coefficient * simulation[i]; } } -void MultiConditionDataProviderDefault::mapAndSetOptimizationToSimulationVariables(int conditionIdx, gsl::span optimization, gsl::span simulation, gsl::span optimizationScale, gsl::span simulationScale) const +void +MultiConditionDataProviderDefault::mapAndSetOptimizationToSimulationVariables( + int conditionIdx, + gsl::span optimization, + gsl::span simulation, + gsl::span /*optimizationScale*/, + gsl::span /*simulationScale*/) const { // TODO redundant auto mapping = getSimulationToOptimizationParameterMapping(conditionIdx); - for(int i = 0; i < model->np(); ++i) { + for (int i = 0; i < model_->np(); ++i) { simulation[i] = optimization[mapping[i]]; } - } -std::vector MultiConditionDataProviderDefault::getParameterScaleOpt() const +std::vector +MultiConditionDataProviderDefault::getParameterScaleOpt() const { - return model->getParameterScale(); + return model_->getParameterScale(); } -amici::ParameterScaling MultiConditionDataProviderDefault::getParameterScaleOpt(int optimizationParameterIndex) const +amici::ParameterScaling +MultiConditionDataProviderDefault::getParameterScaleOpt( + int optimizationParameterIndex) const { return getParameterScaleSim(0, optimizationParameterIndex); } -amici::ParameterScaling MultiConditionDataProviderDefault::getParameterScaleSim( - int /*simulationIdx*/, int optimizationParameterIndex) const +amici::ParameterScaling +MultiConditionDataProviderDefault::getParameterScaleSim( + int /*simulationIdx*/, + int optimizationParameterIndex) const { // TODO assumes no extra optimization parameters - return model->getParameterScale()[optimizationParameterIndex]; + return model_->getParameterScale()[optimizationParameterIndex]; } std::vector -MultiConditionDataProviderDefault::getParameterScaleSim(int simulationIdx) const +MultiConditionDataProviderDefault::getParameterScaleSim( + int /*simulationIdx*/) const { - return model->getParameterScale(); + return model_->getParameterScale(); } - -void MultiConditionDataProviderDefault::updateSimulationParametersAndScale(int /*conditionIndex*/, gsl::span optimizationParams, amici::Model &model) const +void +MultiConditionDataProviderDefault::updateSimulationParametersAndScale( + int /*conditionIndex*/, + gsl::span optimizationParams, + amici::Model& model) const { - logmessage(LOGLVL_WARNING, "MultiConditionDataProviderDefault::updateSimulationParameters: No proper mapping implemented. Ensure this is correct."); - model.setParameters(std::vector(optimizationParams.begin(), optimizationParams.end())); + logmessage(LOGLVL_WARNING, + "MultiConditionDataProviderDefault::updateSimulationParameters: " + "No proper mapping implemented. Ensure this is correct."); + model.setParameters(std::vector(optimizationParams.begin(), + optimizationParams.end())); } -std::unique_ptr MultiConditionDataProviderDefault::getExperimentalDataForCondition(int conditionIdx) const +std::unique_ptr +MultiConditionDataProviderDefault::getExperimentalDataForCondition( + int conditionIdx) const { - return std::make_unique(edata[conditionIdx]); + return std::make_unique(edata_[conditionIdx]); } -std::vector > MultiConditionDataProviderDefault::getAllMeasurements() const +std::vector> +MultiConditionDataProviderDefault::getAllMeasurements() const { - std::vector > measurements; - for(const auto& e: edata) { + std::vector> measurements; + for (const auto& e : edata_) { measurements.push_back(e.getObservedData()); } return measurements; } -std::vector > MultiConditionDataProviderDefault::getAllSigmas() const +std::vector> +MultiConditionDataProviderDefault::getAllSigmas() const { - std::vector > sigmas; - for(const auto& e: edata) { + std::vector> sigmas; + for (const auto& e : edata_) { sigmas.push_back(e.getObservedDataStdDev()); } return sigmas; } +int +MultiConditionDataProviderDefault::getNumOptimizationParameters() const +{ + return model_->np(); +} -int MultiConditionDataProviderDefault::getNumOptimizationParameters() const +std::unique_ptr +MultiConditionDataProviderDefault::getModel() const { - return model->np(); + return std::unique_ptr(model_->clone()); } -std::unique_ptr MultiConditionDataProviderDefault::getModel() const +std::unique_ptr +MultiConditionDataProviderDefault::getSolver() const { - return std::unique_ptr(model->clone()); + return std::unique_ptr(solver_->clone()); } -std::unique_ptr MultiConditionDataProviderDefault::getSolver() const +std::vector MultiConditionDataProviderDefault::getProblemParameterIds() const { - return std::unique_ptr(solver->clone()); + // not implemented + std::terminate(); } -double applyChainRule(double gradient, double parameter, - amici::ParameterScaling oldScale, - amici::ParameterScaling newScale) +double +applyChainRule(double gradient, + double parameter, + amici::ParameterScaling oldScale, + amici::ParameterScaling newScale) { - if(oldScale == newScale) + if (oldScale == newScale) return gradient; // unapply old switch (oldScale) { - case amici::ParameterScaling::log10: - gradient /= getUnscaledParameter(parameter, oldScale) * log(10); - break; - case amici::ParameterScaling::ln: - gradient /= getUnscaledParameter(parameter, oldScale); - break; - case amici::ParameterScaling::none: - break; + case amici::ParameterScaling::log10: + gradient /= getUnscaledParameter(parameter, oldScale) * log(10); + break; + case amici::ParameterScaling::ln: + gradient /= getUnscaledParameter(parameter, oldScale); + break; + case amici::ParameterScaling::none: + break; } // apply switch (newScale) { - case amici::ParameterScaling::log10: - gradient *= getUnscaledParameter(parameter, oldScale) * log(10); - break; - case amici::ParameterScaling::ln: - gradient *= getUnscaledParameter(parameter, oldScale); - break; - case amici::ParameterScaling::none: - break; + case amici::ParameterScaling::log10: + gradient *= getUnscaledParameter(parameter, oldScale) * log(10); + break; + case amici::ParameterScaling::ln: + gradient *= getUnscaledParameter(parameter, oldScale); + break; + case amici::ParameterScaling::none: + break; } return gradient; } - } // namespace parpe diff --git a/src/parpeamici/multiConditionProblem.cpp b/src/parpeamici/multiConditionProblem.cpp index 3e7c46bb3..a1a30ce53 100644 --- a/src/parpeamici/multiConditionProblem.cpp +++ b/src/parpeamici/multiConditionProblem.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -46,12 +45,12 @@ MultiConditionProblem::MultiConditionProblem( : dataProvider(dp), resultWriter(std::move(resultWriter)) { - this->logger = std::move(logger); + this->logger_ = std::move(logger); // run on all data std::vector dataIndices(dataProvider->getNumberOfSimulationConditions()); std::iota(dataIndices.begin(), dataIndices.end(), 0); - costFun = std::make_unique< + cost_fun_ = std::make_unique< SummedGradientFunctionGradientFunctionAdapter > ( std::make_unique( @@ -70,20 +69,20 @@ MultiConditionProblem::MultiConditionProblem( void MultiConditionProblem::fillParametersMin(gsl::span buffer) const { - RELEASE_ASSERT(buffer.size() == parametersMin.size(), ""); + Expects(buffer.size() == parametersMin.size()); std::copy(parametersMin.begin(), parametersMin.end(), buffer.begin()); } void MultiConditionProblem::fillParametersMax(gsl::span buffer) const { - RELEASE_ASSERT(buffer.size() == parametersMax.size(), ""); + Expects(buffer.size() == parametersMax.size()); std::copy(parametersMax.begin(), parametersMax.end(), buffer.begin()); } void MultiConditionProblem::fillInitialParameters(gsl::span buffer) const { if(!startingPoint.empty()) { - RELEASE_ASSERT(buffer.size() == startingPoint.size(), ""); + Expects(buffer.size() == startingPoint.size()); std::copy(startingPoint.begin(), startingPoint.end(), buffer.begin()); } else { OptimizationProblem::fillInitialParameters(buffer); @@ -133,9 +132,9 @@ std::unique_ptr MultiConditionProblem::getReporter() const { return std::make_unique( - costFun.get(), + cost_fun_.get(), std::make_unique(*resultWriter), - std::make_unique(*logger)); + std::make_unique(*logger_)); } std::vector MultiConditionProblem::getTrainingData() const @@ -160,58 +159,66 @@ ::MultiConditionProblemMultiStartOptimizationProblem( OptimizationOptions options, OptimizationResultWriter *resultWriter, LoadBalancerMaster *loadBalancer, std::unique_ptr logger) - : dp(dp), options(std::move(options)), - resultWriter(resultWriter), loadBalancer(loadBalancer), - logger(std::move(logger)) + : data_provider_(dp), options_(std::move(options)), + result_writer_(resultWriter), load_balancer_(loadBalancer), + logger_(std::move(logger)) {} -int MultiConditionProblemMultiStartOptimizationProblem::getNumberOfStarts() const { return options.numStarts; } +int MultiConditionProblemMultiStartOptimizationProblem::getNumberOfStarts() const { return options_.numStarts; } -bool MultiConditionProblemMultiStartOptimizationProblem::restartOnFailure() const { return options.retryOptimization; } +bool MultiConditionProblemMultiStartOptimizationProblem::restartOnFailure() const { return options_.retryOptimization; } std::unique_ptr MultiConditionProblemMultiStartOptimizationProblem::getLocalProblem( int multiStartIndex) const { // generate new OptimizationProblem with data from dp - RELEASE_ASSERT(dp != nullptr, ""); + Expects(data_provider_ != nullptr); std::unique_ptr problem; - if (resultWriter) { + if (result_writer_) { problem = std::make_unique( - dp, loadBalancer, - logger->getChild(std::string("o") + data_provider_, load_balancer_, + logger_->getChild(std::string("o") + std::to_string(multiStartIndex)), - std::make_unique(*resultWriter)); + std::make_unique(*result_writer_)); problem->getResultWriter()->setRootPath( "/multistarts/" + std::to_string(multiStartIndex)); } else { problem = std::make_unique( - dp, loadBalancer, - logger->getChild( + data_provider_, load_balancer_, + logger_->getChild( std::string("o") + std::to_string(multiStartIndex)), nullptr); } - problem->setOptimizationOptions(options); + problem->setOptimizationOptions(options_); problem->setInitialParameters(parpe::OptimizationOptions::getStartingPoint( - dp->getHdf5FileId(), multiStartIndex)); + data_provider_->getHdf5FileId(), multiStartIndex)); - if(options.hierarchicalOptimization) + if(options_.hierarchicalOptimization) return std::unique_ptr( new parpe::HierarchicalOptimizationProblemWrapper( - std::move(problem), dp)); + std::move(problem), data_provider_)); return std::move(problem); } void printSimulationResult(Logger *logger, int jobId, amici::ReturnData const* rdata, double timeSeconds) { + if(!rdata) { + // This should not happen, but apparently we can't rely on AMICI always + // returning some result object + logger->logmessage(LOGLVL_ERROR, + "AMICI simulation failed unexpectedly."); + return; + } + bool with_sensi = rdata->sensi >= amici::SensitivityOrder::first; logger->logmessage(LOGLVL_DEBUG, "Result for %d: %g (%d) (%d/%d/%.4fs%c)", jobId, rdata->llh, rdata->status, - rdata->numsteps[rdata->numsteps.size() - 1], - rdata->numstepsB.empty()?0:rdata->numstepsB[0], + rdata->numsteps.empty()?-1:rdata->numsteps[rdata->numsteps.size() - 1], + rdata->numstepsB.empty()?-1:rdata->numstepsB[0], timeSeconds, with_sensi?'+':'-'); @@ -239,9 +246,9 @@ void saveSimulation(const H5::H5File &file, std::string const& pathStr, std::vector const& parameters, double llh, gsl::span gradient, double timeElapsedInSeconds, - gsl::span states, - gsl::span stateSensi, - gsl::span outputs, int jobId, + gsl::span /*states*/, + gsl::span /*stateSensi*/, + gsl::span /*outputs*/, int jobId, int status, std::string const& label) { // TODO replace by SimulationResultWriter @@ -374,6 +381,27 @@ AmiciSimulationRunner::AmiciResultPackageSimple runAndLogSimulation( * occurred,so clone every time */ auto solver = std::unique_ptr(solverTemplate.clone()); solver->app = &amiciApp; + if (!sendStates) { + /* If we don't need the states, we can save memory here. + * For current optimizers we only need the likelihood. For + * hierarchical optimization we need the model outputs. Here, we + * don't know about this, but for know it seems safe to use + * amici::RDataReporting::likelihood if sensitivities are requested + * and RDataReporting::residuals otherwise + */ + + if(solver->getSensitivityOrder() >= amici::SensitivityOrder::first + && solver->getSensitivityMethod() + == amici::SensitivityMethod::adjoint) { + solver->setReturnDataReportingMode(amici::RDataReporting::likelihood); + } else { + // unset sensitivity method, because `residuals` is not allowed + // with `adjoint`, independent of sensitivity order + solver->setSensitivityMethod(amici::SensitivityMethod::none); + solver->setReturnDataReportingMode(amici::RDataReporting::residuals); + } + + } if(trial - 1 == maxNumTrials) { logger->logmessage(LOGLVL_ERROR, @@ -387,7 +415,7 @@ AmiciSimulationRunner::AmiciResultPackageSimple runAndLogSimulation( * better exception handling, we check those fields to deduce where * the error occurred */ - bool forwardFailed = std::isnan(rdata->x[rdata->x.size() - 1]); + bool forwardFailed = std::isnan(rdata->llh); bool backwardFailed = solver->getSensitivityOrder() >= amici::SensitivityOrder::first && solver->getSensitivityMethod() == amici::SensitivityMethod::adjoint && !rdata->sllh.empty() && std::isnan(rdata->sllh[0]); @@ -433,51 +461,67 @@ AmiciSimulationRunner::AmiciResultPackageSimple runAndLogSimulation( try { rdata = amiciApp.runAmiciSimulation(*solver, edata.get(), model); } catch (std::exception const& e) { + std::cerr<status); + } logger->logmessage( - LOGLVL_WARNING, "Error during simulation: %s (%d)", - e.what(), rdata->status); - if(rdata->status == AMICI_SUCCESS) - // shouldn't happen, but just to be safe - rdata->status = AMICI_ERROR; - rdata->invalidateLLH(); - rdata->invalidateSLLH(); + LOGLVL_WARNING, "Error during simulation: %s (%s)", + e.what(), status.c_str()); } - if(rdata->status == AMICI_SUCCESS) + if(rdata && rdata->status == amici::AMICI_SUCCESS) break; } double timeSeconds = simulationTimer.getTotal(); printSimulationResult(logger, jobId, rdata.get(), timeSeconds); - if (resultWriter && (solverTemplate.getSensitivityOrder() + if (resultWriter && rdata && (solverTemplate.getSensitivityOrder() > amici::SensitivityOrder::none || logLineSearch)) { saveSimulation(resultWriter->getH5File(), resultWriter->getRootPath(), model.getParameters(), rdata->llh, rdata->sllh, timeSeconds, rdata->x, rdata->sx, rdata->y, jobId, rdata->status, logger->getPrefix()); } + if(rdata) { + return AmiciSimulationRunner::AmiciResultPackageSimple { + rdata->llh, + timeSeconds, + (solverTemplate.getSensitivityOrder() + > amici::SensitivityOrder::none) + ? rdata->sllh : std::vector(), + rdata->y, rdata->sigmay, + sendStates ? rdata->x : std::vector(), + rdata->status + }; + } + // AMICI failed expectedly and did not return anything return AmiciSimulationRunner::AmiciResultPackageSimple { - rdata->llh, - timeSeconds, - (solverTemplate.getSensitivityOrder() - > amici::SensitivityOrder::none) - ? rdata->sllh : std::vector(), - rdata->y, - sendStates ? rdata->x : std::vector(), - rdata->status + NAN, + timeSeconds, + (solverTemplate.getSensitivityOrder() + > amici::SensitivityOrder::none) + ? std::vector(model.nplist(), NAN) : std::vector(), + std::vector(model.nytrue, NAN), + std::vector(model.nytrue, NAN), + sendStates ? std::vector(model.nx_rdata, NAN) : std::vector(), + amici::AMICI_UNRECOVERABLE_ERROR }; + } -FunctionEvaluationStatus getModelOutputs( +FunctionEvaluationStatus getModelOutputsAndSigmas( MultiConditionDataProvider *dataProvider, LoadBalancerMaster *loadBalancer, int maxSimulationsPerPackage, OptimizationResultWriter *resultWriter, bool logLineSearch, gsl::span parameters, - std::vector > &modelOutput, + std::vector > &modelOutputs, + std::vector > &modelSigmas, Logger *logger, double * /*cpuTime*/, bool sendStates) { int errors = 0; @@ -485,10 +529,10 @@ FunctionEvaluationStatus getModelOutputs( std::vector dataIndices(dataProvider->getNumberOfSimulationConditions()); std::iota(dataIndices.begin(), dataIndices.end(), 0); - modelOutput.resize(dataIndices.size()); + modelOutputs.resize(dataIndices.size()); auto parameterVector = std::vector(parameters.begin(), parameters.end()); - auto jobFinished = [&](JobData *job, int /*dataIdx*/) { // jobFinished + auto jobFinished = [&errors, &modelOutputs, &modelSigmas](JobData *job, int /*dataIdx*/) { // deserialize auto results = amici::deserializeFromChar ( @@ -497,9 +541,11 @@ FunctionEvaluationStatus getModelOutputs( for (auto const& result : results) { errors += result.second.status; - modelOutput[result.first] = result.second.modelOutput; + modelOutputs[result.first] = result.second.modelOutput; + modelSigmas[result.first] = result.second.modelSigmas; } }; + AmiciSimulationRunner simRunner(parameterVector, amici::SensitivityOrder::none, dataIndices, @@ -515,7 +561,7 @@ FunctionEvaluationStatus getModelOutputs( } else { #endif errors += simRunner.runSharedMemory( - [&](std::vector &buffer, int jobId) { + [&dataProvider, &resultWriter, logLineSearch, &sendStates](std::vector &buffer, int jobId) { messageHandler(dataProvider, resultWriter, logLineSearch, buffer, jobId, sendStates); }); @@ -643,22 +689,24 @@ int AmiciSummedGradientFunction::numParameters() const return dataProvider->getNumOptimizationParameters(); } -FunctionEvaluationStatus AmiciSummedGradientFunction::getModelOutputs( - gsl::span parameters, - std::vector > &modelOutput, - Logger *logger, double *cpuTime) const +std::vector AmiciSummedGradientFunction::getParameterIds() const { - return parpe::getModelOutputs(dataProvider, loadBalancer, - maxSimulationsPerPackage, resultWriter, - logLineSearch, parameters, modelOutput, - logger, cpuTime, sendStates); + return dataProvider->getProblemParameterIds(); } -std::vector > AmiciSummedGradientFunction::getAllSigmas() const { - // TODO: some could be parameter-dependent - return dataProvider->getAllSigmas(); +FunctionEvaluationStatus AmiciSummedGradientFunction::getModelOutputsAndSigmas( + gsl::span parameters, + std::vector > &modelOutputs, + std::vector > &modelSigmas, + Logger *logger, double *cpuTime) const +{ + return parpe::getModelOutputsAndSigmas( + dataProvider, loadBalancer, maxSimulationsPerPackage, resultWriter, + logLineSearch, parameters, modelOutputs, modelSigmas, + logger, cpuTime, sendStates); } + std::vector > AmiciSummedGradientFunction::getAllMeasurements() const { return dataProvider->getAllMeasurements(); } @@ -694,8 +742,9 @@ int AmiciSummedGradientFunction::runSimulations( ? amici::SensitivityOrder::first : amici::SensitivityOrder::none, dataIndices, - [&](JobData *job, int /*jobIdx*/) { - errors += aggregateLikelihood(*job, + [&nllh, &objectiveFunctionGradient, &simulationTimeSec, + &optimizationParameters, &errors, this](JobData *job, int /*jobIdx*/) { + errors += this->aggregateLikelihood(*job, nllh, objectiveFunctionGradient, simulationTimeSec, @@ -715,8 +764,8 @@ int AmiciSummedGradientFunction::runSimulations( } else { #endif errors += simRunner.runSharedMemory( - [&](std::vector &buffer, int jobId) { - messageHandler(buffer, jobId); + [this](std::vector &buffer, int jobId) { + this->messageHandler(buffer, jobId); }); #ifdef PARPE_ENABLE_MPI } @@ -747,7 +796,7 @@ int AmiciSummedGradientFunction::aggregateLikelihood( ResultPackage resultPackage; std::tie(conditionIdx, resultPackage) = result; - errors += resultPackage.status != AMICI_SUCCESS; + errors += resultPackage.status != amici::AMICI_SUCCESS; // sum up negLogLikelihood -= resultPackage.llh; diff --git a/src/parpeamici/optimizationApplication.cpp b/src/parpeamici/optimizationApplication.cpp index a497ca5f0..f44177edb 100644 --- a/src/parpeamici/optimizationApplication.cpp +++ b/src/parpeamici/optimizationApplication.cpp @@ -250,15 +250,15 @@ void OptimizationApplication::runWorker() { LoadBalancerWorker lbw; lbw.run([this](std::vector &buffer, int jobId) { // TODO: this is so damn ugly - auto sgf = dynamic_cast*>(problem->costFun.get()); + auto sgf = dynamic_cast*>(problem->cost_fun_.get()); if(sgf) { // non-hierarchical dynamic_cast(sgf->getWrappedFunction())->messageHandler(buffer, jobId); } else { // hierarchical - auto hierarch = dynamic_cast(problem->costFun.get()); - RELEASE_ASSERT(hierarch, ""); - hierarch->fun->messageHandler(buffer, jobId); + auto hierarch = dynamic_cast(problem->cost_fun_.get()); + Expects(hierarch != nullptr); + hierarch->getWrappedFunction()->messageHandler(buffer, jobId); } }); } diff --git a/src/parpeamici/simulationResultWriter.cpp b/src/parpeamici/simulationResultWriter.cpp index d32f72149..9f62d8da8 100644 --- a/src/parpeamici/simulationResultWriter.cpp +++ b/src/parpeamici/simulationResultWriter.cpp @@ -118,9 +118,8 @@ void SimulationResultWriter::saveMeasurements( return; } - RELEASE_ASSERT(measurements.size() == - static_cast(nt * nytrue), - ""); + Expects(measurements.size() == + static_cast(nt * nytrue)); auto lock = parpe::hdf5MutexGetLock(); @@ -144,8 +143,8 @@ void SimulationResultWriter::saveModelOutputs( return; } - RELEASE_ASSERT(outputs.size() == - static_cast(nt * nytrue), ""); + Expects(outputs.size() == + static_cast(nt * nytrue)); auto lock = parpe::hdf5MutexGetLock(); @@ -169,8 +168,8 @@ void SimulationResultWriter::saveStates( return; } - RELEASE_ASSERT(states.size() == - static_cast(nt * nx), ""); + Expects(states.size() == + static_cast(nt * nx)); auto lock = parpe::hdf5MutexGetLock(); diff --git a/src/parpeamici/standaloneSimulator.cpp b/src/parpeamici/standaloneSimulator.cpp index 0ff5544b0..25177415c 100644 --- a/src/parpeamici/standaloneSimulator.cpp +++ b/src/parpeamici/standaloneSimulator.cpp @@ -20,7 +20,7 @@ namespace parpe { StandaloneSimulator::StandaloneSimulator(MultiConditionDataProvider* dp) - : dataProvider(dp) + : dataProvider(dp) { if (auto env = std::getenv("PARPE_MAX_SIMULATIONS_PER_PACKAGE")) { maxSimulationsPerPackage = std::stoi(env); @@ -30,14 +30,13 @@ StandaloneSimulator::StandaloneSimulator(MultiConditionDataProvider* dp) int StandaloneSimulator::run(const std::string& resultFile, const std::string& resultPath, - std::vector const& optimizationParameters, + std::map& optimizationParameters, LoadBalancerMaster* loadBalancer, H5::H5File const& conditionFile, - std::string conditionFilePath) + std::string conditionFilePath, + bool computeInnerParameters) { - // std::cout<<"file: "<getModel(); auto solver = dataProvider->getSolver(); solver->setSensitivityOrder(amici::SensitivityOrder::none); - std::vector parameters = optimizationParameters; - HierarchicalOptimizationWrapper hierarchical(nullptr, 0, 0); - - /* If the provided parameter vector is shorter than required, this means, we - * got only the result of the outer problem of an hierarchical optimization - * run, and thus, need to compute the inner optimal parameters here. - */ - // TODO: check parameter names! until this is implemented, let's always - // recompute output parameters - bool needComputeAnalyticalParameters = true; - // (parameters.size() != - // (unsigned)dataProvider->getNumOptimizationParameters()); - - if (needComputeAnalyticalParameters) { - if (hdf5GroupExists(conditionFile.getId(), "inputData")) - // TODO: might not be the best place to have that here - conditionFilePath += "/inputData"; + auto wrappedFun = std::make_unique( + dataProvider, loadBalancer, nullptr); + wrappedFun->sendStates = true; + + AmiciSimulationRunner::callbackJobFinishedType jobFinished; + AmiciSimulationRunner::callbackAllFinishedType allFinished; + + std::vector dataIndices( + dataProvider->getNumberOfSimulationConditions()); + std::iota(dataIndices.begin(), dataIndices.end(), 0); + + std::vector parameterValues; + int errors = 0; + + rw.createDatasets(dataProvider->getNumberOfSimulationConditions()); + + // Write IDs + auto resultFileH5 = rw.reopenFile(); + hdf5EnsureGroupExists(resultFileH5.getId(), resultPath.c_str()); + { + auto lock = hdf5MutexGetLock(); + hdf5Write1dStringDataset(resultFileH5, + resultPath, + "stateIds", + model->getStateIds()); + hdf5Write1dStringDataset(resultFileH5, + resultPath, + "observableIds", + model->getObservableIds()); + hdf5Write1dStringDataset(resultFileH5, + resultPath, + "parameterIds", + model->getParameterIds()); + } + + std::cout << "Starting simulation. Number of conditions: " + << dataProvider->getNumberOfSimulationConditions() << std::endl; + std::unique_ptr simRunner; + + if(computeInnerParameters) { + // hierarchical optimization + HierarchicalOptimizationWrapper hierarchical(nullptr, 0, 0); + // TODO: get rid of that. we want fun.evaluate(), independently of // hierarchical or not auto hierarchicalScalingReader = - std::make_unique( - conditionFile, - conditionFilePath + "/scalingParameterIndices", - conditionFilePath + "/scalingParametersMapToObservables"); + std::make_unique( + conditionFile, + conditionFilePath + "/scalingParameterIndices", + conditionFilePath + "/scalingParametersMapToObservables"); auto hierarchicalOffsetReader = - std::make_unique( - conditionFile, - conditionFilePath + "/offsetParameterIndices", - conditionFilePath + "/offsetParametersMapToObservables"); + std::make_unique( + conditionFile, + conditionFilePath + "/offsetParameterIndices", + conditionFilePath + "/offsetParametersMapToObservables"); auto hierarchicalSigmaReader = - std::make_unique( - conditionFile, - conditionFilePath + "/sigmaParameterIndices", - conditionFilePath + "/sigmaParametersMapToObservables"); + std::make_unique( + conditionFile, + conditionFilePath + "/sigmaParameterIndices", + conditionFilePath + "/sigmaParametersMapToObservables"); auto proportionalityFactorIndices = - hierarchicalScalingReader->getOptimizationParameterIndices(); + hierarchicalScalingReader->getOptimizationParameterIndices(); auto offsetParameterIndices = - hierarchicalOffsetReader->getOptimizationParameterIndices(); + hierarchicalOffsetReader->getOptimizationParameterIndices(); auto sigmaParameterIndices = - hierarchicalSigmaReader->getOptimizationParameterIndices(); - - auto wrappedFun = std::make_unique( - dataProvider, loadBalancer, nullptr); - wrappedFun->sendStates = true; + hierarchicalSigmaReader->getOptimizationParameterIndices(); hierarchical = HierarchicalOptimizationWrapper( - std::move(wrappedFun), - std::move(hierarchicalScalingReader), - std::move(hierarchicalOffsetReader), - std::move(hierarchicalSigmaReader), - dataProvider->getNumberOfSimulationConditions(), - model->nytrue, - ErrorModel::normal); - std::cout << "Need to compute analytical parameters: " - << conditionFilePath << " " - << proportionalityFactorIndices.size() - << " parameters.size() == " << parameters.size() - << " ; hierarchical.numParameters() == " - << hierarchical.numParameters() << std::endl; - RELEASE_ASSERT( - parameters.size() == (unsigned)hierarchical.numParameters(), ""); + wrappedFun.get(), + std::move(hierarchicalScalingReader), + std::move(hierarchicalOffsetReader), + std::move(hierarchicalSigmaReader), + dataProvider->getNumberOfSimulationConditions(), + model->nytrue, + ErrorModel::normal); + + // Collect parameter values + auto outerParameterNames = hierarchical.getParameterIds(); + std::vector outerParameters(outerParameterNames.size()); + for(int i = 0; i < static_cast(outerParameterNames.size()); ++i) { + outerParameters[i] = optimizationParameters[outerParameterNames[i]]; + } + Expects(outerParameters.size() == (unsigned)hierarchical.numParameters()); // expand parameter vector auto scalingDummy = hierarchical.getDefaultScalingFactors(); auto offsetDummy = hierarchical.getDefaultOffsetParameters(); auto sigmaDummy = hierarchical.getDefaultSigmaParameters(); - parameters = - spliceParameters(gsl::make_span(optimizationParameters.data(), - optimizationParameters.size()), - proportionalityFactorIndices, - offsetParameterIndices, - sigmaParameterIndices, - scalingDummy, - offsetDummy, - sigmaDummy); - // get outputs, scale - // TODO need to pass aggregate function for writing - } else { - // is already the correct length - // parameters = optimizationParameters; + parameterValues = spliceParameters( + outerParameters, + proportionalityFactorIndices, + offsetParameterIndices, + sigmaParameterIndices, + scalingDummy, + offsetDummy, + sigmaDummy); + + allFinished = [this, &dataIndices, &hierarchical, ¶meterValues, + &outerParameters, &resultFileH5, &resultPath, &model, + &rw](std::vector& jobs) + { + /* all finished */ + // must wait for all jobs to finish because of hierarchical + // optimization and scaling factors + std::vector + simulationResults(dataIndices.size()); + std::vector> modelOutputs( + dataIndices.size()); + std::vector> modelSigmas( + dataIndices.size()); + std::vector> modelStates( + dataIndices.size()); + + // collect all model outputs + for (auto& job : jobs) { + auto results = amici::deserializeFromChar< + std::map>( + job.recvBuffer.data(), job.recvBuffer.size()); + job.recvBuffer = std::vector(); // free buffer + for (auto& result : results) { + swap(simulationResults[result.first], result.second); + modelOutputs[result.first] = + simulationResults[result.first].modelOutput; + modelSigmas[result.first] = + simulationResults[result.first].modelSigmas; + modelStates[result.first] = + simulationResults[result.first].modelStates; + + } + } - auto resultFileH5 = rw.reopenFile(); - hdf5EnsureGroupExists(resultFileH5.getId(), resultPath.c_str()); - auto lock = hdf5MutexGetLock(); - amici::hdf5::createAndWriteDouble1DDataset( - resultFileH5, resultPath + "/problemParameters", parameters); - } + // TODO: redundant with hierarchicalOptimization.cpp + // compute scaling factors and offset parameters + auto allMeasurements = dataProvider->getAllMeasurements(); + Expects(dataIndices.size() == allMeasurements.size()); + + auto scalings = hierarchical.computeAnalyticalScalings( + allMeasurements, modelOutputs); + auto offsets = hierarchical.computeAnalyticalOffsets( + allMeasurements, modelOutputs); + hierarchical.applyOptimalScalings(scalings, modelOutputs); + hierarchical.applyOptimalOffsets(offsets, modelOutputs); + auto sigmas = hierarchical.computeAnalyticalSigmas( + allMeasurements, modelOutputs); + if (!hierarchical.getSigmaParameterIndices().empty()) { + hierarchical.fillInAnalyticalSigmas(modelSigmas, + sigmas); + } - RELEASE_ASSERT( - parameters.size() == - (unsigned)dataProvider->getNumOptimizationParameters(), - "Size of supplied parameter vector does not match model dimensions."); + // save parameters + parameterValues = spliceParameters( + outerParameters, + hierarchical.getProportionalityFactorIndices(), + hierarchical.getOffsetParameterIndices(), + hierarchical.getSigmaParameterIndices(), + scalings, + offsets, + sigmas); + { + auto lock = hdf5MutexGetLock(); + amici::hdf5::createAndWriteDouble1DDataset( + resultFileH5, resultPath + "/problemParameters", parameterValues); + } - rw.createDatasets(dataProvider->getNumberOfSimulationConditions()); + // compute llh + for (int conditionIdx = 0; + (unsigned)conditionIdx < simulationResults.size(); + ++conditionIdx) { + double llh = -parpe::computeNegLogLikelihood( + allMeasurements[conditionIdx], + modelOutputs[conditionIdx], + modelSigmas[conditionIdx]); + + auto edata = dataProvider->getExperimentalDataForCondition( + conditionIdx); + rw.saveTimepoints(edata->getTimepoints(), conditionIdx); + if(!modelStates[conditionIdx].empty()) { + rw.saveStates(modelStates[conditionIdx], edata->nt(), + model->nx_rdata, conditionIdx); + } + rw.saveMeasurements(edata->getObservedData(), + edata->nt(), + edata->nytrue(), + conditionIdx); + rw.saveModelOutputs(modelOutputs[conditionIdx], + edata->nt(), + model->nytrue, + conditionIdx); + rw.saveLikelihood(llh, conditionIdx); + + // to save simulation parameters + dataProvider->updateSimulationParametersAndScale( + conditionIdx, parameterValues, *model); + rw.saveParameters(model->getParameters(), + conditionIdx); - std::vector dataIndices( - dataProvider->getNumberOfSimulationConditions()); - std::iota(dataIndices.begin(), dataIndices.end(), 0); - int errors = 0; - std::cout << "Starting simulation. Number of conditions: " - << dataProvider->getNumberOfSimulationConditions() << std::endl; - auto jobFinished = - [&]( - JobData* job, - int /*dataIdx*/) { /* job finished */ - // if we are running hierarchical optimization we - // need to wait until all jobs are finished - if (needComputeAnalyticalParameters) - return; - - auto results = amici::deserializeFromChar>( - job->recvBuffer.data(), job->recvBuffer.size()); - job->recvBuffer = std::vector(); // free buffer - - for (auto const& result : results) { - errors += result.second.status; - int conditionIdx = result.first; - auto edata = - dataProvider->getExperimentalDataForCondition( - conditionIdx); - - rw.saveTimepoints(edata->getTimepoints(), - conditionIdx); - rw.saveMeasurements(edata->getObservedData(), - edata->nt(), - edata->nytrue(), - conditionIdx); - rw.saveModelOutputs(result.second.modelOutput, - edata->nt(), - model->nytrue, - conditionIdx); - rw.saveLikelihood(result.second.llh, - conditionIdx); - - // to save simulation parameters - dataProvider->updateSimulationParametersAndScale(conditionIdx, parameters, *model); - rw.saveParameters(model->getParameters(), - conditionIdx); - } - }; - - auto allFinished = [&](std::vector& jobs) - -> int { /* all finished */ - if (!needComputeAnalyticalParameters) - return 0; // Work was already done in above function - - // must wait for all jobs to finish because of hierarchical - // optimization and scaling factors - std::vector - simulationResults(dataIndices.size()); - std::vector> modelOutputs( - dataIndices.size()); - std::vector> modelStates( - dataIndices.size()); - - // collect all model outputs - for (auto& job : jobs) { - auto results = amici::deserializeFromChar< - std::map>( - job.recvBuffer.data(), job.recvBuffer.size()); - job.recvBuffer = std::vector(); // free buffer - for (auto& result : results) { - swap(simulationResults[result.first], result.second); - modelOutputs[result.first] = - simulationResults[result.first].modelOutput; - modelStates[result.first] = - simulationResults[result.first].modelStates; - - } - } - - // TODO: redundant with hierarchicalOptimization.cpp - // compute scaling factors and offset parameters - auto allMeasurements = dataProvider->getAllMeasurements(); - RELEASE_ASSERT(dataIndices.size() == allMeasurements.size(), ""); - - auto scalings = hierarchical.computeAnalyticalScalings( - allMeasurements, modelOutputs); - auto offsets = hierarchical.computeAnalyticalOffsets( - allMeasurements, modelOutputs); - hierarchical.applyOptimalScalings(scalings, modelOutputs); - hierarchical.applyOptimalOffsets(offsets, modelOutputs); - auto sigmas = hierarchical.computeAnalyticalSigmas( - allMeasurements, modelOutputs); - auto fullSigmaMatrices = hierarchical.fun->getAllSigmas(); - if (!hierarchical.getSigmaParameterIndices().empty()) { - hierarchical.fillInAnalyticalSigmas(fullSigmaMatrices, - sigmas); - } - - // save parameters - parameters = spliceParameters( - parameters, - hierarchical.getProportionalityFactorIndices(), - hierarchical.getOffsetParameterIndices(), - hierarchical.getSigmaParameterIndices(), - scalings, - offsets, - sigmas); - auto resultFileH5 = rw.reopenFile(); - hdf5EnsureGroupExists(resultFileH5.getId(), resultPath.c_str()); - { - auto lock = hdf5MutexGetLock(); - amici::hdf5::createAndWriteDouble1DDataset( - resultFileH5, resultPath + "/problemParameters", parameters); - hdf5Write1dStringDataset(resultFileH5, - resultPath, - "stateIds", - model->getStateIds()); - hdf5Write1dStringDataset(resultFileH5, - resultPath, - "observableIds", - model->getObservableIds()); - hdf5Write1dStringDataset(resultFileH5, - resultPath, - "parameterIds", - model->getParameterIds()); - - } - // compute llh - for (int conditionIdx = 0; - (unsigned)conditionIdx < simulationResults.size(); - ++conditionIdx) { - double llh = -parpe::computeNegLogLikelihood( - allMeasurements[conditionIdx], - modelOutputs[conditionIdx], - fullSigmaMatrices[conditionIdx]); - - auto edata = dataProvider->getExperimentalDataForCondition( - conditionIdx); - rw.saveTimepoints(edata->getTimepoints(), conditionIdx); - if(!modelStates[conditionIdx].empty()) { - rw.saveStates(modelStates[conditionIdx], edata->nt(), - model->nx_rdata, conditionIdx); - } - rw.saveMeasurements(edata->getObservedData(), - edata->nt(), - edata->nytrue(), - conditionIdx); - rw.saveModelOutputs(modelOutputs[conditionIdx], - edata->nt(), - model->nytrue, - conditionIdx); - rw.saveLikelihood(llh, conditionIdx); - - // to save simulation parameters - dataProvider->updateSimulationParametersAndScale( - conditionIdx, parameters, *model); - rw.saveParameters(model->getParameters(), - conditionIdx); - - } - return 0; - }; + } + return 0; + }; - AmiciSimulationRunner simRunner(parameters, - amici::SensitivityOrder::none, - dataIndices, - jobFinished, - allFinished); + simRunner = std::make_unique( + parameterValues, + amici::SensitivityOrder::none, + dataIndices, + jobFinished, + allFinished); #ifdef PARPE_ENABLE_MPI - if (loadBalancer && loadBalancer->isRunning()) { - errors += simRunner.runDistributedMemory(loadBalancer, - maxSimulationsPerPackage); + if (loadBalancer && loadBalancer->isRunning()) { + errors += simRunner->runDistributedMemory( + loadBalancer, maxSimulationsPerPackage); + } else { +#endif + errors += + simRunner->runSharedMemory([this](std::vector& buffer, int jobId) { + messageHandler(buffer, jobId); + }); +#ifdef PARPE_ENABLE_MPI + } +#endif } else { + // Collect parameter values + auto parameterNames = wrappedFun->getParameterIds(); + parameterValues.resize(parameterNames.size()); + for(int i = 0; i < static_cast(parameterNames.size()); ++i) { + parameterValues[i] = optimizationParameters[parameterNames[i]]; + } + Expects(parameterValues.size() == (unsigned)wrappedFun->numParameters()); + + { + auto lock = hdf5MutexGetLock(); + amici::hdf5::createAndWriteDouble1DDataset( + resultFileH5, resultPath + "/problemParameters", parameterValues); + } + jobFinished = + [&]( + JobData* job, + int /*dataIdx*/) { + /* job finished */ + auto results = amici::deserializeFromChar>( + job->recvBuffer.data(), job->recvBuffer.size()); + job->recvBuffer = std::vector(); // free buffer + + for (auto const& result : results) { + errors += result.second.status; + int conditionIdx = result.first; + auto edata = + dataProvider->getExperimentalDataForCondition( + conditionIdx); + + rw.saveTimepoints(edata->getTimepoints(), + conditionIdx); + if(!result.second.modelStates.empty()) { + rw.saveStates(result.second.modelStates, edata->nt(), + model->nx_rdata, conditionIdx); + } + rw.saveMeasurements(edata->getObservedData(), + edata->nt(), + edata->nytrue(), + conditionIdx); + rw.saveModelOutputs(result.second.modelOutput, + edata->nt(), + model->nytrue, + conditionIdx); + rw.saveLikelihood(result.second.llh, + conditionIdx); + + // to save simulation parameters + dataProvider->updateSimulationParametersAndScale( + conditionIdx, parameterValues, *model); + rw.saveParameters(model->getParameters(), conditionIdx); + } + }; + + simRunner = std::make_unique( + parameterValues, + amici::SensitivityOrder::none, + dataIndices, + jobFinished, + allFinished); + +#ifdef PARPE_ENABLE_MPI + if (loadBalancer && loadBalancer->isRunning()) { + errors += simRunner->runDistributedMemory( + loadBalancer, maxSimulationsPerPackage); + } else { #endif - errors += - simRunner.runSharedMemory([&](std::vector& buffer, int jobId) { - messageHandler(buffer, jobId); - }); + errors += + simRunner->runSharedMemory([this](std::vector& buffer, int jobId) { + messageHandler(buffer, jobId); + }); #ifdef PARPE_ENABLE_MPI - } + } #endif + } return errors; } @@ -338,8 +359,8 @@ StandaloneSimulator::messageHandler(std::vector& buffer, int /*jobId*/) auto model = dataProvider->getModel(); auto solver = dataProvider->getSolver(); auto sim = - amici::deserializeFromChar( - buffer.data(), buffer.size()); + amici::deserializeFromChar( + buffer.data(), buffer.size()); solver->setSensitivityOrder(sim.sensitivityOrder); #if QUEUE_WORKER_H_VERBOSE >= 2 @@ -353,7 +374,7 @@ StandaloneSimulator::messageHandler(std::vector& buffer, int /*jobId*/) // run simulations for all condition indices for (auto conditionIndex : sim.conditionIndices) { dataProvider->updateSimulationParametersAndScale( - conditionIndex, sim.optimizationParameters, *model); + conditionIndex, sim.optimizationParameters, *model); auto result = runSimulation(conditionIndex, *solver, *model); results[conditionIndex] = result; } @@ -400,15 +421,16 @@ StandaloneSimulator::runSimulation(int conditionIdx, auto rdata = amiciApp.runAmiciSimulation(solver, edata.get(), model); - RELEASE_ASSERT(rdata != nullptr, ""); + Expects(rdata != nullptr); return AmiciSimulationRunner::AmiciResultPackageSimple{ rdata->llh, NAN, (solver.getSensitivityOrder() > amici::SensitivityOrder::none) - ? rdata->sllh - : std::vector(), + ? rdata->sllh + : std::vector(), rdata->y, + rdata->sigmay, rdata->x, rdata->status }; @@ -421,20 +443,19 @@ getFinalParameters(std::string const& startIndex, H5::H5File const& file) // find last iteration /multistarts/$/iteration/$/costFunParameters std::string iterationPath = - std::string("/multistarts/") + startIndex + "/iteration/"; + std::string("/multistarts/") + startIndex + "/iteration/"; int iteration = 0; while ( - hdf5GroupExists(file.getId(), - (iterationPath + std::to_string(iteration)).c_str()) && - hdf5DatasetExists(file, - iterationPath + std::to_string(iteration) + - "/costFunParameters")) { + hdf5GroupExists(file, iterationPath + std::to_string(iteration)) && + hdf5DatasetExists(file, + iterationPath + std::to_string(iteration) + + "/costFunParameters")) { ++iteration; } --iteration; // last one did not exist auto bestPairLast = getFunctionEvaluationWithMinimalCost( - iterationPath + std::to_string(iteration) + "/costFunCost", file); + iterationPath + std::to_string(iteration) + "/costFunCost", file); int costFunEvaluationIndex = bestPairLast.first; if (iteration > 0) { @@ -442,7 +463,7 @@ getFinalParameters(std::string const& startIndex, H5::H5File const& file) // iteration might be better than any line search steps of the current // iteration auto bestPairSecondLast = getFunctionEvaluationWithMinimalCost( - iterationPath + std::to_string(iteration - 1) + "/costFunCost", file); + iterationPath + std::to_string(iteration - 1) + "/costFunCost", file); if (bestPairSecondLast.second < bestPairLast.second) { --iteration; costFunEvaluationIndex = bestPairSecondLast.first; @@ -451,7 +472,7 @@ getFinalParameters(std::string const& startIndex, H5::H5File const& file) // get parameters of the selected function evaluation std::string parameterPath = - iterationPath + std::to_string(iteration) + "/costFunParameters"; + iterationPath + std::to_string(iteration) + "/costFunParameters"; H5::DataSet dataset = file.openDataSet(parameterPath); H5::DataSpace filespace = dataset.getSpace(); @@ -492,8 +513,8 @@ getFinalParameters(std::string const& startIndex, H5::H5File const& file) parpe::hdf5Read2DDoubleHyperslab(file.getId(), parameterPath.c_str(), numParam, 1, 0, numIter - 1, parameters.data()); -*/ - return parameters; + */ + return parameters; } std::pair @@ -514,7 +535,7 @@ getFunctionEvaluationWithMinimalCost(std::string const& datasetPath, std::vector cost(numFunctionEvalations, INFINITY); parpe::hdf5Read2DDoubleHyperslab( - file.getId(), datasetPath.c_str(), 1, numFunctionEvalations, 0, 0, cost); + file.getId(), datasetPath.c_str(), 1, numFunctionEvalations, 0, 0, cost); int minIndex = std::min_element(cost.begin(), cost.end()) - cost.begin(); return { minIndex, cost[minIndex] }; } @@ -525,7 +546,7 @@ getParameterTrajectory(std::string const& startIndex, H5::H5File const& file) auto lock = hdf5MutexGetLock(); std::string parameterPath = - std::string("/multistarts/") + startIndex + "/iterCostFunParameters"; + std::string("/multistarts/") + startIndex + "/iterCostFunParameters"; H5::DataSet dataset = file.openDataSet(parameterPath); H5::DataSpace filespace = dataset.getSpace(); @@ -557,7 +578,7 @@ int getNumStarts(H5::H5File const& file, std::string const& rootPath) { auto o = parpe::OptimizationOptions::fromHDF5( - file.getId(), rootPath + "/inputData/optimizationOptions"); + file.getId(), rootPath + "/optimizationOptions"); return o->numStarts; } @@ -569,45 +590,56 @@ runFinalParameters(StandaloneSimulator& sim, std::string const& parameterFilePath, std::string const& resultFileName, std::string const& resultPath, - LoadBalancerMaster* loadBalancer) + LoadBalancerMaster* loadBalancer, bool computeInnerParameters) { - - H5::H5File parameterFile; - { - auto lock = hdf5MutexGetLock(); - parameterFile.openFile(parameterFileName, H5F_ACC_RDONLY); + auto lock = hdf5MutexGetLock(); + H5::H5File parameterFile(parameterFileName, H5F_ACC_RDONLY); + H5::H5File conditionFile(conditionFileName, H5F_ACC_RDONLY); + std::vector parameterNames; + if(hdf5GroupExists(parameterFile, + parameterFilePath + "/parameters/parameterNames")){ + parameterNames = hdf5Read1dStringDataset( + parameterFile, parameterFilePath + "/parameters/parameterNames"); + } else { + parameterNames = hdf5Read1dStringDataset( + parameterFile, parameterFilePath + "/inputData/parameters/parameterNames"); } + lock.unlock(); + int errors = 0; int numStarts = getNumStarts(parameterFile); - for (int i = 0; i < numStarts; ++i) { - std::cout << "Running for start " << i << std::endl; + for (int iStart = 0; iStart < numStarts; ++iStart) { + std::cout << "Running for start " << iStart << std::endl; try { - auto parameters = - parpe::getFinalParameters(std::to_string(i), parameterFile); - auto outerParameters = - getOuterParameters(parameters, parameterFile, parameterFilePath); + auto parameterValues = + parpe::getFinalParameters(std::to_string(iStart), parameterFile); + Expects(parameterValues.size() == parameterNames.size()); + std::map parameters; + for(int i = 0; i < static_cast(parameters.size()); ++i) + parameters[parameterNames[i]] = parameterValues[i]; std::string curResultPath = - resultPath + "multistarts/" + std::to_string(i); - - auto lock = hdf5MutexGetLock(); - H5::H5File conditionFile = hdf5OpenForReading(conditionFileName); - lock.unlock(); + resultPath + "multistarts/" + std::to_string(iStart); errors += sim.run(resultFileName, curResultPath, - outerParameters, + parameters, loadBalancer, conditionFile, - conditionFilePath); + conditionFilePath, + computeInnerParameters); } catch (H5::FileIException const& e) { - std::cerr << "Exception during start " << i << " " + std::cerr << "Exception during start " << iStart << " " << e.getDetailMsg() << std::endl; std::cerr << "... skipping" << std::endl; } } + // lock for destruction of H5Files + // FIXME: won't lock if an unhandled exception occurs + lock.lock(); + return errors; } @@ -619,48 +651,110 @@ runAlongTrajectory(StandaloneSimulator& sim, const std::string& parameterFilePath, std::string const& resultFileName, std::string const& resultPath, - LoadBalancerMaster* loadBalancer) + LoadBalancerMaster* loadBalancer, bool computeInnerParameters) { - H5::H5File parameterFile; - { - auto lock = hdf5MutexGetLock(); - parameterFile.openFile(parameterFileName, H5F_ACC_RDONLY); + auto lock = hdf5MutexGetLock(); + H5::H5File parameterFile(parameterFileName, H5F_ACC_RDONLY); + H5::H5File conditionFile(conditionFileName, H5F_ACC_RDONLY); + std::vector parameterNames; + if(hdf5GroupExists(parameterFile, + parameterFilePath + "/parameters/parameterNames")){ + parameterNames = hdf5Read1dStringDataset( + parameterFile, parameterFilePath + "/parameters/parameterNames"); + } else { + parameterNames = hdf5Read1dStringDataset( + parameterFile, parameterFilePath + "/inputData/parameters/parameterNames"); } + lock.unlock(); + int errors = 0; for (int startIdx = 0; startIdx < getNumStarts(parameterFile); ++startIdx) { try { - auto parameters = - getParameterTrajectory(std::to_string(startIdx), parameterFile); + auto parameterTrajectory = + getParameterTrajectory(std::to_string(startIdx), parameterFile); - for (int iter = 0; (unsigned)iter < parameters.size(); ++iter) { + for (int iter = 0; (unsigned)iter < parameterTrajectory.size(); ++iter) { std::cout << "Running for start " << startIdx << " iter " << iter << std::endl; std::string curResultPath = resultPath + "/multistarts/" + std::to_string(startIdx) + "/iter/" + std::to_string(iter); + auto const& parameterValues = parameterTrajectory[iter]; - auto lock = hdf5MutexGetLock(); - H5::H5File conditionFile = - hdf5OpenForReading(conditionFileName); - lock.unlock(); - - auto outerParameters = getOuterParameters( - parameters[iter], parameterFile, parameterFilePath); + Expects(parameterValues.size() == parameterNames.size()); + std::map parameters; + for(int i = 0; i < static_cast(parameters.size()); ++i) + parameters[parameterNames[i]] = parameterValues[i]; errors += sim.run(resultFileName, curResultPath, - outerParameters, + parameters, loadBalancer, conditionFile, - conditionFilePath); + conditionFilePath, + computeInnerParameters); } } catch (std::exception const& e) { std::cerr << e.what() << std::endl; } } + // lock for destruction of H5Files + // FIXME: won't lock if an unhandled exception occurs + lock.lock(); + + return errors; +} + + +int +runNominalParameters(StandaloneSimulator& sim, + std::string const& conditionFileName, + std::string const& conditionFilePath, + std::string const& parameterFileName, + std::string const& parameterFilePath, + std::string const& resultFileName, + std::string const& resultPath, + LoadBalancerMaster* loadBalancer, + bool computeInnerParameters) +{ + auto lock = hdf5MutexGetLock(); + H5::H5File parameterFile(parameterFileName, H5F_ACC_RDONLY); + H5::H5File conditionFile(conditionFileName, H5F_ACC_RDONLY); + lock.unlock(); + + int errors = 0; + + std::cout << "Running for nominal parameter from " + < parameters; + for(int i = 0; i < static_cast(parameterValues.size()); ++i) + parameters[parameterNames[i]] = parameterValues[i]; + + std::string curResultPath = resultPath + "nominal/"; + + + errors += sim.run(resultFileName, + curResultPath, + parameters, + loadBalancer, + conditionFile, + conditionFilePath, + computeInnerParameters); + + // lock for destruction of H5Files + // FIXME: won't lock if an unhandled exception occurs + lock.lock(); + return errors; } @@ -673,17 +767,29 @@ runSimulationTasks(StandaloneSimulator& sim, std::string const& parameterFilePath, std::string const& resultFileName, std::string const& resultPath, - LoadBalancerMaster* loadBalancer) + LoadBalancerMaster* loadBalancer, + bool computeInnerParameters) { { + std::cout<<"Running "< " + < datasetsToCopy {"/inputData"}; for (auto const& datasetToCopy : datasetsToCopy) { auto source = conditionFilePath + datasetToCopy; + + if(!conditionFile.exists(source)) { + continue; + } + auto dest = resultPath + "/" + datasetToCopy; H5Ocopy(conditionFile.getId(), source.c_str(), resultFile.getId(), dest.c_str(), @@ -699,7 +805,8 @@ runSimulationTasks(StandaloneSimulator& sim, parameterFilePath, resultFileName, resultPath, - loadBalancer); + loadBalancer, + computeInnerParameters); } if (simulationMode == "--along-trajectory") { @@ -710,7 +817,21 @@ runSimulationTasks(StandaloneSimulator& sim, parameterFilePath, resultFileName, resultPath, - loadBalancer); + loadBalancer, + computeInnerParameters); + } + + if (simulationMode == "--nominal") { + return parpe::runNominalParameters(sim, + conditionFileName, + conditionFilePath, + parameterFileName, + parameterFilePath, + resultFileName, + resultPath, + loadBalancer, + computeInnerParameters); + } return EXIT_FAILURE; @@ -724,7 +845,8 @@ runSimulator(MultiConditionDataProvider& dp, std::string const& parameterFileName, std::string const& parameterFilePath, std::string const& resultFileName, - std::string const& resultPath) + std::string const& resultPath, + bool computeInnerParameters) { parpe::StandaloneSimulator sim(&dp); int status = 0; @@ -743,7 +865,8 @@ runSimulator(MultiConditionDataProvider& dp, parameterFilePath, resultFileName, resultPath, - &loadBalancer); + &loadBalancer, + computeInnerParameters); loadBalancer.terminate(); loadBalancer.sendTerminationSignalToAllWorkers(); } else { @@ -762,7 +885,8 @@ runSimulator(MultiConditionDataProvider& dp, parameterFilePath, resultFileName, resultPath, - nullptr); + nullptr, + computeInnerParameters); #ifdef PARPE_ENABLE_MPI } #endif @@ -770,46 +894,5 @@ runSimulator(MultiConditionDataProvider& dp, return status; } -std::vector -getOuterParameters(const std::vector& fullParameters, - const H5::H5File& parameterFile, - const std::string& parameterPath) -{ - // auto options = OptimizationOptions::fromHDF5(parameterFile.getId(), - // parameterPath + "/optimizationOptions"); - AnalyticalParameterHdf5Reader hierarchicalScalingReader( - parameterFile, - parameterPath + "/inputData/scalingParameterIndices", - parameterPath + "/inputData/scalingParametersMapToObservables"); - AnalyticalParameterHdf5Reader hierarchicalOffsetReader( - parameterFile, - parameterPath + "/inputData/offsetParameterIndices", - parameterPath + "/inputData/offsetParametersMapToObservables"); - AnalyticalParameterHdf5Reader hierarchicalSigmaReader( - parameterFile, - parameterPath + "/inputData/sigmaParameterIndices", - parameterPath + "/inputData/sigmaParametersMapToObservables"); - - auto proportionalityFactorIndices = - hierarchicalScalingReader.getOptimizationParameterIndices(); - auto offsetParameterIndices = - hierarchicalOffsetReader.getOptimizationParameterIndices(); - auto sigmaParameterIndices = - hierarchicalSigmaReader.getOptimizationParameterIndices(); - - auto combinedIndices = proportionalityFactorIndices; - combinedIndices.insert(combinedIndices.end(), - offsetParameterIndices.begin(), - offsetParameterIndices.end()); - combinedIndices.insert(combinedIndices.end(), - sigmaParameterIndices.begin(), - sigmaParameterIndices.end()); - std::sort(combinedIndices.begin(), combinedIndices.end()); - - std::vector result(fullParameters.size() - combinedIndices.size()); - parpe::fillFilteredParams(fullParameters, combinedIndices, result); - - return result; -} } // namespace parpe diff --git a/src/parpeamici/steadystateSimulator.cpp b/src/parpeamici/steadystateSimulator.cpp deleted file mode 100644 index 32d243865..000000000 --- a/src/parpeamici/steadystateSimulator.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include - -#include -#include - -#include -#include -#include - -namespace parpe { - -#define XDOT_REL_TOLERANCE 1e-6 - -std::unique_ptr SteadystateSimulator::getSteadystateSolution(amici::Model &model, - amici::Solver &solver, - amici::ExpData *edata, - int *status, - int *iterationDone) { - if (model.nt() > 1) - throw(ParPEException("SteadystateSimulator::getSteadystateSolution " - "works only with nt == 1")); - - std::unique_ptr rdata; - bool inSteadyState = FALSE; - int iterations = 0; - - while (!inSteadyState) { - ++iterations; - - rdata = amici::runAmiciSimulation(solver, edata, model); - - if (rdata->status < 0) { - error("Failed to integrate."); // TODO add dataset info, - // case/control, celline - return rdata; - } - - inSteadyState = reachedSteadyState(rdata->xdot.data(), rdata->x.data(), rdata->nt, - rdata->nx, XDOT_REL_TOLERANCE); - - if (inSteadyState) { - break; - } - - if (iterations >= 100) { - logmessage(LOGLVL_WARNING, "getSteadystateSolutionForExperiment: " - "no steady after %d iterations... " - "aborting...", - iterations); - *status = -1; - break; - } - - if (iterations % 10 == 0) { - logmessage(LOGLVL_DEBUG, "getSteadystateSolutionForExperiment: no " - "steady state after %d iterations... " - "trying on...", - iterations); - } - - // use previous solution as initial conditions - model.setInitialStates(rdata->x); - } - // logmessage(LOGLVL_DEBUG, "getSteadystateSolutionForExperiment: - // steadystate after %d iterations", iterations); - - *iterationDone = iterations; - - return rdata; -} - - -bool SteadystateSimulator::reachedSteadyState(const double *xdot, - const double *x, - int numTimepoints, int numStates, - double tolerance) { - assert(numTimepoints == 1 && - "SteadystateSimulator currently only supports one timepoint!"); - for (int state = 0; state < numStates; ++state) { - double sensitivity = fabs(xdot[state]) / (fabs(x[state]) + tolerance); - if (sensitivity > tolerance) { - // logmessage(LOGLVL_DEBUG, "No steady state: %d: x %e xdot %e - // relxdot %e s %e\n", state, (x[state]), (xdot[state]) , - // (xdot[state]) / (x[state]), sensitivity); - return FALSE; - } - } - return TRUE; -} - -} // namespace parpe diff --git a/src/parpecommon/hdf5Misc.cpp b/src/parpecommon/hdf5Misc.cpp index 3ee4e3533..b2d4bcee7 100644 --- a/src/parpecommon/hdf5Misc.cpp +++ b/src/parpecommon/hdf5Misc.cpp @@ -29,13 +29,13 @@ std::unique_lock hdf5MutexGetLock() herr_t hdf5ErrorStackWalker_cb(unsigned int n, const H5E_error_t *err_desc, void* /*client_data*/) { - assert(err_desc); + Ensures(err_desc != nullptr); const int indent = 2; std::unique_ptr - maj_str { H5Eget_major(err_desc->maj_num), std::free }; + maj_str { H5Eget_major(err_desc->maj_num), &std::free }; std::unique_ptr - min_str { H5Eget_minor(err_desc->min_num), std::free }; + min_str { H5Eget_minor(err_desc->min_num), &std::free }; logmessage(LOGLVL_CRITICAL, "%*s#%03d: %s line %u in %s(): %s", indent, "", n, err_desc->file_name, err_desc->line, err_desc->func_name, @@ -155,7 +155,7 @@ void hdf5Extend2ndDimensionAndWriteToDouble2DArray( H5Sget_simple_extent_dims(filespace, currentDimensions, nullptr); H5Sclose(filespace); - RELEASE_ASSERT(buffer.size() == currentDimensions[0], ""); + Expects(buffer.size() == currentDimensions[0]); hsize_t newDimensions[2] = {currentDimensions[0], currentDimensions[1] + 1}; herr_t status = H5Dset_extent(dataset, newDimensions); @@ -192,7 +192,7 @@ void hdf5Extend3rdDimensionAndWriteToDouble3DArray(hid_t file_id, // extend hid_t filespace = H5Dget_space(dataset); int rank = H5Sget_simple_extent_ndims(filespace); - assert(rank == 3 && "Only works for 3D arrays!"); + RELEASE_ASSERT(rank == 3, "Only works for 3D arrays!"); hsize_t currentDimensions[3]; H5Sget_simple_extent_dims(filespace, currentDimensions, nullptr); @@ -299,7 +299,7 @@ void hdf5Extend2ndDimensionAndWriteToInt2DArray(hid_t file_id, hsize_t currentDimensions[2]; H5Sget_simple_extent_dims(filespace, currentDimensions, nullptr); - RELEASE_ASSERT(buffer.size() == currentDimensions[0], ""); + Expects(buffer.size() == currentDimensions[0]); hsize_t newDimensions[2] = {currentDimensions[0], currentDimensions[1] + 1}; herr_t status = H5Dset_extent(dataset, newDimensions); @@ -343,7 +343,7 @@ void hdf5CreateExtendableInt2DArray(hid_t file_id, hid_t datasetCreationProperty = H5Pcreate(H5P_DATASET_CREATE); H5Pset_chunk(datasetCreationProperty, rank, chunkDimensions); - assert(H5Tget_size(H5T_NATIVE_INT) == sizeof(int)); + Expects(H5Tget_size(H5T_NATIVE_INT) == sizeof(int)); hid_t dataset = H5Dcreate2(file_id, datasetPath, H5T_NATIVE_INT, dataspace, H5P_DEFAULT, datasetCreationProperty, H5P_DEFAULT); @@ -394,7 +394,7 @@ int hdf5Read2DDoubleHyperslab(hid_t file_id, hsize_t offset1, gsl::span buffer) { - RELEASE_ASSERT(buffer.size() == size0 * size1, ""); + Expects(buffer.size() == size0 * size1); std::lock_guard lock(mutexHdf); @@ -409,10 +409,10 @@ int hdf5Read2DDoubleHyperslab(hid_t file_id, H5Sget_simple_extent_dims(dataspace, dims, nullptr); // printf("%lld %lld, %lld %lld, %lld %lld\n", dims[0], dims[1], offset0, // offset1, size0, size1); - assert(dims[0] >= offset0 && dims[0] >= size0 && - "Offset larger than dataspace dimensions!"); - assert(dims[1] >= offset1 && dims[1] >= size1 && - "Offset larger than dataspace dimensions!"); + RELEASE_ASSERT(dims[0] >= offset0 && dims[0] >= size0, + "Offset larger than dataspace dimensions!"); + RELEASE_ASSERT(dims[1] >= offset1 && dims[1] >= size1, + "Offset larger than dataspace dimensions!"); H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, nullptr, count, nullptr); @@ -439,11 +439,12 @@ std::vector hdf5Read1DIntegerHyperslab(H5::H5File const& file, H5::DataSpace filespace = dataset.getSpace(); const int ndims = filespace.getSimpleExtentNdims(); - assert(ndims == 1 && "Only works for 1D arrays!"); + RELEASE_ASSERT(ndims == 1, "Only works for 1D arrays!"); hsize_t length; filespace.getSimpleExtentDims(&length); - assert(length >= offset && "Offset larger than dataspace dimensions!"); + RELEASE_ASSERT(length >= offset, + "Offset larger than dataspace dimensions!"); filespace.selectHyperslab(H5S_SELECT_SET, &count, &offset); @@ -468,7 +469,7 @@ std::vector hdf5Read2DIntegerHyperslab(const H5::H5File &file, H5::DataSpace filespace = dataset.getSpace(); const int ndims = filespace.getSimpleExtentNdims(); - assert(ndims == 2 && "Only works for 2D arrays!"); + RELEASE_ASSERT(ndims == 2, "Only works for 2D arrays!"); hsize_t dims[ndims]; filespace.getSimpleExtentDims(dims); @@ -515,15 +516,15 @@ int hdf5Read3DDoubleHyperslab(hid_t file_id, hsize_t count[] = {size0, size1, size2}; const int ndims = H5Sget_simple_extent_ndims(dataspace); - assert(ndims == rank && "Only works for 3D arrays!"); + RELEASE_ASSERT(ndims == rank, "Only works for 3D arrays!"); hsize_t dims[ndims]; H5Sget_simple_extent_dims(dataspace, dims, nullptr); - assert(dims[0] >= offset0 && dims[0] >= size0 && - "Offset larger than dataspace dimensions!"); - assert(dims[1] >= offset1 && dims[1] >= size1 && - "Offset larger than dataspace dimensions!"); - assert(dims[2] >= offset2 && dims[2] >= size2 && - "Offset larger than dataspace dimensions!"); + RELEASE_ASSERT(dims[0] >= offset0 && dims[0] >= size0, + "Offset larger than dataspace dimensions!"); + RELEASE_ASSERT(dims[1] >= offset1 && dims[1] >= size1, + "Offset larger than dataspace dimensions!"); + RELEASE_ASSERT(dims[2] >= offset2 && dims[2] >= size2, + "Offset larger than dataspace dimensions!"); H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, nullptr, count, nullptr); @@ -628,7 +629,7 @@ void hdf5GetDatasetDimensions(hid_t file_id, int *d3, int *d4) { - assert(file_id >= 0); + Expects(file_id >= 0); std::lock_guard lock(mutexHdf); H5_SAVE_ERROR_HANDLER; @@ -722,8 +723,8 @@ void hdf5CreateExtendableString1DArray(hid_t file_id, const char *datasetPath) datasetCreationProperty.setChunk(rank, chunkDimensions); H5::StrType strType(0, H5T_VARIABLE); - RELEASE_ASSERT(H5T_STRING == H5Tget_class(strType.getId()) - && H5Tis_variable_str(strType.getId()), ""); + Expects(H5T_STRING == H5Tget_class(strType.getId()) + && H5Tis_variable_str(strType.getId())); auto dataset = file.createDataSet(datasetPath, strType, dataspace, datasetCreationProperty); @@ -834,7 +835,7 @@ std::vector hdf5Read1dStringDataset( auto filespace = dataset.getSpace(); const int ndims = filespace.getSimpleExtentNdims(); - assert(ndims == 1 && "Only works for 1D arrays!"); + RELEASE_ASSERT(ndims == 1, "Only works for 1D arrays!"); auto dtype = dataset.getDataType(); auto native_type = H5Tget_native_type(dtype.getId(), H5T_DIR_DEFAULT); @@ -880,4 +881,14 @@ void hdf5Write1dStringDataset( dataset.write((void*)charPtrBuffer.data(), tid1); } +bool hdf5GroupExists(const H5::H5File &file, const std::string &groupName) +{ + return hdf5GroupExists(file.getId(), groupName.c_str()); +} + +hid_t hdf5CreateFile(const std::string &filename, bool overwrite) +{ + return hdf5CreateFile(filename.c_str(), overwrite); +} + } // namespace parpe diff --git a/src/parpecommon/logging.cpp b/src/parpecommon/logging.cpp index f8b418390..0d9037998 100644 --- a/src/parpecommon/logging.cpp +++ b/src/parpecommon/logging.cpp @@ -147,13 +147,9 @@ void printlogmessage(loglevel lvl, const char *message) } // Timestamp - time_t current_time; - struct tm local_time; - time(¤t_time); - localtime_r(¤t_time, &local_time); char dateBuffer[50]; - strftime(dateBuffer, 25, "[%Y-%m-%d %H:%M:%S] ", &local_time); + strFormatCurrentLocaltime(dateBuffer, "[%Y-%m-%d %H:%M:%S] "); fputs(dateBuffer, stdout); printf("[%s] ", loglevelShortStr[static_cast(lvl)]); @@ -177,14 +173,17 @@ void printlogmessage(loglevel lvl, const char *message) #else auto procName = ""; #endif - printf("[%*d/%s] ", 1 + static_cast(log10(mpiCommSize)), mpiRank, procName); + printf("[%*d:%lu/%s] ", 1 + static_cast(log10(mpiCommSize)), + mpiRank, pthread_self(), procName ); printf("%s", message); - printf(ANSI_COLOR_RESET "\n"); + printf("%s\n", ANSI_COLOR_RESET); switch (lvl) { case LOGLVL_CRITICAL: + [[fallthrough]]; case LOGLVL_ERROR: fflush(stdout); + break; default: break; } diff --git a/src/parpecommon/misc.cpp b/src/parpecommon/misc.cpp index f68680213..444a6495f 100644 --- a/src/parpecommon/misc.cpp +++ b/src/parpecommon/misc.cpp @@ -59,7 +59,7 @@ void createDirectoryIfNotExists(char *dirName) { * @return 0 on success, -1 otherwise */ int mkpath(char *file_path, mode_t mode) { - assert(file_path && *file_path); + Expects(file_path && *file_path); for (char *p = strchr(file_path + 1, '/'); p; p = strchr(p + 1, '/')) { *p = '\0'; @@ -75,20 +75,22 @@ int mkpath(char *file_path, mode_t mode) { } int mkpathConstChar(const char *file_path, mode_t mode) { - assert(file_path && *file_path); + Expects(file_path && *file_path); char tmp[strlen(file_path) + 1]; - strcpy(tmp, file_path); + + strncpy(tmp, file_path, sizeof(tmp) -1); + tmp[sizeof(tmp) - 1] = '\0'; + return mkpath(tmp, mode); } void strFormatCurrentLocaltime(gsl::span buffer, const char *format) { - time_t timer; - time(&timer); + time_t current_time; + struct tm local_time; + time(¤t_time); + localtime_r(¤t_time, &local_time); - struct tm *tm_info; - tm_info = localtime(&timer); - - strftime(buffer.data(), buffer.size(), format, tm_info); + strftime(buffer.data(), buffer.size(), format, &local_time); } void runInParallelAndWaitForFinish(void *(*function)(void *), void **args, @@ -166,8 +168,8 @@ double randDouble(double min, double max) { void fillArrayRandomDoubleIndividualInterval(gsl::span min, gsl::span max, gsl::span buffer) { - RELEASE_ASSERT(min.size() == max.size(), ""); - RELEASE_ASSERT(min.size() == buffer.size(), ""); + Expects(min.size() == max.size()); + Expects(min.size() == buffer.size()); for (gsl::span::index_type i = 0; i < buffer.size(); ++i) buffer[i] = randDouble(min[i], max[i]); @@ -265,26 +267,6 @@ double WallTimer::getTotal() return duration.count(); } -bool launchedWithMpi() -{ - if(std::getenv("OMPI_COMM_WORLD_SIZE")) - return true; // OpenMPI - if(std::getenv("MP_PROCS") && atoi(std::getenv("MP_PROCS")) > 1) - return true; - if(std::getenv("PMI_RANK")) - return true; // INTEL MPI / Hydra - - return false; -} - -void initMpiIfNeeded(int *argc, char ***argv) -{ -#ifdef PARPE_ENABLE_MPI - if(parpe::launchedWithMpi()) - MPI_Init(argc, argv); -#endif -} - void finalizeMpiIfNeeded() { #ifdef PARPE_ENABLE_MPI diff --git a/src/parpeloadbalancer/loadBalancerMaster.cpp b/src/parpeloadbalancer/loadBalancerMaster.cpp index e00bc6f20..164b1b8b2 100644 --- a/src/parpeloadbalancer/loadBalancerMaster.cpp +++ b/src/parpeloadbalancer/loadBalancerMaster.cpp @@ -23,8 +23,11 @@ void LoadBalancerMaster::run() { int mpiCommSize; MPI_Comm_size(mpiComm, &mpiCommSize); - assert(mpiCommSize > 1 && - "Need multiple MPI processes!"); // crashes otherwise + + if(mpiCommSize <= 2) { + // crashes otherwise + throw std::runtime_error("Need at least 2 MPI processes!"); + } numWorkers = mpiCommSize - 1; sentJobsData.resize(numWorkers, nullptr); @@ -56,7 +59,7 @@ LoadBalancerMaster::~LoadBalancerMaster() #ifndef QUEUE_MASTER_TEST void LoadBalancerMaster::assertMpiActive() { - assert(getMpiActive()); + Expects(getMpiActive()); } #endif @@ -158,8 +161,8 @@ JobData *LoadBalancerMaster::getNextJob() { } void LoadBalancerMaster::sendToWorker(int workerIdx, JobData *data) { - assert(workerIdx >= 0); - assert(workerIdx < numWorkers); + Expects(workerIdx >= 0); + Expects(workerIdx < numWorkers); workerIsBusy[workerIdx] = true; diff --git a/src/parpeoptimization/CMakeLists.txt b/src/parpeoptimization/CMakeLists.txt index 72f502085..610c2083e 100644 --- a/src/parpeoptimization/CMakeLists.txt +++ b/src/parpeoptimization/CMakeLists.txt @@ -1,5 +1,13 @@ project(parpeoptimization) +find_package(Ceres COMPONENTS + HINTS "${CMAKE_SOURCE_DIR}/ThirdParty/ceres-solver-1.13.0/build/install") + +if(${PARPE_ENABLE_CERES} AND NOT ${CERES_FOUND}) + message(FATAL_ERROR "Supposed to build with CERES support, " + "but CERES not found.") +endif() + set(SRC_LIST optimizationProblem.cpp multiStartOptimization.cpp @@ -17,99 +25,90 @@ set(HEADER_LIST optimizer.h ) +add_library(${PROJECT_NAME} ${SRC_LIST}) + if(${PARPE_ENABLE_IPOPT}) - list(APPEND SRC_LIST localOptimizationIpopt.cpp localOptimizationIpoptTNLP.cpp) - list(APPEND HEADER_LIST localOptimizationIpopt.h localOptimizationIpoptTNLP.h) + target_sources(${PROJECT_NAME} + PRIVATE localOptimizationIpopt.cpp + PRIVATE localOptimizationIpoptTNLP.cpp) + list(APPEND HEADER_LIST + localOptimizationIpopt.h + localOptimizationIpoptTNLP.h) + target_include_directories(${PROJECT_NAME} + PUBLIC ${IPOPT_INCLUDE_DIRS}) + target_link_libraries(${PROJECT_NAME} + PUBLIC ${IPOPT_LIBRARIES}) endif(${PARPE_ENABLE_IPOPT}) if(${PARPE_ENABLE_CERES}) - list(APPEND SRC_LIST localOptimizationCeres.cpp) + target_sources(${PROJECT_NAME} + PRIVATE localOptimizationCeres.cpp) list(APPEND HEADER_LIST localOptimizationCeres.h) + target_include_directories(${PROJECT_NAME} + PUBLIC ${CERES_INCLUDE_DIRS}) + target_link_libraries(${PROJECT_NAME} + PUBLIC ${CERES_LIBRARIES}) + + set(PARPE_CERES_MINIGLOG_REDIRECT FALSE CACHE BOOL + "Custom treatment of Ceres output? Requires miniglog headers in ceres directory.") + if(${PARPE_CERES_MINIGLOG_REDIRECT}) + target_compile_definitions(${PROJECT_NAME} + PUBLIC PARPE_CERES_MINIGLOG_REDIRECT) + endif(${PARPE_CERES_MINIGLOG_REDIRECT}) endif(${PARPE_ENABLE_CERES}) if(${PARPE_ENABLE_DLIB}) - list(APPEND SRC_LIST localOptimizationDlib.cpp) + target_sources(${PROJECT_NAME} + PRIVATE localOptimizationDlib.cpp) list(APPEND HEADER_LIST localOptimizationDlib.h) + find_package(dlib REQUIRED + HINTS "${CMAKE_SOURCE_DIR}/ThirdParty/dlib-19.7/build/install/lib/cmake/dlib/") + target_include_directories(${PROJECT_NAME} + PUBLIC ${dlib_INCLUDE_DIRS}) + target_link_libraries(${PROJECT_NAME} + PUBLIC ${dlib_LIBRARIES}) endif(${PARPE_ENABLE_DLIB}) if(${PARPE_ENABLE_TOMS611}) - list(APPEND SRC_LIST localOptimizationToms611.cpp) + target_sources(${PROJECT_NAME} + PRIVATE localOptimizationToms611.cpp) list(APPEND HEADER_LIST localOptimizationToms611.h) + add_subdirectory(${CMAKE_SOURCE_DIR}/ThirdParty/toms611 toms611) + target_include_directories(${PROJECT_NAME} + PUBLIC ${CMAKE_SOURCE_DIR}/ThirdParty/toms611/) + target_link_libraries(${PROJECT_NAME} + PUBLIC toms611) endif(${PARPE_ENABLE_TOMS611}) if(${PARPE_ENABLE_FSQP}) - list(APPEND SRC_LIST localOptimizationFsqp.cpp) + target_sources(${PROJECT_NAME} + PRIVATE localOptimizationFsqp.cpp) list(APPEND HEADER_LIST localOptimizationFsqp.h) + add_subdirectory(${CMAKE_SOURCE_DIR}/ThirdParty/ffsqp ffsqp) + target_include_directories(${PROJECT_NAME} + PUBLIC ${CMAKE_SOURCE_DIR}/ThirdParty/ffsqp/) + target_link_libraries(${PROJECT_NAME} + PUBLIC fsqp) endif(${PARPE_ENABLE_FSQP}) -add_library(${PROJECT_NAME} ${SRC_LIST}) - target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ${HDF5_INCLUDE_DIRS} ) -if(${PARPE_ENABLE_IPOPT}) - target_include_directories(${PROJECT_NAME} PUBLIC ${IPOPT_INCLUDE_DIRS}) -endif(${PARPE_ENABLE_IPOPT}) - -if(${PARPE_ENABLE_CERES}) - target_include_directories(${PROJECT_NAME} PUBLIC ${CERES_INCLUDE_DIRS}) -endif(${PARPE_ENABLE_CERES}) - - -set(PARPE_CERES_MINIGLOG_REDIRECT FALSE CACHE BOOL "Custom treatment of Ceres output? Requires miniglog headers in ceres directory.") -if(${PARPE_CERES_MINIGLOG_REDIRECT}) - target_compile_definitions(${PROJECT_NAME} PUBLIC PARPE_CERES_MINIGLOG_REDIRECT) -endif(${PARPE_CERES_MINIGLOG_REDIRECT}) - -if(${PARPE_ENABLE_TOMS611}) - add_subdirectory(${CMAKE_SOURCE_DIR}/ThirdParty/toms611 toms611) - target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/ThirdParty/toms611/) -endif(${PARPE_ENABLE_TOMS611}) - -if(${PARPE_ENABLE_DLIB}) - find_package(dlib REQUIRED - HINTS "${CMAKE_SOURCE_DIR}/ThirdParty/dlib-19.7/build/install/lib/cmake/dlib/") - target_include_directories(${PROJECT_NAME} PUBLIC ${dlib_INCLUDE_DIRS}) -endif(${PARPE_ENABLE_DLIB}) - -if(${PARPE_ENABLE_FSQP}) - add_subdirectory(${CMAKE_SOURCE_DIR}/ThirdParty/ffsqp ffsqp) - target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/ThirdParty/ffsqp/) -endif(${PARPE_ENABLE_FSQP}) - - target_link_libraries(${PROJECT_NAME} - parpecommon - ${HDF5_HL_LIBRARIES} - ${HDF5_C_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} + PUBLIC parpecommon + PUBLIC ${HDF5_HL_LIBRARIES} + PUBLIC ${HDF5_C_LIBRARIES} + PUBLIC ${CMAKE_THREAD_LIBS_INIT} ) -if(${PARPE_ENABLE_IPOPT}) - target_link_libraries(${PROJECT_NAME} ${IPOPT_LIBRARIES}) -endif(${PARPE_ENABLE_IPOPT}) - -if(${PARPE_ENABLE_CERES}) - target_link_libraries(${PROJECT_NAME} ${CERES_LIBRARIES}) -endif(${PARPE_ENABLE_CERES}) - -if(${PARPE_ENABLE_DLIB}) - target_link_libraries(${PROJECT_NAME} ${dlib_LIBRARIES}) -endif(${PARPE_ENABLE_DLIB}) - -if(${PARPE_ENABLE_TOMS611}) - target_link_libraries(${PROJECT_NAME} toms611) -endif(${PARPE_ENABLE_TOMS611}) - -if(${PARPE_ENABLE_FSQP}) - target_link_libraries(${PROJECT_NAME} fsqp) -endif(${PARPE_ENABLE_FSQP}) - install(TARGETS ${PROJECT_NAME} EXPORT ParPETargets ARCHIVE DESTINATION lib) -string(REGEX REPLACE "([^;]+)" "${CMAKE_SOURCE_DIR}/include/parpeoptimization/\\1" HEADER_LIST "${HEADER_LIST}") +string(REGEX REPLACE "([^;]+)" + "${CMAKE_SOURCE_DIR}/include/parpeoptimization/\\1" + HEADER_LIST "${HEADER_LIST}") + install( FILES ${HEADER_LIST} DESTINATION diff --git a/src/parpeoptimization/localOptimizationCeres.cpp b/src/parpeoptimization/localOptimizationCeres.cpp index cf1985a01..fbf3ac6bd 100644 --- a/src/parpeoptimization/localOptimizationCeres.cpp +++ b/src/parpeoptimization/localOptimizationCeres.cpp @@ -74,7 +74,7 @@ class MyCeresFirstOrderFunction : public ceres::FirstOrderFunction { public: MyCeresFirstOrderFunction(OptimizationProblem *problem, OptimizationReporter *reporter) : problem(problem), reporter(reporter) { - numParameters = problem->costFun->numParameters(); + numParameters = problem->cost_fun_->numParameters(); // bounds are not natively supported by CERES; a naive check is currently implemented which fails function evaluation if parameters are out of bounds parametersMin.resize(numParameters); @@ -171,7 +171,7 @@ std::tuple > OptimizerCeres::optimize(Optimizat google::AddLogSink(&log); #endif - std::vector parameters(problem->costFun->numParameters()); + std::vector parameters(problem->cost_fun_->numParameters()); problem->fillInitialParameters(parameters); auto reporter = problem->getReporter(); diff --git a/src/parpeoptimization/localOptimizationIpopt.cpp b/src/parpeoptimization/localOptimizationIpopt.cpp index 13599c3aa..6d002bfb7 100644 --- a/src/parpeoptimization/localOptimizationIpopt.cpp +++ b/src/parpeoptimization/localOptimizationIpopt.cpp @@ -330,7 +330,7 @@ const std::vector dblOpts = { extern volatile sig_atomic_t caughtTerminationSignal; #endif -static_assert(sizeof(double) == sizeof(Number), +static_assert(sizeof(double) == sizeof(Ipopt::Number), "Sizeof IpOpt::Number != sizeof double"); @@ -411,7 +411,7 @@ std::tuple > OptimizerIpOpt::optimize(Optimizat // app->Jnlst()->AddJournal(); status = app->Initialize(); - RELEASE_ASSERT(status == Solve_Succeeded, ""); + Expects(status == Solve_Succeeded); status = app->OptimizeTNLP(mynlp); if(status == Invalid_Number_Detected) { diff --git a/src/parpeoptimization/localOptimizationIpoptTNLP.cpp b/src/parpeoptimization/localOptimizationIpoptTNLP.cpp index 03d11b9fe..559a5b9e3 100644 --- a/src/parpeoptimization/localOptimizationIpoptTNLP.cpp +++ b/src/parpeoptimization/localOptimizationIpoptTNLP.cpp @@ -2,27 +2,31 @@ #include +#include +#include #include #include -#include -#include //#include namespace parpe { - -LocalOptimizationIpoptTNLP::LocalOptimizationIpoptTNLP(OptimizationProblem &problem, OptimizationReporter &reporter) - : problem(problem), reporter(reporter) +using namespace Ipopt; + +LocalOptimizationIpoptTNLP::LocalOptimizationIpoptTNLP( + OptimizationProblem& problem, + OptimizationReporter& reporter) + : problem(problem) + , reporter(reporter) +{} + +bool +LocalOptimizationIpoptTNLP::get_nlp_info(Index& n, + Index& m, + Index& nnz_jac_g, + Index& nnz_h_lag, + IndexStyleEnum& index_style) { -} - - -bool LocalOptimizationIpoptTNLP::get_nlp_info(Index &n, Index &m, - Index &nnz_jac_g, - Index &nnz_h_lag, - IndexStyleEnum &index_style) { - n = reporter.numParameters(); m = 0; // number of constrants nnz_jac_g = 0; // numNonZeroElementsConstraintJacobian @@ -32,9 +36,14 @@ bool LocalOptimizationIpoptTNLP::get_nlp_info(Index &n, Index &m, return true; } -bool LocalOptimizationIpoptTNLP::get_bounds_info(Index n, Number *x_l, - Number *x_u, Index /*m*/, - Number * /*g_l*/, Number * /*g_u*/) { +bool +LocalOptimizationIpoptTNLP::get_bounds_info(Index n, + Number* x_l, + Number* x_u, + Index /*m*/, + Number* /*g_l*/, + Number* /*g_u*/) +{ // parameter bounds problem.fillParametersMin(gsl::make_span(x_l, n)); problem.fillParametersMax(gsl::make_span(x_u, n)); @@ -44,69 +53,107 @@ bool LocalOptimizationIpoptTNLP::get_bounds_info(Index n, Number *x_l, return true; } -bool LocalOptimizationIpoptTNLP::get_starting_point(Index n, bool init_x, - Number *x, bool init_z, - Number * /*z_L*/, Number * /*z_U*/, - Index /*m*/, bool init_lambda, - Number * /*lambda*/) { - /* this function is called twice by IpOpt which is a problem if problem->fillInitialParameters provides random parameters, therefore initial point needs to be stored */ +bool +LocalOptimizationIpoptTNLP::get_starting_point(Index n, + bool init_x, + Number* x, + bool init_z, + Number* /*z_L*/, + Number* /*z_U*/, + Index m, + bool init_lambda, + Number* /*lambda*/) +{ + Expects(init_z == false); + Expects(init_lambda == false); + Expects(m == 0); + + /* this function is called twice by IpOpt which is a problem if + * problem->fillInitialParameters provides random parameters, therefore + * initial point needs to be stored */ if (init_x) { - if(initialParameters.empty()) { + if (initialParameters.empty()) { initialParameters.resize(n); problem.fillInitialParameters(initialParameters); - if(reporter.starting(initialParameters)) + if (reporter.starting(initialParameters)) return false; } std::copy(initialParameters.begin(), initialParameters.end(), x); } - RELEASE_ASSERT(init_z == false, ""); - RELEASE_ASSERT(init_lambda == false, ""); - return true; } -bool LocalOptimizationIpoptTNLP::eval_f(Index n, const Number *x, bool /*new_x*/, - Number &obj_value) { +bool +LocalOptimizationIpoptTNLP::eval_f(Index n, + const Number* x, + bool /*new_x*/, + Number& obj_value) +{ auto unlockIpOpt = ipOptReleaseLock(); - return reporter.evaluate(gsl::make_span(x, n), obj_value, gsl::span()) == functionEvaluationSuccess; + return reporter.evaluate(gsl::make_span(x, n), + obj_value, + gsl::span()) == functionEvaluationSuccess; } -bool LocalOptimizationIpoptTNLP::eval_grad_f(Index n, const Number *x, - bool /*new_x*/, Number *grad_f) { +bool +LocalOptimizationIpoptTNLP::eval_grad_f(Index n, + const Number* x, + bool /*new_x*/, + Number* grad_f) +{ auto unlockIpOpt = ipOptReleaseLock(); double obj_value; - return reporter.evaluate( - gsl::make_span(x, n), - obj_value, - gsl::make_span(grad_f, n)) - == functionEvaluationSuccess; + return reporter.evaluate(gsl::make_span(x, n), + obj_value, + gsl::make_span(grad_f, n)) == + functionEvaluationSuccess; } -bool LocalOptimizationIpoptTNLP::eval_g(Index /*n*/, const Number * /*x*/, bool /*new_x*/, - Index /*m*/, Number * /*g*/) { - - assert(false && "no constraints, should never get here"); - - return false; +bool +LocalOptimizationIpoptTNLP::eval_g(Index /*n*/, + const Number* /*x*/, + bool /*new_x*/, + Index /*m*/, + Number* /*g*/) +{ + throw std::runtime_error("no constraints, should never get here"); } -bool LocalOptimizationIpoptTNLP::eval_jac_g(Index /*n*/, const Number * /*x*/, - bool /*new_x*/, Index /*m*/, Index /*nele_jac*/, - Index * /*iRow*/, Index * /*jCol*/, - Number * /*values*/) { +bool +LocalOptimizationIpoptTNLP::eval_jac_g(Index /*n*/, + const Number* /*x*/, + bool /*new_x*/, + Index m, + Index /*nele_jac*/, + Index* /*iRow*/, + Index* /*jCol*/, + Number* /*values*/) +{ // no constraints, nothing to do here, but will be called once + Expects(m == 0); // while constraints not implemented return true; } -bool LocalOptimizationIpoptTNLP::intermediate_callback( - AlgorithmMode /*mode*/, Index /*iter*/, Number obj_value, Number /*inf_pr*/, - Number /*inf_du*/, Number /*mu*/, Number /*d_norm*/, Number /*regularization_size*/, - Number /*alpha_du*/, Number /*alpha_pr*/, Index /*ls_trials*/, const IpoptData *ip_data, - IpoptCalculatedQuantities * /*ip_cq*/) { +bool +LocalOptimizationIpoptTNLP::intermediate_callback( + AlgorithmMode /*mode*/, + Index /*iter*/, + Number obj_value, + Number /*inf_pr*/, + Number /*inf_du*/, + Number /*mu*/, + Number /*d_norm*/, + Number /*regularization_size*/, + Number /*alpha_du*/, + Number /*alpha_pr*/, + Index /*ls_trials*/, + const IpoptData* ip_data, + IpoptCalculatedQuantities* /*ip_cq*/) +{ auto unlockIpOpt = ipOptReleaseLock(); @@ -114,13 +161,16 @@ bool LocalOptimizationIpoptTNLP::intermediate_callback( gsl::span parameters; auto x = ip_data->curr()->x(); auto xx = dynamic_cast(Ipopt::GetRawPtr(x)); - if(xx) + if (xx) parameters = gsl::span(xx->Values(), xx->Dim()); else - logmessage(LOGLVL_WARNING, "Not Ipopt::DenseVector in LocalOptimizationIpoptTNLP::intermediate_callback"); + logmessage(LOGLVL_WARNING, + "Not Ipopt::DenseVector in " + "LocalOptimizationIpoptTNLP::intermediate_callback"); // is always the last step accepted? - int status = reporter.iterationFinished(parameters, obj_value, gsl::span()); + int status = + reporter.iterationFinished(parameters, obj_value, gsl::span()); #ifdef INSTALL_SIGNAL_HANDLER if (caughtTerminationSignal) { @@ -132,24 +182,40 @@ bool LocalOptimizationIpoptTNLP::intermediate_callback( return status == 0; } -void LocalOptimizationIpoptTNLP::finalize_solution( - SolverReturn status, Index n, const Number *x, const Number * /*z_L*/, - const Number * /*z_U*/, Index /*m*/, const Number * /*g*/, const Number * /*lambda*/, - Number obj_value, const IpoptData * /*ip_data*/, - IpoptCalculatedQuantities * /*ip_cq*/) { +void +LocalOptimizationIpoptTNLP::finalize_solution( + SolverReturn status, + Index n, + const Number* x, + const Number* /*z_L*/, + const Number* /*z_U*/, + Index /*m*/, + const Number* /*g*/, + const Number* /*lambda*/, + Number obj_value, + const IpoptData* /*ip_data*/, + IpoptCalculatedQuantities* /*ip_cq*/) +{ auto unlockIpOpt = ipOptReleaseLock(); + // If we finish with objective value of NAN, IpOpt still passes + // obj_value 0.0 along with the respective flag. This does not make too + // much sense. Set to NAN. + if(status == INVALID_NUMBER_DETECTED && obj_value == 0.0) { + obj_value = NAN; + } reporter.finished(obj_value, gsl::span(x, n), status); } - -std::unique_lock ipOptGetLock() +std::unique_lock +ipOptGetLock() { return std::unique_lock(mutexIpOpt); } -InverseUniqueLock ipOptReleaseLock() +InverseUniqueLock +ipOptReleaseLock() { return InverseUniqueLock(&mutexIpOpt); } diff --git a/src/parpeoptimization/minibatchOptimization.cpp b/src/parpeoptimization/minibatchOptimization.cpp index ee9101b00..d7d939e16 100755 --- a/src/parpeoptimization/minibatchOptimization.cpp +++ b/src/parpeoptimization/minibatchOptimization.cpp @@ -103,7 +103,7 @@ std::tuple > runMinibatchOptimization(Minibatch auto data = problem->getTrainingData(); return minibatchOptimizer->optimize(*costFun, data, initialParameters, lowerParameterBounds, upperParameterBounds, - problem->getReporter().get(), problem->logger.get()); + problem->getReporter().get(), problem->logger_.get()); } diff --git a/src/parpeoptimization/optimizationOptions.cpp b/src/parpeoptimization/optimizationOptions.cpp index 10357d18c..a15b19895 100644 --- a/src/parpeoptimization/optimizationOptions.cpp +++ b/src/parpeoptimization/optimizationOptions.cpp @@ -179,9 +179,12 @@ std::vector OptimizationOptions::getStartingPoint(hid_t fileId, auto lock = hdf5MutexGetLock(); H5_SAVE_ERROR_HANDLER; - hid_t dataset; - if (!hdf5DatasetExists(fileId, path) - || (dataset = H5Dopen2(fileId, path, H5P_DEFAULT)) < 0) { + hid_t dataset = -1; + if (hdf5DatasetExists(fileId, path)) { + dataset = H5Dopen2(fileId, path, H5P_DEFAULT); + } + + if (dataset < 0) { logmessage(LOGLVL_DEBUG, "No initial parameters found in %s", path); H5Eclear1(); goto freturn; @@ -191,7 +194,7 @@ std::vector OptimizationOptions::getStartingPoint(hid_t fileId, // read dimensions hid_t dataspace = H5Dget_space(dataset); const int ndims = H5Sget_simple_extent_ndims(dataspace); - assert(ndims == 2); + Expects(ndims == 2); hsize_t dims[ndims]; H5Sget_simple_extent_dims(dataspace, dims, nullptr); if (dims[1] < static_cast(index)) @@ -325,6 +328,7 @@ void printAvailableOptimizers(std::string prefix) <(optimizerName::OPTIMIZER_IPOPT) <<" disabled\n"; #endif + [[fallthrough]]; case optimizerName::OPTIMIZER_CERES: #ifdef PARPE_ENABLE_CERES std::cout<(optimizerName::OPTIMIZER_CERES) <<" disabled\n"; #endif + [[fallthrough]]; case optimizerName::OPTIMIZER_DLIB: #ifdef PARPE_ENABLE_DLIB std::cout<(optimizerName::OPTIMIZER_DLIB) <<" disabled\n"; #endif + [[fallthrough]]; case optimizerName::OPTIMIZER_TOMS611: #ifdef PARPE_ENABLE_TOMS611 std::cout<(optimizerName::OPTIMIZER_TOMS611) <<" disabled\n"; #endif + [[fallthrough]]; case optimizerName::OPTIMIZER_FSQP: #ifdef PARPE_ENABLE_FSQP std::cout<(optimizerName::OPTIMIZER_FSQP) <<" disabled\n"; #endif + [[fallthrough]]; case optimizerName::OPTIMIZER_MINIBATCH_1: std::cout<(optimizerName::OPTIMIZER_MINIBATCH_1) diff --git a/src/parpeoptimization/optimizationProblem.cpp b/src/parpeoptimization/optimizationProblem.cpp index 9d6dc1406..6bcd4b739 100644 --- a/src/parpeoptimization/optimizationProblem.cpp +++ b/src/parpeoptimization/optimizationProblem.cpp @@ -58,7 +58,7 @@ void *getLocalOptimumThreadWrapper(void *optimizationProblemVp) { void optimizationProblemGradientCheck(OptimizationProblem *problem, int numParameterIndicesToCheck, double epsilon) { - int numParameters = problem->costFun->numParameters(); + int numParameters = problem->cost_fun_->numParameters(); numParameterIndicesToCheck = std::min(numParameterIndicesToCheck, numParameters); // choose random parameters to check @@ -76,11 +76,11 @@ void optimizationProblemGradientCheck(OptimizationProblem *problem, gsl::span parameterIndices, double epsilon) { double fc = 0; // f(theta) - std::vector theta(problem->costFun->numParameters()); + std::vector theta(problem->cost_fun_->numParameters()); problem->fillInitialParameters(theta); std::vector gradient(theta.size()); - problem->costFun->evaluate(theta, fc, gradient); + problem->cost_fun_->evaluate(theta, fc, gradient); std::vector thetaTmp(theta); @@ -90,11 +90,11 @@ void optimizationProblemGradientCheck(OptimizationProblem *problem, double fb = 0, ff = 0; // f(theta + eps) , f(theta - eps) thetaTmp[curInd] = theta[curInd] + epsilon; - problem->costFun->evaluate(gsl::span(thetaTmp), ff, + problem->cost_fun_->evaluate(gsl::span(thetaTmp), ff, gsl::span()); thetaTmp[curInd] = theta[curInd] - epsilon; - problem->costFun->evaluate(gsl::span(thetaTmp), fb, + problem->cost_fun_->evaluate(gsl::span(thetaTmp), fb, gsl::span()); // double fd_f = (ff - fc) / epsilon; @@ -139,25 +139,25 @@ void optimizationProblemGradientCheck(OptimizationProblem *problem, OptimizationProblem::OptimizationProblem( std::unique_ptr costFun, std::unique_ptr logger) - : costFun(std::move(costFun)), logger(std::move(logger)) { + : cost_fun_(std::move(costFun)), logger_(std::move(logger)) { } const OptimizationOptions &OptimizationProblem::getOptimizationOptions() const { - return optimizationOptions; + return optimization_options_; } void OptimizationProblem::setOptimizationOptions(const OptimizationOptions &options) { - optimizationOptions = options; + optimization_options_ = options; } std::unique_ptr OptimizationProblem::getReporter() const { return std::make_unique < OptimizationReporter > ( - costFun.get(), std::make_unique < Logger > (*logger)); + cost_fun_.get(), std::make_unique < Logger > (*logger_)); } void OptimizationProblem::fillInitialParameters(gsl::span buffer) const { - int numParameters = costFun->numParameters(); + int numParameters = cost_fun_->numParameters(); std::vector parametersMin(numParameters); std::vector parametersMax(numParameters); fillParametersMin(parametersMin); @@ -170,15 +170,15 @@ void OptimizationProblem::fillInitialParameters(gsl::span buffer) const OptimizationReporter::OptimizationReporter(GradientFunction *gradFun, std::unique_ptr logger) : OptimizationReporter(gradFun, nullptr, std::move(logger)) { - defaultLoggerPrefix = this->logger->getPrefix(); + default_logger_prefix_ = this->logger_->getPrefix(); } OptimizationReporter::OptimizationReporter(GradientFunction *gradFun, std::unique_ptr rw, std::unique_ptr logger) : - resultWriter(std::move(rw)), logger(std::move(logger)) { + result_writer_(std::move(rw)), logger_(std::move(logger)) { setGradientFunction(gradFun); - defaultLoggerPrefix = this->logger->getPrefix(); + default_logger_prefix_ = this->logger_->getPrefix(); } FunctionEvaluationStatus OptimizationReporter::evaluate(gsl::span parameters, @@ -194,72 +194,72 @@ FunctionEvaluationStatus OptimizationReporter::evaluate(gsl::span return functionEvaluationFailure; if (gradient.data()) { - if (!haveCachedGradient + if (!have_cached_gradient_ || !std::equal(parameters.begin(), parameters.end(), - cachedParameters.begin())) { + cached_parameters_.begin())) { // Have to compute anew - cachedStatus = gradFun->evaluate( - parameters, cachedCost, cachedGradient, - logger ? logger : this->logger.get(), &functionCpuSec); - haveCachedCost = true; - haveCachedGradient = true; + cached_status_ = grad_fun_->evaluate( + parameters, cached_cost_, cached_gradient_, + logger ? logger : this->logger_.get(), &functionCpuSec); + have_cached_cost_ = true; + have_cached_gradient_ = true; } // recycle old result - std::copy(cachedGradient.begin(), cachedGradient.end(), gradient.begin()); - fval = cachedCost; + std::copy(cached_gradient_.begin(), cached_gradient_.end(), gradient.begin()); + fval = cached_cost_; } else { - if (!haveCachedCost + if (!have_cached_cost_ || !std::equal(parameters.begin(), parameters.end(), - cachedParameters.begin())) { + cached_parameters_.begin())) { // Have to compute anew - cachedStatus = gradFun->evaluate( - parameters, cachedCost, gsl::span(), - logger ? logger : this->logger.get(), &functionCpuSec); - haveCachedCost = true; - haveCachedGradient = false; + cached_status_ = grad_fun_->evaluate( + parameters, cached_cost_, gsl::span(), + logger ? logger : this->logger_.get(), &functionCpuSec); + have_cached_cost_ = true; + have_cached_gradient_ = false; } - fval = cachedCost; + fval = cached_cost_; } // update cached parameters - cachedParameters.resize(numParameters_); - std::copy(parameters.begin(), parameters.end(), cachedParameters.begin()); + cached_parameters_.resize(num_parameters_); + std::copy(parameters.begin(), parameters.end(), cached_parameters_.begin()); - cpuTimeIterationSec += functionCpuSec; - cpuTimeTotalSec += functionCpuSec; + cpu_time_iteration_sec_ += functionCpuSec; + cpu_time_total_sec_ += functionCpuSec; if (cpuTime) *cpuTime = functionCpuSec; if (afterCostFunctionCall( - parameters, cachedCost, - gradient.data() ? cachedGradient : gsl::span()) != 0) + parameters, cached_cost_, + gradient.data() ? cached_gradient_ : gsl::span()) != 0) return functionEvaluationFailure; - return cachedStatus; + return cached_status_; } int OptimizationReporter::numParameters() const { - return gradFun->numParameters(); + return grad_fun_->numParameters(); } void OptimizationReporter::printObjectiveFunctionFailureMessage() const { - if (logger) - logger->logmessage(LOGLVL_ERROR, "Objective function evaluation failed!"); + if (logger_) + logger_->logmessage(LOGLVL_ERROR, "Objective function evaluation failed!"); } bool OptimizationReporter::starting(gsl::span initialParameters) const { // If this is called multiple times (happens via IpOpt), don't do anything - if (started) + if (started_) return false; - wallTimer.reset(); + wall_timer_.reset(); - if (resultWriter) - resultWriter->starting(initialParameters); + if (result_writer_) + result_writer_->starting(initialParameters); - started = true; + started_ = true; - logger->setPrefix(defaultLoggerPrefix + "i" + std::to_string(numIterations)); + logger_->setPrefix(default_logger_prefix_ + "i" + std::to_string(num_iterations_)); return false; } @@ -267,33 +267,33 @@ bool OptimizationReporter::starting(gsl::span initialParameters) c bool OptimizationReporter::iterationFinished(gsl::span parameters, double objectiveFunctionValue, gsl::span objectiveFunctionGradient) const { - double wallTimeIter = wallTimer.getRound(); - double wallTimeOptim = wallTimer.getTotal(); + double wallTimeIter = wall_timer_.getRound(); + double wallTimeOptim = wall_timer_.getTotal(); - if (logger) - logger->logmessage(LOGLVL_INFO, + if (logger_) + logger_->logmessage(LOGLVL_INFO, "iter: %d cost: %g time_iter: wall: %gs cpu: %gs time_optim: wall: %gs cpu: %gs", - numIterations, objectiveFunctionValue, wallTimeIter, - cpuTimeIterationSec, wallTimeOptim, - cpuTimeTotalSec); + num_iterations_, objectiveFunctionValue, wallTimeIter, + cpu_time_iteration_sec_, wallTimeOptim, + cpu_time_total_sec_); - if (resultWriter) - resultWriter->logOptimizerIteration( - numIterations, parameters.empty() ? cachedParameters : parameters, objectiveFunctionValue, + if (result_writer_) + result_writer_->logOptimizerIteration( + num_iterations_, parameters.empty() ? cached_parameters_ : parameters, objectiveFunctionValue, // This might be misleading, the gradient could evaluated at other parameters if there was a line search inbetween - objectiveFunctionGradient.empty() ? cachedGradient : objectiveFunctionGradient, wallTimeIter, - cpuTimeIterationSec); - ++numIterations; + objectiveFunctionGradient.empty() ? cached_gradient_ : objectiveFunctionGradient, wallTimeIter, + cpu_time_iteration_sec_); + ++num_iterations_; - logger->setPrefix(defaultLoggerPrefix + "i" + std::to_string(numIterations)); + logger_->setPrefix(default_logger_prefix_ + "i" + std::to_string(num_iterations_)); - cpuTimeIterationSec = 0.0; + cpu_time_iteration_sec_ = 0.0; return false; } bool OptimizationReporter::beforeCostFunctionCall(gsl::span /*parameters*/) const { - ++numFunctionCalls; + ++num_function_calls_; //timeCostEvaluationBegin = clock(); return false; @@ -302,15 +302,15 @@ bool OptimizationReporter::beforeCostFunctionCall(gsl::span /*para bool OptimizationReporter::afterCostFunctionCall(gsl::span parameters, double objectiveFunctionValue, gsl::span objectiveFunctionGradient) const { - double wallTime = wallTimer.getTotal(); + double wallTime = wall_timer_.getTotal(); if (!std::isfinite(objectiveFunctionValue)) printObjectiveFunctionFailureMessage(); - if (resultWriter) { - resultWriter->logObjectiveFunctionEvaluation( + if (result_writer_) { + result_writer_->logObjectiveFunctionEvaluation( parameters, objectiveFunctionValue, - objectiveFunctionGradient, numIterations, numFunctionCalls, + objectiveFunctionGradient, num_iterations_, num_function_calls_, wallTime); } return false; @@ -319,43 +319,48 @@ bool OptimizationReporter::afterCostFunctionCall(gsl::span paramet void OptimizationReporter::finished(double optimalCost, gsl::span parameters, int exitStatus) const { - double timeElapsed = wallTimer.getTotal(); + double timeElapsed = wall_timer_.getTotal(); - if ((optimalCost <= cachedCost || cachedParameters.empty()) && !parameters.empty()) { - cachedCost = optimalCost; - cachedParameters.assign(parameters.begin(), parameters.end()); - } else if (cachedCost > optimalCost && parameters.empty()) { + if ((optimalCost <= cached_cost_ || cached_parameters_.empty()) && !parameters.empty()) { + cached_cost_ = optimalCost; + cached_parameters_.assign(parameters.begin(), parameters.end()); + } else if (cached_cost_ > optimalCost && parameters.empty()) { // the optimal value is not from the cached parameters and we did not get // the optimal parameters from the optimizer. since we don't know them, rather set to nan - if (logger) - logger->logmessage(LOGLVL_INFO, "cachedCost != optimalCost && parameters.empty()"); - cachedParameters.assign(cachedParameters.size(), NAN); - cachedCost = optimalCost; + if (logger_) + logger_->logmessage(LOGLVL_INFO, "cachedCost != optimalCost && parameters.empty()"); + cached_parameters_.assign(cached_parameters_.size(), NAN); + cached_cost_ = optimalCost; } // else: our cached parameters were better. use those - if (logger) - logger->logmessage(LOGLVL_INFO, "Optimizer status %d, final llh: %e, " + if (logger_) + logger_->logmessage(LOGLVL_INFO, "Optimizer status %d, final llh: %e, " "time: wall: %f cpu: %f.", exitStatus, - cachedCost, timeElapsed, cpuTimeTotalSec); + cached_cost_, timeElapsed, cpu_time_total_sec_); - if (resultWriter) - resultWriter->saveOptimizerResults(cachedCost, cachedParameters, - timeElapsed, cpuTimeTotalSec, + if (result_writer_) + result_writer_->saveOptimizerResults(cached_cost_, cached_parameters_, + timeElapsed, cpu_time_total_sec_, exitStatus); } double OptimizationReporter::getFinalCost() const { - return cachedCost; + return cached_cost_; } const std::vector &OptimizationReporter::getFinalParameters() const { - return cachedParameters; + return cached_parameters_; } void OptimizationReporter::setGradientFunction(GradientFunction *gradFun) const { - this->gradFun = gradFun; - numParameters_ = gradFun->numParameters(); - cachedGradient.resize(numParameters_); + this->grad_fun_ = gradFun; + num_parameters_ = gradFun->numParameters(); + cached_gradient_.resize(num_parameters_); +} + +std::vector OptimizationReporter::getParameterIds() const +{ + return grad_fun_->getParameterIds(); } void OptimizationProblemImpl::fillParametersMin(gsl::span buffer) const { diff --git a/templates/CMakeLists.template.txt b/templates/CMakeLists.template.txt index 1712b517a..e2ca8c047 100644 --- a/templates/CMakeLists.template.txt +++ b/templates/CMakeLists.template.txt @@ -18,6 +18,9 @@ endif() set(MODEL_NAME mymodel) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + # call project to select language and required by some modules project(${MODEL_NAME}) # for IDE @@ -25,8 +28,9 @@ set(BUILD_TESTS FALSE CACHE BOOL "Build tests?") find_package(Amici REQUIRED) find_package(ParPE REQUIRED) +find_package(OpenMP) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -Wno-unused-function -fopenmp -D_GNU_SOURCE") # -D_GNU_SOURCE for pthread recursive mutex issues +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-function -fopenmp -D_GNU_SOURCE") # -D_GNU_SOURCE for pthread recursive mutex issues execute_process(COMMAND sh -c "cd ${CMAKE_CURRENT_SOURCE_DIR} && git describe --abbrev=4 --dirty=-dirty --always --tags | tr -d '\n'" OUTPUT_VARIABLE GIT_VERSION) message(STATUS "Building version ${GIT_VERSION}") diff --git a/templates/main.cpp b/templates/main.cpp index cb9c8bca8..963239056 100644 --- a/templates/main.cpp +++ b/templates/main.cpp @@ -11,7 +11,9 @@ #include // to avoid including model-specific header files -std::unique_ptr getModel(); +namespace amici::generic_model { + std::unique_ptr getModel(); +} class MyOptimizationApplication : public parpe::OptimizationApplication { public: @@ -30,7 +32,7 @@ class MyOptimizationApplication : public parpe::OptimizationApplication { // setup data and problem dataProvider = std::make_unique( - getModel(), inFileArgument); + amici::generic_model::getModel(), inFileArgument); // read options from file auto optimizationOptions = parpe::OptimizationOptions::fromHDF5(dataProvider->getHdf5FileId()); diff --git a/templates/main_debug.cpp b/templates/main_debug.cpp index f22450385..41243328f 100644 --- a/templates/main_debug.cpp +++ b/templates/main_debug.cpp @@ -7,7 +7,9 @@ #include // to avoid including model-specific header files +namespace amici::generic_model { std::unique_ptr getModel(); +} using namespace parpe; int main(int argc, char **argv) { @@ -23,7 +25,8 @@ int main(int argc, char **argv) { inFileArgument.c_str()); // setup data and problem - MultiConditionDataProviderHDF5 dataProvider(getModel(), inFileArgument); + MultiConditionDataProviderHDF5 dataProvider( + amici::generic_model::getModel(), inFileArgument); auto options = OptimizationOptions::fromHDF5(dataProvider.getHdf5FileId()); diff --git a/templates/main_nominal.cpp b/templates/main_nominal.cpp index 32cef5c0b..7273fb745 100644 --- a/templates/main_nominal.cpp +++ b/templates/main_nominal.cpp @@ -9,7 +9,9 @@ #include // to avoid including model-specific header files +namespace amici::generic_model { std::unique_ptr getModel(); +} using namespace parpe; int main(int argc, char **argv) { @@ -41,7 +43,8 @@ int main(int argc, char **argv) { inFileArgument.c_str()); // setup data and problem - MultiConditionDataProviderHDF5 dataProvider(getModel(), inFileArgument); + MultiConditionDataProviderHDF5 dataProvider( + amici::generic_model::getModel(), inFileArgument); auto options = OptimizationOptions::fromHDF5(dataProvider.getHdf5FileId()); std::unique_ptr rw; @@ -59,7 +62,7 @@ int main(int argc, char **argv) { double fval = NAN; std::vector gradient(optimizationParams.size(), NAN); - problem.costFun->evaluate(optimizationParams, fval, gradient); + problem.cost_fun_->evaluate(optimizationParams, fval, gradient); std::cout< #endif +namespace amici::generic_model { std::unique_ptr getModel(); +} void printUsage() { std::cerr<<"Error: wrong number of arguments.\n"; std::cerr<<"Usage: ... CONDITION_FILE_NAME CONDITION_FILE_PATH " - "[PARAMETER_FILE_NAME PARAMETER_FILE_PATH] " + "PARAMETER_FILE_NAME PARAMETER_FILE_PATH " "OUTFILENAME OUTFILEPATH " - "--at-optimum|--along-trajectory " - "--mpi|--nompi\n"; + "--at-optimum|--along-trajectory|--nominal " + "--mpi|--nompi --compute-inner|--nocompute-inner\n"; // |--parameter-matrix=PATH-UNSUPPORTED } int main(int argc, char **argv) { int status = EXIT_SUCCESS; - if(argc != 7 && argc != 9) { + if(argc != 10) { printUsage(); return EXIT_FAILURE; } + bool computeInner; + if(std::string(argv[argc -1]) == "--compute-inner") { + computeInner = true; + } else if(std::string(argv[argc -1]) == "--nocompute-inner") { + computeInner = false; + } else { + printUsage(); + return EXIT_FAILURE; + } - if(std::string(argv[argc -1]) == "--mpi") { + if(std::string(argv[argc -2]) == "--mpi") { #ifdef PARPE_ENABLE_MPI MPI_Init(&argc, &argv); #else throw std::runtime_error("parPE was built without MPI support."); #endif - } else if(std::string(argv[argc -1]) == "--nompi") { + } else if(std::string(argv[argc -2]) == "--nompi") { ; } else { printUsage(); return EXIT_FAILURE; } - if(argc == 7) { - std::string dataFileName = argv[1]; - std::string dataFilePath = argv[2]; - std::string resultFileName = argv[3]; - std::string resultPath = argv[4]; - std::string simulationMode = argv[5]; - - // TODO: testing-only remove result file - // remove(resultFileName.c_str()); - - parpe::MultiConditionDataProviderHDF5 dp(getModel(), dataFileName.c_str(), dataFilePath + "/inputData"); - status = parpe::runSimulator(dp, simulationMode, - dataFileName, dataFilePath, - dataFileName, dataFilePath, - resultFileName, resultPath); - } else if(argc == 9) { - // simulate on test set: need optimizer result and test set data as inputs - std::string conditionFileName = argv[1]; - std::string conditionFilePath = argv[2]; - std::string parameterFileName = argv[3]; - std::string parameterFilePath = argv[4]; - std::string resultFileName = argv[5]; - std::string resultPath = argv[6]; - std::string simulationMode = argv[7]; - - // TODO: testing-only remove result file - remove(resultFileName.c_str()); - - auto dpPath = conditionFilePath; - { - // check if this is a result file or a new input file - // TODO: this should be handled cleaner - auto file = parpe::hdf5OpenForReading(conditionFileName); - if(parpe::hdf5GroupExists( - file.getId(), - (conditionFilePath + "/inputData").c_str())) - dpPath = conditionFilePath + "/inputData"; - } - - parpe::MultiConditionDataProviderHDF5 dp(getModel(), conditionFileName.c_str(), conditionFilePath); - - status = parpe::runSimulator(dp, simulationMode, - conditionFileName, conditionFilePath, - parameterFileName, parameterFilePath, - resultFileName, resultPath); - } + // simulate on test set: need optimizer result and test set data as inputs + std::string conditionFileName = argv[1]; + std::string conditionFilePath = argv[2]; + std::string parameterFileName = argv[3]; + std::string parameterFilePath = argv[4]; + std::string resultFileName = argv[5]; + std::string resultPath = argv[6]; + std::string simulationMode = argv[7]; + + // TODO: testing-only remove result file + remove(resultFileName.c_str()); + + parpe::MultiConditionDataProviderHDF5 dp( + amici::generic_model::getModel(), + conditionFileName, + conditionFilePath); + + status = parpe::runSimulator(dp, simulationMode, + conditionFileName, conditionFilePath, + parameterFileName, parameterFilePath, + resultFileName, resultPath, computeInner); parpe::finalizeMpiIfNeeded(); diff --git a/tests/parpeamici/amiciSimulationRunnerTest.h b/tests/parpeamici/amiciSimulationRunnerTest.h index 1b72c8f62..8a43e5b4f 100644 --- a/tests/parpeamici/amiciSimulationRunnerTest.h +++ b/tests/parpeamici/amiciSimulationRunnerTest.h @@ -7,21 +7,26 @@ #include - -TEST(simulationWorkerAmici, testSerializeResultPackageMessage) { - parpe::AmiciSimulationRunner::AmiciResultPackageSimple - results = { 1.1, 2.345, std::vector(1.0, 2.0), - std::vector(3.0, 4.0), - std::vector(1.0, 2.0), 10 }; +TEST(simulationWorkerAmici, testSerializeResultPackageMessage) +{ + parpe::AmiciSimulationRunner::AmiciResultPackageSimple results = { + 1.1, + 2.345, + std::vector(1, 2.0), + std::vector(3, 4.0), + std::vector(3, 4.0), + std::vector(1, 2.0), + 10 + }; int msgSize = 0; - auto buffer = std::unique_ptr( - amici::serializeToChar(results, &msgSize)); + auto buffer = + std::unique_ptr(amici::serializeToChar(results, &msgSize)); parpe::AmiciSimulationRunner::AmiciResultPackageSimple resultsAct = - amici::deserializeFromChar< - parpe::AmiciSimulationRunner::AmiciResultPackageSimple>( - buffer.get(), msgSize); + amici::deserializeFromChar< + parpe::AmiciSimulationRunner::AmiciResultPackageSimple>(buffer.get(), + msgSize); EXPECT_EQ(resultsAct, results); } diff --git a/tests/parpeamici/hierarchicalOptimizationTest.h b/tests/parpeamici/hierarchicalOptimizationTest.h index d560bb433..d59108f40 100644 --- a/tests/parpeamici/hierarchicalOptimizationTest.h +++ b/tests/parpeamici/hierarchicalOptimizationTest.h @@ -62,15 +62,14 @@ class AnalyticalParameterProviderMock class AmiciSummedGradientFunctionMock : public parpe::AmiciSummedGradientFunction { public: - MOCK_CONST_METHOD4(getModelOutputs, parpe::FunctionEvaluationStatus( + MOCK_CONST_METHOD5(getModelOutputsAndSigmas, parpe::FunctionEvaluationStatus( gsl::span parameters, std::vector > &modelOutput, + std::vector > &modelSigmas, parpe::Logger *logger, double *cpuTime)); MOCK_CONST_METHOD0(getAllMeasurements, std::vector>()); - MOCK_CONST_METHOD0(getAllSigmas, std::vector>()); - // MOCK_CONST_METHOD6(evaluate, parpe::FunctionEvaluationStatus( // gsl::span parameters, // int dataset, @@ -154,7 +153,7 @@ TEST_F(hierarchicalOptimization, hierarchicalOptimization) { "/sigmaParametersMapToObservables"); parpe::HierarchicalOptimizationWrapper hierarchicalOptimizationWrapper( - std::move(funUnqiue), + funUnqiue.get(), std::move(scalingReaderUnique), std::move(offsetReaderUnique), std::move(sigmaReaderUnique), numConditions, numObservables, parpe::ErrorModel::normal); @@ -183,15 +182,19 @@ TEST_F(hierarchicalOptimization, hierarchicalOptimization) { scalingDummy, offsetDummy, sigmaDummy); EXPECT_EQ(onesFullParameters, splicedParameter); - ON_CALL(*fun, getModelOutputs(_, _, _, _)) + ON_CALL(*fun, getModelOutputsAndSigmas(_, _, _, _, _)) .WillByDefault(DoAll(SetArgReferee<1>(modelOutput), + SetArgReferee<2>(sigmas), Return(parpe::functionEvaluationSuccess))); // Ensure it is called with proper parameter vector: - EXPECT_CALL(*fun, getModelOutputs( - gsl::span(onesFullParameters), _, _, _)); + EXPECT_CALL(*fun, getModelOutputsAndSigmas( + gsl::span(onesFullParameters), _, _, _, _)); - auto outputs = hierarchicalOptimizationWrapper.getUnscaledModelOutputs( + std::vector> outputs; + std::vector> modelSigmas; + std::tie(outputs, modelSigmas) = + hierarchicalOptimizationWrapper.getUnscaledModelOutputsAndSigmas( reducedParameters, nullptr, nullptr); Mock::VerifyAndClearExpectations(fun); @@ -247,7 +250,7 @@ TEST_F(hierarchicalOptimization, testNoAnalyticalParameters) { EXPECT_CALL(*sigmaProvider, getOptimizationParameterIndices()); parpe::HierarchicalOptimizationWrapper w( - std::move(fun), std::move(scalingProvider), + fun.get(), std::move(scalingProvider), std::move(offsetProvider), std::move(sigmaProvider), numConditions, numObservables, parpe::ErrorModel::normal); @@ -521,11 +524,11 @@ TEST_F(hierarchicalOptimization, testWrappedFunIsCalledWithGradient) { ON_CALL(*scalingProvider, getObservablesForParameter(0, 0)) .WillByDefault(ReturnRefOfCopy(res)); ON_CALL(*fun, numParameters()).WillByDefault(Return(numParameters_)); - ON_CALL(*fun, getModelOutputs(_, _, _, _)) + ON_CALL(*fun, getModelOutputsAndSigmas(_, _, _, _, _)) .WillByDefault(DoAll(SetArgReferee<1>(modelOutput), + SetArgReferee<2>(sigmas), Return(parpe::functionEvaluationSuccess))); ON_CALL(*fun, getAllMeasurements()).WillByDefault(Return(measurements)); - ON_CALL(*fun, getAllSigmas()).WillByDefault(Return(sigmas)); EXPECT_CALL(*fun, numParameters()).Times(2); EXPECT_CALL(*scalingProvider, getOptimizationParameterIndices()); @@ -533,10 +536,10 @@ TEST_F(hierarchicalOptimization, testWrappedFunIsCalledWithGradient) { EXPECT_CALL(*sigmaProvider, getOptimizationParameterIndices()); parpe::HierarchicalOptimizationWrapper hierarchicalWrapper( - std::move(fun), std::move(scalingProvider), - std::move(offsetProvider), std::move(sigmaProvider), - numConditions, numObservables, - parpe::ErrorModel::normal); + fun.get(), std::move(scalingProvider), + std::move(offsetProvider), std::move(sigmaProvider), + numConditions, numObservables, + parpe::ErrorModel::normal); Mock::VerifyAndClearExpectations(funNonOwning); Mock::VerifyAndClearExpectations(scalingProviderNonOwning); // Mock::VerifyAndClearExpectations(*offsetProvider); @@ -552,7 +555,7 @@ TEST_F(hierarchicalOptimization, testWrappedFunIsCalledWithGradient) { // ensure fun::evaluate is called with gradient EXPECT_CALL(*funNonOwning, numParameters()); - EXPECT_CALL(*funNonOwning, getModelOutputs(_, _, _, _)); + EXPECT_CALL(*funNonOwning, getModelOutputsAndSigmas(_, _, _, _, _)); EXPECT_CALL(*scalingProviderNonOwning, getConditionsForParameter(0)).Times(2); EXPECT_CALL(*scalingProviderNonOwning, getObservablesForParameter(0, 0)).Times(2); EXPECT_CALL(*funNonOwning, evaluate(_, _, _, Ne(gsl::span()), _, _)); @@ -565,7 +568,7 @@ TEST_F(hierarchicalOptimization, testWrappedFunIsCalledWithGradient) { // test fun::evaluate is not called if no gradient (only get outputs) EXPECT_CALL(*funNonOwning, numParameters()); - EXPECT_CALL(*funNonOwning, getModelOutputs(_, _, _, _)); + EXPECT_CALL(*funNonOwning, getModelOutputsAndSigmas(_, _, _, _, _)); EXPECT_CALL(*scalingProviderNonOwning, getConditionsForParameter(0)) .Times(2); EXPECT_CALL(*scalingProviderNonOwning, getObservablesForParameter(0, 0)) @@ -580,7 +583,7 @@ TEST(hierarchicalOptimization1, likelihoodOfMatchingData) { const double pi = atan(1)*4; const double llhOffset = 0.5 * log(2 * pi); - const double expected = llhOffset * data.size(); + const double expected = llhOffset * static_cast(data.size()); auto actual = parpe::computeNegLogLikelihood(data, data, sigmas); EXPECT_EQ(expected, actual); diff --git a/tests/parpeamici/simulationResultWriterTest.h b/tests/parpeamici/simulationResultWriterTest.h index 2299a4529..cb82c9ffc 100644 --- a/tests/parpeamici/simulationResultWriterTest.h +++ b/tests/parpeamici/simulationResultWriterTest.h @@ -16,9 +16,8 @@ TEST(simulationResultWriter, testResultWriter) { // setup ResultWriter - char tmpName[TMP_MAX]; - if(!std::tmpnam(tmpName)) - std::abort(); + const char* tmpName = "parpeTest_testResultWriter.h5"; + auto _ = gsl::finally([tmpName] { remove(tmpName); }); parpe::SimulationResultWriter rw(tmpName, "/testResultWriter/"); rw.saveLlh = true; @@ -38,10 +37,10 @@ TEST(simulationResultWriter, testResultWriter) { edata.setObservedData(measurements); amici::ReturnData rdata( - timepoints, 0, 1, nx, nx, nx, nytrue, nytrue, 0, 0, 0, 0, 0, 0, + timepoints, 0, 1, nx, nx, nx, 0, nytrue, nytrue, 0, 0, 0, 0, 0, 0, timepoints.size(), 0, 0, std::vector(), amici::SecondOrderMode::none, amici::SensitivityOrder::none, - amici::SensitivityMethod::none); + amici::SensitivityMethod::none, amici::RDataReporting::full); std::iota(rdata.x.begin(), rdata.x.end(), 0); rdata.llh = 1.2345; rdata.y.resize(measurements.size()); @@ -52,7 +51,7 @@ TEST(simulationResultWriter, testResultWriter) { // write rw.createDatasets(numSimulations); - EXPECT_TRUE(parpe::hdf5GroupExists(file.getId(), "/testResultWriter/")); + EXPECT_TRUE(parpe::hdf5GroupExists(file, "/testResultWriter/")); EXPECT_TRUE(parpe::hdf5DatasetExists(file, rw.llhPath)); EXPECT_TRUE(parpe::hdf5DatasetExists(file, rw.xPath)); EXPECT_TRUE(parpe::hdf5DatasetExists(file, rw.yMesPath)); @@ -71,9 +70,8 @@ TEST(simulationResultWriter, testResultWriter) { } TEST(simulationResultWriter, testResultWriterNewExistingFile) { - char tmpName[TMP_MAX]; - if(!std::tmpnam(tmpName)) - std::abort(); + const char* tmpName = "parpeTest_testResultWriterNewExistingFile.h5"; + auto _ = gsl::finally([tmpName] { remove(tmpName); }); // create file parpe::SimulationResultWriter rw1(tmpName, "/testResultWriter/"); diff --git a/tests/parpecommon/commonTests.h b/tests/parpecommon/commonTests.h index 03bb41080..eb78764f7 100644 --- a/tests/parpecommon/commonTests.h +++ b/tests/parpecommon/commonTests.h @@ -78,21 +78,17 @@ TEST(commonMisc, testCreateDirectoryIfNotExists) { char dir[] {"/"}; parpe::createDirectoryIfNotExists(dir); - char tmpName[TMP_MAX]; - if(!std::tmpnam(tmpName)) - std::abort(); + char tmpName[] = "parpeTest_testCreateDirectoryIfNotExists"; + auto _ = gsl::finally([tmpName] { rmdir(tmpName); }); + parpe::createDirectoryIfNotExists(tmpName); - rmdir(tmpName); } TEST(commonMisc, testRecursiveMkpath) { - char tmpName[TMP_MAX]; - if(!std::tmpnam(tmpName)) - std::abort(); - std::string name(tmpName); - name += "/a/b/c"; + std::string name {"parpeTest_testRecursiveMkpath/a/b/c"}; + auto _ = gsl::finally([name] { rmdir(name.c_str()); }); + parpe::mkpathConstChar(name.c_str(), 0755); - rmdir(name.c_str()); } TEST(commonMisc, testRandDouble) { diff --git a/tests/parpecommon/hdf5MiscTests.h b/tests/parpecommon/hdf5MiscTests.h index 2b671db25..6d7f09e58 100644 --- a/tests/parpecommon/hdf5MiscTests.h +++ b/tests/parpecommon/hdf5MiscTests.h @@ -15,16 +15,16 @@ class hdf5Misc : public ::testing::Test { H5::H5Library::dontAtExit(); parpe::initHDF5Mutex(); - fileId = parpe::hdf5CreateFile(std::tmpnam(tempFileName), false); + fileId = parpe::hdf5CreateFile(tempFileName, false); } void TearDown() override { if(fileId) H5Fclose(fileId); - std::remove(tempFileName); + std::remove(tempFileName.c_str()); } - char tempFileName[TMP_MAX]; + std::string tempFileName {"parpeTest_hdf5Misc.h5"}; hid_t fileId = 0; }; @@ -51,7 +51,7 @@ TEST_F(hdf5Misc, testErrorStackWalker) { H5_SAVE_ERROR_HANDLER; // provoke error by asking to truncate a file that is already open - hid_t fileId = H5Fcreate(tempFileName, H5F_ACC_TRUNC, + hid_t fileId = H5Fcreate(tempFileName.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); EXPECT_TRUE(fileId <= 0); diff --git a/tests/parpecommon/testingMisc.cpp b/tests/parpecommon/testingMisc.cpp index 7ff977b53..e3cc80d4d 100644 --- a/tests/parpecommon/testingMisc.cpp +++ b/tests/parpecommon/testingMisc.cpp @@ -12,6 +12,7 @@ #include #include +#include #include namespace parpe { @@ -85,17 +86,12 @@ std::string captureStreamToString(const std::function& f, std::string captureStreamToString(const std::function& f, std::FILE* captureStream, int captureStreamFd) { - // use fmemopen instead of file? - - char tempFileName[TMP_MAX]; - if(!std::tmpnam(tempFileName)) - std::abort(); - - int newStreamFd = open(tempFileName, O_CREAT | O_WRONLY, S_IRWXU); - assert(newStreamFd >= 0); + char tempFileName [] = "parpeTestCaptureXXXXXX"; + int newStreamFd = mkstemp(tempFileName); + Expects(newStreamFd >= 0); int oldStreamFd = dup(captureStreamFd); - assert(oldStreamFd >= 0); + Expects(oldStreamFd >= 0); fflush(captureStream); dup2(newStreamFd, captureStreamFd); // replace original fd by tmp file diff --git a/tests/parpeoptimization/localOptimizationCeresTest.h b/tests/parpeoptimization/localOptimizationCeresTest.h index 486756cbf..ec14a1ff5 100644 --- a/tests/parpeoptimization/localOptimizationCeresTest.h +++ b/tests/parpeoptimization/localOptimizationCeresTest.h @@ -39,7 +39,7 @@ TEST(localOptimizationCeres, testOptimization) { // Needed to run on shippable.com auto params = std::get<2>(result); double optimalCost = NAN; - problem.costFun->evaluate(params, optimalCost, gsl::span()); + problem.cost_fun_->evaluate(params, optimalCost, gsl::span()); EXPECT_NEAR(42.0, optimalCost, 1e-6); } @@ -57,10 +57,10 @@ TEST(localOptimizationCeres, testReporterCalled) { problem.setOptimizationOptions(o); EXPECT_CALL(*problem.reporter, starting(_)); - EXPECT_CALL(*dynamic_cast(problem.costFun.get()), + EXPECT_CALL(*dynamic_cast(problem.cost_fun_.get()), numParameters()).Times(3); EXPECT_CALL(*problem.reporter, beforeCostFunctionCall(_)).Times(1 + o.maxOptimizerIterations); - EXPECT_CALL(*dynamic_cast(problem.costFun.get()), + EXPECT_CALL(*dynamic_cast(problem.cost_fun_.get()), evaluate_impl(_, _, Ne(gsl::span()), _, _)).Times(1 + o.maxOptimizerIterations); EXPECT_CALL(*problem.reporter, iterationFinished(_, _, _)).Times(1 + o.maxOptimizerIterations); EXPECT_CALL(*problem.reporter, afterCostFunctionCall(_, _, _)).Times(1 + o.maxOptimizerIterations); diff --git a/tests/parpeoptimization/localOptimizationIpoptTest.h b/tests/parpeoptimization/localOptimizationIpoptTest.h index 981a94345..29f1870f6 100644 --- a/tests/parpeoptimization/localOptimizationIpoptTest.h +++ b/tests/parpeoptimization/localOptimizationIpoptTest.h @@ -17,9 +17,9 @@ TEST(localOptimizationIpopt, testOptimizationResult) { EXPECT_CALL(*problem.reporter, starting(_)); EXPECT_CALL(*problem.reporter, finished(_, _, 0)); - EXPECT_CALL(*dynamic_cast(problem.costFun.get()), + EXPECT_CALL(*dynamic_cast(problem.cost_fun_.get()), evaluate_impl(_, _, Eq(gsl::span()), _, _)).Times(AtLeast(1)); - EXPECT_CALL(*dynamic_cast(problem.costFun.get()), + EXPECT_CALL(*dynamic_cast(problem.cost_fun_.get()), evaluate_impl(_, _, Ne(gsl::span()), _, _)).Times(AtLeast(1)); // TODO mock().ignoreOtherCalls(); @@ -44,11 +44,11 @@ TEST(localOptimizationIpopt, testReporterCalled) { EXPECT_CALL(*problem.reporter, starting(_)); EXPECT_CALL(*problem.reporter, beforeCostFunctionCall(_)).Times(3 + o.maxOptimizerIterations * 2); - EXPECT_CALL(*dynamic_cast(problem.costFun.get()), + EXPECT_CALL(*dynamic_cast(problem.cost_fun_.get()), evaluate_impl(_, _, Ne(gsl::span()), _, _)).Times(1 + o.maxOptimizerIterations); - EXPECT_CALL(*dynamic_cast(problem.costFun.get()), + EXPECT_CALL(*dynamic_cast(problem.cost_fun_.get()), evaluate_impl(_, _, Eq(gsl::span()), _, _)).Times(o.maxOptimizerIterations); - EXPECT_CALL(*dynamic_cast(problem.costFun.get()), + EXPECT_CALL(*dynamic_cast(problem.cost_fun_.get()), numParameters()).Times(2 + 0*o.maxOptimizerIterations); EXPECT_CALL(*problem.reporter, iterationFinished(_, _, _)).Times(1 + o.maxOptimizerIterations); EXPECT_CALL(*problem.reporter, afterCostFunctionCall(_, _, _)).Times(3 + o.maxOptimizerIterations * 2); diff --git a/tests/parpeoptimization/minibatchOptimizationTest.h b/tests/parpeoptimization/minibatchOptimizationTest.h index a39a4d036..955609e9d 100644 --- a/tests/parpeoptimization/minibatchOptimizationTest.h +++ b/tests/parpeoptimization/minibatchOptimizationTest.h @@ -112,10 +112,10 @@ class minibatchOptimizationLinearModel : public ::testing::Test { auto sgf = std::make_unique < parpe::SummedGradientFunctionGradientFunctionAdapter > (std::move(lm2), dataIndices); auto p = std::make_unique(); - p->costFun = std::move(sgf); + p->cost_fun_ = std::move(sgf); p->setParametersMin(std::vector(trueParameters.size(), 0.0)); p->setParametersMax(std::vector(trueParameters.size(), 5.0)); - p->logger = std::make_unique(); + p->logger_ = std::make_unique(); return p; } diff --git a/tests/parpeoptimization/optimizationOptionsTest.h b/tests/parpeoptimization/optimizationOptionsTest.h index 9565ebcb7..fc2cdeb9f 100644 --- a/tests/parpeoptimization/optimizationOptionsTest.h +++ b/tests/parpeoptimization/optimizationOptionsTest.h @@ -104,9 +104,8 @@ TEST(optimizationOptions, setCeresOptions) { #endif TEST(optimizationOptions, fromHDF5) { - char tmpName[TMP_MAX]; - if(!std::tmpnam(tmpName)) - std::abort(); + const char* tmpName = "parpeTest_fromHDF5.h5"; + auto _ = gsl::finally([tmpName] { remove(tmpName); }); // fail on non-existing file (hide hdf5 errors) parpe::captureStreamToString([tmpName](){ @@ -138,6 +137,4 @@ TEST(optimizationOptions, fromHDF5) { EXPECT_EQ(optimizer, static_cast(o->optimizer)); EXPECT_EQ(optimizer, o->getIntOption("someOption")); EXPECT_TRUE(o->toString().size() > 50); - - remove(tmpName); } diff --git a/tests/parpeoptimization/optimizationProblemTest.h b/tests/parpeoptimization/optimizationProblemTest.h index c6520531f..639849609 100644 --- a/tests/parpeoptimization/optimizationProblemTest.h +++ b/tests/parpeoptimization/optimizationProblemTest.h @@ -85,6 +85,10 @@ class SummedGradientFunctionLinearModelTest return numParameters_; } + std::vector getParameterIds() const override { + return std::vector {"p1", "p2"}; + } + int numParameters_ = 2; }; diff --git a/tests/parpeoptimization/optimizationResultWriterTest.h b/tests/parpeoptimization/optimizationResultWriterTest.h index 179d6b1b2..2f05edbd7 100644 --- a/tests/parpeoptimization/optimizationResultWriterTest.h +++ b/tests/parpeoptimization/optimizationResultWriterTest.h @@ -13,7 +13,7 @@ TEST(optimizationResultWriter, testResultWriter) { H5::H5File file(tmpFilename, H5F_ACC_RDONLY); - EXPECT_TRUE(parpe::hdf5GroupExists(file.getId(), "/bla")); + EXPECT_TRUE(parpe::hdf5GroupExists(file, "/bla")); w.setRootPath("/bla2"); diff --git a/tests/parpeoptimization/quadraticTestProblem.cpp b/tests/parpeoptimization/quadraticTestProblem.cpp index 1d1c37bc8..213c820b7 100644 --- a/tests/parpeoptimization/quadraticTestProblem.cpp +++ b/tests/parpeoptimization/quadraticTestProblem.cpp @@ -23,7 +23,7 @@ QuadraticTestProblem::QuadraticTestProblem(std::unique_ptr logger) setOptimizationOptions(options); // will keep ref, but will be passed as unique pointer, so getReporter // must only be called once - reporter = new NiceMock(costFun.get(), + reporter = new NiceMock(cost_fun_.get(), std::make_unique()); } @@ -90,6 +90,11 @@ int QuadraticGradientFunction::numParameters() const return 1; } +std::vector QuadraticGradientFunction::getParameterIds() const +{ + return std::vector {"p1"}; +} + bool OptimizationReporterTest::starting(gsl::span /*parameters*/) const { // mock().actualCall("OptimizationReporterTest::starting"); diff --git a/tests/parpeoptimization/quadraticTestProblem.h b/tests/parpeoptimization/quadraticTestProblem.h index 519d58e2e..77830b2df 100644 --- a/tests/parpeoptimization/quadraticTestProblem.h +++ b/tests/parpeoptimization/quadraticTestProblem.h @@ -107,6 +107,7 @@ class QuadraticGradientFunction : public GradientFunction { double *cpuTime = nullptr) const override; int numParameters() const override; + std::vector getParameterIds() const override; }; class QuadraticGradientFunctionMock : public GradientFunction { @@ -130,6 +131,7 @@ class QuadraticGradientFunctionMock : public GradientFunction { } MOCK_CONST_METHOD0(numParameters, int()); + MOCK_CONST_METHOD0(getParameterIds, std::vector()); private: